Click to See Complete Forum and Search --> : XSL,XPath: How to use xpath expression in source xml
markupper
08-15-2007, 07:28 AM
I would like to ask for help. For example my xml source has some attribute node whose value is an xpath expression. How would I use that value as an xpath expression in my xsl?
e.g.
<tag attr=/tag2/somechild/>
<tag2><somechild>value</somechild></tag2>
<tag3><somechild2>value2</somechild2></tag3>
In my case, the value of the attribute "attr" is dynamic (changing), and I want my xsl file to access the value according to the value of "attr" (an xpath expression). How can I do this? That is, how can I write the xpath expression that would select the value that the value of the "attr" points to?
In essence, I would like to have something like:
<xsl:for-each select="the xpath expression in the value of attr">, and
<xsl:value-of select="the xpath expression in the value of attr">
but how can I do this?
Thank you very much!
jkmyoung
08-15-2007, 12:31 PM
exslt
http://www.exslt.org/dyn/functions/evaluate/
If you are able to call an external function, you could use either javascript's or .Net's SelectNodes property. eg http://www.thescripts.com/forum/thread177329.html
markupper
08-15-2007, 09:42 PM
Thanks! I'll try.
Are there other ways, especially those that are innate in xsl. That is, anything that does not call external functions?
Thanks in advance.
jkmyoung
08-16-2007, 10:35 AM
If you have a really simple path, it's possible to do the value-of purely in XSLT. Basically, it's a recursive template, that holds 2 variables.
1. Current Context position.
2. Current String.
Can't currently find the code for it, but am looking.
For-each is harder, and would probably require the use of either multiple templates and/or a node-set extension function.
jkmyoung
08-16-2007, 12:39 PM
<xsl:template name="evaluate">
<xsl:param name="xpath"/>
<xsl:choose>
<xsl:when test="$xpath=''">
<xsl:value-of select="."/>
</xsl:when>
<xsl:when test="contains($xpath, '//')">
<xsl:variable name="temp" select="substring-after($xpath,'//')"/>
<xsl:variable name="searchNode">
<xsl:choose>
<xsl:when test="contains($temp, '/')">
<xsl:value-of select="substring-before($temp, '/')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$temp"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="//*[name() = $searchNode]">
<xsl:call-template name="evaluate">
<xsl:with-param name="xpath" select="substring(substring-after($temp, $searchNode),2)"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:when test="starts-with($xpath, '/')">
<xsl:variable name="temp" select="substring-after($xpath,'/')"/>
<xsl:variable name="searchNode">
<xsl:choose>
<xsl:when test="contains($temp, '/')">
<xsl:value-of select="substring-before($temp, '/')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$temp"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="/*[name() = $searchNode]">
<xsl:call-template name="evaluate">
<xsl:with-param name="context" select="/*"/>
<xsl:with-param name="xpath" select="substring(substring-after($temp, $searchNode),2)"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="contains($xpath, '/')">
<xsl:variable name="nodeName" select="substring-before($xpath,'/')"/>
<xsl:for-each select="./*[name() = $nodeName]">
<xsl:call-template name="evaluate">
<xsl:with-param name="xpath" select="substring-after($xpath, '/')"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="*[name() = $xpath]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I couldn't find it, so I wrote this instead.
Takes xpaths in forms
node
node/child/nextchild
/root/node
//nodeAnywhere/node
etc.
Wildcards * not accepted.
markupper
08-16-2007, 05:03 PM
Thanks! I'll try this asap and let you know. It looks good, though!
markupper
08-17-2007, 07:15 AM
I guess it works. I just have to do some xpath-ing specific to the convention of my xml files. Thanks a lot!:)