相同的XPath - 不同的结果

时间:2016-02-10 11:43:21

标签: php html xpath domdocument

@Override public void onNothingSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        Intent details = new Intent(PlaceActivity.this, Details.class);
        details.putExtra("name", myArrayList.get(arg2).getName());
        details.putExtra("rating", myArrayList.get(arg2).getRating());
        details.putExtra("vicinity", myArrayList.get(arg2).getVicinity());
        details.putExtra("lat", myArrayList.get(arg2).getLat());
        details.putExtra("lon", myArrayList.get(arg2).getLon());
        startActivity(details);
    }

第一个XPath选择两个表,而第二个表只获取目标(第二个)表。为什么呢?

test on eval.in

2 个答案:

答案 0 :(得分:4)

接受的答案纠正了错误,但并没有真正解释为什么原始路径表达式出错了。

您的第一个表达式如下:

//table[//b[contains(@class, "2")]]

它有两个谓词,一个嵌套在另一个中:

//table[//b[contains(@class, "2")]]
           ^---------------------^       inner predicate
       ^--------------------------^      outer predicate

将谓词视为应用于谓词左侧上下文的过滤器。在极端情况下,这样的谓词都不会丢弃所有中间结果节点。

每个中间结果节点仅在其右侧的谓词评估为true时保留。在内部谓词的情况下:

//b[contains(@class, "2")]

//b生成一组中间b元素节点(整个文档中的所有b个元素节点),然后由谓词[contains(@class, "2")]过滤。给定输入XML文档,谓词中的表达式仅返回true b元素的

//b[contains(@class, "2")]反过来又作为外部谓词的内容:

//table[outer predicate]

现在//table选择整个文档中所有table个元素节点作为中间结果,并且对于每个节点,都会检查谓词中的表达式。

重要的是,外部谓词//b[contains(@class, "2")]将为两个 true元素返回table。这是因为对于它们两者而言,确实在整个文档中的某个位置存在b元素,其class属性包含2

您实际想要做的是:从每个table元素的角度评估外部谓词表达式 - 接受的答案显示了如何执行此操作。即,在谓词中使用.//而不是//

答案 1 :(得分:2)

XPath谓词[//b...]中存在错误。它应该是[.//b...]

说明: [...]是谓词,它们仅充当过滤器。当您说a[b]时,您选择满足谓词a的所有[b]个节点。如果ab是元素,它将从当前上下文节点中选择包含a元素作为子元素的所有b元素。

  • //bAbbreviatedAbsoluteLocationPath,并选择整个文档中的所有b个元素节点。这两个表都在一个符合b元素的文档中,因此无论您在何处应用它,谓词[//b]始终为true。
  • .//bAbbreviatedRelativeLocationPath,并选择所有b元素节点作为后代(子节点及其子节点,递归地)。谓词[.//b]仅适用于具有后代元素table的{​​{1}}元素。

b//b等步骤路径表达式,当用作.//b[//b]等谓词时,如果选择的节点集为 true 步路径表达式不为空。

由于[.//b]而不是//b,所应用的谓词不会改变任何内容。 .//b选择整个文档中//b[contains(@class, "2")]属性中包含“2”的所有元素。您基本上是对文档执行检查,而不是对所需class元素下面的树执行检查,并且table元素的文档检查都已满足,因为两者都在包含{{1}的文档中在其table属性中包含“2”的元素。