This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
XSL to generate XPaths
- To: XSL mailing list <xsl-list at lists dot mulberrytech dot com>
- Subject: [xsl] XSL to generate XPaths
- From: Michael Strasser <M dot Strasser at myrealbox dot com>
- Date: Wed, 16 May 2001 09:26:38 +1000
- Organization: StrassCom Pty Ltd
- Reply-To: xsl-list at lists dot mulberrytech dot com
This XSL document generates a text list of all XPaths of element and
attribute nodes in an XML document. XPaths are unique and only include
subscripts when necessary.
I created this over the past couple of weeks to use in a project I'm
working on. Here it is for anybody else who may find it useful. You can, of
course, change the delimiter from newline ( ) to anything else (like a
comma).
All comments welcome. Sorry about e-mail line-wrapping. Have fun!
--
Michael Strasser
Brisbane, Australia
--- snip ---
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
all-xpaths.xsl
Transform an XML document to a text listing of all its element and
attribute nodes as unique XPath specifications.
Output is a newline-separated list.
Michael Strasser, May 2001
M.Strasser@gpo.com
-->
<!-- Output is plain text. -->
<xsl:output method="text" media-type="text/plain"/>
<!-- Root element match: apply to all child nodes. -->
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- Element and attribute match: this is where the work is done. -->
<xsl:template match="*|@*">
<xsl:param name="path" select="''"/>
<!--
Create this node's XPath specifier by appending information to
the path param passed to this template. A variable is created
because its value is used twice.
This code is a bit complicated to make the output a bit pretty:
if a node has no siblings with the same name there is no need
to include a subscript to make the XPath unique.
-->
<xsl:variable name="this-path">
<xsl:value-of select="concat($path, '/')"/>
<!-- If this is an attribute node, output '@' before its name. -->
<xsl:if test="../@*[name() = name(current())]">
<xsl:text>@</xsl:text>
</xsl:if>
<xsl:value-of select="name()"/>
<!--
If the parent has more than one node with the same name as
the current one...
-->
<xsl:if test="count(../*[name() = name(current())]) > 1">
<!--
Include the current node's subscript in the list of those
with the same name.
-->
<xsl:value-of select="concat('[', count(preceding-sibling::*[name()
= name(current())]) + 1, ']')"/>
</xsl:if>
</xsl:variable>
<!-- If this is not the first node in the document, output a newline
first. -->
<xsl:if test="preceding::*|ancestor::*">
<xsl:text> </xsl:text>
</xsl:if>
<!-- Send this node's path to the output stream now. -->
<xsl:value-of select="$this-path"/>
<!-- Apply to this node's children, passing its path as a starting
point. -->
<xsl:apply-templates select="*|@*">
<xsl:with-param name="path" select="$this-path"/>
</xsl:apply-templates>
</xsl:template>
<!-- Ignore comment, text and PI nodes. -->
<xsl:template match="comment()|text()|processing-instruction()"/>
</xsl:stylesheet>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list