Please sorry if the following questions might seem silly, but due to my inexperience I can't be sure about the reliability of this method.
I'm trying to build myself an XPath 1.0 location path evaluator using XSLT 1.0.
The idea is simple. The transform takes in input the xpath expression to evaluate and then apply the templates to selected nodes. A template for each kind of node is defined to copy the node (and some more information) on the output. The input document will be transformed obsviously using an XSLT 1.0 compliant processor.
What I would like to know from your expertise, is w开发者_JS百科hether this approach is absolutely, fall-free and reliable way to test location paths and display selected node-sets. I'm not asking for someone debugging my code. I've tested against various input documents and it seems working correctly. I'd like to know just if I'm missing something from the point of view of XPath.
Will this work correctly with any XPath 1.0 location path?
Will this be limited to XPath 1.0/XSLT 1.0? I do not see any controindication to extend the template to XPath 2.0 just by changing its version (and the XSLT processor obviously).
Here's the transform which should be used as XPath tester. Notice:
- I've omitted the templates for comment and pi nodes to make the transform not too heavy, but they are currently managed in a similar way.
- It doesn't need to manage namespaces at the moment.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="path-expr" select="*"/>
<xsl:template match="/">
<xpath-tester>
<node-sets count="{count($path-expr)}">
<xsl:apply-templates select="$path-expr" mode="path-expr"/>
</node-sets>
</xpath-tester>
</xsl:template>
<xsl:template match="node()|@*" mode="path-expr">
<node-set
position="{position()}"
id="{generate-id()}"
parent-id="{name(parent::*[1])}-{generate-id(parent::*[1])}">
<xsl:apply-templates select="." mode="output"/>
</node-set>
</xsl:template>
<xsl:template match="*" mode="output">
<xsl:attribute name="type">element</xsl:attribute>
<node>
<xsl:copy-of select="."/>
</node>
</xsl:template>
<xsl:template match="@*" mode="output">
<xsl:attribute name="type">attribute</xsl:attribute>
<node>
<xsl:copy-of select="."/>
</node>
</xsl:template>
<xsl:template match="text()" mode="output">
<xsl:attribute name="type">text</xsl:attribute>
<node>
<xsl:copy-of select="."/>
</node>
</xsl:template>
</xsl:stylesheet>
Sounds similar to a pet project of mine; feel free to have a look at my code, it's a bit too big to paste here:
http://www.flynn1179.net/xml/FullDisplayXml.xslt
It transforms any XML document into an html page with collapsible nodes, and by modifying the 'match' attribute of a key near the top, you can specify an XPath to nodes, and have it produce a list of them or highlight them in the source.
I asked a very similar question to this here: How can you pass in a parameter to an xslt that can be used in a xsl:key?, although I was trying to apply the parameter to the key, which doesn't work.
NB: That code's a work in progress, it's kind of ugly in places, and I'm fairly sure there's a few things it doesn't handle properly, or could do better, but hopefully it's useful. I use a derivative of it on my XML sandbox page: http://www.flynn1179.net/xml/ (it's also a work in progress, I know there's a couple of bugs in it)
You may be interested to look into the code of my 11years old XPath Vizualizer.
Dynamic evaluation within XSLT itself isn't directly supported in XSLT 2.0 and althogh there might be such support in XSLT 3.0 / XPath 3.0, this is not necessary at all.
First @Martin pointed out
you would need dynamic XPath evaluation supported to be able to treat the string with the XPath as a node-set
I've extended the transform a bit, in order to handle dynamic XPath evaluation. The transform is now able to accept an input string and evaluate it to an XPath.
Now it's Saxon dependent as by usage of saxon:evaluate
. In a similar way and with the support of function-available
one could implement other extensions and make this more portable.
Here the three new templates (and the two new parameters) which replace the root template in my original transform (given the namespace declaration xmlns:saxon="http://icl.com/saxon"
).
<xsl:param name="path-expr" select="false()"/>
<xsl:param name="xpath" select="*"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$path-expr">
<xsl:apply-templates select="/" mode="dyn"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="/" mode="base"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/" mode="dyn">
<xpath-tester>
<node-sets count="{count(saxon:evaluate($path-expr))}">
<xsl:apply-templates select="saxon:evaluate($path-expr)"
mode="path-expr"/>
</node-sets>
</xpath-tester>
</xsl:template>
<xsl:template match="/" mode="base">
<xpath-tester>
<node-sets count="{count($xpath)}">
<xsl:apply-templates select="$xpath"
mode="path-expr"/>
</node-sets>
</xpath-tester>
</xsl:template>
Second @Martin pointed out
I suspect you will run into trouble with outputting attribute and element nodes together
I've made test and run into this problem, but worked around as above it works fine even in that situation.
精彩评论