XML.orgXML.org
FOCUS AREAS |XML-DEV |XML.org DAILY NEWSLINK |REGISTRY |RESOURCES |ABOUT
OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index]
Re: [xml-dev] How to get XPath in a XSLT shylesheet


> 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]


News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 1993-2007 XML.org. This site is hosted by OASIS