Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove unwanted elements and attributes from XML file using XSLT

Tags:

xml

xslt

I have XML file , I want to copy it as it is , but I want to filter some unwanted elements and attributes , for example the following is the original file :

<root>
<e1 att="test1" att2="test2"> Value</e1>
<e2 att="test1" att2="test2"> Value 2 <inner class='i'>inner</inner></e2>
<e3 att="test1" att2="test2"> Value 3</e3>

</root>

After the filtration ( e3 element and att2 attribute have been removed ) :

<root>
<e1 att="test1" > Value</e1>
<e2 att="test1" > Value 2 <inner class='i'>inner</inner></e2>
</root>

Notes:

  • I prefer to use ( for-each element instead of apply-templates if that possible )
  • I have some problems with xsl:element and xsl:attribute since I could not write the current node name

Thanks

like image 555
Abdullah Avatar asked Dec 27 '22 20:12

Abdullah


2 Answers

I know you'd prefer to use for-each, but why not use an identity transform and then override that template with what you don't want to keep?

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="e3|@att2"/>

</xsl:stylesheet>

produces:

<root>
   <e1 att="test1"> Value</e1>
   <e2 att="test1"> Value 2 <inner class="i">inner</inner>
   </e2>
</root>
like image 170
Daniel Haley Avatar answered Dec 30 '22 10:12

Daniel Haley


As @DevNull has shown you, using the identity transform is much easier and less verbose. Anyway, here is one possible solution with for-each and without apply-templates as you requested:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="/root">
   <root>
    <xsl:for-each select="child::node()">
     <xsl:choose>
      <xsl:when test="position()=last()-1"/>
      <xsl:otherwise>
       <xsl:copy>
        <xsl:copy-of select="@att"/>
        <xsl:copy-of select="child::node()"/>
       </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
   </xsl:for-each>
  </root>
</xsl:template>


Note about using identity transform

If your situation is really what it looks like, I mean unknown name of the elements, the @DevNull won't work and you would need somthing more general like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
   <xsl:strip-space elements="*"/>

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

    <xsl:template match="root/child::node()[position()=last()]|@att2"/>

</xsl:stylesheet>

This solution will work even with last elements e4 or e1000.

like image 35
Emiliano Poggi Avatar answered Dec 30 '22 09:12

Emiliano Poggi