0

Does anyone know how to copy only the first n nodes in a xml file and delete the rest using xslt? So say I only want to copy the first 10 nodes and delete the rest of the nodes that belong to the same parent.

1
  • Please show some sample input XML, your expected result and how far you've got on your own with the XSLT. Hints: You can edit your own question. Use the "010101" button to format stuff as code. Commented Dec 2, 2009 at 9:50

4 Answers 4

3

You should just remove them from your result set, as:

<!-- note you must to encode 'greater than' and 'lower than' characters -->
<xsl:for-each select="parent/nodes[position() &lt;= 10]">
    ...
</xsl:for-each>
Sign up to request clarification or add additional context in comments.

Comments

3

Add the following template to the identity transform:

<xsl:template match="/*/*[position() &lt; 11]"/>

How it works: The identity transform copies any node it matches to the result document, recursively. But the match criteria on the identity transform have the lowest possible priority; if a node is matched by any template with a higher priority, that template will be used instead. (The priority rules are obscure, but they're so well designed that you rarely need to know about them; generally speaking, if a node is matched by two templates, XSLT will select the template whose pattern is more specific.)

In this case, we're saying that if a node is an element that's a child of the top-level element (the top level element is the first element under the root, or /*, and its child elements are thus /*/*) and its position in that list of nodes is 11 or higher, it shouldn't be copied.

Edit:

Oof. Everything about the above is correct except for the most important thing. What I wrote will copy every child of the top-level element except for the first ten.

Here's a complete (and correct) version of the templates you'll need:

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

<xsl:template match="/*/*[position() &gt; 10]"/>

That's it. The first template copies everything that's not matched by the second template. The second template matches all elements after the first 10 and does nothing with them, so they don't get copied to the output.

Comments

1

Sorry the code didn't paste properly below. Here is what it should be:

    <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>
    <xsl:template match="inner"/>    
    <xsl:template match="/*/*[position() &lt; 11]">
<xsl:call-template name="identity"/>  
    </xsl:template>

1 Comment

I've edited my answer to make it a) more detailed and b) not wrong.
0

Use the identity transform, which will copy the source tree to the output tree, and add a template to exclude the elements you want to eliminate. Then, as you don't want to eliminate all of them but only those after the first ten, add one final template for the special ones that are to be allowed through, based on their position:

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

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

  <xsl:template match="inner"/>

  <xsl:template match="inner[position() &lt; 11]">
    <xsl:call-template name="identity"/>
  </xsl:template>

</xsl:stylesheet>

to be used with the XML

<?xml version="1.0" encoding="UTF-8"?>
<outer>
  <inner foo="1"/>
  <inner foo="2"/>
  <inner foo="3"/>
  <inner foo="4"/>
  <inner foo="5"/>
  <inner foo="6"/>
  <inner foo="7"/>
  <inner foo="8"/>
  <inner foo="9"/>
  <inner foo="10"/>
  <inner foo="11"/>
  <inner foo="12"/>
  <inner foo="13"/>
  <inner foo="14"/>
</outer>

1 Comment

This transform will mess up any descendant element that has 11 or more elements named inner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.