我知道以前有人回答过这个问题,但我很好奇如何在没有钥匙的情况下实现这个目标。
我有这个XML,我必须得到{%tab%}和{%endtab%}之间的节点。
<element>
<hello>{%tab%}</hello>
<hello>yes</hello>
<hello>{%endtab%}</hello>
<hello>no</hello>
<hello>no</hello>
<hello>{%tab%}</hello>
<hello>yes</hello>
<hello>{%endtab%}</hello>
</element>这就是我得到的:
<xsl:template match="hello[preceding-sibling::hello[not(normalize-space(text())!='{%tab%}')]]
[following-sibling::hello[not(normalize-space(text())!='{%endtab%}')]]
[
(preceding-sibling::hello[not(normalize-space(text())!='{%tab%}')])[1]/(following-sibling::hello[not(normalize-space(text())!='{%endtab%}')])[1]
= (following-sibling::hello[not(normalize-space(text())!='{%endtab%}')])[1]
]">
<strong><xsl:value-of select="." /></strong>
</xsl:template>这将选择所有节点,这些节点后面是{%endtab%},前面是{%tab%}节点。
hello[preceding-sibling::hello[not(normalize-space(text())!='{%tab%}')]]
[following-sibling::hello[not(normalize-space(text())!='{%endtab%}')]]这方面的问题是,"no“节点也被选中,因为它们也位于这些节点之间。因此,我必须确保某个节点后面的{%endtab%} (它的第一次出现)与前面的{%选项卡%}后面的{%选项卡%}相同,这是我对这个XPath所做的:
[
(preceding-sibling::hello[not(normalize-space(text())!='{%tab%}')])[1]
/(following-sibling::hello[not(normalize-space(text())!='{%endtab%}')])[1]
= (following-sibling::hello[not(normalize-space(text())!='{%endtab%}')])[1]
]但是,这并没有像预期的那样过滤"no“节点。
发布于 2015-03-16 00:29:12
这个XPath表达式
/*/*[not(. = '{%tab%}' or . = '{%endtab%}')
and preceding-sibling::*[. = '{%tab%}' or . = '{%endtab%}'][1] = '{%tab%}'
and following-sibling::*[. = '{%tab%}' or . = '{%endtab%}'][1] = '{%endtab%}'
]选择顶部元素的子元素,该元素位于具有字符串值{%tab%}的兄弟元素和具有字符串值{%endtab%}的兄弟元素之间。
这里是一个使用简单XSLT转换的运行示例
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/*[not(. = '{%tab%}' or . = '{%endtab%}')
and preceding-sibling::*[. = '{%tab%}' or . = '{%endtab%}'][1] = '{%tab%}'
and following-sibling::*[. = '{%tab%}' or . = '{%endtab%}'][1] = '{%endtab%}'
]"/>
</xsl:template>
</xsl:stylesheet>当此转换应用于所提供的源XML文档时,则为。
<element>
<hello>{%tab%}</hello>
<hello>yes</hello>
<hello>{%endtab%}</hello>
<hello>no</hello>
<hello>no</hello>
<hello>{%tab%}</hello>
<hello>yes</hello>
<hello>{%endtab%}</hello>
</element>想要的,正确的结果产生
<hello>yes</hello>
<hello>yes</hello>发布于 2015-03-15 01:45:35
忽略下面的兄弟姐妹,计算前面的tab和前面的endtab。如果它们不相等,那么您要么是endtab,要么是yes。排除您是endtab的情况。
请允许我不再使用normalize-space(),以使示例更清晰。
<xsl:template match="hello[
(. != '{%endtab%}')
and
(
count(preceding-sibling::hello[. = '{%tab%}'])
!= count(preceding-sibling::hello[. = '{%endtab%}'])
)
]">发布于 2015-03-16 03:41:48
两份普遍感兴趣的说明:
1.
我知道以前有人回答过这个问题,但我很好奇如何在没有钥匙的情况下实现这个目标。
使用键的解决方案链接如下:
https://stackoverflow.com/a/28179346/3016153
2.
由于XSLT2.0解决方案之前已经有人提出,我建议另一个我认为要简单得多的解决方案:
XSLT2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/element">
<xsl:copy>
<xsl:for-each-group select="hello" group-starting-with="hello[.='{%tab%}']">
<xsl:for-each-group select="current-group()" group-ending-with="hello[.='{%endtab%}']">
<xsl:if test="current-group()[self::hello[.='{%tab%}']]">
<xsl:for-each select="current-group()[not(position()=1 or position()=last())]">
<strong><xsl:value-of select="." /></strong>
</xsl:for-each>
</xsl:if>
</xsl:for-each-group>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>https://stackoverflow.com/questions/29056074
复制相似问题