使用 XSLT 删除具有 empty/no 属性的空节点

Removing empty nodes with empty/no attributes using XSLT

我想:


示例

之前

<a>
  <b>
    <c attr="1"/>
    <d/>
  </b>
</a>

之后

<a>
  <b>
    <c attr="1"/>
  </b>
</a>

我有以下 XSLT:

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

效果很好,但前提是我的 XML 至少有一个 non-empty 节点! 示例:

XML:

<ns1:form xmlns:ns1="http://aaa.com">
  <ns1:test>
    <a></a>
    <b attr1=""/>
    <c attr="123"/>
    <d attr="">
      <e attr="12">NOT EMPTY NODE</e>
    </d>
  </ns1:test>
</ns1:form>

之后:

<?xml version="1.0" encoding="UTF-8"?><ns1:form xmlns:ns1="http://aaa.com">
  <ns1:test>
    <c attr="123"/>
    <d>
      <e attr="12">NOT EMPTY NODE</e>
    </d>
  </ns1:test>
</ns1:form>

工作正常,但跳过此 non-empty 节点:

<ns1:form xmlns:ns1="http://aaa.com">
  <ns1:test>
    <a></a>
    <b attr1=""/>
    <c attr="123"/>
    <d attr="">
      <e attr="12"></e>
    </d>
  </ns1:test>
</ns1:form>

输出是:

<?xml version="1.0" encoding="UTF-8"?>

有人知道为什么会这样吗?我的代码:

    TransformerFactory factory = TransformerFactory.newInstance();
    InputStream in = new FileInputStream(new File("transform.xslt"));

    Source xslt = new StreamSource(in);
    Transformer transformer = factory.newTransformer(xslt);
    Source text = new StreamSource(new File("input.xml"));

    StringReader reader = new StringReader(xml);
    Source text = new StreamSource(reader);
    transformer.transform(text, new StreamResult(writer));

干杯

更新

使用 XSLT 后输出为:

<?xml version="1.0" encoding="UTF-8"?><ns1:form xmlns:ns1="http://aaa.com">
<ns1:test>


<c attr="123"/>
<d>
    <e attr="12">e</e>
</d>
</ns1:test>
</ns1:form>

我想知道为什么我的 output.xml 中有空格?


一般来说,空节点就是一个节点,即

1) istelf 没有属性或全为空 AND

2) 没有值 f.e。 <a></a><b/>

3) has no children which carried any data (has no children 满足条件1和2) 解释空节点的示例:

<a>
  <b attr="1">
  </b>
  <c>
  <d attr="2">
    <e> value </e>
    <f></f>
  </d>
</a>

a 不为空,因为它有 child b 和属性 attr="1" (足够了,但它还有:x, xx, xxx)

b 不为空,因为它具有 non-empty 属性

c 不为空,因为它有 d 节点和属性 attr="2" (x) 并且还有 child e 和一些值 (xxx)

d 不为空,因为它具有 non-empty 属性 (xx)

e 不为空,因为它有一个值 (xxx)

f 为空

您不应使 <xsl:apply-templates/> 成为条件 - 否则样式表将在第一个不满足条件的节点处停止,并且永远不会到达其子节点。


顺便说一句,如果正确理解您的条件,您可以将其简化为:

<xsl:template match="*[string() or @*[string()]]">
    <xsl:copy>
        <xsl:copy-of select = "@*[string()]"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>