【问题标题】:If XSLT or XQuery can Query Subtrees如果 XSLT 或 XQuery 可以查询子树
【发布时间】:2018-07-11 12:33:50
【问题描述】:

假设我有一棵这样的树(但实际上,像 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>

【问题讨论】:

  • 所以你想让选择器从现有的树中返回你的新树?例如,x 不是来自第一棵树的 b 的子节点,但您希望 XPath/CSS 选择器返回您的树,其中 xb 的子节点,对吧?
  • 别这么想。我希望 XPath/CSS 从第一个图像中返回与第二个图像中的任何一个树匹配的子树。第一张图是完整树,第二张图是查询树。如果不匹配,则不会返回任何内容。
  • 嗯...好的。因此,关于第一个“子树”,您希望选择器返回 a 节点,以防 它包含 f 子节点和 b 子节点,其中 c 子节点具有 de 子节点 i> 等等...?
  • 所以对于第二张图片中的a,b,c,d,e,f 图像,我希望它返回与第一张图片中的这些标签匹配的实际节点(第一张图片与之匹配)。
  • 那么不仅a节点,而且在case结构匹配的情况下所有6个节点?我不确定,但它看起来像一个 X-Y 问题。你能分享更真实的例子(真正的 HTML/XML DOM 示例)和你想要的输出吗?

标签: xml xslt xpath css-selectors xquery


【解决方案1】:

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,但您当然可以删除/注释掉 &lt;xsl:copy-of select="$stylesheet"/&gt;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多