这是我的输入xml:
<root>
<node1/>
<node2/>
<node3/>
<node4/>
<othertags/>
</root>
输出必须是:
<root>
<othertags/>
</root>
如果4个节点中的任何一个不为空,则必须删除所有标记。
示例:
<root>
<node1/>
<node2/>
<node3/>
<node4>sample_text</node4>
<othertags/>
</root>
然后输出必须与输入xml相同。
<root>
<node1/>
<node2/>
<node3/>
<node4>sample_text</node4>
<othertags/>
</root>
这是我设计的XSL代码::
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/node1[.='' and ../node2/.='' and ../node3/.='' and ../node4/.='']
|/root/node2[.='' and ../node1/.='' and ../node3/.='' and ../node4/.='']
|/root/node3[.='' and ../node1/.='' and ../node2/.='' and ../node4/.='']
|/root/node4[.='' and ../node1/.='' and ../node2/.='' and ../node3/.='']"/>
正如您所看到的,代码需要更多的努力,并且随着节点数量的增加而变得更加庞大。有没有其他方法可以克服这个瓶颈?
答案 0 :(得分:2)
您是否尝试过(未经测试)
<xsl:template match="node1|node2|node3|node4">
<xsl:if test="
(preceding-sibling::*|.|following-sibling::*)[
self::node1 or self::node2 or self::node3 or self::node4
][.!='']
">
<xsl:copy-of select="." />
</if>
</xsl:template>
答案 1 :(得分:0)
模式“filter-that-nodes”检查条件,“not-those-nodes”删除不需要的节点。未过滤的节点将匹配其中一个无模式应用模板,就好像我们只是说'在'根'模板内部一样。
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates mode="filter-those-nodes"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="filter-those-nodes">
<xsl:choose>
<xsl:when test="'' = concat(node1, node2, node3, node4)">
<xsl:apply-templates mode="filter-those-nodes"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node1 | node2 | node3 | node4" mode="not-those-nodes">
<!-- filtered out -->
</xsl:template>
<xsl:template match="*" mode="not-those-nodes">
<xsl:apply-templates select="." />
</xsl:template>
答案 2 :(得分:0)
更精确,更优化的解决方案:
<强>予。 “常规”XSLT 1.0
<xsl:variable name="vNotAllEmpty" select=
"/*/*
[self::node1|self::node2|self::node3|self::node4]
[not(. = '')]
"/>
<xsl:template match="node()|@*" name="indent">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"/*/*/node1|/*/*/node2|/*/*/node3|/*/*/node4">
<xsl:if test="$vNotAllEmpty">
<xsl:call-template name="indent"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
为什么更精确??因为特定模板仅匹配作为顶部元素的子节点的node{N}
个节点。
为什么效率更高?因为决定是否处理node{N}
节点的测试只执行一次,而每个节点发生一次。
<强> II。使用FXSL
FXSL library 具有方便的模板/函数,可以确定节点集中的所有节点或某些节点是否为真(或者对它们应用的条件是否为真)。 / p>
对于这个问题,最合适的FXSL模板是someTrue
。这是完整的转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="someTrue.xsl"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="vallNodes" select=
"/*/*[starts-with(name(), 'node')]"/>
<xsl:variable name="vNotAllEmpty">
<xsl:call-template name="someTrue">
<xsl:with-param name="pList"
select="$vallNodes"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="node()|@*" name="indent">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="visInspectedNode" select=
"count(.|$vallNodes) = count($vallNodes)"/>
<xsl:if test=
"not($visInspectedNode)
or
($visInspectedNode and string($vNotAllEmpty))
">
<xsl:call-template name="indent"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
请注意以下:
要处理的节点(在$vallNodes
中保留)可能有数百和数千个。
该解决方案具有高度可扩展性。我们可以分别使用FXSL模板allTrueP
和someTrueP
来测试所有节点或某些节点是否满足指定条件。
扫描所有节点并累积真值的逻辑是在这些模板中固定的,你从不编码这个逻辑 - 因此不会浪费额外的时间,也不可能提交错误。
答案 3 :(得分:0)
<xsl:template match="/root/node()[name()='node1' or name()='node2' or name()='node3' or name()='node4']
[../node1/.='' and ../node2/.='' and ../node3/.='' and ../node4/.='']"/>