使用libxml2向已有XML追加数据失败的技术求助
解决libxml2修改XML后未写入文件的问题
我看了你的代码和XML文件,问题主要出在没有将内存中修改后的文档写回磁盘,还有几处节点操作的逻辑错误。咱们一步步来修正:
核心问题分析
- 未保存修改到文件:
xmlReadFile只是把XML加载到内存,修改后必须调用xmlSaveFile或xmlSaveFormatFile才能将变更写入原文件。 - 节点添加逻辑错误:你用
xmlAddSibling(result, pNode)是错误的,result是XPath查询对象,不是节点。根据你的需求,应该找到匹配的srcAddr节点的父节点(也就是policySecurity),然后给这个父节点添加新的子节点。 - 变量未声明:
root_element没有显式声明,会导致编译警告或错误。 - 错误处理不完整:比如
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
相关产品推荐
相关产品推荐

