[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Embedding the XPath of an input Text Fragment in output


Subject: Re: [xsl] Embedding the XPath of an input Text Fragment in output
From: Florent Georges <lists@xxxxxxxxxxxx>
Date: Fri, 13 Jun 2008 13:43:51 +0200 (CEST)

David Carlisle wrote:

  Hi

> The schematron sources have several variants of this, targetting
> different use cases. using name() is fine for human-oriented paths
> in error reprorting etc

  By the way, the template rule for generating the paths in the
Schematron skeleton, for human purpose, is:

    <xsl:template match="node() | @*"
mode="schematron-get-full-path-2">
       <!--report the element hierarchy-->
       <xsl:for-each select="ancestor-or-self::*">
          <xsl:text>/</xsl:text>
          <xsl:value-of select="name(.)"/>
          <xsl:if test="preceding-sibling::*[name(.)=name(current())]">
             <xsl:text>[</xsl:text>
             <xsl:value-of select="
                
count(preceding-sibling::*[name(.)=name(current())])+1"/>
             <xsl:text>]</xsl:text>
          </xsl:if>
       </xsl:for-each>
       <!--report the attribute-->
       <xsl:if test="not(self::*)">
          <xsl:text/>/@<xsl:value-of select="name(.)"/>
       </xsl:if>
    </xsl:template>

  A few remarks.  1) The test as it is make that the first element
with a particular name never has a positional predicate, and the
following always have one: "elem", then "elem[2]", "elem[3]",
etcetera.  I would rather say that if there is only one element of a
particular name, you can drop the predicate, if not you should add
"[1]".

  2) The test for reporting the attribute is wrong if one asks the
path to something else than an element or an attribute.

  3) This has been developed for XSLT 1.0 initially, but even in the
XSLT 2.0 version it uses name() instead of node-name().

  So for an XSLT 2.0 version, to generate paths targeted at human
beings, I propose the following.  Any comment?

    <!-- for any kind of node, report the elements path -->
    <xsl:template match="node() | @*" priority="-2" mode="path">
       <xsl:for-each select="ancestor-or-self::*">
          <xsl:text>/</xsl:text>
          <xsl:value-of select="name(.)"/>
       </xsl:for-each>
    </xsl:template>

    <!-- add a positional predicate if there are other siblings of the
         same name -->
    <xsl:template match="*" mode="path">
       <xsl:next-match/>
       <xsl:if test="
           count(../*[node-name(.) eq node-name(current())]) gt 1">
          <xsl:text>[</xsl:text>
          <xsl:value-of select="
              count(preceding-sibling::*[
                        node-name(.) eq node-name(current())
                      ])
                + 1"/>
          <xsl:text>]</xsl:text>
       </xsl:if>
    </xsl:template>

    <!-- add a positional predicate if there are other siblings of the
         same name -->
    <xsl:template match="processing-instruction()" mode="path">
       <xsl:next-match/>
       <xsl:if test="count(../processing-instruction()[
                                  node-name(.) eq node-name(current())
                                ]) gt 1">
          <xsl:text>[</xsl:text>
          <xsl:value-of select="
              count(preceding-sibling::processing-instruction()[
                        node-name(.) eq node-name(current())
                      ])
                + 1"/>
          <xsl:text>]</xsl:text>
       </xsl:if>
    </xsl:template>

    <!-- add the attribute step -->
    <xsl:template match="@*" mode="path">
       <xsl:next-match/>
       <xsl:text>/@</xsl:text>
       <xsl:value-of select="name(.)"/>
    </xsl:template>

    <!-- add the string text() and maybe a positional predicate -->
    <xsl:template match="text()" mode="path">
       <xsl:next-match/>
       <xsl:text>/text()</xsl:text>
       <xsl:if test="count(../text()) gt 1">
          <xsl:text>[</xsl:text>
          <xsl:value-of select="count(preceding-sibling::text()) + 1"/>
          <xsl:text>]</xsl:text>
       </xsl:if>
    </xsl:template>

    <!-- add the string comment() and maybe a positional predicate -->
    <xsl:template match="text()" mode="path">
       <xsl:next-match/>
       <xsl:text>/comment()</xsl:text>
       <xsl:if test="count(../comment()) gt 1">
          <xsl:text>[</xsl:text>
          <xsl:value-of select="
              count(preceding-sibling::comment()) + 1"/>
          <xsl:text>]</xsl:text>
       </xsl:if>
    </xsl:template>

  Regards,

--drkm

























      _____________________________________________________________________________ 
Envoyez avec Yahoo! Mail. Une boite mail plus intelligente http://mail.yahoo.fr


Current Thread
Keywords