<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    MDA之路

    MDA,UML,XML,Eclipse及Java相關(guān)的Blog
    posts - 53, comments - 494, trackbacks - 0, articles - 2
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
     

    C++的XML編程經(jīng)驗――LIBXML2庫使用指南

    寫這篇文章的原因有如下幾點(diǎn):1)C++標(biāo)準(zhǔn)庫中沒有操作XML的方法,用C++操作XML文件必須熟悉一種函數(shù)庫,LIBXML2是其中一種很優(yōu)秀的XML庫,而且它同時支持多種編程語言;2)LIBXML2庫的Tutorial寫得不太好,尤其是編碼轉(zhuǎn)換的部分,不適用于中文編碼的轉(zhuǎn)換;3)網(wǎng)上的大多數(shù)關(guān)于Libxml2的介紹僅僅是翻譯了自帶的資料,沒有詳細(xì)介紹如何在windows平臺下進(jìn)行編程,更很少提到如何解決中文問題。

    基于以上幾點(diǎn)原因,決定寫一個在Windows平臺下,使用C/C++語言,應(yīng)用LibXml2庫來進(jìn)行xml文檔操作,同時使用ICONV庫進(jìn)行中文編碼轉(zhuǎn)換的文檔。其中還涉及了MakefileXPATH等相關(guān)內(nèi)容。本文中所有的源代碼在http://www.tkk7.com/Files/wxb_nudt/xml_src.rar

    1.       下載與安裝LIBXML2ICONV

    Libxml2是一個C語言的XML程序庫,可以簡單方便的提供對XML文檔的各種操作,并且支持XPATH查詢,以及部分的支持XSLT轉(zhuǎn)換等功能。Libxml2的下載地址是http://xmlsoft.org/,完全版的庫是開源的,并且?guī)в欣映绦蚝驼f明文檔。最好將這個庫先下載下來,因為這樣可以查看其中的文檔和例子。

    windows版本的的下載地址是http://www.zlatkovic.com/libxml.en.html;這個版本只提供了頭文件、庫文件和dll,不包含源代碼、例子程序和文檔。在文本中,只需要下載libxml2庫、iconv庫和zlib庫就行了(注意,libxml2庫依賴iconvzlib庫,本文中重點(diǎn)關(guān)注libxml2iconvzlib不介紹),我使用的版本是libxml2-2.6.30.win32.zipzlib-1.2.3.win32.zipiconv-1.9.2.win32.zip

    在編程的時候,我們使用windows版本的libxml2zlibiconv,將其解壓縮到指定文件夾,例如D:"libxml2-2.6.30.win32D:"zlib-1.2.3.win32以及D:"iconv-1.9.2.win32。事實上,我們知道在windows下面使用頭文件、庫文件和dll是不需要安裝的,它又沒有使用任何需要注冊的組件或者數(shù)據(jù)庫,只需要告訴編譯器和鏈接器這些資源的位置就可以了。

    注意:要在path變量中加上D:"iconv-1.9.2.win32"bin;D:"zlib-1.2.3.win32"bin;D:"libxml2-2.6.30.win32"bin這三個地址,否則在執(zhí)行的時候就找不到。或者使用更簡單的方法,把其中的三個dll到拷貝到system32目錄中。

    有兩種方法來編譯鏈接基于libxml2的程序,第一種是在VC環(huán)境中設(shè)置libinclude路徑,并在link設(shè)置中添加libxml2.libiconv.lib;第二種是用編譯器選項告訴編譯器cl.exe頭文件的位置,并用鏈接器選項告訴鏈接器link.exe庫文件的位置,同時在windows環(huán)境變量path中添加libxml2bin文件夾的位置,以便于程序運(yùn)行時可以找到dll(也可以將dll拷貝到system32目錄下)。顯然我選擇了第二種,那么編譯鏈接一個名為CreateXmlFile.cpp源文件的命令如下:

    cl /c /I D:"iconv-1.9.2.win32"include /I D:"libxml2-2.6.30.win32"include CreateXmlFile.cpp

    link /libpath:D:"iconv-1.9.2.win32"lib /libpath:D:"libxml2-2.6.30.win32"lib CreateXmlFile.obj iconv.lib libxml2.lib

    顯然這樣很費(fèi)時,那么再不用makefile就顯得矯情了,于是,一個典型的使用nmake.exeVC自帶的makefile工具)的文件如下:MAKEFILE

    #

    # 本目錄下所有源代碼的makefile,使用方法是nmake TARGET_NAME=源代碼文件名字(不加后綴)

    # 例如 nmake TARGET_NAME=CreateXmlFile

    # Author: Wang Xuebin

    #

    # Flags - 編譯debug版本

    #

    #指定要使用的庫的路徑,需要用戶修改的變量一般放在makefile文件的最上面

    LIBXML2_HOME = D:"libxml2-2.6.30.win32

    ICONV_HOME = D:"iconv-1.9.2.win32

    #指定編譯器選項,/c表明cl命令只編譯不鏈接;/MTd表明使用多線程debug;/Zi表明產(chǎn)生完整的調(diào)試信息;

    #/Od表明關(guān)閉編譯優(yōu)化;/D _DEBUG表明定義一個名為_DEBUG的宏

    CPP_FLAGS=/c /MTd /Zi /Od /D _DEBUG

    #鏈接選項,/DEBUG表明創(chuàng)建Debug信息

    EXE_LINK_FLAGS=/DEBUG

    #指定鏈接的庫

    LIBS=iconv.lib libxml2.lib

    #指定編譯路徑選項,鏈接路徑選項

    INCLUDE_FLAGS= /I $(LIBXML2_HOME)"include /I $(ICONV_HOME)"include

    LIB_PATH_FLAGS = /libpath:$(ICONV_HOME)"lib /libpath:$(LIBXML2_HOME)"lib

    #################################################

    #

    # Targets 目標(biāo)

    #

    $(TARGET_NAME) : $(TARGET_NAME).exe

    clean : $(TARGET_NAME).exe

    $(TARGET_NAME).obj : $(TARGET_NAME).cpp

        cl $(CPP_FLAGS) $(INCLUDE_FLAGS) $(TARGET_NAME).cpp

    $(TARGET_NAME).exe : $(TARGET_NAME).obj

     link $(EXE_LINK_FLAGS) $(LIB_PATH_FLAGS) $(TARGET_NAME).obj $(LIBS)

    clean : $(TARGET_NAME).exe

     del $(TARGET_NAME).exe

     del $(TARGET_NAME).obj

     del $(TARGET_NAME).ilk

     del $(TARGET_NAME).pdb

    本文不準(zhǔn)備介紹makefile的寫法,但后續(xù)例子程序的編譯鏈接依葫蘆畫瓢都沒有問題,執(zhí)行編譯鏈接的命令如下:

    nmake TARGET_NAME=CreateXmlFile

    執(zhí)行清理的命令如下:

    nmake TARGET_NAME=CreateXmlFile clean

    2.       Libxml2中的數(shù)據(jù)類型和函數(shù)

    一個函數(shù)庫中可能有幾百種數(shù)據(jù)類型以及幾千個函數(shù),但是記住大師的話,90%的功能都是由30%的內(nèi)容提供的。對于libxml2,我認(rèn)為搞懂以下的數(shù)據(jù)類型和函數(shù)就足夠了。

    2.1   內(nèi)部字符類型xmlChar

    xmlCharLibxml2中的字符類型,庫中所有字符、字符串都是基于這個數(shù)據(jù)類型。事實上它的定義是:xmlstring.h

    typedef unsigned char xmlChar;

    使用unsigned char作為內(nèi)部字符格式是考慮到它能很好適應(yīng)UTF-8編碼,而UTF-8編碼正是libxml2的內(nèi)部編碼,其它格式的編碼要轉(zhuǎn)換為這個編碼才能在libxml2中使用。

    還經(jīng)常可以看到使用xmlChar*作為字符串類型,很多函數(shù)會返回一個動態(tài)分配內(nèi)存的xmlChar*變量,使用這樣的函數(shù)時記得要手動刪除內(nèi)存。

    2.2   xmlChar相關(guān)函數(shù)

    如同標(biāo)準(zhǔn)c中的char類型一樣,xmlChar也有動態(tài)內(nèi)存分配、字符串操作等相關(guān)函數(shù)。例如xmlMalloc是動態(tài)分配內(nèi)存的函數(shù);xmlFree是配套的釋放內(nèi)存函數(shù);xmlStrcmp是字符串比較函數(shù)等等。

    基本上xmlChar字符串相關(guān)函數(shù)都在xmlstring.h中定義;而動態(tài)內(nèi)存分配函數(shù)在xmlmemory.h中定義。

    2.3   xmlChar*與其它類型之間的轉(zhuǎn)換

    另外要注意,因為總是要在xmlChar*char*之間進(jìn)行類型轉(zhuǎn)換,所以定義了一個宏BAD_CAST,其定義如下:xmlstring.h

    #define BAD_CAST (xmlChar *)

    原則上來說,unsigned charchar之間進(jìn)行強(qiáng)制類型轉(zhuǎn)換是沒有問題的。

    2.4   文檔類型xmlDoc、指針xmlDocPtr

    xmlDoc是一個struct,保存了一個xml的相關(guān)信息,例如文件名、文檔類型、子節(jié)點(diǎn)等等;xmlDocPtr等于xmlDoc*,它搞成這個樣子總讓人以為是智能指針,其實不是,要手動刪除的。

    xmlNewDoc函數(shù)創(chuàng)建一個新的文檔指針。

    xmlParseFile函數(shù)以默認(rèn)方式讀入一個UTF-8格式的文檔,并返回文檔指針。

    xmlReadFile函數(shù)讀入一個帶有某種編碼的xml文檔,并返回文檔指針;細(xì)節(jié)見libxml2參考手冊。

    xmlFreeDoc釋放文檔指針。特別注意,當(dāng)你調(diào)用xmlFreeDoc時,該文檔所有包含的節(jié)點(diǎn)內(nèi)存都被釋放,所以一般來說不需要手動調(diào)用xmlFreeNode或者xmlFreeNodeList來釋放動態(tài)分配的節(jié)點(diǎn)內(nèi)存,除非你把該節(jié)點(diǎn)從文檔中移除了。一般來說,一個文檔中所有節(jié)點(diǎn)都應(yīng)該動態(tài)分配,然后加入文檔,最后調(diào)用xmlFreeDoc一次釋放所有節(jié)點(diǎn)申請的動態(tài)內(nèi)存,這也是為什么我們很少看見xmlNodeFree的原因。

    xmlSaveFile將文檔以默認(rèn)方式存入一個文件。

    xmlSaveFormatFileEnc可將文檔以某種編碼/格式存入一個文件中。

    2.5   節(jié)點(diǎn)類型xmlNode、指針xmlNodePtr

    節(jié)點(diǎn)應(yīng)該是xml中最重要的元素了,xmlNode代表了xml文檔中的一個節(jié)點(diǎn),實現(xiàn)為一個struct,內(nèi)容很豐富:tree.h

    typedef struct _xmlNode xmlNode;

    typedef xmlNode *xmlNodePtr;

    struct _xmlNode {

        void           *_private;/* application data */

        xmlElementType   type;   /* type number, must be second ! */

        const xmlChar   *name;      /* the name of the node, or the entity */

        struct _xmlNode *children; /* parent->childs link */

        struct _xmlNode *last;   /* last child link */

        struct _xmlNode *parent;/* child->parent link */

        struct _xmlNode *next;   /* next sibling link */

        struct _xmlNode *prev;   /* previous sibling link */

        struct _xmlDoc *doc;/* the containing document */

        /* End of common part */

        xmlNs           *ns;        /* pointer to the associated namespace */

        xmlChar         *content;   /* the content */

        struct _xmlAttr *properties;/* properties list */

        xmlNs           *nsDef;     /* namespace definitions on this node */

        void            *psvi;/* for type/PSVI informations */

        unsigned short   line;   /* line number */

        unsigned short   extra; /* extra data for XPath/XSLT */

    };

    可以看到,節(jié)點(diǎn)之間是以鏈表和樹兩種方式同時組織起來的,nextprev指針可以組成鏈表,而parentchildren可以組織為樹。同時還有以下重要元素:

    l         節(jié)點(diǎn)中的文字內(nèi)容:content

    l         節(jié)點(diǎn)所屬文檔:doc

    l         節(jié)點(diǎn)名字:name

    l         節(jié)點(diǎn)的namespacens

    l         節(jié)點(diǎn)屬性列表:properties

    Xml文檔的操作其根本原理就是在節(jié)點(diǎn)之間移動、查詢節(jié)點(diǎn)的各項信息,并進(jìn)行增加、刪除、修改的操作。

    xmlDocSetRootElement函數(shù)可以將一個節(jié)點(diǎn)設(shè)置為某個文檔的根節(jié)點(diǎn),這是將文檔與節(jié)點(diǎn)連接起來的重要手段,當(dāng)有了根結(jié)點(diǎn)以后,所有子節(jié)點(diǎn)就可以依次連接上根節(jié)點(diǎn),從而組織成為一個xml樹。

    2.6   節(jié)點(diǎn)集合類型xmlNodeSet、指針xmlNodeSetPtr

    節(jié)點(diǎn)集合代表一個由節(jié)點(diǎn)組成的變量,節(jié)點(diǎn)集合只作為Xpath的查詢結(jié)果而出現(xiàn)(XPATH的介紹見后面),因此被定義在xpath.h中,其定義如下:

    /*

     * A node-set (an unordered collection of nodes without duplicates).

     */

    typedef struct _xmlNodeSet xmlNodeSet;

    typedef xmlNodeSet *xmlNodeSetPtr;

    struct _xmlNodeSet {

        int nodeNr;          /* number of nodes in the set */

        int nodeMax;      /* size of the array as allocated */

        xmlNodePtr *nodeTab;/* array of nodes in no particular order */

        /* @@ with_ns to check wether namespace nodes should be looked at @@ */

    };

    可以看出,節(jié)點(diǎn)集合有三個成員,分別是節(jié)點(diǎn)集合的節(jié)點(diǎn)數(shù)、最大可容納的節(jié)點(diǎn)數(shù),以及節(jié)點(diǎn)數(shù)組頭指針。對節(jié)點(diǎn)集合中各個節(jié)點(diǎn)的訪問方式很簡單,如下:

    xmlNodeSetPtr nodeset = XPATH查詢結(jié)果;

    for (int i = 0; i < nodeset->nodeNr; i++)

    {

     nodeset->nodeTab[i];

    }

    注意,libxml2是一個c函數(shù)庫,因此其函數(shù)和數(shù)據(jù)類型都使用c語言的方式來處理。如果是c++,我想我寧愿用STL中的vector來表示一個節(jié)點(diǎn)集合更好,而且沒有內(nèi)存泄漏或者溢出的擔(dān)憂。

    3.       簡單xml操作例子

    了解以上基本知識之后,就可以進(jìn)行一些簡單的xml操作了。當(dāng)然,還沒有涉及到內(nèi)碼轉(zhuǎn)換(使得xml中可以處理中文)、xpath等較復(fù)雜的操作。

    3.1   創(chuàng)建xml文檔

    有了上面的基礎(chǔ),創(chuàng)建一個xml文檔顯得非常簡單,其流程如下:

    l         xmlNewDoc函數(shù)創(chuàng)建一個文檔指針doc

    l         xmlNewNode函數(shù)創(chuàng)建一個節(jié)點(diǎn)指針root_node

    l         xmlDocSetRootElementroot_node設(shè)置為doc的根結(jié)點(diǎn);

    l         root_node添加一系列的子節(jié)點(diǎn),并設(shè)置子節(jié)點(diǎn)的內(nèi)容和屬性;

    l         xmlSaveFilexml文檔存入文件;

    l         xmlFreeDoc函數(shù)關(guān)閉文檔指針,并清除本文檔中所有節(jié)點(diǎn)動態(tài)申請的內(nèi)存。

    注意,有多種方式可以添加子節(jié)點(diǎn):第一是用xmlNewTextChild直接添加一個文本子節(jié)點(diǎn);第二是先創(chuàng)建新節(jié)點(diǎn),然后用xmlAddChild將新節(jié)點(diǎn)加入上層節(jié)點(diǎn)。

    源代碼文件是CreateXmlFile.cpp,如下:

    /********************************************************************

        created:   2007/11/09

        created:   9:11:2007   15:34

        filename: CreateXmlFile.cpp

        author:       Wang xuebin

        depend:       libxml2.lib

        build:     nmake TARGET_NAME=CreateXmlFile

        purpose:   創(chuàng)建一個xml文件

    *********************************************************************/

    #include <stdio.h>

    #include <libxml/parser.h>

    #include <libxml/tree.h>

    #include <iostream.h>

    int main()

    {

        //定義文檔和節(jié)點(diǎn)指針

        xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");

        xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root");

        //設(shè)置根節(jié)點(diǎn)

        xmlDocSetRootElement(doc,root_node);

        //在根節(jié)點(diǎn)中直接創(chuàng)建節(jié)點(diǎn)

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content");

        //創(chuàng)建一個節(jié)點(diǎn),設(shè)置其內(nèi)容和屬性,然后加入根結(jié)點(diǎn)

        xmlNodePtr node = xmlNewNode(NULL,BAD_CAST"node2");

        xmlNodePtr content = xmlNewText(BAD_CAST"NODE CONTENT");

        xmlAddChild(root_node,node);

        xmlAddChild(node,content);

        xmlNewProp(node,BAD_CAST"attribute",BAD_CAST "yes");

        //創(chuàng)建一個兒子和孫子節(jié)點(diǎn)

        node = xmlNewNode(NULL, BAD_CAST "son");

        xmlAddChild(root_node,node);

        xmlNodePtr grandson = xmlNewNode(NULL, BAD_CAST "grandson");

        xmlAddChild(node,grandson);

        xmlAddChild(grandson, xmlNewText(BAD_CAST "This is a grandson node"));

        //存儲xml文檔

        int nRel = xmlSaveFile("CreatedXml.xml",doc);

        if (nRel != -1)

        {

           cout<<"一個xml文檔被創(chuàng)建,寫入"<<nRel<<"個字節(jié)"<<endl;

        }

        //釋放文檔內(nèi)節(jié)點(diǎn)動態(tài)申請的內(nèi)存

        xmlFreeDoc(doc);

        return 1;

    }

    編譯鏈接命令如下:

    nmake TARGET_NAME=CreateXmlFile

    然后執(zhí)行可執(zhí)行文件CreateXmlFile.exe,會生成一個xml文件CreatedXml.xml,打開后如下所示:

    <?xml version="1.0"?>

    <root>

        <newNode1>newNode1 content</newNode1>

        <newNode2>newNode2 content</newNode2>

        <newNode3>newNode3 content</newNode3>

        <node2 attribute="yes">NODE CONTENT</node2>

        <son>

           <grandson>This is a grandson node</grandson>

        </son>

    </root>

    最好使用類似XMLSPY這樣的工具打開,因為這些工具可以自動整理xml文件的柵格,否則很有可能是沒有任何換行的一個xml文件,可讀性較差。

    3.2   解析xml文檔

    解析一個xml文檔,從中取出想要的信息,例如節(jié)點(diǎn)中包含的文字,或者某個節(jié)點(diǎn)的屬性,其流程如下:

    l         xmlReadFile函數(shù)讀出一個文檔指針doc

    l         xmlDocGetRootElement函數(shù)得到根節(jié)點(diǎn)curNode

    l         curNode->xmlChildrenNode就是根節(jié)點(diǎn)的子節(jié)點(diǎn)集合;

    l         輪詢子節(jié)點(diǎn)集合,找到所需的節(jié)點(diǎn),用xmlNodeGetContent取出其內(nèi)容;

    l         xmlHasProp查找含有某個屬性的節(jié)點(diǎn);

    l         取出該節(jié)點(diǎn)的屬性集合,用xmlGetProp取出其屬性值;

    l         xmlFreeDoc函數(shù)關(guān)閉文檔指針,并清除本文檔中所有節(jié)點(diǎn)動態(tài)申請的內(nèi)存。

    注意:節(jié)點(diǎn)列表的指針依然是xmlNodePtr,屬性列表的指針也是xmlAttrPtr,并沒有xmlNodeList或者xmlAttrList這樣的類型。看作列表的時候使用它們的nextprev鏈表指針來進(jìn)行輪詢。只有在Xpath中有xmlNodeSet這種類型,其使用方法前面已經(jīng)介紹了。

    源代碼如下:ParseXmlFile.cpp

    /********************************************************************

        created:   2007/11/15

        created:   15:11:2007   11:47

        filename: ParseXmlFile.cpp

        author:       Wang xuebin

        depend:       libxml2.lib

        build:     nmake TARGET_NAME=ParseXmlFile

        purpose:   解析xml文件

    *********************************************************************/

    #include <libxml/parser.h>

    #include <iostream.h>

    int main(int argc, char* argv[])

    {

        xmlDocPtr doc;           //定義解析文檔指針

        xmlNodePtr curNode;      //定義結(jié)點(diǎn)指針(你需要它為了在各個結(jié)點(diǎn)間移動)

        xmlChar *szKey;          //臨時字符串變量

        char *szDocName;

        if (argc <= 1) 

        {

           printf("Usage: %s docname"n", argv[0]);

           return(0);

        }

        szDocName = argv[1];

        doc = xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER); //解析文件

        //檢查解析文檔是否成功,如果不成功,libxml將指一個注冊的錯誤并停止。

        //一個常見錯誤是不適當(dāng)?shù)木幋a。XML標(biāo)準(zhǔn)文檔除了用UTF-8UTF-16外還可用其它編碼保存。

        //如果文檔是這樣,libxml將自動地為你轉(zhuǎn)換到UTF-8。更多關(guān)于XML編碼信息包含在XML標(biāo)準(zhǔn)中.

        if (NULL == doc)

        {  

           fprintf(stderr,"Document not parsed successfully. "n");    

           return -1;

        }

        curNode = xmlDocGetRootElement(doc); //確定文檔根元素

        /*檢查確認(rèn)當(dāng)前文檔中包含內(nèi)容*/

        if (NULL == curNode)

        {

           fprintf(stderr,"empty document"n");

           xmlFreeDoc(doc);

           return -1;

        }

        /*在這個例子中,我們需要確認(rèn)文檔是正確的類型。“root”是在這個示例中使用文檔的根類型。*/

        if (xmlStrcmp(curNode->name, BAD_CAST "root"))

        {

           fprintf(stderr,"document of the wrong type, root node != root");

           xmlFreeDoc(doc);

           return -1;

        }

        curNode = curNode->xmlChildrenNode;

        xmlNodePtr propNodePtr = curNode;

        while(curNode != NULL)

        {

           //取出節(jié)點(diǎn)中的內(nèi)容

           if ((!xmlStrcmp(curNode->name, (const xmlChar *)"newNode1")))

           {

               szKey = xmlNodeGetContent(curNode);

               printf("newNode1: %s"n", szKey);

               xmlFree(szKey);

           }

           //查找?guī)в袑傩?/span>attribute的節(jié)點(diǎn)

           if (xmlHasProp(curNode,BAD_CAST "attribute"))

           {

               propNodePtr = curNode;

           }

           curNode = curNode->next;

        }

        //查找屬性

        xmlAttrPtr attrPtr = propNodePtr->properties;

        while (attrPtr != NULL)

        {

           if (!xmlStrcmp(attrPtr->name, BAD_CAST "attribute"))

           {

               xmlChar* szAttr = xmlGetProp(propNodePtr,BAD_CAST "attribute");

               cout<<"get attribute = "<<szAttr<<endl;

               xmlFree(szAttr);

           }

           attrPtr = attrPtr->next;

        }

        xmlFreeDoc(doc);

        return 0;

    }

    編譯鏈接命令如下:

    nmake TARGET_NAME=ParseXmlFile

    執(zhí)行命令如下,使用第一次創(chuàng)建的xml文件作為輸入:

    ParseXmlFile.exe CreatedXml.xml

    觀察源代碼可發(fā)現(xiàn),所有以查詢方式得到的xmlChar*字符串都必須使用xmlFree函數(shù)手動釋放。否則會造成內(nèi)存泄漏。

    3.3   修改xml文檔

    有了上面的基礎(chǔ),修改xml文檔的內(nèi)容就很簡單了。首先打開一個已經(jīng)存在的xml文檔,順著根結(jié)點(diǎn)找到需要添加、刪除、修改的地方,調(diào)用相應(yīng)的xml函數(shù)對節(jié)點(diǎn)進(jìn)行增、刪、改操作。源代碼見ChangeXmlFile,編譯鏈接方法如上。執(zhí)行下面的命令:

    ChangeXmlFile.exe CreatedXml.xml

    可以得到一個修改后的xml文檔ChangedXml.xml,如下:

    <?xml version="1.0"?>

    <root>

        <newNode2>content changed</newNode2>

        <newNode3 newAttr="YES">newNode3 content</newNode3>

        <node2 attribute="no">NODE CONTENT</node2>

        <son>

           <grandson>This is a grandson node</grandson>

           <newGrandSon>new content</newGrandSon>

        </son>

    </root>

    需要注意的是,并沒有xmlDelNode或者xmlRemoveNode函數(shù),我們刪除節(jié)點(diǎn)使用的是以下一段代碼:

           if (!xmlStrcmp(curNode->name, BAD_CAST "newNode1"))

           {

               xmlNodePtr tempNode;

               tempNode = curNode->next;

               xmlUnlinkNode(curNode);

               xmlFreeNode(curNode);

               curNode = tempNode;

               continue;

           }

    即將當(dāng)前節(jié)點(diǎn)從文檔中斷鏈(unlink),這樣本文檔就不會再包含這個子節(jié)點(diǎn)。這樣做需要使用一個臨時變量來存儲斷鏈節(jié)點(diǎn)的后續(xù)節(jié)點(diǎn),并記得要手動刪除斷鏈節(jié)點(diǎn)的內(nèi)存。

    3.4   使用XPATH查找xml文檔

    簡而言之,XPATH之于xml,好比SQL之于關(guān)系數(shù)據(jù)庫。要在一個復(fù)雜的xml文檔中查找所需的信息,XPATH簡直是必不可少的工具。XPATH語法簡單易學(xué),并且有一個很好的官方教程,見http://www.zvon.org/xxl/XPathTutorial/Output_chi/introduction.html。這個站點(diǎn)的XML各種教程齊全,并且有包括中文在內(nèi)的各國語言版本,真是讓我喜歡到非常!

    使用XPATH之前,必須首先熟悉幾個數(shù)據(jù)類型和函數(shù),它們是使用XPATH的前提。在libxml2中使用Xpath是非常簡單的,其流程如下:

    l         定義一個XPATH上下文指針xmlXPathContextPtr context,并且使用xmlXPathNewContext函數(shù)來初始化這個指針;

    l         定義一個XPATH對象指針xmlXPathObjectPtr result,并且使用xmlXPathEvalExpression函數(shù)來計算Xpath表達(dá)式,得到查詢結(jié)果,將結(jié)果存入對象指針中;

    l         使用result->nodesetval得到節(jié)點(diǎn)集合指針,其中包含了所有符合Xpath查詢結(jié)果的節(jié)點(diǎn);

    l         使用xmlXPathFreeContext釋放上下文指針;

    l         使用xmlXPathFreeObject釋放Xpath對象指針;

    具體的使用方法可以看XpathForXmlFile.cpp的這一段代碼,其功能是查找符合某個Xpath語句的對象指針:

    xmlXPathObjectPtr getNodeSet(xmlDocPtr doc, const xmlChar *szXpath)

    {

        xmlXPathContextPtr context;    //XPATH上下文指針

        xmlXPathObjectPtr result;       //XPATH對象指針,用來存儲查詢結(jié)果

        context = xmlXPathNewContext(doc);     //創(chuàng)建一個XPath上下文指針

        if (context == NULL)

        {  

           printf("context is NULL"n");

           return NULL;

        }

        result = xmlXPathEvalExpression(szXpath, context); //查詢XPath表達(dá)式,得到一個查詢結(jié)果

        xmlXPathFreeContext(context);             //釋放上下文指針

        if (result == NULL)

        {

           printf("xmlXPathEvalExpression return NULL"n");

           return NULL; 

        }

        if (xmlXPathNodeSetIsEmpty(result->nodesetval))   //檢查查詢結(jié)果是否為空

        {

           xmlXPathFreeObject(result);

           printf("nodeset is empty"n");

           return NULL;

        }

        return result;   

    }

    一個完整的使用Xpath的例子在代碼XpathForXmlFile.cpp中,它查找一個xml文件中符合"/root/node2[@attribute='yes']"語句的結(jié)果,并且將找到的節(jié)點(diǎn)的屬性和內(nèi)容打印出來。編譯鏈接命令如下:

    nmake TARGET_NAME=XpathForXmlFile

    執(zhí)行方式如下:

    XpathForXmlFile.exe CreatedXml.xml

    觀察結(jié)果可以看出找到了一個節(jié)點(diǎn),即root下面node2節(jié)點(diǎn),它的attribute屬性值正好等于yes。更多關(guān)于Xpath的內(nèi)容可以參考XPATH官方手冊。只有掌握了XPATH,才掌握了使用大型XML文件的方法,否則每尋找一個節(jié)點(diǎn)都要從根節(jié)點(diǎn)找起,會把人累死。

    4.       ICONV解決XML中的中文問題

    Libxml2中默認(rèn)的內(nèi)碼是UTF-8,所有使用libxml2進(jìn)行處理的xml文件,必須首先顯式或者默認(rèn)的轉(zhuǎn)換為UTF-8編碼才能被處理。

    要在xml中使用中文,就必須能夠在UTF-8GB2312內(nèi)碼(較常用的一種簡體中文編碼)之間進(jìn)行轉(zhuǎn)換。Libxml2提供了默認(rèn)的內(nèi)碼轉(zhuǎn)換機(jī)制,并且在libxml2Tutorial中有一個例子,事實證明這個例子并不適合用來轉(zhuǎn)換中文。

    所以需要我們顯式的使用ICONV來進(jìn)行內(nèi)碼轉(zhuǎn)換,libxml2本身也是使用ICONV進(jìn)行轉(zhuǎn)換的。ICONV是一個專門用來進(jìn)行編碼轉(zhuǎn)換的庫,基本上支持目前所有常用的編碼。它是glibc庫的一個部分,常常被用于UNIX系統(tǒng)中。當(dāng)然,在windows下面使用也沒有任何問題。前面已經(jīng)提到了ICONV的安裝和使用方法,這里主要講一下編程相關(guān)問題。

    本節(jié)其實和xml以及libxml2沒有太大關(guān)系,你可以把它簡單看作是一個編碼轉(zhuǎn)換方面的專題。我們僅僅需要學(xué)會使用兩個函數(shù)就可以了,即從UTF-8轉(zhuǎn)換到GB2312的函數(shù)u2g,以及反向轉(zhuǎn)換的函數(shù)g2u,源代碼在wxb_codeConv.c中:

    /********************************************************************

        created:   2007/11/15

        created:   15:11:2007   10:30

        filename: wxb_codeConv.c

        author:       Wang xuebin

        depend:       iconv.lib

        build:     不需要build,被包含到其它源代碼中

        purpose:   提供從UTF-8GB2312的內(nèi)碼轉(zhuǎn)換,以及反向的轉(zhuǎn)換

    *********************************************************************/

    #include "iconv.h"

    #include <string.h>

    //代碼轉(zhuǎn)換:從一種編碼轉(zhuǎn)為另一種編碼  

    int code_convert(char* from_charset, char* to_charset, char* inbuf,

                   int inlen, char* outbuf, int outlen)

    {

        iconv_t cd;

        char** pin = &inbuf;  

        char** pout = &outbuf;

        cd = iconv_open(to_charset,from_charset);  

        if(cd == 0)

           return -1;

        memset(outbuf,0,outlen);  

        if(iconv(cd,(const char**)pin,(unsigned int *)&inlen,pout,(unsigned int*)&outlen)

           == -1)

           return -1;  

        iconv_close(cd);

        return 0;  

    }

    //UNICODE碼轉(zhuǎn)為GB2312碼  

    //成功則返回一個動態(tài)分配的char*變量,需要在使用完畢后手動free,失敗返回NULL

    char* u2g(char *inbuf)  

    {

        int nOutLen = 2 * strlen(inbuf) - 1;

        char* szOut = (char*)malloc(nOutLen);

        if (-1 == code_convert("utf-8","gb2312",inbuf,strlen(inbuf),szOut,nOutLen))

        {

           free(szOut);

           szOut = NULL;

        }

        return szOut;

    }  

    //GB2312轉(zhuǎn)為UNICODE  

    //成功則返回一個動態(tài)分配的char*變量,需要在使用完畢后手動free,失敗返回NULL

    char* g2u(char *inbuf)  

    {

        int nOutLen = 2 * strlen(inbuf) - 1;

        char* szOut = (char*)malloc(nOutLen);

        if (-1 == code_convert("gb2312","utf-8",inbuf,strlen(inbuf),szOut,nOutLen))

        {

           free(szOut);

           szOut = NULL;

        }

        return szOut;

    }  

    使用的時候?qū)⑦@個c文件include到其它源文件中。include一個c文件并不奇怪,在c語言的年代我們常常這么干,唯一的害處的編譯鏈接出來的可執(zhí)行程序體積變大了。當(dāng)然這時因為我們這段代碼很小的原因,再大一點(diǎn)我就要用dll了。

    UTF-8GB2312的一個典型使用流程如下:

    l         得到一個UTF-8的字符串szSrc

    l         定義一個char*的字符指針szDes,并不需要給他動態(tài)審判內(nèi)存;

    l         szDes = u2g(szSrc),這樣就可以得到轉(zhuǎn)換后的GB2312編碼的字符串;

    l         使用完這個字符串后使用free(szDes)來釋放內(nèi)存。

    本文并不準(zhǔn)備講述iconv中的函數(shù)細(xì)節(jié),因為那幾個函數(shù)以及數(shù)據(jù)類型都非常簡單,我們還是重點(diǎn)看一下如何在libxml2中使用編碼轉(zhuǎn)換來處理帶有中文的xml文件。下面是使用以上方法來創(chuàng)建一個帶有中文的XML文件的例子程序CreateXmlFile_cn.cpp,源代碼如下:

    /********************************************************************

        created:   2007/11/17

        created:   9:11:2007   15:34

        filename: CreateXmlFile.cpp

        author:       Wang xuebin

        depend:       libxml2.lib iconv.lib

        build:     nmake TARGET_NAME=CreateXmlFile_cn

        purpose:   創(chuàng)建一個xml文件,其中包含中文

    *********************************************************************/

    #include <stdio.h>

    #include <libxml/parser.h>

    #include <libxml/tree.h>

    #include <iostream.h>

    #include "wxb_codeConv.c" //自己寫的編碼轉(zhuǎn)換函數(shù)

    int main(int argc, char **argv)

    {

        //定義文檔和節(jié)點(diǎn)指針

        xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");

        xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root");

        //設(shè)置根節(jié)點(diǎn)

        xmlDocSetRootElement(doc,root_node);

        //一個中文字符串轉(zhuǎn)換為UTF-8字符串,然后寫入

        char* szOut = g2u("節(jié)點(diǎn)1的內(nèi)容");

        //在根節(jié)點(diǎn)中直接創(chuàng)建節(jié)點(diǎn)

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content");

        xmlNewChild(root_node, NULL, BAD_CAST "node1",BAD_CAST szOut);

        free(szOut);

        //創(chuàng)建一個節(jié)點(diǎn),設(shè)置其內(nèi)容和屬性,然后加入根結(jié)點(diǎn)

        xmlNodePtr node = xmlNewNode(NULL,BAD_CAST"node2");

        xmlNodePtr content = xmlNewText(BAD_CAST"NODE CONTENT");

        xmlAddChild(root_node,node);

        xmlAddChild(node,content);

        szOut = g2u("屬性值");

        xmlNewProp(node,BAD_CAST"attribute",BAD_CAST szOut);

        free(szOut);

        //創(chuàng)建一個中文節(jié)點(diǎn)

        szOut = g2u("中文節(jié)點(diǎn)");

        xmlNewChild(root_node, NULL, BAD_CAST szOut,BAD_CAST "content of chinese node");

        free(szOut);

        //存儲xml文檔

        int nRel = xmlSaveFormatFileEnc("CreatedXml_cn.xml",doc,"GB2312",1);

        if (nRel != -1)

        {

           cout<<"一個xml文檔被創(chuàng)建,寫入"<<nRel<<"個字節(jié)"<<endl;

        }

        xmlFreeDoc(doc);

        return 1;

    }

    編譯鏈接命令如下:

    nmake TARGET_NAME=CreateXmlFile_cn

    完成后執(zhí)行CreateXmlFile_cn.exe可以生成一個xml文件CreatedXml_cn.xml,其內(nèi)容如下:

    <?xml version="1.0" encoding="GB2312"?>

    <root>

        <newNode1>newNode1 content</newNode1>

        <newNode2>newNode2 content</newNode2>

        <newNode3>newNode3 content</newNode3>

        <node1>節(jié)點(diǎn)1的內(nèi)容</node1>

        <node2 attribute="屬性值">NODE CONTENT</node2>

        <中文節(jié)點(diǎn)>content of chinese node</中文節(jié)點(diǎn)>

    </root>

    觀察可知,節(jié)點(diǎn)的名稱、內(nèi)容、屬性都可以使用中文了。在解析、修改和查找XML文檔時都可以使用上面的方法,只要記住,進(jìn)入xml文檔之前將中文編碼轉(zhuǎn)換為UTF-8編碼;從XML中取出數(shù)據(jù)時,不管三七二十一都可以轉(zhuǎn)換為GB2312再用,否則你很有可能見到傳說中的亂碼!

    5.       XML來做點(diǎn)什么

    有了以上的基礎(chǔ),相信已經(jīng)可以順利的在c/c++程序中使用XML文檔了。那么,我們到底要用XML來做什么呢?我隨便說一說自己的想法:

    第一,可以用來作為配置文件。例如很多組件就是用XML來做配置文件;當(dāng)然,我們知道用INI做配置文件更簡單,只要熟悉兩個函數(shù)就可以了;不過,復(fù)雜一點(diǎn)的配置文件我還是建議采用XML

    第二,可以用來作為在程序之間傳送數(shù)據(jù)的格式,這樣的話最好給你的xml先定義一個XML Schema,這樣的數(shù)據(jù)首先可以做一個良構(gòu)校驗,還可以來一個Schema校驗,如此的話出錯率會比沒有格式的數(shù)據(jù)小得多。目前XML已經(jīng)廣泛作為網(wǎng)絡(luò)之間的數(shù)據(jù)格式了;

    第三,可以用來作為你自定義的數(shù)據(jù)存儲格式,例如對象持久化之類的功能;

    最后,可以用來顯示你的技術(shù)很高深,本來你要存儲一個1,結(jié)果你這樣存儲了:

    <?xml version="1.0" encoding="GB2312"?>

    <root>

        <My_Program_Code content="1"></My_Program_Code>

    </root>

    然后再用libxml2取出來,最好還來幾次編碼轉(zhuǎn)換,是不是讓人覺得你很牛呢,哈哈!說笑了,千萬不要這么做。

    6.       小結(jié)

    本文是實用編程技術(shù)的第四篇,有興趣的可以看看我的前三篇:

    DLL編寫教程

    紙黃金均價管理小軟件黃金秘書

    Socket編程指南及示例程序

    另外,關(guān)于XML也可以看看我寫的這幾篇博客:

    XML的本質(zhì)討論

    XSL:轉(zhuǎn)換從哪里開始?

    數(shù)據(jù)庫和XML數(shù)據(jù)讀取性能比較

    畢業(yè)之后,對一些實用的編程技術(shù)更加感興趣,因此感覺能力小有提高,比天天鉆研理論進(jìn)步了一小點(diǎn)了。最后按慣例,貼一副女兒近照。


    評論

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-11-18 10:47 by maysnow
    文章好,大俠女兒照片更好!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-11-20 23:08 by lyx1228
    能不能把黃金秘書里家入刪除功能,我們這種非專業(yè)不會修改數(shù)據(jù)庫啊

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-11-21 23:04 by wxb_nudt
    @lyx1228
    好的,我正準(zhǔn)備加呢。最近沒有時間,下周末完成吧。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-11-25 15:07 by 瘋的邊緣
    能寫個完整的嗎?比如完整的C++教程一類的.

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-11-28 00:05 by wxb_nudt
    @瘋的邊緣
    完整的C++教程?滿世界都是啊,沒有必要重新發(fā)明一次輪子吧,謝謝你的關(guān)注!我認(rèn)為要使用LIBXML2,這篇文章已經(jīng)夠用了.

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2007-12-01 00:17 by xml-learner
    非常實用的文章 謝謝!
    另:每xmlNodeGetContent一個節(jié)點(diǎn)都必須用xmlFree來釋放嗎
    xmlFreeDoc能夠自動釋放這些內(nèi)存嗎

    xmlNodeListGetString(名字可能不對,忘了)和上面的有什么區(qū)別
    xmlParseFile和xmlReadFile呢

    再次感謝!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-01-17 15:24 by ok
    很好,謝謝

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2008-01-25 13:00 by swl
    不錯,看了立馬就能運(yùn)行,試了一下libxml2是不是對javascript也不解析,處理網(wǎng)頁時碰到這樣節(jié)點(diǎn)需要跳過

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-01-29 11:08 by jean.li
    非常感謝

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-07-18 09:21 by shunruo
    您將XPATH比作SQL。SQL可以對多表聯(lián)合查詢,XPATH可否對多個XML文件進(jìn)行聯(lián)合查詢?如果不行的話,有沒有什么庫可以?或有沒有什么辦法?

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-08-15 10:11 by kuku
    很崇拜大蝦,看過您的幾篇原創(chuàng)文章,寫的都很好
    想拜大蝦為師父,呵呵

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-09-22 10:54 by 灌了又灌
    libxml2的tutorial實在太差勁了,看了半天還不如這篇文章說的清楚。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-09-24 16:36 by mangshe0
    在UTF-8與GB2312轉(zhuǎn)換 過程中 如果需轉(zhuǎn)換字節(jié)小于等于2 則會失敗。
    其他的地方寫得都是在是太好了!贊!!!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2008-09-24 17:49 by wxb_nudt
    @mangshe0
    sorry,這個錯誤我的同事早已經(jīng)給我指出過,在我的源碼里面已經(jīng)更正了。但是博客上忘記了,謝謝你提醒。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-10-28 20:52 by coolsword@yeah.net
    為什么我在VC中編譯總是出現(xiàn)這兩個錯誤,只要包含paser.h就會有這兩個錯誤
    d:\program files\microsoft visual studio\vc98\include\bhtypes.h(19) : error C2146: syntax error : missing ';' before identifier 'UNALIGNED'
    d:\program files\microsoft visual studio\vc98\include\bhtypes.h(19) : fatal error C1004: unexpected end of file found

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2008-11-25 14:10 by gaoguzhan@yahoo.com.cn
    if (!xmlStrcmp(curNode->name, BAD_CAST "newNode1"))

    {

    xmlNodePtr tempNode;

    tempNode = curNode->next;

    xmlUnlinkNode(curNode);

    xmlFreeNode(curNode);

    curNode = tempNode;

    continue;

    }

    最近用該代碼試圖刪去一個節(jié)點(diǎn),為什么刪除后總是會多出一個換行呢?
    另外:不用臨時變量,也可以刪除一個節(jié)點(diǎn),而不影響XML 文檔。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2009-07-25 17:55 by xid
    您好,請問我如何使用c語言實現(xiàn)schema對xml文件的驗證。謝謝

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2009-10-07 14:55 by faicker
    最后一個寫入文件指定的編碼是錯誤的,實際上文件還是UTF-8編碼的。不是GB2312。可以用UltraEdit打開看一下漢字占用的字節(jié)數(shù),是3個字節(jié)。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2009-10-07 15:00 by faicker
    上面說錯了。⊙﹏⊙b汗

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2010-01-20 15:11 by agui
    請問libxml2是基于DOM還是SAX模型來解析呢?從上面的例子來看好像是DOM模型

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2010-01-21 15:50 by xu xinli
    很好的文章.
    非常感謝您的分享!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2010-02-05 16:36 by song
    為什么我在解析xml文件時,在這行出錯
    doc = xmlReadFile(szDocName, "GB2312", XML_PARSE_RECOVER); //解析文件
    說是內(nèi)存錯誤,exe文件直接死掉,謝謝

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2010-04-03 11:06 by zl
    謝謝樓主,看了之后非常的有收獲。也希望網(wǎng)絡(luò)上多一些樓主這樣的好人。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2010-05-10 11:21 by baiyuhei
    您好!我在windows下用的 code::blocks來使用libxml2函數(shù)庫,設(shè)置好了lib和include路徑,并在link設(shè)置中添加libxml2.lib和iconv.lib,測試您寫的CreateXmlFile.cpp程序時能夠正常運(yùn)行,但是測試ParseXmlFile.cpp
    時,編譯的時候出現(xiàn)錯誤:undefined reference to `__imp__xmlFree'
    請問這是怎么個問題呢?謝謝!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2010-12-24 22:23 by dana9919@163.com
    想問一下,用libxml2解析出來的數(shù)據(jù)是不是全是string格式的,如果我在xml中的數(shù)據(jù)是float的,用libxml2解析出來后是不是還要從string轉(zhuǎn)到float?

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-01-07 15:50 by hit
    請問有沒有支持xquery的xml解析器?前提是我想用C/C++最近找這些資料,還沒有發(fā)現(xiàn)這種解析器。您知道哪個可以么?

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-02-17 09:30 by Joseph Pan
    寫的很好,受用了!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2011-03-13 13:40 by hehe
    呵呵 照單全收!連你女兒的照片也copy走了!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-06-01 22:06 by okok
    多謝,很有幫助!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-08-19 17:35 by 309381787
    謝謝樓主分享,受益匪淺。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-09-28 10:30 by feimataxue
    很不錯啊,感謝中.但是在使用過程中遇到問題:
    我用libxml2解析xml文檔,但是在抽取網(wǎng)頁內(nèi)容中,有時候會出現(xiàn)亂碼或者打印不出來。
    具體步驟:
    按你說的,在抽取之前,先把網(wǎng)頁轉(zhuǎn)成utf-8,然后調(diào)用libxml2的接口xmlReadFile(szDocName, NULL, XML_PARSE_RECOVER);來解析文檔;在得到我想要的節(jié)點(diǎn)后:
    (1)如果我使用u2g((char*)szValue)來轉(zhuǎn)碼,結(jié)果打印不出來我想要的節(jié)點(diǎn)中的信息;
    (2)如果我不使用u2g函數(shù)來轉(zhuǎn)碼,而是直接cout << (char*)szValue << endl;卻輸出亂碼,真的很糾結(jié)啊!
    請大俠看看是什么問題,我的qq:175994124,先謝過了!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-09-28 10:41 by feimataxue
    補(bǔ)充上面的貼子:
    szValue由下面得到:
    szValue = xmlNodeGetContent(curNode);

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-11-07 19:16 by tainying
    看了之后,真的是豁然開朗,太牛了!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2011-11-10 12:43 by 陳年號
    看了一遍又一遍,受益匪淺···總能得到新的理解···

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-01-09 11:03 by Awey
    你好,最近在做32位移植64位的工作,請問libxml支持64位嗎?

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-03-06 14:06 by gsh
    在用xmllib2 中xpath的節(jié)點(diǎn)路徑如果有漢字時就有問題,比如"/root/節(jié)點(diǎn)1[position=1]"就查不到應(yīng)該返回的值,變成沒值了。誰能幫忙解決這個問題呀!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-03-06 14:07 by gsh
    /root/節(jié)點(diǎn)1[position()=1]

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2012-03-09 12:08 by gsh
    這個沒人處理呀,郁悶中!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2012-03-12 09:00 by gsh
    博主消失中

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-06-25 21:25 by cesholl
    @gsh
    先轉(zhuǎn)為UTF8字串再查找

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2012-08-06 11:30 by sky
    :-) 經(jīng)典的東西永遠(yuǎn)不老,這篇文章已經(jīng)存在這么多年了,還是這么多人關(guān)注,而且樓主也能隨時給大家答疑,膜拜一下神牛....

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-08-25 18:05 by amitapba
    寫的很不錯 感謝原創(chuàng)

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2012-09-01 20:31 by 林杰
    你好,我使用xmlReadFile讀取文件,根節(jié)點(diǎn)總是不正確,設(shè)置了noblank選項,以及把XML文件轉(zhuǎn)成UTF-8編碼,返回的根節(jié)點(diǎn)總是出問題,不知你有沒有遇到過類似的問題?我用的是VS2010,LIBXML2.77版本。

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2013-02-21 10:31 by 天天笑
    雖然我是學(xué)JAVA的,但是我仍然能感覺到這個篇文章寫得非常透徹!

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2013-05-15 21:42 by 李勇
    樓主講解的很詳細(xì)啊,很容易就懂了

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2013-12-07 09:34 by eternal_tune
    受教
    int nOutLen = 2 * strlen(inbuf) - 1;
    樓主這里是不是應(yīng)該+1

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南[未登錄]  回復(fù)  更多評論   

    2014-03-17 11:06 by dingding
    請問樓主能說一下XMLLIB里的錯誤處理有關(guān)的東西么?新人不太懂

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2014-08-18 16:53 by xiejanee
    想使用libxml2中的xmlFreeDoc函數(shù)進(jìn)行內(nèi)存釋放,但是程序執(zhí)行完該函數(shù)后內(nèi)存并沒有釋放,這個代碼到底有何用?求大俠指教該如何釋放doc指向的內(nèi)存!附代碼:
    xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");
    xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST"database");
    xmlDocSetRootElement(doc, root_node);
    xmlFreeDoc(doc);

    # re: C++的XML編程經(jīng)驗――LIBXML2庫使用指南  回復(fù)  更多評論   

    2014-12-22 19:53 by 張成磊
    樓主,你好,我有一點(diǎn)不明白,希望樓主能夠解惑。在3.1節(jié)中,創(chuàng)建了一個CreateXmlFile.cpp之后,下面這句代碼是放在哪里運(yùn)行呀?
    nmake TARGET_NAME=ParseXmlFile(編譯鏈接命令)
    主站蜘蛛池模板: 永久黄网站色视频免费| 最近最新的免费中文字幕| 国产亚洲人成A在线V网站| 一级黄色免费大片| 中文字幕人成人乱码亚洲电影| 免费看黄福利app导航看一下黄色录像| 日韩电影免费在线| 偷自拍亚洲视频在线观看99| 免费a级毛片在线观看| 一级做性色a爰片久久毛片免费| 亚洲性日韩精品一区二区三区| 日韩久久无码免费毛片软件| 国产亚洲av片在线观看18女人| 99久久99这里只有免费的精品| 国产亚洲免费的视频看| 亚欧免费一级毛片| 亚洲AV无码乱码在线观看代蜜桃| 国产三级在线观看免费| 国产AV无码专区亚洲AV琪琪 | 中文字幕乱码免费看电影| 亚洲国产精品无码久久久蜜芽 | 国产美女在线精品免费观看| 亚洲av无码专区在线观看下载| 亚洲成人一区二区| 国产猛男猛女超爽免费视频| 久久亚洲日韩看片无码| 女人张开腿等男人桶免费视频 | 一个人免费高清在线观看| 亚洲av色香蕉一区二区三区| 国产精品亚洲玖玖玖在线观看| 免费在线看黄网站| 亚洲第一区视频在线观看| 免费不卡视频一卡二卡| 国产精品亚洲综合| 亚洲AV无码一区二区二三区入口 | 四虎亚洲精品高清在线观看| 亚洲AV无码一区二区三区在线观看 | 国产成人免费AV在线播放 | 亚洲AV之男人的天堂| 久久精品毛片免费观看| 国产精品亚洲va在线观看|