UltraNurd
UltraNurd

Reputation: 1334

XSL Ignore Empty Children Recursively

Trying something kind of wacky in cleaning up some verbose XML, which is to remove all empty nodes recursively.

For this purpose, I consider a node to be "empty" if it has (a) no child nodes, (b) whitespace-only content, (c) only "empty" child nodes. That is, I consider the following to be "empty" because all of the leaves are empty/whitespace-only nodes:

<foo>
  <bar>
    <baz/>
  </bar>
  <quux>  </quux>
</foo>

I tried using <xsl:if test="child::node()"> in my templates, but that didn't seem to work. It's entirely possible the answer is "walk the tree yourself, silly", but it seems like the sort of thing XSL should be able to do?

I would expect

<foo>
  <bar>
    <baz/>
  </bar>
  <quux>  </quux>
  <quuux>Actual content</quuux>
</foo>

to come back as

<foo>
  <quuux>Actual content</quuux>
</foo>

with this filter I have in mind.

Upvotes: 2

Views: 1757

Answers (2)

Pavel Minaev
Pavel Minaev

Reputation: 101595

The reason why child::node() didn't work for you was because you do have child nodes there - they're whitespace text nodes. Instead, try something like normalize-space() != ''. You probably don't want an if there, either - put it in match instead:

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

<xsl:template match="*[normalize-space() = '']"/>

Upvotes: 5

Santiago Cepas
Santiago Cepas

Reputation: 4094

Pavel's answer is correct. Two small mistakes though: you need to close the xsl:copy node, and apply:templates uses select instead of match. This would be the final version:

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

<xsl:template match="*[normalize-space() = '']"/>

Upvotes: 4

Related Questions