wavelength
wavelength

Reputation: 41

How to match text and other nodes in XSLT

I am looking for a way to extract a node and copy it to a different location in the output. I was hoping to do this with xsl:analyze-string but wasn't able to because the select expression of xsl:analyze-string doesn't work if the selection is a collection of nodes (for example, a text node, followed by an element, followed by a text node.) It worked only when I modified the input to just have one text node. But my input is entry[2] below, which is not just text. Even if I select entry[2]/p, the text has XML tags in it, which are element nodes in addition to the text. So here is the input XML:

<rows>
    <row>
        <entry>
            <p>ID <varname>IdValue</varname></p>
            <p>Date <varname>date</varname></p>
            <p>sObject <varname>myObj</varname></p>
        </entry>
        <entry>
            <p>The <varname>IdValue</varname> argument provides humor.</p>
            <p>The <varname>date</varname> argument specifies how young this language is.</p>
            <p>The <varname>myObj</varname> argument specifies the darkness of times.</p>    
        </entry>   
    </row>
</rows>

and here is the desired output XML:

<section>
    <parameters>
        <param>
            <pn><varname>IdValue</varname></pn>
            <pv>The <varname>IdValue</varname> argument provides humor.</pv>
        </param>
        <param>
            <pn><varname>date</varname></pn>
            <pv>The <varname>date</varname> argument specifies how young this language is.</pv>
        </param>
        <param>
            <pn><varname>myObj</varname></pn>
            <pv>The <varname>myObj</varname> argument specifies the darkness of times.</pv>
        </param>
    </parameters>
</section>

For each varname found in entry[1], how do I find the matching description in entry[2]?

Upvotes: 1

Views: 1153

Answers (1)

Tomalak
Tomalak

Reputation: 338118

The simplest XSLT solution I can think of goes like this

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="rows">
    <section>
      <xsl:apply-templates select="row" />
    </section>
  </xsl:template>

  <xsl:template match="row">
    <parameters>
      <xsl:apply-templates select="entry[1]/p/varname" />
    </parameters>
  </xsl:template>

  <xsl:template match="entry[1]/p/varname">
    <param>
      <pn>
        <xsl:copy-of select="." />
      </pn>
      <pv>
        <xsl:copy-of select="ancestor::row/entry[2]//p[varname = current()]/node()" />
      </pv>
    </param>
  </xsl:template>
</xsl:stylesheet>

and produces

<section>
  <parameters>
    <param>
      <pn><varname>IdValue</varname></pn>
      <pv>The <varname>IdValue</varname> argument provides humor.</pv>
    </param>
    <param>
      <pn><varname>date</varname></pn>
      <pv>The <varname>date</varname> argument specifies how young this language is.</pv>
    </param>
    <param>
      <pn><varname>myObj</varname></pn>
      <pv>The <varname>myObj</varname> argument specifies the darkness of times.</pv>
    </param>
  </parameters>
</section>

Note the use of the current() XSLT function.

Upvotes: 2

Related Questions