Recursive Empty Node Cleanup

时间:2016-02-12 20:05:06

标签: xml xslt xslt-1.0

I'm attempting to clean up a file with arbitrary element names that looks like:

<root>
    <nodeone>
        <subnode>with stuff</subnode>
    </nodeone>
    <nodeone>
        <subnode>with other stuff</subnode>
    </nodeone>
    <nodeone>
        <subnode />
    </nodeone>
</root>

into a file that looks like:

<root>
    <nodeone>
        <subnode>with stuff</subnode>
    </nodeone>
    <nodeone>
        <subnode>with other stuff</subnode>
    </nodeone>
</root>

You can see that all of "nodeone" that had the empty children disappeared. I've used a solution that removes the empty <subnode>, but keeps the <nodeone>. The desired result is that both of those elements are removed.

My current attempt at a solution (which does precisely nothing) is:

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

    <xsl:template match="node()|@*">
        <xsl:call-template name="backwardsRecursion">
            <xsl:with-param name="elementlist" select="/*/node/*[normalize-space()]"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="backwardsRecursion">
        <xsl:param name="elementlist"/>

        <xsl:if test="$elementlist">
            <xsl:apply-templates select="$elementlist[last()]"/>

            <xsl:call-template name="backwardsRecursion">
                <xsl:with-param name="elementlist" select="$elementlist[position() &lt; last()]"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="/*/node/*[normalize-space()]">
          <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

XSLT is not something I use terribly often, so I'm a bit lost.

1 个答案:

答案 0 :(得分:2)

Start with identity transformation,

<?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()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

and add a template to squelch elements without signficant, non-space-normalized string values,

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

and you'll get the results you seek.

Altogether:

<?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()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

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

</xsl:stylesheet>