开发者

How to remove certain nodes in an xml using xslt?

Does any one know how to make the following transformation using xslt?

Source code:

<?xml version="1.0" encoding="UTF-8"?>
<body>
  <termEntry id="1">
   <langSet lang="eng-us">
    <ntig>
     <termGrp>
      <term></term>
     </termGrp>
    </ntig>
    <ntig>
     <termGrp>
      <term></term>
     </termGrp>
    </ntig>
   </langSet>

   <langSet lang="ara-ae">
    <ntig>
     <termGrp>
      <term>123</term>
     </termGrp>
    </ntig>
   </langSet>
</termEntry>

<termEntry id="2">
 <langSet lang="eng-us">
  <ntig>
   <termGrp>
    <term></term>
   </termGrp>
  </ntig>
  <ntig>
   <termGrp>
    <term></term>
 开发者_JAVA百科  </termGrp>
  </ntig>
  <ntig>
   <termGrp>
    <term>123</term>
   </termGrp>
  </ntig>
 </langSet>
</termEntry>
</body>

Request: 1.if the value in <term></term> is null\empty, delete its grandparent node, namely

<ntig></ntig>

2.In this way, if all <term> tags are empty, delete the whole <langset> node.

Expected result

<?xml version="1.0" encoding="UTF-8"?>
<body>
  <termEntry id="1">

   <langSet lang="ara-ae">
    <ntig>
     <termGrp>
      <term>123</term>
     </termGrp>
    </ntig>
   </langSet>
  </termEntry>

  <termEntry id="2">
   <langSet lang="eng-us">
    <ntig>
     <termGrp>
      <term>123</term>
     </termGrp>
    </ntig>
   </langSet>
 </termEntry>
</body>


The identity transform plus a couple of simple empty templates is what you need here. You want to copy all your input to the output unless it meets your criteria, in which case you want to suppress it.

A stylesheet such as:

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

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

    <xsl:template match="ntig[descendant::term[. = '']]"/>
    <xsl:template match="langSet[not(descendant::term[. != ''])]"/>

</xsl:stylesheet>

will do what you need. The template which matches ntig elements will suppress those elements with empty term grandchildren. The template which matches langSet elements suppresses those langSets where there are no descendant term elements which have content.


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="ntig[not(*/term[string-length()>0])]"/>
 <xsl:template match="langSet[not(*/*/term[string-length()>0])]"/>
</xsl:stylesheet>

when applied on the provided XML document:

<body>
    <termEntry id="1">
        <langSet lang="eng-us">
            <ntig>
                <termGrp>
                    <term></term>
                </termGrp>
            </ntig>
            <ntig>
                <termGrp>
                    <term></term>
                </termGrp>
            </ntig>
        </langSet>
        <langSet lang="ara-ae">
            <ntig>
                <termGrp>
                    <term>123</term>
                </termGrp>
            </ntig>
        </langSet>
    </termEntry>
    <termEntry id="2">
        <langSet lang="eng-us">
            <ntig>
                <termGrp>
                    <term></term>
                </termGrp>
            </ntig>
            <ntig>
                <termGrp>
                    <term></term>
                </termGrp>
            </ntig>
            <ntig>
                <termGrp>
                    <term>123</term>
                </termGrp>
            </ntig>
        </langSet>
    </termEntry>
</body>

produces the wanted result:

<body>
   <termEntry id="1">
      <langSet lang="ara-ae">
         <ntig>
            <termGrp>
               <term>123</term>
            </termGrp>
         </ntig>
      </langSet>
   </termEntry>
   <termEntry id="2">
      <langSet lang="eng-us">
         <ntig>
            <termGrp>
               <term>123</term>
            </termGrp>
         </ntig>
      </langSet>
   </termEntry>
</body>

Explanation:

  1. The identity rule (template) copies every node "as-is".

  2. The template overriding the identity rule for ntig[not(*/term[string-length()>0])] has an empty body -- this effectively ignores (deletes) any ntig element that doesn't have at lest one term grandchild with positive string-length().

  3. The template overriding the identity rule for langSet[not(*/*/term[string-length()>0])] has an empty body -- this effectively ignores (deletes) any langSet element that doesn't have at lest one term great-grandchild with positive string-length().

Do note that specifying templates like this violates the definition of the problem:

<xsl:template match="ntig[descendant::term[. = '']]"/> 
<xsl:template match="langSet[not(descendant::term[. != ''])]"/>   

Because the requirement is to "if the value in is null\empty, delete its grandparent node".

However, the first template above deletes not only the grand-parent ntig, but any ancestor ntig.

The current solution does not commit such a mistake.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜