RE: [xsl] transforming based on implicit cross-references

Subject: RE: [xsl] transforming based on implicit cross-references
From: Syd Bauman <Syd_Bauman@xxxxxxxxx>
Date: Mon, 21 Dec 2009 08:26:03 -0500
Hmmm ... my validator tells me that a variable is not allowed in the
value of a match= attribute in XSLT 1.0, and my reading of
http://www.w3.org/TR/xslt#patterns supports that.

So I tried a slightly different crack at this problem. I think the
following does what OP (Ed Fair?) wants. I've annotated it, both in
the hopes that the annotations are helpful to OP and others
interested in how to do this sort of thing, and so that the real
experts on this list might be able to point out any errors (unlikely)
or silly methodology (likely) I've employed, or explain things
better.

---------

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:param name="personOfInterest">Anna</xsl:param>

  <!-- match root, start generating output tree -->
  <xsl:template match="/">
    <result>
      <!-- since OP didn't say how deep in the input tree -->
      <!-- <timestamp> elements are buried, just pick out -->
      <!-- all descendant <timestamp>s and process -->
      <xsl:apply-templates select="//timestamp"/>
    </result>
  </xsl:template>

  <xsl:template match="timestamp">
    <!-- spit out the actual time stamp [I find this data structure -->
    <!-- fragile and scary, but it's what OP had in the input, so ...] -->
    <xsl:variable name="timestamp" select="text()[1]"/>
    <!-- select my descendant<person> element of interest, if any, and -->
    <!-- make it the current node (or is that context node?) -->
    <xsl:for-each select="people/person[normalize-space(.) = $personOfInterest]">
      <!-- Now that I have it (the right <person> node), I want to know its  -->
      <!-- position within the set of input <person> nodes. I can't use -->
      <!-- position(), though, as I'm now processing a little sub-tree that -->
      <!-- has only this 1 node (OP said there will always be at most one node -->
      <!-- that matches a person's name), so position() will always be 1 -->
      <xsl:variable name="position" select="count( preceding-sibling::person ) + 1"/>
      <!-- spit out an output <timestamp> with ... -->
      <timestamp>
        <!-- ... a copy of the input time stamp, and ... -->
        <xsl:apply-templates select="$timestamp"/>
        <!-- ... a copy of the element I'm looking at (a <person>) ... -->
        <xsl:copy>
          <!-- ... with the content of the element I'm looking at -->
          <xsl:value-of select="."/>
        </xsl:copy>
        <!-- Now process the corresponding <location> for this person -->
        <xsl:apply-templates select="following-sibling::locations/location[position() = $position]"/>
      </timestamp>
    </xsl:for-each>
  </xsl:template>

  <!-- template will only be triggered for the 1 location that has the same ordinality -->
  <!-- as the <person> we've found, so ... -->
  <xsl:template match="location">
    <!-- ... just generate a copy of element & its data content -->
    <xsl:copy>
      <xsl:value-of select="."/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

---------

-- 
 Syd Bauman, EMT-Paramedic
 Senior XML Programmer/Analyst
 Brown University Women Writers Project
 Syd_Bauman@xxxxxxxxx      401-863-3835

Current Thread