Reputation: 107
For this xml:
<G>
<P>
<A>
<b>value b</b>
<c>value c</c>
</A>
<A>
<b>value b2</b>
<c>value c2</c>
</A>
<D>value ew</D>
<D>value e2</D>
<E>value f</E>
</P>
<P>
<A>
<b>value bx</b>
<c>value cx</c>
</A>
<A>
<b>value b2x</b>
<c>value c2x</c>
</A>
<D>value exw</D>
<D>value ex2</D>
<D>value ex2</D>
<E>value fx</E>
</P>
</G>
The tags like A and D can occur multiple times , the original xml on which I am working has large number of tags and many of them have multiple occurences.
I have to genetrate output as :
value b value c value ew value f
value b value c value e2 value f
value b2 value c2 value ew value f
value b2 value c2 value e2 value f
value bx value cx value exw value fx
value bx value cx value ex2 value fx
value bx value cx value ex3 value fx
value b2x value c2x value exw value fx
value b2x value c2x value ex2 value fx
value b2x value c2x value ex3 value fx
This xslt generates correct output if A tag has multiple occurence ,but when other tags like D in above xml repeat this does not work.
<xsl:for-each select="//A">
<xsl:value-of select="b"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="c"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="ancestor::P/D"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="ancestor::P/E"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
Please suggest correct xslt
Upvotes: 0
Views: 216
Reputation: 70618
I think this can be achieved by using repeated calls to templates. First you have a template to match A but instead of outputting the b and c elements, you pass them as parameters to a template that matches the D elemenet
<xsl:template match="A">
<xsl:apply-templates select="following-sibling::D">
<xsl:with-param name="prefix">
<xsl:value-of select="b"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="c"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
And then, within the the template that matches the D element, you concatenate the prefix with the value of D, and pass it to a template that matches the E element.
<xsl:template match="D">
<xsl:param name="prefix"/>
<xsl:apply-templates select="following-sibling::E">
<xsl:with-param name="prefix">
<xsl:value-of select="$prefix"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="."/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
And then the template that matches the E element can output the whole string. Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//A"/>
</xsl:template>
<xsl:template match="A">
<xsl:apply-templates select="following-sibling::D">
<xsl:with-param name="prefix">
<xsl:value-of select="b"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="c"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="D">
<xsl:param name="prefix"/>
<xsl:apply-templates select="following-sibling::E">
<xsl:with-param name="prefix">
<xsl:value-of select="$prefix"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="."/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="E">
<xsl:param name="prefix"/>
<xsl:value-of select="$prefix"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="."/>
<xsl:value-of select="' '"/>
</xsl:template>
</xsl:stylesheet>
When applied to your XML sample, the following is output
value b,value c,value ew,value f
value b,value c,value e2,value f
value b2,value c2,value ew,value f
value b2,value c2,value e2,value f
value bx,value cx,value exw,value fx
value bx,value cx,value ex2,value fx
value bx,value cx,value ex2,value fx
value b2x,value c2x,value exw,value fx
value b2x,value c2x,value ex2,value fx
value b2x,value c2x,value ex2,value fx
Upvotes: 1
Reputation: 501
Here's a possible solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name='s' select='","' />
<xsl:template match="A">
<xsl:variable name='b' select='b' />
<xsl:variable name='c' select='c' />
<xsl:for-each select="../D"><xsl:value-of select='$b' /><xsl:value-of select='$s' /><xsl:value-of select='$c' /><xsl:value-of select='$s' /><xsl:value-of select='.'/><xsl:value-of select='$s' /><xsl:value-of select='../E'/><xsl:text>
</xsl:text></xsl:for-each>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
Note that it looks for all A, and for each A outputs a line for each D sibling of A. Note sure that this is what you wanted
It gives the output:
value b,value c,value ew,value f
value b,value c,value e2,value f
value b2,value c2,value ew,value f
value b2,value c2,value e2,value f
value bx,value cx,value exw,value fx
value bx,value cx,value ex2,value fx
value bx,value cx,value ex2,value fx
value b2x,value c2x,value exw,value fx
value b2x,value c2x,value ex2,value fx
value b2x,value c2x,value ex2,value fx
Upvotes: 1