consecutive xmlXPathEval's with libxml2
I'm using libxml2 to parse a html document and I got a question. What's the difference between
xmlXPathObjectPtr obj = xmlXPathEval((xmlChar*)"//div[@id='gall_list']//td//h3/img[@alt]", ctx);
printf("%d", obj->nodesetval->nodeNr);
and
xmlXPathObjectPtr obj1 = xmlXPathEval((xmlChar*)"//div[@id='gall_list']//td//h3", ctx);
xmlXPathObjectPtr obj2 = xmlXPathEval((xmlChar*)"img[@alt]", ctx);
printf("%d", obj2->nodesetval->nodeNr);
? If I'm correct, they're supposed to be the same, right? But the second one is not working correctly. I've changed the "img[@alt]" part of the obj2 part to "./img[@alt]", but it didn't work either.
Can anybody let me know what's wrong with the second one? Just FYI, the following one worked correctly:
xmlXPathObjectPtr obj1 = xmlXPathEval((xmlChar*)"//div[@id='gall_list']//td", ctx);
xmlXPathObjectPtr obj2 = xmlXPathEval((xmlChar*)".//h3/img[@alt]", ctx);
printf("%d", obj2->nodesetval->开发者_如何学PythonnodeNr);
Thanks a lot in advance!
Your first two code snippets should definitely behave differently since xmlXPathEval operates on the same context node for both expressions. In your third snippet you are searching for all descendants (//) of the context node, if this node is the document element then all img elements with alt attributes inside a h3 element will be returned. The context does not change automatically based on the result from the first call.
It is possible to set the context node yourself through the node
field of xmlXPathContext
like in the following snippet. Note that I translated this from vala and did not check type names.
xmlXPathObjectPtr obj1 = xmlXPathEval((xmlChar*)"//div[@id='gall_list']//td//h3", ctx);
xmlXPathNodeSetPtr nodeset = obj1->nodesetval;
xmlNodePtr node = nodeset->item(0);
// Set the context node for the following xpath expressions
ctx.node = node;
xmlXPathObjectPtr obj2 = xmlXPathEval((xmlChar*)"img[@alt]", ctx);
I'm looking at the docs for xmlXPathEval() and I can't see a reason why the first two code blocks above should do the same thing: In other words, why should the XPath processor's context in evaluating the second XPath be affected by the evaluation of the first? The doc doesn't say that xmlXPathEval() will change the passed-in context... Does xmlXPathEval() do that?
Seems to me what you would need to do, in order to get your second code example to work, is to pass in a ctx that is based on obj1 (the result of the first xmlXPathEval()) as the second argument to the second xmlXPathEval(). However I can't see how to derive an xmlXPathContextPtr from an xmlXPathObjectPtr.
The reason your 3rd code example "works" is that the result of the first XPath evaluation is ignored; the XPath expression .//h3/img[@alt]
will select the specified <img>
elements when the context is simply the root node (/
). But it will match all img elements that are children of h3 elements and that have an alt attribute, not only those that are descendants of div[@id='gall_list']
.
精彩评论