C libxml2 : 解析xmlPath循环遍历,提取孙节点参数。可能的?

C libxml2 : Parse xmlPath to traverse in a loop and extract parameters of grandchild nodes. Possible?

我是 Xpath 和 XML 的初学者。 我安装了 libxml2,我可以成功解析 XML 文件。 我还可以使用 xmlXPathContext 读取特定节点的值。 问题陈述和example.xml如下。

我在 shell 中实现了相同的功能,方法是 运行 为根的所有 children 设置一个 for 循环,即 Child 1,2,以及3 寻找匹配。然后我将 Child 的索引号存储在找到匹配项的位置。 对于这个特定的 child,为 GChild 提取 Param1 和 Param2 的值。 我们可以使用 xpath 运行 类似的循环吗?我们如何在循环中引用 Child ? “Root/Child[i]/” ?

例如, 我得到输入为“ABCD2”。 然后我需要通过遍历所有 Child 1,2,3 来搜索“ABCD2”。 当我们知道匹配所在的是 Child 2 时,提取 Child 的特定 GChild 的 Param1 和 Param2,即 Child 的 GChild2 2. 也就是说,我们应该将“HIJK123”和“HIJK345”作为 2 个变量的输出。

example.xml
<Root>
    <Child> 
        <GChild>    
        <Param> "ABCD1" </Param>
        </GChild>
        
        <GChild>    
            <Param> "EFGH123" </Param>                          
            <Param> "EFGH345" </Param>
        </GChild>

        <GChild>    
        <Param> "IJKL123" </Param>
        </GChild>
    </Child>
        
    <Child>
        <GChild>    
        <Param> "ABCD2" </Param>
        </GChild>
        
        <GChild>
            <Param> "HIJK123" </Param>                          
            <Param> "HIJK345" </Param>
        </GChild>

        <GChild>    
        <Param> "LMNO123" </Param>
        </GChild>
    </Child>

    <Child>
        <GChild>    
        <Param1> "ABCD3" </Param1>
        </GChild1>
        
        <GChild>    
            <Param> "PQRS123" </Param>                          
            <Param> "PQRS345" </Param>
        </GChild>

        <GChild>    
        <Param> "TUVW123" </Param>
        </GChild>
    </Child>
</Root>

如果您想要做的只是 return 任何在第一个 GChild 元素中包含 input-matching Param 节点的子元素的第二个 GChild 元素的所有 Param 节点,那么此 XPath 将工作:

//*/GChild[2]/Param[../../GChild[1]/Param[contains(text(),'ABCD2')]]

您可以在 http://xpather.com/DCioM5P4

尝试 XPath

下面是一些使用该 XPath 的示例代码,您的示例 XML 有效:

#include <libxml/xpath.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    if(argc<2) return printf("Usage: %s <search_value>\n",argv[0]);

    char xPath[100];
    sprintf(xPath,"//*/GChild[2]/Param[../../GChild[1]/Param[contains(text(),'%s')]]",argv[1]);

    char buffer[] = "<?xml version=\"1.0\"?>\n\
        <Root>\n\
            <Child>\n\
                <GChild>\n\
                    <Param> \"ABCD1\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"EFGH123\" </Param>\n\
                    <Param> \"EFGH345\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"IJKL123\" </Param>\n\
                </GChild>\n\
            </Child>\n\
            <Child>\n\
                <GChild>\n\
                    <Param> \"ABCD2\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"HIJK123\" </Param>\n\
                    <Param> \"HIJK345\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"LMNO123\" </Param>\n\
                </GChild>\n\
            </Child>\n\
            <Child>\n\
                <GChild>\n\
                    <Param> \"ABCD3\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"PQRS123\" </Param>\n\
                    <Param> \"PQRS345\" </Param>\n\
                </GChild>\n\
                <GChild>\n\
                    <Param> \"TUVW123\" </Param>\n\
                </GChild>\n\
            </Child>\n\
        </Root>\n\
    ";
    xmlDocPtr document = xmlParseDoc((xmlChar*)buffer);

    xmlXPathContextPtr xPathCtx = xmlXPathNewContext(document);
    xPathCtx->node = xmlDocGetRootElement(document);

    xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((xmlChar*)xPath, xPathCtx);
    if(xpathObj == NULL){
        printf("Failed to evaluate xpath\n");
    }

    xmlNodeSetPtr nodeset = xpathObj->nodesetval;
    if(!xmlXPathNodeSetIsEmpty(nodeset)){
        printf("Found nodes using: %s\n",xPath);
        for(int i=0; i<xmlXPathNodeSetGetLength(nodeset); i++){
            xmlNodePtr node = xmlXPathNodeSetItem(nodeset,i);
            printf("<%s>%s</%s>\n",node->name,xmlNodeGetContent(node),node->name);
        }
    }else{
        printf("Failed to find nodes using: %s\n",xPath);
    }

    xmlXPathFreeObject(xpathObj);
    xmlXPathFreeContext(xPathCtx);

    return 0;
}