【问题标题】:Set difference with XPath 1.0 - how do I get .//table without .//table//table?设置与 XPath 1.0 的差异 - 如何在没有 .//table//table 的情况下获得 .//table?
【发布时间】:2011-01-04 17:56:43
【问题描述】:

我正在尝试查找当前节点下的所有表,但不包括嵌套表。换句话说,如果我有这个,我想找到“是”而不是“否”:

<table> <!-- outer table - no -->
  <tr><td>
    <div> <!-- *** context node *** -->
      <table> <!-- yes -->
        <tr><td>
          <table> ... </table> <!-- no -->
        </td></tr>
      </table>
      <table> <!-- yes -->
        <tr><td>
          <table> ... </table> <!-- no -->
        </td></tr>
      </table>
    </div>
  </td></tr>
</table>

在 XPath 1.0 中是否有任何简单的方法可以做到这一点? (在 2.0 中,应该是 .//table except .//table//table,但我没有 2.0 选项。)

编辑:请,到目前为止的答案不尊重当前上下文节点的想法。我不知道第一层桌子可能在多远(并且可能会有所不同),我也不知道我是否可能在另一张桌子(或两个或三个)内。

从字面上看,我想要 XPath 2.0 中的 .//table except .//table//table,但我只有 XPath 1。

【问题讨论】:

  • 我认为只写一个 XPath 1.0 是不可能的,因为我需要多次使用一个上下文,这是不允许的。我可以使用两个 XPath,一个 XPath 用于获取变量的值,第二个 XPath 用于获取所需的表吗?
  • 你把它做成CW是什么原因?这是一个相当棘手的问题,它会有一个正确的答案,它不是 CW 的候选人。
  • 什么是“CW”?你在那里称呼谁为“你”?我?我是怎么把它变成“CW”的? :)
  • CW 是“社区 Wiki”——在最基本的层面上,它使您的问题 a:其他人更容易编辑,并且 b:您不会从中获得任何代表点数;但实际上它往往暗示这是一个更基于讨论的问题。您通过单击复选框来完成此操作,并且没有“撤消” - 但最终如果您得到合适的答案,这不会产生很大的不同。

标签: xpath set-difference


【解决方案1】:

在这里和其他地方对其进行调查后,答案似乎是“你不能,这就是我们拥有 XPath 2.0 的原因”。哦,好吧。

【讨论】:

    【解决方案2】:

    我不知道如何让上下文节点在嵌套谓词中被评估,但你需要的是这样的:

    descendant::table[not(ancestor::table[ancestor::div])]
    

    只能引用上下文节点,而不是div

    EDIT:如果为上下文节点设置变量,

    <xsl:variable name="contextNode" select="." />
    

    那么你可以在 XPATH 谓词中引用它:

    descendant::table[not(ancestor::table[ancestor::*[generate-id(.)=generate-id($contextNode)]])]
    

    【讨论】:

    • 是的,这仍然行不通,因为它会排除任何 div 中的任何表中的任何表。 :) 不再尊重上下文。
    • 更新了我的答案。它不是纯 XPATH,而是 XPATH 1.0(和 XSLT 1.0)解决方案。
    • 是的,这里没有 XSLT。所以这也不行。 {叹息}。
    【解决方案3】:

    .//table[not(.//table)] 呢?抱歉,我正在打电话。

    【讨论】:

    • 不,它会找到所有没有表格的表格。我想要所有不在表格中的表格。
    • 好的,.//table[not(ancestor::table)] 怎么样?不过,这很可能效率低下,除非您在 eXist 之类的东西中执行此操作,它具有支持它的索引。
    • 不。只要它们不在 any 表中,就会找到所有表。但是考虑一下如果我们的上下文节点已经在一个表中会发生什么。它会发现什么都没有。不,不是答案。
    【解决方案4】:

    嗯,如果我理解了,content_list就可以解决:

    my $table_one = $tree->findnodes('/html//table')->[1];
    
    for ( $table_one->content_list ) {
        last if $_->exists('table');
        print $_->as_text;
    }   
    

    :)

    【讨论】:

    • 不。这不尊重上下文节点。
    【解决方案5】:

    我想你想要 child::table aka table

    #!/usr/bin/perl --
    use strict;
    use warnings;
    
    use HTML::TreeBuilder;
    {
      my $tree = HTML::TreeBuilder->new();
    
      $tree->parse(<<'__HTML__');
    <table> <!-- outer table - no -->
      <tr><td>
        <div> <!-- *** context node *** -->
          <table> <!-- yes -->
            <tr><td>
              <table> ... </table> <!-- no -->
            </td></tr>
          </table>
          <table> <!-- yes -->
            <tr><td>
              <table> ... </table> <!-- no -->
            </td></tr>
          </table>
        </div>
      </td></tr>
    </table>
    __HTML__
    
      sub HTML::Element::addressx {
        return join(
          '/',
          '/', # // ROOT
          reverse(    # so it starts at the top
            map {
              my $n = $_->pindex() || '0';
              my $t = $_->tag;
              $t . '['. $n .']'
              }         # so that root's undef -> '0'
              $_[0],    # self and...
            $_[0]->lineage
          )
        );
      } ## end sub HTML::Element::addressx
    
      for my $td ( $tree->look_down( _tag => qr/div|table/i ) ) {
        print $td->addressx, "\n";
      }
      $tree->delete;
      undef $tree;
    }
    __END__
    //html[0]/body[1]/table[0]
    //html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]
    //html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[0]
    //html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[0]/tr[0]/td[0]/table[0]
    //html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[1]
    //html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[1]/tr[0]/td[0]/table[0]
    

    第二部分

    #!/usr/bin/perl --
    
    use strict;
    use warnings;
    
    use HTML::TreeBuilder::XPath;
    
    my $tree = HTML::TreeBuilder::XPath->new;
    $tree->parse_content(<<'__HTML__');
    <table> <!-- outer table - no -->
      <tr><td>
        <div> <!-- *** context node *** -->
          <table> <!-- yes -->
            <tr><td>
              <table> ... </table> <!-- no -->
            </td></tr>
          </table>
          <table> <!-- yes -->
            <tr><td>
              <table> ... </table> <!-- no -->
            </td></tr>
          </table>
        </div>
      </td></tr>
    </table>
    __HTML__
    
    
    
    #~ for my $result ($tree->findnodes(q{//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]})) {
    for my $result ($tree->findnodes(q{/html/body/table/tr/td/div})) {
        print $result->as_HTML,"\n\n";
        for my $table( $result->findnodes(q{table}) ){ ## child::table
            print "$table\n";
            print $table->as_HTML,"\n\n\n";
        }
    
    }
    
    __END__
    <div><table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table><table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table></div>
    
    
    HTML::Element=HASH(0xc6c964)
    <table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table>
    
    
    
    HTML::Element=HASH(0xc6cbf4)
    <table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table>
    

    【讨论】:

    • 不,不考虑上下文节点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 2021-02-12
    相关资源
    最近更新 更多