ahliang1412
ahliang1412

Reputation: 177

XSLT-select following items until particular tag

Consider I have this XML file:

<text>
  <w>John</w>
  <x>Smith</x>
  <z>Andy</z>
  <w>Goo</w>
  <w>Joseph</w>
  <y>Lee</y>
  <x>Kenny</x>
  <z>Maria</z>
  <y>Zoe</y>
  <z>Martin</z>
</text>

Now I wish to select elements between 1st <z> and 2nd <z>

So the output will be :

  <w>Goo</w>
  <w>Joseph</w>
  <y>Lee</y>
  <x>Kenny</x>

What I know is we can "copy-of" select the "following siblings" of "z[1]" but I don't know how to stop it on "z[2]"

Upvotes: 4

Views: 2471

Answers (2)

Wayne
Wayne

Reputation: 60414

Select the intersection of the following two node-sets:

  • All nodes after the first z
  • All nodes before the second z

The intersection of these two sets will be all nodes between the first and second z elements. Use the following expression:

/*/z/following-sibling::*[
    count(.|/*/z[2]/preceding-sibling::*) =
    count(/*/z[2]/preceding-sibling::*)]

Note: This uses the Kayessian node-set intersection formula. In general, use the following to find the intersection of $set1 and $set2:

$set1[count(.|$set2)=count($set2)]

Upvotes: 4

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56162

You can use XPath:

text/*[preceding-sibling::z and following-sibling::z[2]]

e.g.:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="/">
    <xsl:apply-templates select="text/*[preceding-sibling::z and following-sibling::z[2]]"/>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 2

Related Questions