Cees
Cees

Reputation: 33

Filter elements without an attribute but keep elements with including their parents with XSLT

I am trying to filter an xml document for leaf elements that contain a specific attribute but I would like to keep the higher level document in tact. And I would like to do this with XSLT.

The document to begin with looks like this:

<root>
  <a name="foo">
    <b name="bar" critical="yes"/>
  </a>
  <a name="foo2" critical="yes">
    <b name="bar2">
    <b name="bar3">
  </a>
  <a name="foo3">
    <b name="bar4">
    <b name="bar5">
  </a>
</root>

The result should look like this:

<root>
  <a name="foo">
    <b name="bar" critical="yes"/>
  </a>
  <a name="foo2" critical="yes">
  </a>
</root>

Since XSLT is not my native language, any help is very appreciated.

Upvotes: 3

Views: 77

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243479

This transformation:

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

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

 <xsl:template match="*[not(descendant-or-self::*[@critical='yes'])]"/>
</xsl:stylesheet>

when applied on the provided XML document (corrected for well-formedness):

<root>
  <a name="foo">
    <b name="bar" critical="yes"/>
  </a>
  <a name="foo2" critical="yes">
    <b name="bar2"/>
    <b name="bar3"/>
  </a>
  <a name="foo3">
    <b name="bar4"/>
    <b name="bar5"/>
  </a>
</root>

produces the wanted, correct result:

<root>
   <a name="foo">
      <b name="bar" critical="yes"/>
   </a>
   <a name="foo2" critical="yes"/>
</root>

Upvotes: 1

Related Questions