0
votes

I decided to open a new topic because in previous I did not precisly define what I'm expecting. My XML on input looks:

    <tag5>
                <addresses/>
                <identifiedBaseServices/>
                <sharedGroups>
                   <names></names>
                   <types></types>
     </tag5>
     <contain>
                <attributes/>
                <addresses/>
                <identifiedBaseServices/>
                <sharedGroups>
                   <names></names>
                   <types></types>
                </sharedGroups>
     </contain>
<smth>
           <tag1></tag1>
               <tag3> TEXT </tag3>
</smth>

All what I want is delete empty nodes except some which I explicit define. For example I don't want to remove

attributes, 

So xml OUTPUT shoud looks:

 <contain>
            <attributes/>
 </contain>


<smth>
           <tag3> TEXT </tag3>
</smth>

I was looking for some solution, after few hours i got smth like:

<xsl:strip-space elements="*"/>
<xsl:template match="*[descendant::text() or descendant-or-self::*/@*[string()]]">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>   
<xsl:template match="attributes[not(node())]" priority="1">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="*[not(.//text() | .//@*)]"/>

</xsl:stylesheet>

It works almost fine but only then if eg. contain some data.When everything is null then that XSL code remove ALL empty tag...

Is anyone here who could help me? Thanks in advance..

1

1 Answers

1
votes

I think this is what you want:

<?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" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:strip-space elements="*"/>


    <xsl:template match="*[.//attributes] | attributes">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates />        
        </xsl:element>
    </xsl:template>

    <xsl:template match="*[descendant::text() or descendant-or-self::*/@*[string()]]">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>  

</xsl:stylesheet>

I've removed your text template - it was stripping out the empty node you want to keep. Instead, we have a template to match any node that has attributes as a child or the attributes node itself. We then keep just that tag and ignore the rest of its children. I don't think this will handle attributes (XML attributes that is) if you want to keep those on the attributes node.

Takes this document:

<rt>
    <tag5>
        <addresses/>
        <identifiedBaseServices/>
        <sharedGroups>
            <names/>
            <types/>
        </sharedGroups>
    </tag5>
    <contain>
        <attributes/>
        <addresses/>
        <identifiedBaseServices/>
        <sharedGroups>
            <names/>
            <types/>
        </sharedGroups>
    </contain>
    <smth>
        <tag1/>
        <tag3> TEXT </tag3>
    </smth>
</rt>

And produces this output:

<?xml version="1.0" encoding="UTF-8"?>
<rt>
   <contain>
      <attributes/>
   </contain>
   <smth>
      <tag3> TEXT </tag3>
   </smth>
</rt>