I've been trying to come up with a decent solution to this, but I couldn't even find an indecent one.
I have a XML file that looks a bit like this:
<Root>
<Something>
<SomethingElse>Value of SomethingElse</SomethingElse>
</Something>
...
<Map>
<Node>
<Path>/Root/Something/SomethingElse</Path>
</Node>
<Map>
...
</Root>
What I want to do is write an XSL transformation that would take the <Path> element and use its text() value as an XPath query to apply a transformation to the <SomethingElse> element, resulting in something like e.g.:
<text>Value of SomethingElse</text>
The first thing that popped into my mind was something along the lines of:
<xsl:template match="Path">
<text><xsl:value-of select="{text()}"/></text>
</xsl:template>
but this of course doesn't work as select is not a value attribute.
I have no idea how to go about this. Google search only returned results on how to use XPath to obtain text values, not the other way around.
I would also like to apply further transformations to the returned <SomethingElse> element, but that should be a piece of cake once I figure out how to do this.
Thanks a bunch for getting this far,
Slampisko
With pure XSLT 1.0 and even 2.0 you need to use two stylesheets, the first takes the input and creates a second stylesheet as its result with the XPath expression you want to use, then you run the second stylesheet against the original input.
Or you need to check whether your XSLT processor supports an extension function to evaluate a string as a path expression, like Saxon has with http://www.saxonica.com/documentation/extensions/functions/evaluate.xml or like AltovaXML has with its altova:evaluate function http://manual.altova.com/AltovaXML/altovaxmlcommunity/index.html?xextaltova_general.htm.
While full dynamic XPath evaluation isn't part of either XSLT 1.0/XPath 1.0 or XSLT 2.0/XPath 2.0, one can produce an XSLT 1.0 implementation of something that would work in a rather limited way:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="text()"/>
<xsl:template match="Path" name="eval">
<xsl:param name="pPath" select="."/>
<xsl:param name="pContext" select="/"/>
<xsl:choose>
<!-- If there is something to evaluate -->
<xsl:when test="string-length($pPath) >0">
<xsl:variable name="vPath" select=
"substring($pPath,2)"/>
<xsl:variable name="vNameTest">
<xsl:choose>
<xsl:when test="not(contains($vPath, '/'))">
<xsl:value-of select="$vPath"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=
"substring-before($vPath, '/')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="eval">
<xsl:with-param name="pPath" select=
"substring-after($pPath, $vNameTest)"/>
<xsl:with-param name="pContext" select=
"$pContext/*[name()=$vNameTest]"/>
</xsl:call-template>
</xsl:when>
<!-- Otherwise we have evaluated completely the path -->
<xsl:otherwise>
<xsl:copy-of select="$pContext"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<Root>
<Something>
<SomethingElse>Value of SomethingElse</SomethingElse>
</Something>
...
<Map>
<Node>
<Path>/Root/Something/SomethingElse</Path>
</Node>
</Map>
...
</Root>
the wanted, correct result is produced:
<SomethingElse>Value of SomethingElse</SomethingElse>
We assume the following limitations:
Every XPath expression that we evaluate must consist of a sequence of name-tests, delimited by the XPath '/' operator -- that is, every location step only specifies a single element name.
No axes or predicates can be contained in any location step.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With