XPath 是一门在 XML 文档中查找信息的语言, 基于XML的树状结构,提供在数据结构树中找寻节点的能力,用于在 XML 文档中通过元素和属性进行导航。XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
xpath通过"路径表达式"(Path Expression)来选择节点。在形式上,"路径表达式"与传统的文件系统非常类似。
斜杠(/)作为路径内部的分割符。
同一个节点有绝对路径和相对路径两种写法。
绝对路径(absolute path)必须用"/"起首,后面紧跟根节点,比如/step/step/...。
相对路径(relative path)则是除了绝对路径以外的其他写法,比如 step/step,也就是不使用"/"起首。
"."表示当前节点。
".."表示当前节点的父节点
nodename(节点名称):表示选择该节点的所有子节点
"/":表示选择根节点
"//":表示选择任意位置的某个节点
"@": 表示选择某个属性
xpath路径表达式可以参考https://www.cnblogs.com/sunny-bear/articles/5400441.html
(1)xmlXPathNewContext函数
xmlXPathContextPtr xmlXPathNewContext(xmlDocPtr doc)
创建一个新的上下文指针,释放时调用xmlXPathFreeContext
参数doc: XML文档指针
返回:新的上下文指针
(2)xmlXPathRegisterNs函数
int xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)
注册新的命名空间。如果@ns_uri为NULL,则取消注册命名空间
ctxt: XPath上下文
prefix: 命名空间前缀不能为NULL或空字符串
ns_uri: 命名空间名称
返回: 成功时为0,出错时为-1
(3)xmlXPathEvalExpression函数
xmlXPathObjectPtr xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)
xmlXPathEval()的别名。在给定的上下文和XPath位置路径中找到符合要求的元素。
参数str: XPath表达式
参数ctxt: XPath上下文
返回: 查询结果指针。
通过libxml2对xml进行解析的方法有两种,一种是比较简单的使用libxml2提供的接口来对xml一层一层的解析,缺点是层数嵌套比较多时效率不好。另一种方法是使用xpath,通过你给出路径,它可以快速的查找出目标节点。
那么下面来看看两种方法有什么不同。
第一种,递归调用接口一层一层的查找所要找的节点。
xmlNodePtr getXmlNodeByName(xmlNodePtr root,char *name)//通过节点名找到对应节点
{
if(NULL ==root || NULL ==name)
{
return NULL;}
xmlNodePtr pnode=xmlFirstElementChild(root);//返回根节点的子节点
while(pnode!=NULL)
{
if(!strcmp(pnode->name,name))
return pnode;
xmlNodePtr pnode_1 = getXmlNodeByName(pnode,name);//递归查找下一层
if(pnode_1!=NULL)
return pnode_1;
pnode = xmlNextElementSibling(pnode);//返回同一层的节点
}
return NULL;
}
调用方法:
cur = getXmlNodeByName(root,"Object");//从root中找到名字为Object的节点
第二种,通过路径直接找出所要查找的节点。
xmlXPathObjectPtr getNodeset(xmlDocPtr pdoc, const xmlChar *xpath)
{
if(pdoc == NULL|| xpath == NULL)return NULL;
xmlXPathContextPtr context = NULL; //定义XPath上下文指针
xmlXPathObjectPtr result = NULL; //定义XPath结果指针
context = xmlXPathNewContext(pdoc);//用xml文档指针来初始化context指针
if(context!=NULL)
{
result = xmlXPathEvalExpression(xpath, context);//计算xpath的查询结果,
//并存入result中
if(result == NULL)return NULL;
if (xmlXPathNodeSetIsEmpty(result->nodesetval))
//使用result->nodesetval得到节点集合指针,其中包含了所有符合Xpath查询结果的节点
{
xmlXPathFreeObject(result);//使用释放Xpath对象指针;
printf("nodeset is empty\n");
return NULL;
}
}
return NULL;
}
调用方法:
char tmpxpath[128];
sprintf(tmpxpath,"///AnalyticsModule[@Type='Face_Search_Engine']//SimpleItem[@Name='fastpicnum']",valuestring);
xmlXPathObjectPtr tmpxPathObj_ptr = getNodeset(RuleDoc,tmpxpath);//返回查询结果
if((tmpxPathObj_ptr)&&(tmpxPathObj_ptr->nodesetval))//判断查询结果和节点集合指针是否为空
{
tmpxNode = tmpxPathObj_ptr->nodesetval->nodeTab[0];
······//处理
}
以上tmpxpath表示的路径含义是在根目录下任意位置找到AnalyticsModule且其属性Type='Face_Search_Engine’,然后在从AnalyticsModule下任意位置找到属性为Name='fastpicnum'的tt:SimpleItem。
查询到的节点会放到查询节点集合指针中,例如本例子中给的路径比较明确,只有一个,则一般都是节点集合的第一个元素,如果想找出某个路径下的全部子元素,可以使用下面的例子
xmlChar *xpath = BAD_CAST ("/producttype/product/*"); //xpath语句,路径为product的所有子元素
xmlXPathObjectPtr result = getNodeset(pdoc, xpath); //调用函数,查询XPath表达式,得到一个查询结果
int i;
for (i = 0; i < result ->nodeNr; i++)
{
tmpxNode = result ->nodeTab[i];//遍历
······//处理
}
更多libxml2接口可以参考libxml2官网