zoukankan      html  css  js  c++  java
  • 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]
    ", 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, "-------------------------------------
    ");    
        fprintf(stdout, "XML:
    %s
    ", 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]不存在
    ", 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!
    ");
            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]
    ", cur->name, pszContent);
                    xmlFree(pszContent);
                }
                else if(cur->children->type == XML_ELEMENT_NODE)
                {
                    fprintf(stdout, "NODE:[%s]
    ", 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]
    ", 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]
    ", 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]
    ", 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]
    ", 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文档失败
    ");
            return -1;
        }
        
        xml_root = xmlDocGetRootElement(xml_doc);
        if(NULL == xml_root)
        {
            fprintf(stderr, "获取XML根节点失败
    ");
            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
    ", argv[0]);
            return -1;
        }
        
        memset(filename, 0, sizeof(filename));
        strcpy(filename, argv[1]);
        if(NULL == (fp = fopen(filename, "r")))
        {
            fprintf(stderr, "打开文件[%s]失败
    ", 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失败
    ");
            free(data);
            return -1;
        }
        free(data);
        fprintf(stdout, "JSON:
    %s
    [%d]
    ", 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数据存在属性节点的的处理

  • 相关阅读:
    getContentResolver()内容解析者查询联系人、插入联系人
    ContentProvider备份短信,以xml文件存储
    ContentProvider详解
    bindService初步了解
    Service之来电监听(失败的案例)
    Android帧动画
    AlertDialog之常见对话框(单选对话框、多选对话框、进度条对话框)
    BroadcastReceiver之(手动代码注册广播)屏幕锁屏、解锁监听、开机自启
    BroadcastReceiver之有序广播
    [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/stupid-vincent/p/6507557.html
Copyright © 2011-2022 走看看