如何通过xmlXPathNodeEval()将XPath限制为子树?

时间:2014-12-23 20:12:51

标签: xpath libxml2

要仅在某个子树内评估XPath表达式,libxml2函数xmlXPathNodeEval()似乎是要走的路。在给定的上下文中评估XPath表达式的documentation specifies'。但这究竟意味着什么?

请考虑以下小例子:

#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xmlstring.h>
#include <stdio.h>
int main(int argc, char **argv)
{
  const char inp[] =
    "<root>\n"
    " <sub>\n"
    "  <e>0</e>\n"
    "  <Foo>\n"
    "    <e>1</e><e>2</e><e>3</e>\n"
    "    <FooSub><e>3a</e></FooSub>\n"
    "  </Foo>\n"
    "  <Bar>\n"
    "    <e>4</e><e>5</e><e>6</e>\n"
    "  </Bar>\n"
    " </sub>\n"
    " <e>7</e>\n"
    "</root>\n";
  xmlDoc *doc = xmlParseMemory(inp, sizeof(inp)-1);
  xmlXPathContext *ctx = xmlXPathNewContext(doc);
  xmlXPathObject *p = xmlXPathEval(BAD_CAST "//Foo[1]", ctx);

  xmlNode *new_root = *p->nodesetval->nodeTab;
  printf("New root: %s\n", BAD_CAST new_root->name);
  xmlXPathObject *q = xmlXPathNodeEval(new_root, BAD_CAST argv[1], ctx);

  for (int i = 0; i<q->nodesetval->nodeNr; ++i) {
    const xmlChar *cnt = xmlNodeGetContent(q->nodesetval->nodeTab[i]);
    printf("%s ", BAD_CAST cnt);
    xmlFree((xmlChar*)cnt);
  }
  puts("");

  xmlXPathFreeObject(q);
  xmlXPathFreeObject(p);
  xmlXPathFreeContext(ctx);
  xmlFreeDoc(doc);
  return 0;
}

编译通过(在我的例子中使用libxml的2.9.1版本):

$ gcc -g -std=c99 -Wall -I/usr/include/libxml2 -lxml2 relative.c

致电

$ ./a.out '//e'

我希望得到以下结果:

New root: Foo
1 2 3 3a

但我得到了:

New root: Foo
0 1 2 3 3a 4 5 6 7

似乎我必须使用self::node()轴说明符(短.)来获得我想要的结果,即:

$ ./a.out './/e'
New root: Foo
1 2 3 3a 

基本上我正在解释句子&#39;在给定的上下文中评估XPath位置路径&#39;从文档中可以看出:XPath表达式在给定节点的self::node()上下文中进行评估 - 但由于必须明确指定self::node(),因此不是这种情况。

因此,一个相关的问题可能是:libxml2的行为及其对术语“上下文”的使用。与XPath规范一致吗?

1 个答案:

答案 0 :(得分:2)

XPath选择输入树中的节点,以斜杠/开头的路径从上下文节点的文档节点向下选择节点。因此,正确地发现,如果要选择相对于上下文节点的后代,则需要.//foo。作为替代方案,您可以使用descendant::foo