给出xml文件
<a>
<b>
<d>v</d>
</b>
<c>
<d>v</d>
</c>
</a>
xpath&#34; // d / text()&#34;
我想仅将xpath应用于c而不是整个文档。
这必须与libxml2 2.7.6
一起使用这样做不起作用;
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
xpathCtx->node = node;
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
返回的xpathObj包含对/ a / b / d和/ a / c / d的重新声明。预计只有/ a / c / d。
答案 0 :(得分:1)
如果要查找相对于另一个节点的后代,请使用路径.//d
或.//d/text()
。以//d
开头的路径将搜索根节点(也称为文档节点)的所有d
后代元素。
答案 1 :(得分:1)
解决:
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
//Update the document to set node as root
xmlNodePtr myParent = node->parent;
xmlNodePtr originalRootElement = xmlDocGetRootElement( node->doc );
xmlDocSetRootElement( node->doc, node );
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
//xpathObj contains only /a/c/d, as expected
//restore the xml document
xmlDocSetRootElement( originalRootElement->doc, originalRootElement );
xmlAddChild( myParent, node );
使用valdrind测试。
上面的例子给出了这个想法。在下面的完整实现中(感谢Julo的评论):
//Update Doc to support xpath on logical root node and restore the document structure at scope exit
class XmlDoc_UpdateDocAndRestoreAtScopeExit {
public:
XmlDoc_UpdateDocAndRestoreAtScopeExit( _xmlDoc* doc, _xmlNode* logicalRootNode) :
_doc ( doc ),
_logicalRootNode ( logicalRootNode ),
_originalRootElement( 0 ),
_refParent ( 0 ),
_refPrevSibling ( 0 ),
_refNextSibling ( 0 ),
_toRestore(false)
{
_originalRootElement = xmlDocGetRootElement( doc );
_refParent = _logicalRootNode->parent;
_refPrevSibling = _logicalRootNode->prev;
_refNextSibling = _logicalRootNode->next;
if ( _logicalRootNode != _originalRootElement ) {
xmlDocSetRootElement( _doc, _logicalRootNode );
_toRestore = true;
}
}
~XmlDoc_UpdateDocAndRestoreAtScopeExit() {
if ( _toRestore ) {
//Restore the root node
xmlDocSetRootElement( _doc, _originalRootElement );
//Restore the node at its original place
if ( 0 != _refPrevSibling ) {
xmlAddNextSibling( _refPrevSibling, _logicalRootNode );
} else if ( 0 != _refNextSibling ) {
xmlAddPrevSibling( _refNextSibling, _logicalRootNode );
} else {
xmlAddChild( _refParent, _logicalRootNode );
}
}
}
private:
XmlDoc_UpdateDocAndRestoreAtScopeExit() ; // not implemented
XmlDoc_UpdateDocAndRestoreAtScopeExit(const XmlDoc_UpdateDocAndRestoreAtScopeExit &) ; // not implemented
XmlDoc_UpdateDocAndRestoreAtScopeExit & operator= (const XmlDoc_UpdateDocAndRestoreAtScopeExit &) ; // not implemented
private:
_xmlDoc* _doc;
_xmlNode* _logicalRootNode;
_xmlNode* _originalRootElement;
_xmlNode* _refParent;
_xmlNode* _refPrevSibling;
_xmlNode* _refNextSibling;
bool _toRestore;
};
//Somewhere in the code...
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
//Here set the _rootNodePtr as the root of the document to use xpath on your "logical" root
//At scope exit the document's structure will be restored.
XmlDoc_UpdateDocAndRestoreAtScopeExit xmlDoc_UpdateDocAndRestoreAtScopeExit( node->doc, node );
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
//xpathObj contains only /a/c/d, as expected