【问题标题】:Appending data in existing XML using libxml2使用 libxml2 在现有 XML 中附加数据
【发布时间】:2019-02-22 04:36:02
【问题描述】:

好吧,我正在尝试使用 C 编程和 libxml2 modulel 附加数据,但我面临很多问题,因为我对此还很陌生。 我的代码设计为首先根据用户输入从 XML 文件中获取一个元素节点,然后获取该子节点的父节点并在其中附加另一个子节点。

XML 文件:

<policyList>
        <policySecurity>
                <policyName>AutoAdd</policyName>
                <deviceName>PA-722</deviceName>
                <status>ACTIVE</status>
                <srcZone>any</srcZone>
                <dstZone>any</dstZone>
                <srcAddr>5.5.5.5</srcAddr>
                <dstAddr>5.5.5.4</dstAddr>
                <srcUser>any</srcUser>
                <application>any</application>
                <service>htds</service>
                <urlCategory>any</urlCategory>
                <action>deny</action>
        </policySecurity>
        <policySecurity>
                <policyName>Test-1</policyName>
                <deviceName>PA-710</deviceName>
                <status>ACTIVE</status>
                <srcZone>any</srcZone>
                <dstZone>any</dstZone>
                <srcAddr>192.168.1.23</srcAddr>
                <dstAddr>8.8.8.8</dstAddr>
                <srcUser>vivek</srcUser>
                <application>any</application>
                <service>http</service>
                <urlCategory>any</urlCategory>
                <action>deny</action>
        </policySecurity>
</policyList>

C 代码:

int main(){
xmlDocPtr pDoc = xmlReadFile("/var/www/db/db_policy.xml", NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
    if (pDoc == NULL)
    {
        fprintf(stderr, "Document not parsed successfully.\n");
        return 0;
    }

root_element = xmlDocGetRootElement(pDoc);
if (root_element == NULL)
 {
        fprintf(stderr, "empty document\n");
        xmlFreeDoc(pDoc);
        return 0;
    }

printf("Root Node is %s\n", root_element->name);



        xmlChar* srcaddr = "5.5.5.5";
        xmlChar *xpath = (xmlChar*) "//srcAddr";
        xmlNodeSetPtr nodeset;
        xmlXPathObjectPtr result;
        int i;
        xmlChar *keyword;
        xmlXPathContextPtr context;
        xmlNodePtr resdev;
        xmlChar* resd;
         context = xmlXPathNewContext(pDoc);
        if (context == NULL) {
                printf("Error in xmlXPathNewContext\n");
        }
        result = xmlXPathEvalExpression(xpath, context);
        xmlXPathFreeContext(context);
        if (result == NULL) {
                printf("Error in xmlXPathEvalExpression\n");
        }
         if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
                xmlXPathFreeObject(result);
                printf("No result\n");
        };

        if (result) {
                nodeset = result->nodesetval;
                for (i=0; i < nodeset->nodeNr; i++) {
                        keyword = xmlNodeListGetString(pDoc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
                printf("keyword: %s\n", keyword);
                if(strcmp(keyword, srcaddr) == 0){
                        xmlNodePtr pNode = xmlNewNode(0, (xmlChar*)"service");
                        xmlNodeSetContent(pNode, (xmlChar*)"nonser");
                        xmlAddSibling(result, pNode);
                        printf("added");
                        }
                xmlFree(keyword);
                }
                xmlXPathFreeObject (result);
        }
        xmlFreeDoc(pDoc);
        xmlCleanupParser();
        return (1);
}

在运行此代码时,它会被编译和执行(有一些警告,但没有任何阻碍执行),但它不会向我的 XML 文件添加任何内容。

【问题讨论】:

  • 您希望在内存中更改文件还是仅更改 DOM 表示形式?
  • @StephanLechner 已更改的文件,其中附加了数据。实际上,应该修改同一个文件(使用正确的词以免造成混淆),其中要添加另一个标签service,内容为nonser

标签: c xml libxml2


【解决方案1】:

我认为这个话题很老,但我也遇到了类似的问题。所以,我只是分享给那些仍然有类似问题的人。

在运行此代码时,它会被编译和执行(带有一些警告,但没有任何阻碍执行),但它不会向我的 XML 文件添加任何内容。

首先:在我看来,C 语言中的警告比错误更糟糕,因为它会让你运行错误的代码。所以,我的第一个建议是不要忽视警告(尽管我无法建议任何人,但无论如何)。

第二:当我运行这段代码时,我看到了一个有意义的警告:

> warning: passing argument 1 of ‘xmlAddSibling’ from incompatible
> pointer type [-Wincompatible-pointer-types]
> 
> note: expected ‘xmlNodePtr {aka struct _xmlNode *}’ but argument is of
> type ‘xmlXPathObjectPtr {aka struct _xmlXPathObject *}’

当您检查来自http://www.xmlsoft.org/html/libxml-tree.html 的 xmlAddSibling 时,您可以看到:

xmlNodePtr  xmlAddSibling       (xmlNodePtr cur, xmlNodePtr elem)

这意味着两个参数的类型都应该是 xmlNodePtr。但是,“结果”具有 xmlXPathObjectPtr 的类型,这意味着指针类型完全不同。您真正想要做的是根据您比较的字符串将孩子添加到您找到的父母中:(if(strcmp(keyword, srcaddr) == 0))。

所以你找到父母的方法是完全正确的。但是有两个问题:首先,您从未更新过“结果”(如果我们假设您认为“结果”是不正确的父级),因为“nodeset->nodeTab[i]”在一个永远不会放任何东西的 for 循环中结果”。第二个问题是即使您根据“nodeset->nodeTab[i]”更新了“结果”,它们仍然具有不同类型的指针(正如我们之前讨论的那样)。因此,您必须为正确的父级和正确的指针类型使用 xmlAddSibling。正如你在下面看到的,“nodeTab”的类型是我们正在寻找的“xmlNodePtr”,而“nodeset->nodeTab[i]”是父节点。

Structure xmlNodeSet
struct _xmlNodeSet {
    int nodeNr  : number of nodes in the set
    int nodeMax : size of the array as allocated
    > `xmlNodePtr * nodeTab : array of nodes in no particular order`

}

所以你应该改变:

xmlAddSibling(result, pNode);

到:

xmlAddSibling(nodeset->nodeTab[i], pNode);

最后:您没有保存更改。所以,通过添加保存它

xmlSaveFileEnc("note.xml", pDoc, "UTF-8");

之前

xmlFreeDoc(pDoc);

通过这些更改,我能够使用您的 XML 文件运行您的代码,并且没有任何警告。

【讨论】:

    【解决方案2】:

    您的命令修改了内存中 XML 的 DOM 表示,但您错过了将其写回文件。因此,添加以下行应该可以解决您的问题:

       ...
    }
    
    // write back to file:
    xmlSaveFileEnc("/var/www/db/db_policy.xml", pDoc, "UTF-8");
    
    xmlFreeDoc(pDoc);
    xmlCleanupParser();
    return (1);
    

    【讨论】:

    • 谢谢你的帮助,但它仍然没有添加我想要的兄弟姐妹。此外,它还改变了 xml 文件的方向,我的意思是,整个文件现在写在一行中,并且是 pretty_print 方式。 :(
    猜你喜欢
    • 1970-01-01
    • 2015-02-19
    • 2011-07-24
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    相关资源
    最近更新 更多