You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用libxml2向已有XML追加数据失败的技术求助

解决libxml2修改XML后未写入文件的问题

我看了你的代码和XML文件,问题主要出在没有将内存中修改后的文档写回磁盘,还有几处节点操作的逻辑错误。咱们一步步来修正:

核心问题分析

  1. 未保存修改到文件:xmlReadFile只是把XML加载到内存,修改后必须调用xmlSaveFile或xmlSaveFormatFile才能将变更写入原文件。
  2. 节点添加逻辑错误:你用xmlAddSibling(result, pNode)是错误的,result是XPath查询对象,不是节点。根据你的需求,应该找到匹配的srcAddr节点的父节点(也就是policySecurity),然后给这个父节点添加新的子节点。
  3. 变量未声明:root_element没有显式声明,会导致编译警告或错误。
  4. 错误处理不完整:比如xmlXPathNewContext失败后没有及时终止程序,可能引发后续空指针问题。

修改后的完整代码

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

int main(){
    const char* xmlFilePath = "/var/www/db/db_policy.xml";
    xmlDocPtr pDoc = xmlReadFile(xmlFilePath, NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
    
    if (pDoc == NULL) {
        fprintf(stderr, "Document not parsed successfully.\n");
        return 1;
    }
    
    xmlNodePtr root_element = xmlDocGetRootElement(pDoc);
    if (root_element == NULL) {
        fprintf(stderr, "Empty document\n");
        xmlFreeDoc(pDoc);
        return 1;
    }
    
    printf("Root Node is %s\n", root_element->name);
    
    xmlChar* srcaddr = (xmlChar*)"5.5.5.5";
    xmlChar *xpath = (xmlChar*)"//srcAddr";
    xmlNodeSetPtr nodeset;
    xmlXPathObjectPtr result;
    int i;
    xmlChar *keyword;
    xmlXPathContextPtr context;
    
    context = xmlXPathNewContext(pDoc);
    if (context == NULL) {
        fprintf(stderr, "Error in xmlXPathNewContext\n");
        xmlFreeDoc(pDoc);
        return 1;
    }
    
    result = xmlXPathEvalExpression(xpath, context);
    xmlXPathFreeContext(context);
    
    if (result == NULL) {
        fprintf(stderr, "Error in xmlXPathEvalExpression\n");
        xmlFreeDoc(pDoc);
        return 1;
    }
    
    if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
        fprintf(stderr, "No matching srcAddr nodes found\n");
        xmlXPathFreeObject(result);
        xmlFreeDoc(pDoc);
        return 1;
    }
    
    nodeset = result->nodesetval;
    for (i=0; i < nodeset->nodeNr; i++) {
        keyword = xmlNodeListGetString(pDoc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
        printf("Found srcAddr: %s\n", keyword);
        
        if(strcmp((char*)keyword, (char*)srcaddr) == 0){
            // 获取当前srcAddr节点的父节点(policySecurity)
            xmlNodePtr parentNode = nodeset->nodeTab[i]->parent;
            if(parentNode != NULL && !xmlStrcmp(parentNode->name, (xmlChar*)"policySecurity")){
                // 创建新的service节点并设置内容
                xmlNodePtr pNode = xmlNewNode(NULL, (xmlChar*)"service");
                xmlNodeSetContent(pNode, (xmlChar*)"nonser");
                // 将新节点添加为父节点的最后一个子节点
                xmlAddChild(parentNode, pNode);
                printf("Successfully added new service node to matching policySecurity\n");
            }
        }
        xmlFree(keyword);
    }
    
    // 将修改后的文档写回原文件
    int saveResult = xmlSaveFile(xmlFilePath, pDoc);
    if(saveResult == -1){
        fprintf(stderr, "Failed to save XML file\n");
    } else {
        printf("XML file saved successfully, %d bytes written\n", saveResult);
    }
    
    xmlXPathFreeObject(result);
    xmlFreeDoc(pDoc);
    xmlCleanupParser();
    
    return 0;
}

关键修改点说明

  • 添加文件保存步骤:用xmlSaveFile把内存中的修改写入原文件,这是你最核心的遗漏点。如果需要格式化输出(带缩进),可以用xmlSaveFormatFile(xmlFilePath, pDoc, 1),最后一个参数1表示启用格式化。
  • 修正节点添加逻辑:通过nodeset->nodeTab[i]->parent获取匹配节点的父节点,然后用xmlAddChild将新节点追加到父节点的子节点列表末尾,符合你“找到其父节点后追加子节点”的需求。
  • 完善错误处理:每个可能失败的操作(比如创建XPath上下文、查询结果为空)都添加了终止流程和资源释放,避免内存泄漏或崩溃。
  • 补全变量声明:显式声明root_element为xmlNodePtr类型,符合C语言的规范。

编译提示

记得编译时链接libxml2库,比如用gcc:

gcc your_code.c -o xml_modifier $(xml2-config --cflags --libs)

内容的提问来源于stack exchange,提问作者user9208269

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:03:43