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數據存在屬性節點的的處理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM