给出如下文件:
<root>
<a>
<b>
<c>Sometext</c>
</b>
<b>
<d/>
</b>
<b>
<e>
<f>Some interesting__text some more</f>
</e>
</b>
</a>
<h>
<g>Another piece of very_interesting__text</g>
</h>
</root>
我想了解以下内容:
<root>
<a>
<b>
<e>
<f>Some interesting__text some more</f>
</e>
</b>
</a>
<h>
<g>Another piece of very_interesting__text</g>
</h>
<interesting>interesting__text</interesting>
<interesting>very_interesting__text</interesting>
</root>
基本上,我需要找出包含有趣文本的任何节点的所有父节点,这些节点可以使用正则表达式\w+__\w+
进行匹配。
作为奖励,我想在文档末尾的某处添加所有有趣的部分。
可以包含有趣部分的节点可以任意命名,因此对特定节点名称的任何依赖都不能成为解决方案的一部分。
我认为XSLT是一个很好的方法来解决这个问题,但我很难将样式表放在一起。显然,我可以在代码中执行此操作,但更喜欢样式表,因为我已经在我的脚本中使用了其他内容,所以这会简化一些事情。
提前致谢。
编辑:示例XML中有一个错误,其中一条评论询问为什么标签正在转换为标签 - 现在已经在上面更正了。
答案 0 :(得分:4)
这是我的XSLT 2.0建议:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pattern" select="'\w+__\w+'"/>
<xsl:output indent="yes"/>
<xsl:variable name="text" select="//text()[matches(., $pattern)]"/>
<xsl:variable name="nodes" select="$text/ancestor-or-self::node()"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@* , node()[$nodes intersect .]"/>
<xsl:apply-templates select="$text" mode="interesting"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()[$nodes intersect .]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="interesting">
<interesting><xsl:value-of select="."/></interesting>
</xsl:template>
</xsl:stylesheet>
使用Saxon 9.5,它转换
<root>
<a>
<b>
<c>Sometext</c>
</b>
<b>
<d/>
</b>
<b>
<e>
<f>Some interesting__text some more</f>
</e>
</b>
</a>
<f>
<g>Another piece of very_interesting__text</g>
</f>
</root>
到
<root>
<a>
<b>
<e>
<f>Some interesting__text some more</f>
</e>
</b>
</a>
<f>
<g>Another piece of very_interesting__text</g>
</f>
<interesting>Some interesting__text some more</interesting>
<interesting>Another piece of very_interesting__text</interesting>
</root>
示例节点没有属性,如果他们可以在真实XML中拥有它们,那么添加模板
<xsl:template match="@*">
<xsl:copy/>
</xsl:template>
要过滤interesting
元素集合中的文本节点,可以使用analyze-string
,以便将text()
的模板更改为
<xsl:template match="text()" mode="interesting">
<interesting>
<xsl:analyze-string select="." regex="{$pattern}">
<xsl:matching-substring>
<xsl:value-of select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
</interesting>
</xsl:template>
结果更改为
<root>
<a>
<b>
<e>
<f>Some interesting__text some more</f>
</e>
</b>
</a>
<f>
<g>Another piece of very_interesting__text</g>
</f>
<interesting>interesting__text</interesting>
<interesting>interesting__text</interesting>
</root>
如果还应提取very_
子字符串,则可能需要更改或修改模式。
答案 1 :(得分:-1)
<xsl:template match="root">
<xsl:element name="root">
<xsl:apply-templates/>
<interesting>interesting__text</interesting>
<interesting>very_interesting__text</interesting>
</xsl:element>
</xsl:template>
<xsl:template match="b[1]"/>
<xsl:template match="b[2]"/>
<xsl:template match="b[3]">
<xsl:element name="b">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="e">
<xsl:element name="e">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="f">
<xsl:element name="f">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="h">
<xsl:element name="h">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="g">
<xsl:element name="g">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>