Re: [xsl] copy single node once from one location to another

Subject: Re: [xsl] copy single node once from one location to another
From: Peter Davis <pdavis152@xxxxxxxxx>
Date: Fri, 6 Sep 2002 15:25:31 -0700
On Friday 06 September 2002 14:46, Thomas Olausson wrote:
> I'd like to write a XSLT that moves the data_text to the corresponding
> index of "a", expressed in data_nr. In the above case, /mydoc/a[2]

Define a key to look up the <specials> element corresponding to a specific 
<data_nr> value.  Later, you can pass a number to the key() function to get 
the corresponding <specials>, and then you can get the <data_text> element as 
a child of that.

<xsl:key name="specials" match="specials" use="data_nr"/>

You want to copy everything verbatim except for a few special cases, so define 
a basic identity template.  It will copy each element and its attributes, and 
it will apply-templates to its children.  You can define other templates to 
match specific elements that will override this one.

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

Define a template to handle <a> specially.  You want to copy <a>, its 
attributes, and its children just like for the normal identity template, but 
you also want to copy the <data_text> from the corresponding <specials> 
element.  The correct <specials> element is found by counting the number of 
<a> elements that come before the current one, and using that as the value 
for the proper <data_nr> (see the <xsl:key> element above).

It might be more efficient to use the position() function here, but to do that 
you'd have to make a special template to copy <mydoc> and only copy the <a> 
children.  That's because the plain <xsl:apply-templates> in the identity 
template will select *all* children (node()s actually) of <mydoc>, including 
whitespace-only text nodes and any other non-<a> elements.  Those extra nodes 
will mess up the position() function.

<xsl:template match="a">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
    <xsl:apply-templates select="key('specials',
      count(preceding-sibling::a) + 1)/data_text"/>
  </xsl:copy>
</xsl:template>

Now, define a special template to copy <data_text>, but rename it to <data>.

<xsl:template match="data_text">
  <data>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
  </data>
</xsl:template>

That's all untested, but hopefully it'll get you on the right track.

-- 
Peter Davis

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread