Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Remove those empty elements ! Improved

Status
Not open for further replies.

heikkidoeleman

Programmer
Feb 22, 2010
1
FR
Hello,

after seeing this thread426-1088712 old thread on removing empty elements, I think its solution is not ideal as it will remove empty elements that have non-empty attributes too.

A solution that does not remove empty elements that have non-empty attributes is the following:

Code:
  <xsl:template match="node()">
    <xsl:if test=". != '' or normalize-space(.//@*) != '' ">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:if test="normalize-space(.) != '' ">
		<xsl:variable name="attributeName" select="name()"/>
		 <xsl:attribute name="{$attributeName}" select="."/>
    </xsl:if>
  </xsl:template>

For good measure I've treated whitespace-only values as if they are empty, too.


 
[0] I did not recall I read the quoted thread. In any case, it served its time and I am not going to look at it too critically.

[1] Instead, how about looking at your proposal to stay at the heat of it? I have several observations to make.

[1.1] This may not be straightly compliant to the recommendation of xslt 1.0, although some implementation may tolerate it.
> <xsl:attribute name="{$attributeName}" [red]select="."[/red]/>
The problem is that the attribute "select" is not in the admissible attribute set of the xsl:attribute element. Some implementation(s) may consider it a serious error and refuse to go further, and I think they have reason to do so.

[1.1.1] If you want to avoid such problem, just use xsl:value-of child for that purpose and it would be fine.

[1.2]
>For good measure I've treated whitespace-only values as if they are empty, too.
It is fine as a premise for the functionality sought after. But, I don't think your implementation deliver. I will show you in the following.

[2] Let's take a generic xml with ingredients putting the needed behaviour in an acute manner.

[2.1][tt]
<root>
<a>
<b />
<b></b>
<c> </c>
<d at="pqr">
<e>
<f></f>
</e>
</d>
</a>
<a>
<b />
<b></b>
<c> </c>
<d at=" ">
<e>
<f></f>
</e>
</d>
</a>
<a>
<b />
<b></b>
<c> </c>
<d at="">
<e>
<f></f>
</e>
</d>
</a>
</root>
[/tt]
[2.2] I would then propose instead this xsl for the functionality sought after.
[tt]
<xsl:stylesheet version="1.0" xmlns:xsl="[ignore][/ignore]">
<xsl:template match="/">
<xsl:apply-templates select="node()" />
</xsl:template>
<xsl:template match="/*">
<!-- against all conditions, keep the root undeleted -->
<xsl:copy>
<xsl:apply-templates select="*|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="node()">
<xsl:if test="not(normalize-space(text()) = '' and count(./@*[normalize-space()!='']|.//*/@*[normalize-space()!='']) = 0)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>

<xsl:template match="@*">
<xsl:if test="normalize-space() != ''">
<xsl:copy-of select="." />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
[/tt]
[2.3] Run the transformation with my xsl document and compare the result with yours. One of the detail that you've to take care of is the cascade/after-effect. An non-empty element with empty child elements once removed would itself become empty an apt to be removed. That has not be properly taken care of in your posting.

[3] In any case, I would say help others if you have good skill on xslt and would encourage you to do thereof. Good helpers are in short supply.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top