XSLT:如何在任何深度解析文档以仅保留有趣的节点以及所有父节点?

时间:2014-05-31 07:01:11

标签: xslt

给出如下文件:

<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中有一个错误,其中一条评论询问为什么标签正在转换为标签 - 现在已经在上面更正了。

2 个答案:

答案 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>