要仅在某个子树内计算 XPath 表达式,libxml2 函数xmlXPathNodeEval()似乎是最佳选择。该文档指定XPath 表达式是在“给定上下文中”计算的。但这究竟意味着什么呢?
考虑下面的小例子:
#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;
}
Run Code Online (Sandbox Code Playgroud)
通过编译(在我的例子中使用 libxml 版本 2.9.1):
$ gcc -g -std=c99 -Wall -I/usr/include/libxml2 -lxml2 relative.c
Run Code Online (Sandbox Code Playgroud)
对于通话
$ ./a.out '//e'
Run Code Online (Sandbox Code Playgroud)
我期望以下输出:
新根:Foo 1 2 3 3a
但我得到的是:
新根:Foo 0 1 2 3 3a 4 5 6 7
看来我必须使用self::node()轴说明符(short .)来获得我想要的结果,即:
$ ./a.out './/e'
New root: Foo
1 2 3 3a
Run Code Online (Sandbox Code Playgroud)
基本上,我将文档中的“评估给定上下文中的 XPath 位置路径”这句话解释为:XPath 表达式在给self::node()定节点的上下文中进行评估 - 但由于必须明确指定,因此self::node()情况并非如此。
因此,一个相关的问题可能是:libxml2 的行为及其对术语“上下文”的使用是否与 XPath 规范一致?
XPath 选择输入树中的节点,并且以斜线开头的路径/从上下文节点的文档节点向下选择节点。因此,正如您正确发现的那样,如果您想选择相对于上下文节点的后代,则需要.//foo. 作为替代方案,您可以使用descendant::foo.
| 归档时间: |
|
| 查看次数: |
1227 次 |
| 最近记录: |