7 回答
dsteinweg让我走上了正轨……我最终做了:
<xsl:template match="b">
<xsl:if test="./* or ./text()">
<xsl:element name="b">
<xsl:apply-templates/>
</xsl:element>
</xsl:if>
</xsl:template>
此转换忽略任何没有任何子节点的 <b> 元素。在此上下文中的节点是指元素、文本、注释或处理指令节点。
<xsl:stylesheet 版本="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:输出省略-xml-declaration="yes"/> <xsl:template match="node()|@*"> <xsl:复制> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:模板> <xsl:template match="b[not(node()]"/> </xsl:样式表>
请注意,这里我们使用了最基本的 XSLT 设计模式之一——使用身份转换并为特定节点覆盖它。
将只为名为“b”的元素且没有(任何节点)子节点的节点选择覆盖模板。这个模板是空的(没有任何内容),所以其应用的效果是匹配节点被忽略/丢弃,并且不在输出中重现。
这种技术非常强大,被广泛用于此类任务,也可用于重命名、更改内容或属性、将子节点或兄弟节点添加到任何可以匹配的特定节点(可以使用除命名空间节点之外的任何类型的节点作为 <xsl:template/> 的“匹配”属性中的匹配模式
希望这有帮助。
干杯,
迪米特·诺瓦切夫
我想知道这是否可行?
<xsl:template match="b">
<xsl:if test="b/text()">
...
看看这是否可行。
<xsl:template match="b">
<xsl:if test=".!=''">
<xsl:element name="b">
<xsl:apply-templates/>
</xsl:element>
</xsl:if>
</xsl:template>
另一种方法是执行以下操作:
<xsl:template match="b[not(text())]" />
<xsl:template match="b">
<b>
<xsl:apply-templates/>
</b>
</xsl:template>
您可以将所有逻辑放在谓词中,并设置一个模板以仅匹配您想要的内容并将其删除:
<xsl:template match="b[not(node())] />
这假设您稍后在转换中有一个身份模板,听起来就像您所做的那样。这将自动复制任何带有内容的“b”标签,这就是你想要的:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
编辑:现在像下面的 Dimitri 一样使用 node()。
如果您有权更新原始 XML,则可以尝试在根元素上使用xml:space=preserve
<html xml:space="preserve">
...
</html>
这样,空的 <b> </b> 标记中的空间被保留,因此可以与 XSLT 中的 <b /> 区分开来。
<xsl:template match="b">
<xsl:if test="text() != ''">
....
</xsl:if>
</xsl:template>