我正在尝试选择1)来自具有特定属性的节点的所有节点,并且2)自己具有特定属性。所以,如果我有以下XML:
<node id="1"><child attr="valueOfInterest"/></node>
<node id="2"><child attr="boringValue"/></node>
...
<node id="3"><child attr="valueOfInterest"/></node>
<node id="4"><child attr="boringValue"/></node>
<node id="5"><child attr="boringValue"/></node>
<node id="6"><child attr="boringValue"/></node>
...
我的XSLT遍历每个node
标记。在每个node
,我希望它选择自node
node
child
attr
以来valueOfInterest
以来发生的所有先前<xsl:variable name="prev_vals"
select="preceding-sibling::node/child[@attr = $someValueICareAbout]/@attr"/>
attr
}}。所以,如果我在节点#2,我想要一个空节点集。如果我在节点#6,我想选择节点#4和5.我目前有以下XSLT:
attr
因此,此XSLT获取特定值的所有前面的node
值。我如何仅获取node
之后child
之前的attr
值,id
具有node
具有特定<xsl:variable name="prev_children_of_interest"
select="preceding-sibling::node/child[@attr != $someValueICareAbout]"/>
<xsl:variable name="mru_child_of_interest"
select="$prev_children_of_interest[count($prev_children_of_interest)]"/>
值的最新值child
,“valueOfInterest”)? attr=valueOfInterest
标记上的child
属性不保证会增加,因此我们无法与之进行比较。
编辑:我认为这些可能有用:
mru_child_of_interest
这是所有以前的parent
标记{{1}},然后是最近使用的(最接近当前节点){{1}}标记,其中包含我正在寻找的属性。从{{1}}我们可以找到最近使用的{{1}}标记,但是我们如何查找该标记之后的节点?
答案 0 :(得分:6)
我不确定我是否正确理解了您的问题,但这里有一些XSL 1.0(其他each-nodes
属性仅供参考):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="nodes">
<xsl:copy>
<xsl:apply-templates select="node"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node">
<xsl:variable name="someValueICareAbout">valueOfInterest</xsl:variable>
<xsl:variable name="recentParticularNode"
select="preceding-sibling::node[child/@attr = $someValueICareAbout][1]"/>
<xsl:variable name="recentParticularNodePosition"
select="count($recentParticularNode/preceding-sibling::node) + 1"/>
<xsl:variable name="currentPosition" select="position()"/>
<xsl:if test="child/@attr != $someValueICareAbout">
<each-nodes id="{@id}" cp="{$currentPosition}"
rpnp="{$recentParticularNodePosition}">
<xsl:copy-of
select="../node[position() > $recentParticularNodePosition
and position() < $currentPosition]"/>
</each-nodes>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输入XML:
<?xml version="1.0" encoding="UTF-8"?>
<nodes>
<node id="1"><child attr="valueOfInterest"/></node>
<node id="2"><child attr="boringValue2"/></node>
<node id="3"><child attr="valueOfInterest"/></node>
<node id="4"><child attr="boringValue4"/></node>
<node id="5"><child attr="boringValue5"/></node>
<node id="6"><child attr="boringValue6"/></node>
</nodes>
结果XML:
<?xml version="1.0" encoding="UTF-8"?>
<nodes>
<each-nodes id="2" cp="2" rpnp="1"/>
<each-nodes id="4" cp="4" rpnp="3"/>
<each-nodes id="5" cp="5" rpnp="3">
<node id="4">
<child attr="boringValue4"/>
</node>
</each-nodes>
<each-nodes id="6" cp="6" rpnp="3">
<node id="4">
<child attr="boringValue4"/>
</node>
<node id="5">
<child attr="boringValue5"/>
</node>
</each-nodes>
</nodes>
答案 1 :(得分:3)
看起来你想要两组的交集。集合1是最后一个valueOfInterest
之后的所有节点。 Set 2是当前节点之前不包含valueOfInterest
的所有节点。对于XPath 1.0,以下内容将为您提供交集(找到引用here)。
$set1[count($set2|.)=count($set2)]
根据您的输入,以下XSL演示了您要查找的节点集
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="someValueICareAbout">valueOfInterest</xsl:variable>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[child/@attr='boringValue']">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:variable name="set1" select="preceding-sibling::node[child/@attr='valueOfInterest'][1]/following-sibling::node "/>
<xsl:variable name="set2" select="preceding-sibling::node[child/@attr='boringValue']"/>
<predecessors>
<xsl:copy-of select="$set1[count($set2|.)=count($set2)]"/>
</predecessors>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这是输出
<xml>
<node id="1">
<child attr="valueOfInterest"/>
</node>
<node id="2">
<child attr="boringValue"/>
<predecessors/>
</node>
<node id="3">
<child attr="valueOfInterest"/>
</node>
<node id="4">
<child attr="boringValue"/>
<predecessors/>
</node>
<node id="5">
<child attr="boringValue"/>
<predecessors>
<node id="4">
<child attr="boringValue"/>
</node>
</predecessors>
</node>
<node id="6">
<child attr="boringValue"/>
<predecessors>
<node id="4">
<child attr="boringValue"/>
</node>
<node id="5">
<child attr="boringValue"/>
</node>
</predecessors>
</node>
</xml>
请注意,我在[1]
中使用preceding-sibling::node[child/@attr='valueOfInterest'][1]
的原因是因为preceding-sibling
see here推翻了节点集的顺序。
如果您有XPath 2.0,则可以使用intersect
运算符
<predecessors>
<xsl:copy-of select="$set1 intersect $set2"/>
</predecessors>
这会产生相同的结果。
答案 2 :(得分:3)
此转换完全复制了所需的节点:
<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[not(child/attr='valueOfInterest')]">
<xsl:variable name="vFollowing" select=
"preceding-sibling::node
[child/@attr='valueOfInterest'][1]
/following-sibling::node"/>
<xsl:variable name="vPreceding" select=
"preceding-sibling::node"/>
<xsl:copy-of select=
"$vFollowing[count(. | $vPreceding)
=
count($vPreceding)
]
"/>
======================
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
应用于此XML文档(基于提供的XML片段并将其包装在顶部元素中以使其成为格式良好的XML文档):
<t>
<node id="1">
<child attr="valueOfInterest"/>
</node>
<node id="2">
<child attr="boringValue"/>
</node>...
<node id="3">
<child attr="valueOfInterest"/>
</node>
<node id="4">
<child attr="boringValue"/>
</node>
<node id="5">
<child attr="boringValue"/>
</node>
<node id="6">
<child attr="boringValue"/>
</node>...
</t>
产生了想要的正确结果:
======================
======================
<node id="2">
<child attr="boringValue"/>
</node>
======================
======================
<node id="4">
<child attr="boringValue"/>
</node>
======================
<node id="4">
<child attr="boringValue"/>
</node>
<node id="5">
<child attr="boringValue"/>
</node>
======================
<强>解释强>:
这里我们使用众所周知的 Kayessian 公式(由SO用户@Michael Kay发现),用于两个节点集$ns1
和{{1}的交集}:
ns1 [count(。| $ ns2)= count($ ns2)]
我们只需将$ns2
和$vFollowing
替换为上述公式中的$vPreceding
和$ns1
。
$ns2
节点$vFollowing is defined to contain exactly all the following sibling elements named
node`(有趣)。
of the nearest
是当前(匹配)节点的兄弟之前的所有$vPreceding
元素的集合。
0.3。它们的交集正好是所需的节点集。
答案 3 :(得分:2)
这是在XSLT 2.0中实现它的一种方法:
<xsl:variable name="prevVOI"
select="(preceding-sibling::node[child/@attr = 'valueOfInterest'])[last()]" />
<xsl:variable name="prevNodesAfterVOI"
select="preceding-sibling::node[. >> $prevVOI]" />