MAT0718
MAT0718

Reputation: 55

Skip first node and Copy rest of the nodes using XSLT 3.0

I will need to skip first Worker node and copy rest of the nodes using XSLT 3.0

My source XML is

<?xml version="1.0" encoding="UTF-8"?>
<Workers>
    <Worker>
        <Employee>Emp</Employee>
        <ID>Identifier</ID>
    </Worker>
    <Worker>
        <Employee>12344</Employee>
        <ID>1245599</ID>
    </Worker>
    <Worker>
        <Employee>25644</Employee>
        <ID>7823565</ID>
    </Worker>
</Workers>

and desired output is

<?xml version="1.0" encoding="utf-8"?>
<Workers>
   <Worker>
      <Employee>12344</Employee>
      <ID>1245599</ID>
   </Worker>
   <Worker>
      <Employee>25644</Employee>
      <ID>7823565</ID>
   </Worker>
</Workers>

and XSLT that i have is

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

    <xsl:strip-space elements="*"/>
    <xsl:output method="xml" indent="yes"/>


    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="Worker[position() = 1]"/>

</xsl:stylesheet>

Above XSLT produces the output that I was expecting but I'm looking to see if there is a better way to skip the first node without using postion()as I'm not sure how efficient my current code is to process large files( approximately 800 MB)

I had to use following to remove white spaces from my result XML

<xsl:strip-space elements="*"/>

Can anyone check my code and provide any suggestion to improvise my code please?

===============

With Michael Kay's suggestion, my code looks like this

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"  xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:strip-space elements="*"/>
   <xsl:output method="xml" indent="yes"/> 
    
  <!-- <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template> -->
 
 <!-- Removed above Identity Transformation -->

    <xsl:mode streamable="yes" on-no-match="shallow-copy"/>
    
    <xsl:template match="Workers">
        <xsl:copy>
            <xsl:apply-templates select="tail(Worker)"/>
        </xsl:copy>
    </xsl:template>    
    
</xsl:stylesheet>

Upvotes: 0

Views: 363

Answers (1)

Michael Kay
Michael Kay

Reputation: 163342

I would write it

<xsl:template match="Worker[1]"/>

for readability, but it's all the same.

Match patterns with positional predicates can perform badly, so you're right to be cautious, but a simple one like this should be OK. In fact the main adverse consequence is probably that Saxon will allocate preceding-sibling pointers in the TinyTree, so that it can compute the node's sibling position.

Saxon effectively implements it as

<xsl:template match="Worker[not(preceding-sibling::Worker)]"/>

and you might prefer to write it that way. However, neither form is streamable.

To make it streamable, you could drop the unwanted nodes by not selecting them:

<xsl:template match="Workers">
  <xsl:copy>
    <xsl:apply-templates select="tail(Worker)"/>
  </xsl:copy>
</xsl:template>

which might also be fractionally faster in the non-streaming case; and it saves memory because preceding-sibling pointers aren't needed.

Upvotes: 1

Related Questions