Andy Niu �����ĵ�

Andy Niu

Andy Niu Help  1.0.0.0
Rapidxml

变量

 节点加入另一个xml
 
 修改节点的值
 
 解析xml会修改内存的值
 
 打包成string
 
 map的打包和解析
 

详细描述

变量说明

map的打包和解析
#include "rapidxml/rapidxml.hpp"
#include "rapidxml/rapidxml_utils.hpp"
#include "rapidxml/rapidxml_print.hpp"

#include <stdio.h>
#include <string>
#include <map>
using namespace std;
using namespace rapidxml;

bool ParseXml2Map(map<string,string>& outMap,const string& inXml)
{
    try
    {
        xml_document<char> doc;
        doc.parse<0>(doc.allocate_string(inXml.c_str()));
        xml_node<char>* root = doc.first_node("root");

        for(xml_node<char>* node = root->first_node(); node != NULL; node = node->next_sibling())
        {
            outMap[node->name()] = node->value();
        }
    }
    catch(parse_error& e)
    {
        printf("Parse Xml Err[%s] Where[%s]", 
            e.what(),
            e.where<char>());
        return false;
    }
    return true;
}

bool PacketMap2Xml(string& outXml,const map<string,string>& inMap)
{
    try
    {
        xml_document<char> doc;
        xml_node<char>* root = doc.allocate_node(node_element, "root");
        doc.append_node(root);

        for(map<string,string>::const_iterator iter = inMap.begin(); iter != inMap.end(); ++iter)
        {
            xml_node<char>* ele = doc.allocate_node(node_element,iter->first.c_str(),iter->second.c_str());
            root->append_node(ele);
        }
        print(back_inserter(outXml), doc, 0);
    }
    catch (...)
    {
        return false;
    }
    return true;
}
修改节点的值
1、rapidxml修改节点的value,修改之后,序列化还是原来的值,具体原因是什么,要看rapidxml是怎么实现的。如下:
void TestRapidXml()
{
    char* xmlContent = new char[1024];
    sprintf(xmlContent,"<root><head>aaa</head><body x=\"10\">bbb</body></root>");

    xml_document<> xmlDoc;
    xmlDoc.parse<0>(xmlContent);

    xml_node<>* body = xmlDoc.first_node()->first_node("body");
    body->value("ccc");

    xml_attribute<>* x = body->first_attribute("x");
    x->value("20");    

    string xmlStr = "";
    // xmlString为 <root><head>aaa</head><body x=\"20\">bbb</body></root>
    // 也就是说,attr的value可以修改成功,而node的value还是旧值。
    rapidxml::print(std::back_inserter(xmlStr),xmlDoc,0); 
    
    delete []xmlContent;
}
2、怎么解决上面的问题,笨办法,既然不能修改,我就添加一个新的,删除老的。如下:
void TestRapidXml()
{
    char* xmlContent = new char[1024];
    sprintf(xmlContent,"<root><head>aaa</head><body x=\"10\">bbb</body></root>");

    xml_document<> xmlDoc;
    xmlDoc.parse<0>(xmlContent);

    xml_node<>* root = xmlDoc.first_node();

    xml_node<>* body = root->first_node("body");
    xml_node<>* newBody = xmlDoc.allocate_node(node_element,
        xmlDoc.allocate_string("body"),xmlDoc.allocate_string("ccc"));
    // 插入一个新的body
    root->insert_node(body,newBody);
    
    // 复制老body的attr
    for(xml_attribute<>* attr = body->first_attribute();attr!=NULL;attr=attr->next_attribute())
    {
        xml_attribute<>* copy = xmlDoc.allocate_attribute(xmlDoc.allocate_string(attr->name()),
            xmlDoc.allocate_string(xmlDoc.allocate_string(attr->value())));
        newBody->append_attribute(copy);
    }
    // 删除老的body
    root->remove_node(body);

    string xmlStr = "";
    // xmlString为 <root><head>aaa</head><body x=\"10\">ccc</body></root>
    rapidxml::print(std::back_inserter(xmlStr),xmlDoc,0); 
    
    delete []xmlContent;
}
3、还有一个办法,就是使用 xmlDoc.parse<parse_no_data_nodes>(xmlContent); 如下:
void TestRapidXml()
{
    char* xmlContent = new char[1024];
    sprintf(xmlContent,"<root><head>aaa</head><body x=\"10\">bbb</body></root>");

    xml_document<> xmlDoc;
    //xmlDoc.parse<0>(xmlContent);
    xmlDoc.parse<parse_no_data_nodes>(xmlContent);

    xml_node<>* body = xmlDoc.first_node()->first_node("body");
    body->value("ccc");
    
    xml_attribute<>* x = body->first_attribute("x");
    x->value("20");    

    string xmlStr = "";
    // xmlString为 <root><head>aaa</head><body x=\"20\">ccc</body></root>
    rapidxml::print(std::back_inserter(xmlStr),xmlDoc,0); 
    
    delete []xmlContent;
}
打包成string
void TestRapidXml()
{
    char* xmlContent = new char[1024];
    sprintf(xmlContent,"<root><head>aaa</head><body>bbb</body></root>");

    xml_document<> xmlDoc;
    xmlDoc.parse<0>(xmlContent);    

    // back_inserter 返回一个输出流,rapidxml的print方法向里面写数据
    string xmlStr = "";
    rapidxml::print(std::back_inserter(xmlStr),xmlDoc,0); // 序列化整个doc

    xmlStr = "";
    xml_node<>* root = xmlDoc.first_node();
    xml_node<>* node = root->first_node()->next_sibling();
    internal::print_element_node(std::back_inserter(xmlStr), node, 0,0); // 序列化一个节点
    
    // 注意:要序列化之后,才能释放内存,因为rapidxml为了效率,没有使用整体拷贝,而是复制指针,
    // 因此,在序列化的时候还要使用内存的值。
    delete []xmlContent;
}
节点加入另一个xml
void TestRapidXml()
{
    char* xmlContent = new char[1024];
    sprintf(xmlContent,"<root><head>aaa</head><body>bbb</body></root>");

    xml_document<> xmlDoc;
    xmlDoc.parse<0>(xmlContent);

    char* xmlContent2 = new char[1024];
    sprintf(xmlContent2,"<point x=\"1\" y =\"1\"/><point x=\"2\" y =\"2\"/>");
    xml_document<> xmlDoc2;
    xmlDoc2.parse<0>(xmlContent2);

    xml_node<>* root = xmlDoc.first_node();
    for(xml_node<>* node = xmlDoc2.first_node();node!=NULL;node=node->next_sibling())
    {
        // 注意:这里使用xmlDoc,是大的xml,不要使用xmlDoc2.
        root->append_node(xmlDoc.clone_node(node));
    }

    string xmlStr = "";
    rapidxml::print(std::back_inserter(xmlStr),xmlDoc,0); 
    
    delete []xmlContent;
    delete []xmlContent2;
}
解析xml会修改内存的值
1、使用rapidxml解析的时候,也就是 调用xmlDoc.parse<0>(xmlContent),
    特别注意,rapidxml会修改内存的值,把右尖括号>修改为'\0',
    因此特别注意,如果char指针指向的内容还要使用,需要做个备份。
2、如果char指针指向的内容,不再使用,不需要做备份,rapidxml会直接修改内存。
    这个时候不要忘记delete []释放资源。delete释放内存,跟内存中的取值没有关系,取值为0,也会正确地释放内存。
    比如使用new分配内存8个字节,操作系统会多分配一些内存,额外的内存记录分配了多少内存,
    这样在释放的时候,就知道应该释放多少内存。
3、有没有其他办法呢?
  使用xmlDoc.parse<parse_non_destructive>(xmlContent); 告诉rapidxml解析的时候,不要修改内存的值。
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.