xml转json

#include    <stdlib.h>
#include    <string.h>
#include    <stdio.h>
#include    <sys/stat.h>
#include    <iconv.h>
#include    <unistd.h>
#include    <errno.h>

#include    <libxml/xmlmemory.h>
#include    <libxml/parser.h>

#include    "cJSON.h"

/*
    编码转换函数
    1、from_charset 原始编码格式
    2、to_charset   转换编码格式
    3、outlen       转换后的数据长度,注意:要赋初始值
*/
static int string_conv(const char* from_charset, const char* to_charset, char* inbuf,
        size_t inlen, char* outbuf, size_t* outlen)
{
    iconv_t cd;
    size_t iResult;
    int iRet ;

    char** pin = &inbuf;
    char** pout = &outbuf;

    cd = iconv_open(to_charset, from_charset);
    if (cd < 0) {
        //转换失败,看看原因是什么
        fprintf(stderr, "conv code error : %s[%d]\n", strerror(errno), errno);
        return -1;
    }
    memset(outbuf, 0, *outlen);

    iResult = iconv(cd, pin, &inlen, pout, outlen);
    iconv_close(cd);
    return iResult;
}

/*
    输出XML数据
    1、data        XML数据
    2、len        数据长度
*/
void    print_xml(const char* data, size_t len)
{
    xmlDocPtr doc;
    xmlBufferPtr buff;
    xmlChar *dump;
    int size;

    buff = xmlBufferCreate();
    doc = xmlReadMemory(data, len, "", "", 0);
    xmlDocDumpFormatMemory( doc, &dump, &size, 1 );
    xmlBufferEmpty( buff );
    xmlBufferAdd( buff, dump, size );
    xmlFree( dump );
    
    fprintf(stdout, "-------------------------------------\n");    
    fprintf(stdout, "XML:\n%s\n", xmlBufferContent(buff));
    xmlBufferFree(buff);
    xmlFreeDoc(doc);
    return ;
}

/*
    从文件中获取XMLDOC    
*/
xmlDocPtr    parseDoc(const char* docname)
{
    xmlDocPtr    doc;    
    FILE    *fp = NULL;
    struct    stat st;
    char    *data = NULL;
    char    szLine[1024];

    //    从文件中读取数据
    if(NULL == (fp = fopen(docname, "r")))
    {
        fprintf(stderr, "文件[%s]不存在\n", docname);
        return NULL;
    }

    memset(&st, 0, sizeof(st));
    stat(docname, &st);
    data = (char*)malloc(st.st_size);
    memset(data, 0, st.st_size);
    
    memset(szLine, 0, sizeof(szLine));
    while(fgets(szLine, sizeof(szLine), fp))
    {
        strncpy(data + strlen(data), szLine, strlen(szLine));
        memset(szLine, 0, sizeof(szLine));
    }
    fclose(fp);

    //    采用读取数据的方式来解析XML
    xmlKeepBlanksDefault(0);
/*    直接解析文件XML
    doc = xmlParseFile(docname);
*/
    doc = xmlReadMemory((char*)data, st.st_size, "", "gbk", 1);
    if(NULL == doc)
    {
        fprintf(stderr, "Document parsed failed!\n");
        return NULL;
    }

    print_xml(data, strlen(data));
    free(data);
    return doc;
}

/*
    递归输出XML所有节点信息
*/
void    printXmlChildren(xmlNodePtr xml_root)
{
    xmlNodePtr    cur = NULL;
    xmlChar        *pszContent;
    for(cur = xml_root; cur; cur = cur->next)
    {
        if(cur->type == XML_ELEMENT_NODE)
        {
            if(cur->children->type == XML_TEXT_NODE)
            {
                pszContent = xmlNodeGetContent(cur);
                fprintf(stdout, "NODE:[%s][%s]\n", cur->name, pszContent);
                xmlFree(pszContent);
            }
            else if(cur->children->type == XML_ELEMENT_NODE)
            {
                fprintf(stdout, "NODE:[%s]\n", cur->name);
                printXmlChildren(cur->children);
            }
        }
    }
    
    return ;
}

/*
    XML数据转换成JSON数据
*/
void    _xml_json(xmlNodePtr xml_node, cJSON** json_node)
{
    xmlNodePtr    xml_cur = NULL, xml_loop = NULL, xml_tmp = NULL;
    xmlAttrPtr    xml_attr = NULL;
    cJSON        *json_cur = NULL, *json_array = NULL;
    char        szTmp[1024], szName[1025], szValue[1024];
    xmlChar        *pszContent = NULL;
    size_t        len = 0;

    for(xml_cur = xml_node; xml_cur; xml_cur = xml_cur->next)
    {
        if(xml_cur->type == XML_ELEMENT_NODE)
        {
//            fprintf(stdout, "cur:[%s]\n", xml_cur->name);
//            下级节点是内容
            if(xml_cur->children->type == XML_TEXT_NODE)
            {
                //    判断同级节点是否存在项目名称的节点数据,如果存在,则为循环节点
                xml_loop = xml_cur->next;
                while(xml_loop)
                {
                    xml_tmp = xml_loop->next;
                    if(0 == xmlStrcmp(xml_loop->name, xml_cur->name))
                    {
//                        fprintf(stdout, "--->loop:[%s]\n", xml_loop->name);
                        if(NULL == json_array)
                            json_array = cJSON_CreateArray();
                        //    XML内容编码格式为UTF,需要转换成GBK
                        xml_attr = xml_loop->properties;
                        //    无属性节点直接设置为string
                        if(NULL == xml_attr)
                        {
                            memset(szValue, 0, sizeof(szValue));
                            pszContent = xmlNodeGetContent(xml_loop);
                            len = strlen(pszContent);
                            string_conv("UTF-8", "GBK", pszContent, 
                                strlen(pszContent), szValue, &len);    
                            xmlFree(pszContent);
                            json_cur = cJSON_CreateString(szValue);
                        }
                        //    有属性节点,需要创建节点
                        else
                        {
                            //    属性节点的值放在"#text"中
                            memset(szName, 0, sizeof(szName));    
                            strcpy(szName, "#text");
                            json_cur = cJSON_CreateObject();
                            memset(szValue, 0, sizeof(szValue));
                            pszContent = xmlNodeGetContent(xml_loop);
                            len = strlen(pszContent);
                            string_conv("UTF-8", "GBK", pszContent,
                                strlen(pszContent), szValue, &len);
                            xmlFree(pszContent);
                            cJSON_AddStringToObject(json_cur, szName, szValue);

                            while(xml_attr)
                            {
                                //    其余属性节点添加"@"
                                memset(szName, 0, sizeof(szName));
                                sprintf(szName, "@%s", xml_attr->name);
                                memset(szValue, 0, sizeof(szValue));
                                string_conv("UTF-8", "GBK", xml_attr->children->content, 
                                    strlen(xml_attr->children->content), szValue, &len);
                                cJSON_AddStringToObject(json_cur, szName, szValue);
                                xml_attr = xml_attr->next;    
                            }
                        }
                        cJSON_AddItemToArray(json_array, json_cur);    
                        xmlUnlinkNode(xml_loop);        //    处理完成后删除该节点,要不然FOR循环会再处理一次
                        xmlFreeNode(xml_loop);
                    }
                    xml_loop = xml_tmp;
                }

                xml_attr = xml_cur->properties;
                //    无属性节点直接设置成string
                if(NULL == xml_attr)
                {
                    memset(szValue, 0, sizeof(szValue));    
                    pszContent = xmlNodeGetContent(xml_cur);
                    len = strlen(pszContent);
                    //    XML内容编码格式为UTF,需要转换成GBK
                    string_conv("UTF-8", "GBK", pszContent, strlen(pszContent),
                        szValue, &len);                    
                    xmlFree(pszContent);
                    json_cur = cJSON_CreateString(szValue);        

                }
                //    有属性需要创建节点,并转换xml属性的数据
                else
                {
                    json_cur = cJSON_CreateObject();    
                    memset(szName, 0, sizeof(szName));
                    strcpy(szName, "#text");
                    memset(szValue, 0, sizeof(szValue));
                    pszContent = xmlNodeGetContent(xml_cur);
                    len = strlen(pszContent);
                    string_conv("UTF-8", "GBK", pszContent, strlen(pszContent),
                        szValue, &len);
                    xmlFree(pszContent);
                    cJSON_AddStringToObject(json_cur, szName, szValue);
                    
                    while(xml_attr)
                    {
                        memset(szName, 0, sizeof(szName));
                        snprintf(szName, sizeof(szName), "@%s", xml_attr->name);
                        memset(szValue, 0, sizeof(szValue));
                        len = strlen(xml_attr->children->content);
                        string_conv("UTF-8", "GBK", xml_attr->children->content, strlen(xml_attr->children->content),
                            szValue, &len);
                        cJSON_AddStringToObject(json_cur, szName, szValue);
                        xml_attr = xml_attr->next;
                    }
                }
                //    判断是否是循环数据,如果是的插入到array再存放到数据中
                if(NULL != json_array)
                {
                    cJSON_AddItemToArray(json_array, json_cur);
                    cJSON_AddItemToObject(*json_node, xml_cur->name, json_array);
                    json_array = NULL;
                }
                else
                    cJSON_AddItemToObject(*json_node, xml_cur->name, json_cur);
            }

            //    下级节点也是节点
            else if(xml_cur->children->type == XML_ELEMENT_NODE)
            {
                //    判断同级节点是否存在项目名称的节点数据,如果存在,则为循环节点
                xml_loop = xml_cur->next;
                while(xml_loop)
                {
                    xml_tmp = xml_loop->next;
                    if(0 == xmlStrcmp(xml_loop->name, xml_cur->name))
                    {
//                        fprintf(stdout, "--->loop:[%s]\n", xml_loop->name);
                        if(NULL == json_array)
                            json_array = cJSON_CreateArray();
                        json_cur = cJSON_CreateObject();
                        xml_attr = xml_loop->properties;
                        while(xml_attr)
                        {
                            memset(szName, 0, sizeof(szName));
                            snprintf(szName, sizeof(szName) - 1, "@%s", xml_attr->name);
                            memset(szValue, 0, sizeof(szValue));
                            len = strlen(xml_attr->children->content);
                            string_conv("UTF-8", "GBK", xml_attr->children->content, strlen(xml_attr->children->content),
                                szValue, &len);
                            cJSON_AddStringToObject(json_cur, szName, szValue);
                            xml_attr=xml_attr->next;
                        }
                        //    使用递归的方法转换该节点数据
                        _xml_json(xml_loop->children, &json_cur);
                        cJSON_AddItemToArray(json_array, json_cur);
                        xmlUnlinkNode(xml_loop);        //    处理完成的节点需要删除,要不然FOR循环会再处理一次
                        xmlFreeNode(xml_loop);
                    }        
                            
                    xml_loop = xml_tmp;
                }
            
                json_cur = cJSON_CreateObject();    
                xml_attr = xml_cur->properties;
                while(xml_attr)
                {
                    memset(szName, 0, sizeof(szName));
                    snprintf(szName, sizeof(szName) - 1, "@%s", xml_attr->name);
//fprintf(stdout, "name:[%s]\n", szName);
                    memset(szValue, 0, sizeof(szValue));
                    len = strlen(xml_attr->children->content);
                    string_conv("UTF-8", "GBK", xml_attr->children->content, strlen(xml_attr->children->content),
                        szValue, &len);
                    cJSON_AddStringToObject(json_cur, szName, szValue);
                    xml_attr = xml_attr->next;
                }
                _xml_json(xml_cur->children, &json_cur);
                //    判断是否是循环数据,如果是的插入到array再存放到数据中
                if(NULL != json_array)
                {
                    cJSON_AddItemToArray(json_array, json_cur);
                    cJSON_AddItemToObject(*json_node, xml_cur->name, json_array);
                    json_array = NULL;
                }
                else
                    cJSON_AddItemToObject(*json_node, xml_cur->name, json_cur);
            }
        }
    }
    
    return ;
}

//    注意,参数json为返回数据,需要释放
long    xml2json(const char* xml, const long xml_len, char** json, long* json_len)
{
    xmlBufferPtr buff;
    xmlDocPtr    xml_doc;
    xmlNodePtr    xml_root;
    cJSON        *json_root;
    char        *p = NULL;

    xmlKeepBlanksDefault(0);
    buff = xmlBufferCreate();    
    xml_doc = xmlReadMemory(xml, xml_len, "", "gbk", 0);
    if(NULL == xml_doc)    
    {
        fprintf(stderr, "解析XML文档失败\n");
        return -1;
    }
    
    xml_root = xmlDocGetRootElement(xml_doc);
    if(NULL == xml_root)
    {
        fprintf(stderr, "获取XML根节点失败\n");
        xmlFree(xml_doc);
        return -1;
    }

    json_root = cJSON_CreateObject();
    _xml_json(xml_root, &json_root);    
    *json = cJSON_Print(json_root);
    *json_len = strlen(*json);
    cJSON_Delete(json_root);
    xmlFreeDoc(xml_doc);
    xmlBufferFree(buff);
    xmlCleanupParser();
    return 0;
}
    
int main(int argc, char* argv[])
{
    char    filename[1024];
    struct    stat st;
    FILE    *fp = NULL;
    char    line[1024], *data = NULL, *json=NULL;
    long    len;

    if(1 >= argc)
    {
        fprintf(stderr, "Usage:[%s] xmlfilename\n", argv[0]);
        return -1;
    }
    
    memset(filename, 0, sizeof(filename));
    strcpy(filename, argv[1]);
    if(NULL == (fp = fopen(filename, "r")))
    {
        fprintf(stderr, "打开文件[%s]失败\n", filename);
        return -1;
    }
    memset(&st, 0, sizeof(st));
    stat(filename, &st);
    data = (char*)malloc(st.st_size + 1);
    memset(line, 0, sizeof(line));
    while(fgets(line, sizeof(line) - 1, fp))
    {
        strncpy(data + strlen(data), line, strlen(line));
        memset(line, 0, sizeof(line));
    }
    fclose(fp);
    if(0 != xml2json(data, strlen(data), &json, &len))
    {
        fprintf(stderr, "XML转JSON失败\n");
        free(data);
        return -1;
    }
    free(data);
    fprintf(stdout, "JSON:\n%s\n[%d]\n", json, len);
    free(json);
    
    return 0;
}

 

 

问题记录:

1、数据编码问题,libxml2内部编码格式是UTF-8,使用xmlNodeGetContent()方法获取的数据需要转换成GBK编码格式,本文采用conv库转换编码格式

2、内存释放问题

  1)、xmlNodeGetContent()方法获取的数据需要释放

  2)、xmlUnlinkNode()方法删除节点后需要将使用xmlFreeNode()方法释放内存

  3)、JSON数据可以使用cJSON_Delete()方法一次释放

  4)、cJSON_Print()方法返回的字符串数据需要释放

3、XML数据存在循环结构的处理

4、XML数据存在属性节点的的处理

posted @ 2017-03-06 00:04  linux.vincent  阅读(2034)  评论(2编辑  收藏  举报