<?xml version="1.0"?> 
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:tracexsl="http://www.ibm.com/xsl-example/tracexsl">

<!-- We're going to be generating XSLT code, which brings up the
     question of how to distinguish between what we're processing and
     what we're copying into the output. We _could_ use <xsl:element>
     to hand-construct the generated elements... but an easier
     solution is to write them as literal result elements in a
     temporary namespace, and tell the processor that when it writes
     them out it should put them into XSLT's namespace instead.  -->
  <xsl:namespace-alias stylesheet-prefix="tracexsl" result-prefix="xsl"/>

<!-- For selective debugging, set the tracegroups parameter. (If
     you're using the Xalan command-line "Process" tool, that's done
     by adding the option
	-PARAM tracegroups ...whatever...

     Only those templates which have a tracexsl:trace atttribute other
     than "no" that is contained in this value will be traced. The
     default behavior is to trace everything except the pseudo-XPath
     generator template except those set to "no".

     (The test being used is currently simple string contaiment, so
     if tracegroups is "food" and an element's tracexsl:trace attribute
     contains "foo", it will be considered a match. Improving that
     is left as an exercise for the reader.) -->
  <xsl:param name="tracegroups" select="''"/>

<!-- Most of the stylesheet we want to annotate should be passed
     through unchanged; we can let the canonical identity
     tranformation rule handle it.  -->
  <xsl:template match="@*|node()" priority="-1">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

<!-- The new code is going to invoke our XPath generation template,
     so we need to copy that into the generated stylesheet. In fact,
     I've chosen to regenerate the xsl:stylesheet element, in order
     to ensure that Xalan declares the tracexsl: prefix at this high
     level (and thus avoids repeatedly declaring it lower down.)

     Since I want to be able to run this stylesheet against itself for
     testing purposes, I'm testing whether the pseudo-xpath generator
     template already exists. That may be a significant efficiency
     hit, since it requires that we scan through the entire source
     stylesheet...  but stylesheets are generally small documents, and
     this annotation probably won't be done in a time-critical context
     very often, so I'm willing to accept that cost. If it bothers
     you, you could remove the xsl:if test.

     Note that this template has the tracexsl:trace attribute set,
     for demonstration purposes.  -->
  <xsl:template match="xsl:stylesheet" tracexsl:trace="stylesheet">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()"/>
      <xsl:if test="not(xsl:template[@name='pseudo-xpath-to-current-node'])">
        <xsl:text>&#xA;&#xA;</xsl:text>
        <xsl:copy-of select="document('')/xsl:stylesheet/xsl:template[@name='pseudo-xpath-to-current-node']" />
        <xsl:text>&#xA;&#xA;</xsl:text>
      </xsl:if>
    </xsl:copy>
  </xsl:template>

<!-- To display what templates are firing when, and what they're
     processing, we insert a pair of comments into each.

     Selective tracing: if the $tracegroups parameter is set, only
     templates which have that value in their tracexsl:trace
     attribute will have the message inserted. If it isn't set, all
     templates will be traced, *EXCEPT* those which have
     tracexsl:trace="no".

     Note that this template has the tracexsl:trace attribute set,
     for demonstration purposes.  -->
  <xsl:template match="xsl:template[not(@tracexsl:trace='no')
     and ($tracegroups='' or
       @tracexsl:trace and
       contains($tracegroups,@tracexsl:trace))]" tracexsl:trace="template">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="xsl:param"/>
      <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
      <tracexsl:comment>
         <xsl:text>[TraceXSL Begin]</xsl:text>
	 <xsl:if test="@match">
           <xsl:text> match="</xsl:text>
           <xsl:value-of select="@match"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
	 <xsl:if test="@name">
           <xsl:text> name="</xsl:text>
           <xsl:value-of select="@name"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
	 <xsl:if test="@mode">
           <xsl:text> mode="</xsl:text>
           <xsl:value-of select="@mode"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
         <xsl:text> source=</xsl:text>
	 <tracexsl:call-template name="pseudo-xpath-to-current-node"/>
      </tracexsl:comment>
      <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>

      <xsl:apply-templates select="node()[not(name()='xsl:param')]"/>

      <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
      <tracexsl:comment>
         <xsl:text>[TraceXSL END]</xsl:text>
	 <xsl:if test="@match">
           <xsl:text> match="</xsl:text>
           <xsl:value-of select="@match"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
	 <xsl:if test="@name">
           <xsl:text> name="</xsl:text>
           <xsl:value-of select="@name"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
	 <xsl:if test="@mode">
           <xsl:text> mode="</xsl:text>
           <xsl:value-of select="@mode"/>
           <xsl:text>"</xsl:text>
	 </xsl:if>
         <xsl:text> source=</xsl:text>
	 <tracexsl:call-template name="pseudo-xpath-to-current-node"/>
      </tracexsl:comment>
      <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
    </xsl:copy>
  </xsl:template>  
     
<!-- We'd like to know when the stylesheet is switching Modes, since
     that affects the selection of templates... so generate a
     new message at the time any mode is explicitly specified.
     (Ideally, I'd like to only generate this message when the mode
     CHANGES... but that gets complicated; we'd wind up having
     to generate parameters to keep track of the current state as
     the annotated stylesheet runs. I'd also like to fold this
     into the same one-liner reporting the template execution,
     but that too requires parameters.)  -->
  <xsl:template match="xsl:apply-templates[@mode]">
    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
    <tracexsl:comment>
      <xsl:text>[TraceXSL] APPLY MODE="</xsl:text>
      <xsl:value-of select="@mode"/>
      <xsl:text>"</xsl:text>
    </tracexsl:comment>
    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>

    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>

    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
    <tracexsl:comment>
      <xsl:text>[TraceXSL] END MODE="</xsl:text>
      <xsl:value-of select="@mode"/>
      <xsl:text>"</xsl:text>
    </tracexsl:comment>
    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
  </xsl:template>

<!-- We'd like to know when the stylesheet is calling a template
     explicitly, by name, rather than by normal matching.

     (Ideally, I'd like to fold this into the same one-liner rporting
     the template execution, but that would require generating
     parameters to pass it down the call stack.)  -->
  <xsl:template match="xsl:call-template">
    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>
    <tracexsl:comment>
      <xsl:text>[TraceXSL] CALL NAME="</xsl:text>
          <xsl:value-of select="@name"/>
      <xsl:text>"</xsl:text>
    </tracexsl:comment>
    <tracexsl:text xml:space="preserve">&#10;</tracexsl:text>

    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

 <!-- This template will generate something closely resembling an
     XPath to the current node.

     The main thing that keeps this from being a real XPath is the
     namespace issue. XPath 1.0 doesn't offer us a pure
     namespace-based syntax; it insists on using prefixes... but does
     not provide any syntax for declaring those prefixes. That's
     particularly annoying since it might be necessary for me to
     create new prefixes, if a single prefix was mapped to different
     namespace URIs at different points in the path. We could work up
     logic to do this, but without a syntax for declaring the prefixes
     it's unclear that doing so would actually be worth the effort;
     we'd just produce prefixes that nobody would know how to
     interpret.

     So for now I'm just outputting QNames as I find
     them... essentially, producing a namespace-unaware version of the
     XPath. It's _wrong_, but it will work for some simple cases, and
     if you understand its limitations it's good enough for use in
     messages reported to humans.

     I've proposed that XPath 2.0 add either an in-line declaration
     syntax or a URI-based QName syntax, to make machine-generated
     XPaths more robust/portable. We'll see whether anyone picks up on
     those suggestions.  -->
  <xsl:template name="pseudo-xpath-to-current-node" tracexsl:trace="no">
     <!-- Special-case for the root node, which otherwise
          wouldn't generate any path at all. A bit of a kluge,
	  but it's simple and efficient. -->
     <xsl:if test="not(parent::node())">
	   <xsl:text>/</xsl:text>
     </xsl:if>

     <xsl:for-each select="ancestor-or-self::node()">
       <xsl:choose>
         <xsl:when test="not(parent::node())">
	   <!-- This clause recognizes the root node, which doesn't need
	        to be explicitly represented in the XPath. -->
	 </xsl:when>
         <xsl:when test="self::text()">
	   <xsl:text>/text()[</xsl:text>
	   <xsl:number level="single"/>
	   <xsl:text>]</xsl:text>
	 </xsl:when>
         <xsl:when test="self::comment()">
	   <xsl:text>/comment()[</xsl:text>
	   <xsl:number level="single"/>
	   <xsl:text>]</xsl:text>
	 </xsl:when>
         <xsl:when test="self::processing-instruction()">
	   <xsl:text>/processing-instruction()[</xsl:text>
	   <xsl:number level="single"/>
	   <xsl:text>]</xsl:text>
	 </xsl:when>
         <xsl:when test="self::*">
	   <!-- This test for Elements works because the Principal
		Node Type of the self:: axis happens to be Element.
		-->
           <xsl:text>/</xsl:text>
	   <xsl:value-of select="name(.)"/>
	   <xsl:text>[</xsl:text>
	   <xsl:number level="single"/>
	   <xsl:text>]</xsl:text>
	 </xsl:when>
	 <xsl:when test="self::node()[name()='xmlns' | starts-with(name(),'xmlns:')]">
	   <!-- This recognizes namespace nodes, though it's a bit
		ugly.  (XSLT 1.0 doesn't seem to have a more elegant
		test; XSLT 2.0 is expected to fix that. However, XSLT
		2.0 is expected to completely remove the concept of
		namespace nodes having parents, which will make the
		concept of generating an XPath to one rather more
		complicated ...  if, indeed, it is possible at all.)
		Namespace declarations are unique; a count is not
		required.  -->
	   <xsl:text>/namespace::</xsl:text>
	   <xsl:value-of select="local-name(.)"/>
	 </xsl:when>
         <xsl:otherwise>
	   <!-- If we've reached this clause, the node must be an
		attribute.  Attributes are unique; a count is not
		required.  -->
	   <xsl:text>/@</xsl:text>
	   <xsl:value-of select="name(.)"/>
	 </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>
