XSLT或XQuery是否可以查询子树

时间:2018-07-10 13:07:24

标签: xml xslt xpath css-selectors xquery

说我有一棵这样的树(但实际上,有成千上万个节点,例如HTML文档):

                               a
                   ____________|____________
                  |                         |
                  b                         f
      ____________|                     ____|____
     |            |                    |         |
     c            m                    x         y
 ____|____      __|__                            |
|  |   |  |    |     |                           w
d  e   r  s    q     u
          |
          t

我想使用这种“树正则表达式”查询子树(其中*表示跳过节点,字母是节点标签或标记):

 __           __          __                                    __ 
/               \        /                                        \
|        a      |        |      a           a             a       |
|      /   \    |        |    /   \         |           /   \     |
|      b   f    |        |    b   f         z           *   f     |
|      |        |   OR   |    |       AND       AND   /   \  \    |  
|      c        |        |    x                       n   o   w   | 
|    /   \      |        |                            |           |      
|    d   e      |        |                            p           |    
\__           __/        \__                                    __/     

想知道XSLT,XQuery,XPath,CSS选择器或类似的东西是否可以执行这样的查询。如果是这样,它将如何在高水平上完成。我只是很快地写出了这个示例,而没有真正考虑它是否会很好地工作,因此也许仅尝试部分查询(例如第一个块或最后一个块)会很困难。

更新

这与示例HTML文档中的图片几乎相同:

<a>
  <b id="foo">
    <c>
      <d id="bar"></d>
      <e></e>
      <r></r>
      <s>
        <t></t>
      </s>
    </c>
    <m>
      <q></q>
      <u></u>
    </m>
  </b>
  <f id="baz">
    <x></x>
    <y>
      <w></w>
    </y>
  </f>
</a>

这将是与之匹配的模式:

<a>
  <b>
    <c>
      <d></d>
      <e></e>
    </c>
  </b>
  <f></f>
</a>

这将是输出:

<a>
  <b id="foo">
    <c>
      <d id="bar"></d>
      <e></e>
    </c>
  </b>
  <f id="baz"></f>
</a>

或者这个,要么:

<a>
  <b id="foo">
    <c>
      <d id="bar"></d>
      <e></e>
    </c>
  </b>
  <f id="baz">
    <x></x>
    <y>
      <w></w>
    </y>
  </f>
</a>

1 个答案:

答案 0 :(得分:2)

https://xsltfiddle.liberty-development.net/eiZQaFo/1,我尝试实现注释中的建议,即使用XSLT 3将显示的“模式”树(作为参数提供)转换为XSLT 3样式表,然后应用于使用XPath 3.1 transform函数显示的原始输入树时,XSLT是

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
    version="3.0">

  <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

  <xsl:output indent="yes"/>

  <xsl:param name="pattern-tree">
      <a>
  <b>
    <c>
      <d></d>
      <e></e>
    </c>
  </b>
  <f></f>
</a>
  </xsl:param>

  <xsl:variable name="stylesheet">
      <axsl:stylesheet version="3.0">
          <axsl:mode on-no-match="deep-skip"/>
          <axsl:template match="{string-join($pattern-tree//*!string-join(ancestor-or-self::*/name(), '/'), ' | ')}">
              <axsl:copy>
                  <axsl:apply-templates select="@* | node()"/>
              </axsl:copy>
          </axsl:template>
          <axsl:template match="@*">
              <axsl:copy/>
          </axsl:template>
      </axsl:stylesheet>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:copy-of select="$stylesheet"/>
      <xsl:sequence select="transform(map { 'source-node' : /, 'stylesheet-node' : $stylesheet })?output"/>
  </xsl:template>

</xsl:stylesheet>

有输出(为进行调试和解释,它包含生成的XSLT,但是您当然可以删除/注释<xsl:copy-of select="$stylesheet"/>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
   <xsl:mode on-no-match="deep-skip"/>
   <xsl:template match="a | a/b | a/b/c | a/b/c/d | a/b/c/e | a/f">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="@*">
      <xsl:copy/>
   </xsl:template>
</xsl:stylesheet>
<a>
   <b id="foo">
      <c>
         <d id="bar"/>
         <e/>
      </c>
   </b>
   <f id="baz"/>
</a>