[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
Re: [xml-dev] How to get XPath in a XSLT shylesheet
- From: David Carlisle <davidc@nag.co.uk>
- To: mike@saxonica.com
- Date: Tue, 9 Jan 2007 10:48:02 GMT
> Highly dubious in a human-authored document, but it can happen quite easily
> in one that's generated as the output of a transformation.
although actually along a sibling axis you have quite hard to
"accidentally" get multiple prefixes. I don't think the posted code was
mine (but it could have been, I don't remember:-) but in xslt1 it's
relatively inconvenient to avoid name() here if you want to ask for the
siblings with the same name. (you'd have to test for, and display,
namespace uri and local name separately.) Things are better in xpath2.
A more serious objection though is not the multiple prefies, it's that if
the document just uses a single default namespace (which is not a rare
case at all) then the code will display unprefixed paths, which would be
fine for documentation, but don't actually work (again they could work
in xpath2)
If the intention is for the path to select into the original source, I'd
probably use * rather than name() for elements, something like this:
<a xmlns="data:,foo" xmlns:a="data:,foo" xmlns:b="data:,foo" >
<b x="1" y="2"/>
<a:b/>
<b:b/>
<b a:x="1" b:y="2"/>
</a>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*|@*" mode="get-full-path">
<xsl:apply-templates select="parent::*"
mode="get-full-path"/>
<xsl:text>/</xsl:text>
<xsl:if test="count(. | ../@*) =
count(../@*)">@</xsl:if>
<xsl:value-of select="name()"/>
<xsl:text>[</xsl:text>
<xsl:value-of
select="1+count(preceding-sibling::*[name()=name(current())])"/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="*" mode="get-full-path-2">
<xsl:apply-templates select="parent::*"
mode="get-full-path-2"/>
<xsl:text>/*</xsl:text>
<xsl:if test="../*[2]">
<xsl:text>[</xsl:text>
<xsl:value-of
select="1+count(preceding-sibling::*)"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="@*" mode="get-full-path-2">
<xsl:apply-templates select="parent::*"
mode="get-full-path-2"/>
<xsl:text>/@</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''"><xsl:value-of select="name()"/></xsl:when>
<xsl:otherwise>
<xsl:text>*[local-name()='</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()"/>
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
=== plan a
<xsl:for-each select="//*|//*/@*">
: <xsl:apply-templates mode="get-full-path" select="."/>
</xsl:for-each>
=== plan b
<xsl:for-each select="//*|//*/@*">
: <xsl:apply-templates mode="get-full-path-2" select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
$ saxon path.xml path.xsl
<?xml version="1.0" encoding="utf-8"?>
=== plan a
: /a[1]
: /a[1]/b[1]
: /a[1]/b[1]/@x[1]
: /a[1]/b[1]/@y[1]
: /a[1]/a:b[1]
: /a[1]/b:b[1]
: /a[1]/b[2]
: /a[1]/b[2]/@a:x[1]
: /a[1]/b[2]/@b:y[1]
=== plan b
: /*
: /*/*[1]
: /*/*[1]/@x
: /*/*[1]/@y
: /*/*[2]
: /*/*[3]
: /*/*[4]
: /*/*[4]/@*[local-name()='x' and namespace-uri()='data:,foo']
: /*/*[4]/@*[local-name()='y' and namespace-uri()='data:,foo']
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]