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:
The identity rule (template) copies every node "as-is".
The template overriding the identity rule for
ntig[not(*/term[string-length()>0])]
has an empty body -- this effectively ignores (deletes) anyntig
element that doesn't have at lest oneterm
grandchild with positivestring-length()
.The template overriding the identity rule for
langSet[not(*/*/term[string-length()>0])]
has an empty body -- this effectively ignores (deletes) anylangSet
element that doesn't have at lest oneterm
great-grandchild with positivestring-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.
精彩评论