Reputation: 4054
Consider the following XML:
<root>
<a>
<pos>
<c val="abc"></c>
<c val="def"></c>
<c val="ghi"></c>
<c val="jkl"></c>
<c val="mno"></c>
</pos>
<b>
<c></c>
</b>
<b>
<c></c>
<d>here</d>
</b>
<b>
<e>and</e>
<c></c>
<d>for</d>
</b>
<b>
<c></c>
<c></c>
<d>also</d>
</b>
</a>
<a>
<pos>
<c val="pqr"></c>
<c val="stu"></c>
<c val="vwx"></c>
<c val="yz"></c>
</pos>
<b>
<c></c>
<d>what</d>
</b>
<b>
<c></c>
</b>
<b>
<d>how</d>
</b>
<b>
<c></c>
<d>where</d>
<c></c>
</b>
</a>
</root>
Now in my output, when ever I encounter a <c></c>
inside a b
, I need to put the corresponding value of the val
attribute of a <c></c>
from the <pos></pos>
node. By corresponding value I mean the index of node c
inside pos
should be the same as the index of c
in all the b
nodes combined.
The desired output is:
<start>
<level>
abc
</level>
<level>
def
here
</level>
<level>
and
ghi
for
</level>
<level>
jkl
mno
also
</level>
<start>
<start>
<level>
pqr
what
</level>
<level>
stu
</level>
<level>
how
</level>
<level>
vwx
where
yz
</level>
</start>
I attempted it with the following XSL:
<xsl:template match="root">
<star>
<xsl:apply-templates select="a"/>
</start>
</xsl:template>
<xsl:template match="a">
<xsl:apply-templates select="b"/>
</xsl:template>
<xsl:template match="b">
<level>
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="name() = 'd'">
<xsl:value-of select="."/>
</xsl:when>
<xsl:when test="name() = 'e'">
<xsl:value-of select="."/>
</xsl:when>
<xsl:when test="name() = 'c'">
<xsl:variable name="posCount">
<!-- I don't know what to do here -->
</xsl:valiable>
<xsl:for-each select="ancestor::a[1]/pos">
<xsl:for-each select="c[position() = $posCount]">
<xsl:value-of select="@val"/>
</xsl:for-each>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</level>
</xsl:template>
What I need to do is somehow get the position count of each c
inside all the b
s combined and then use the value of val
attribute of correspondingly positioned c
from inside pos
.
How can I proceed to do it?
Note: I am using XSLT 1.0
Thnx in advance!!
Upvotes: 4
Views: 16142
Reputation: 116959
The index number you are looking for can be obtained quite easily by using the xsl:number
element. For example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="root">
<root>
<xsl:apply-templates select="a"/>
</root>
</xsl:template>
<xsl:template match="a">
<start>
<xsl:apply-templates select="b"/>
</start>
</xsl:template>
<xsl:template match="b">
<level>
<xsl:text> </xsl:text>
<xsl:apply-templates select="*"/>
</level>
</xsl:template>
<xsl:template match="d|e">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="b/c">
<xsl:variable name="i">
<xsl:number count="b/c" from="a" level="any" />
</xsl:variable>
<xsl:value-of select="ancestor::a/pos/c[number($i)]/@val"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
Notes:
1. I have added a root
element to the output to make it a valid XML;
2. It would be best to use a key to get the corresponding value from pos/c
.
Upvotes: 7
Reputation: 5432
I think this will do:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<levels>
<xsl:apply-templates select="//b[c]"/>
</levels>
</xsl:template>
<xsl:template match="b">
<level>
<xsl:apply-templates />
</level>
</xsl:template>
<xsl:template match="c">
<xsl:variable name="pos" select="count(preceding::b/c) + count(preceding-sibling::c) + 1"/>
<xsl:value-of select="//pos/c[$pos]/@val"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0