使用 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());
。
我必须替换多个 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());
。