I need to move the <sectionid/>
and the <sponsor/>
elements inside the corresponding <amendment/>
.
Here is an example:
From :
<root>
<sectionid>A</sectionid>
<sponsor>john</sponsor>
<sponsor>paul</sponsor>
<amendment>
<id>1</id>
<text>some text</text>
</amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<amendment>
<id>5</id>
<text>some text</text>
</amendment>
<amendment>
<id>4</id>
<text>some text</text>
</amendment>
<sponsor>max</sponsor>
<amendment>
<id>6</id>
<text>some text</text>
</amendment>
<amendment>
<id>7</id>
<text>some text</text>
</amendment>
</root>
to:
<root>
<amendment>
<sectionid>A</sectionid>
<sponsor>john</sponsor>
<sponsor>paul</paul>
<id>1</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>5</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>4</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>max</sponsor>
<id>6</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>max</sponsor>
<id>7</id>
<text>some text</text>
</amendment>
</root>
Note 1: the <section/>
element applies to all the <amendments/>
before the next <sectionid/>
Note 2: the <sponsor/>
element applies to all the <amendments/>
before the next <sponsor/>
list.
Note 3: The values of //amendment/id
are not sequential.
How can this transformation be done with XSLT 1.0.
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:param name="pSectionId"/>
<xsl:param name="pSponsors"/>
<xsl:copy>
<xsl:apply-templates select="node()[1]|@*"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="pSectionId" select="$pSectionId"/>
<xsl:with-param name="pSponsors" select="$pSponsors"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="sectionid">
<xsl:param name="pSectionId"/>
<xsl:param name="pSponsors"/>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="pSectionId" select="."/>
<xsl:with-param name="pSponsors" select="$pSponsors"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="sponsor">
<xsl:param name="pSectionId"/>
<xsl:param name="pSponsors"/>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="pSectionId" select="$pSectionId"/>
<xsl:with-param name="pSponsors" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="sponsor[preceding-sibling::node()[1]/self::sponsor]">
<xsl:param name="pSectionId"/>
<xsl:param name="pSponsors"/>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="pSectionId" select="$pSectionId"/>
<xsl:with-param name="pSponsors" select="$pSponsors|."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="amendment">
<xsl:param name="pSectionId"/>
<xsl:param name="pSponsors"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:copy-of select="$pSectionId|$pSponsors"/>
<xsl:apply-templates select="node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="pSectionId" select="$pSectionId"/>
<xsl:with-param name="pSponsors" select="$pSponsors"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Output:
<root>
<amendment>
<sectionid>A</sectionid>
<sponsor>john</sponsor>
<sponsor>paul</sponsor>
<id>1</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>5</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>4</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>max</sponsor>
<id>6</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>max</sponsor>
<id>7</id>
<text>some text</text>
</amendment>
</root>
Note: Fine grained traversal. Linear complexity.
Edit: New input sample.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="amendment">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:variable name="vSectionId"
select="preceding-sibling::sectionid[1]"/>
<xsl:variable name="vprevAmendment"
select="preceding-sibling::amendment[1]"/>
<xsl:apply-templates select="$vSectionId" mode="copy"/>
<xsl:variable name="vsectSponsors"
select="preceding-sibling::sponsor
[generate-id(preceding-sibling::sectionid[1])
=
generate-id($vSectionId)
]"/>
<xsl:variable name="vamdSponsors"
select="preceding-sibling::sponsor
[generate-id(preceding-sibling::amendment[1])
=
generate-id($vprevAmendment)
]"/>
<xsl:apply-templates mode="copy"
select="$vamdSponsors|$vsectSponsors[not($vamdSponsors)]"/>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="copy">
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="sectionid|sponsor"/>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<sectionid>A</sectionid>
<sponsor>john</sponsor>
<sponsor>paul</sponsor>
<amendment>
<id>1</id>
<text>some text</text>
</amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<amendment>
<id>5</id>
<text>some text</text>
</amendment>
<amendment>
<id>4</id>
<text>some text</text>
</amendment>
<sponsor>max</sponsor>
<amendment>
<id>6</id>
<text>some text</text>
</amendment>
</root>
produces the wanted, correct results:
<root>
<amendment>
<sectionid>A</sectionid>
<sponsor>john</sponsor>
<sponsor>paul</sponsor>
<id>1</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>5</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>peter</sponsor>
<id>4</id>
<text>some text</text>
</amendment>
<amendment>
<sectionid>B</sectionid>
<sponsor>max</sponsor>
<id>6</id>
<text>some text</text>
</amendment>
</root>