使用这个 XPath 1.0 表达式(类似于@Flynn1179 的做法,但使用严格的> 比较,并且也有排除节点的限制,其父节点也在更改的节点中,并且从结果中排除<c> 元素本身。此外,我使用的是preceding:: 轴而不是preceding-sibling:: 轴。这允许<c> 开始和结束类型元素位于文档中的不同级别(不是兄弟姐妹)):
//node()
[count(preceding::c[@type='changeStart'])
> count(preceding::c[@type='changeEnd'])
and not(parent::*
[count(preceding::c[@type='changeStart'])
> count(preceding::c[@type='changeEnd'])]
)
and not(self::c[@type[.='changeStart' or .='changeEnd']])
]
基于 XSLT 的验证:
<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="/">
<xsl:for-each select=
"//node()
[count(preceding::c[@type='changeStart'])
> count(preceding::c[@type='changeEnd'])
and not(parent::*
[count(preceding::c[@type='changeStart'])
> count(preceding::c[@type='changeEnd'])]
)
and not(self::c[@type[.='changeStart' or .='changeEnd']])
]">
<xsl:value-of select="concat('
',position(), '. ')"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<doc>
<p><c type="changeStart"/><style type="underline">text</style><c type="changeEnd"/><t/>In addition
to voting Finance Company and Business Company, Inc.: (i) the name
of the <c type="changeStart"/>new public entity<c type="changeEnd"/> will be “Finance Company.”
as Finance Company’s corporate existence is perpetual as opposed to Business Company, Inc.’s corprate
existence terminating <c type="changeStart"/> <c type="changeEnd"/>
</p>
</doc>
产生正确的结果:
1. <style type="underline">text</style>
2. new public entity
为了也得到带有两个空格的文本节点,请从上述转换中删除<xsl:strip-space elements="*"/> 声明。
这是一个更具挑战性的案例。在这个 XML 文档上应用转换:
<t>
<x>
<c type="changeStart"/>
<y> content
<z>
<p>
</p>
</z>
</y>
<c type="changeStart"/>
<v>
</v>
<c type="changeEnd"/>
<r/>
<c type="changeEnd"/>
<s/>
</x>
</t>
产生正确的结果:
1. <y> content
<z>
<p/>
</z>
</y>
2. <v/>
3. <r/>