Reputation: 1278
In the following XML and XSLT, in xml where element 'i' is present location, by there I need to find the preceding-siblings last child text.
Input1.xml
<root>
<aa>
<a>
<b>Text1</b>
<c>Text2</c>
<d>Text3
<n>Text11
<o>Text12
<p>Text13</p>
</o>
</n>
</d>
</a>
<e>
<f>
<g>Text4</g>
</f>
<h>Text5
<j>Text7</j>
<k>Text8</k>
</h>
</e>
<i>Text6</i>
</aa>
</root>
Child.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="i">
<xsl:variable name="var0"><xsl:apply-templates select="preceding-sibling::*[1]"/></xsl:variable>
<xsl:variable name="var1">
<xsl:for-each select="var0">
<xsl:value-of select="child::*[last()]"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="var2">
<xsl:for-each select="$var1">
<xsl:value-of select="child::*[last()]"/>
</xsl:for-each>
</xsl:variable>
<ppp><xsl:copy-of select="."/><jj>-The last preceding child text is <xsl:value-of select="$var2"/>-</jj></ppp>
</xsl:template>
</xsl:stylesheet>
Required output is
Text6The last preceding child text is - Text8
Upvotes: 1
Views: 3795
Reputation: 8058
It looks like you mean previous sibling's last descendent non-whitespace, not last child text. (Remember, the indendation you've shown us in the XML file is also text nodes.)
Get the preceding sibling element. Get its text-node descendants. From those select the non-whitespace ones. From those, select the last one.
Should be something like:
select="preceding-sibling::*/descendant::text()[normalize-space()!=''][last()]"
(where I'm taking advantage of the fact that the principal node type of preceding-sibling is element).
That finds the text node. To get its containing element, add one more step to the path:
select="preceding-sibling::*/descendant::text()[normalize-space()!=''][last()]/parent::*"
(again, taking advantage of the fact that the principal node type of parent is element).
If you're going to work with XPath and XSLT, it's worth spending some time really getting used to predicates. They're what permits layering complex constraints into a single path, and they add a LOT of power to the language.
Upvotes: 7
Reputation: 20741
To test whether a node is of type text you add text() after the selector:
preceding-sibling::text()
And it seems to me that all you need in var2 is this:
preceding::text()
and var2 will be the text node you're looking for.
Upvotes: 2