使用 pugixml search/traverse/replace 多个标签的 C++ 最佳方法?

C++ Best way to search/traverse/replace multiple tags with pugixml?

我必须替换多个 template_xml 多个标签来构建一些 Web 服务请求。虽然使用 pugixml 我可以访问这样的标签 doc.child("tag1").child("tag2").etc 我不知道这是否是最好的方法,因为使用多个模板和多个嵌套标签,每个标签会有多行代码(因为它们有不同的路径)。

我的输入将是一个结构或包含多个 std::strings 的东西,我需要替换它。这是一个 xml 模板。

示例xml_template:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:es="http://mywebservice.com/">
   <soapenv:Header />
   <soapenv:Body>
      <es:Tag1>
         %(auth)
         <es:AnotherTag>
            <es:Date>
               <es:CantReg>%(num_records)</es:CantReg>
               <es:Pto>%(pto_data)</es:Pto>
               <es:DataType>%(data_type)</es:DataType>
            </es:Date>
            <es:Req>
               <es:DetRequest>
                  %(user_data)
                  <es:CA>%(CA)</es:CA>
                  <es:GenDate>%(datetime_date)</es:GenDate>
               </es:DetRequest>
            </es:Req>
         </es:AnotherTag>
      </es:Tag1>
   </soapenv:Body>
</soapenv:Envelope>

我虽然使用正则表达式,但可能有更好的方法直接使用 xml。 Pugixml 有这个例子,但它不会遍历所有 xml 子项(nested/depth 完整),在我的情况下有多个 strtings/template 我仍然会对每个模板有不同的功能和每个标签。

普吉xml 例子:

    pugi::xml_document doc;
    if (!doc.load_file("xgconsole.xml")) return -1;

    pugi::xml_node tools = doc.child("Profile").child("Tools");
    for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling())
    {
        std::cout << "Tool:";
        for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute())
            std::cout << " " << attr.name() << "=" << attr.value();

        std::cout << std::endl;
    }
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Profile FormatVersion="1">
    <Tools>
        <Tool Filename="jam" AllowIntercept="true">
            <Description>Jamplus build system</Description>
        </Tool>
        <Tool Filename="mayabatch.exe" AllowRemote="true" OutputFileMasks="*.dae" DeriveCaptionFrom="lastparam" Timeout="40" />
        <Tool Filename="meshbuilder_*.exe" AllowRemote="false" OutputFileMasks="*.mesh" DeriveCaptionFrom="lastparam" Timeout="10" />
        <Tool Filename="texbuilder_*.exe" AllowRemote="true" OutputFileMasks="*.tex" DeriveCaptionFrom="lastparam" />
        <Tool Filename="shaderbuilder_*.exe" AllowRemote="true" DeriveCaptionFrom="lastparam" />
    </Tools>
</Profile>

无法在 pugixml 中找到类似 doc.find_tag_by_name(tag_name) 的方法,只有 doc.find_child_by_attribute() 但深度不够,仅适用于那个标签。

理想的情况是有一个我调用的函数 replace_tag(std::string tag, std:.string new_text) 然后我为每个我需要的 string/tag 做一个 for 循环的另一个函数。

这样做的好方法是什么?可能是一种算法,当 node.name() 匹配我的 tag_name (或直接替换它)时搜索所有 xml 和 return 节点路径但我不是很熟悉搜索算法既不具有 xml 结构的搜索算法。

终于用上了这个

int get_tag_value(pugi::xml_document *xml_doc, std::string tag_name, std::string *tag_value)
{
    std::string search_str = "//*/";  // xpath search for nested tags
    search_str += tag_name;

    pugi::xpath_node xpath_node = xml_doc->select_node(search_str.c_str());  // search node
    if(!xpath_node)
        return -1;
    pugi::xml_node selected_node = xpath_node.node().first_child();
    *tag_value = selected_node.value();
    return 0;
}

与 replace_tag 类似,但在末尾使用 selected_node.set_value(value.c_str());