Reputation: 13
Need sequence number based on the nesting of the element. In below example all the reference elements which is not child of any reference element will have sequence number, any nested reference element should have parent sequence number + decimal + position of current reference element.
Input.xml
<root>
<front>
<reference1 type="ref" href="a.xml">
<reference1 type="ref" href="x.xml"/>
<reference1 type="ref" href="z.xml"/>
</reference>
</front>
<reference2 type="ref" href="b.xml"/>
<reference2 type="ref" href="c.xml">
<reference2 type="ref" href="d.xml">
<reference2 type="ref" href="y.xml"/>
</reference>
</reference>
<back>
<reference3 type="ref" href="e.xml"/>
</back>
</root>
Output.xml
<root>
<reference href="a.xml" sequence="1"/>
<reference href="x.xml" sequence="1.1"/>
<reference href="z.xml" sequence="1.2"/>
<reference href="b.xml" sequence="2"/>
<reference href="c.xml" sequence="3"/>
<reference href="d.xml" sequence="3.1"/>
<reference href="y.xml" sequence="3.1.1"/>
<reference href="e.xml" sequence="4"/>
</root>
I am trying this but not able to get the logic:
<xsl:template match="/">
<root>
<xsl:for-each select="//reference">
<reference>
<xsl:attribute name="href">
<xsl:value-of select="@href"/>
</xsl:attribute>
<xsl:if test="not(child::reference)">
<xsl:attribute name="sequence">
<xsl:value-of select="position()"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="child::reference">
<!-- something to be done here -->
</xsl:if>
</reference>
</xsl:for-each>
</root>
Thanks
Upvotes: 1
Views: 494
Reputation: 52868
My suggestion would be to use <xsl:number level="multiple"/>
to do the counting for you. I think that in order for the counts to be correct, you'd have to narrow it down to just reference
elements. I might be wrong and there could be an easier way, but I only had a few minutes to spend on this.
In my example, I use a moded template and assigned the cleaned results to a variable. I then apply-templates to that variable to do the actual transform.
This will only work in XSLT 2.0, but since you tagged the question 2.0 you should be ok.
XML Input (added a couple of <foo/>
elements for testing)
<root>
<front>
<reference href="a.xml">
<reference href="x.xml"/>
<reference href="z.xml"/>
</reference>
</front>
<reference href="b.xml"/>
<foo/>
<reference href="c.xml">
<reference href="d.xml">
<foo>
<reference href="y.xml"/>
</foo>
</reference>
</reference>
<back>
<reference href="e.xml"/>
</back>
</root>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="refs">
<refs>
<xsl:apply-templates select="/*//reference[not(ancestor::reference)]" mode="clean"/>
</refs>
</xsl:variable>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="$refs"/>
</xsl:copy>
</xsl:template>
<xsl:template match="reference">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="x">
<xsl:number level="multiple"/>
</xsl:attribute>
</xsl:copy>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="reference" mode="clean">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select=".//reference[ancestor::reference[1] is current()]" mode="clean"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<root>
<reference href="a.xml" x="1"/>
<reference href="x.xml" x="1.1"/>
<reference href="z.xml" x="1.2"/>
<reference href="b.xml" x="2"/>
<reference href="c.xml" x="3"/>
<reference href="d.xml" x="3.1"/>
<reference href="y.xml" x="3.1.1"/>
<reference href="e.xml" x="4"/>
</root>
EDIT
Here's an updated stylesheet for the updated input in the question. I only needed to change reference
to *[@type='ref']
and add a count
attribute to xsl:number
.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="refs">
<refs>
<xsl:apply-templates select="/*//*[@type='ref'][not(ancestor::*[@type='ref'])]" mode="clean"/>
</refs>
</xsl:variable>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="$refs"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@type='ref']">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="x">
<xsl:number count="*[@type='ref']" level="multiple"/>
</xsl:attribute>
</xsl:copy>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[@type='ref']" mode="clean">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select=".//*[@type='ref'][ancestor::*[@type='ref'][1] is current()]" mode="clean"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1