精华内容
下载资源
问答
  • ubuntu libxml2 使用
    2021-07-21 16:28:01

    ubuntu 下libxml2的安装:

        sudo apt-get install libxml2

        sudo apt-get install libxml2-dev

    libxml2的使用:

    libxml2的安装及使用[总结] - Rabbit_Dale - 博客园 (cnblogs.com)

    问题1:编译报错 fatal error: libxml/parser.h: No such file or directory

    原因:parser.h安装到/usr/include/libxml2/libxml/parser.h,而不是/usr/include/libxml/parser.h

    创建一个软链接解决问题:

            ln -s /usr/include/libxml2/libxml   /usr/include/libxml

    更多相关内容
  • 首先,libxml2的官方文档被墙了,只能百度。找到一篇文章:https://www.cnblogs.com/catgatp/p/6505427.html 文章里介绍的方法很实用,我拿过来修改后自己测试并调整。 示例代码如下,参照着使用就行了。 #include &...

    最近做项目总是有解析xml的需求,而迅速定位到所需节点然后进行读取、修改、删除操作是常有的事情,为此,我学习了xpath的用法,总结如下:
    首先,libxml2的官方文档被墙了,只能百度。找到一篇文章:https://www.cnblogs.com/catgatp/p/6505427.html
    文章里介绍的方法很实用,我拿过来修改后自己测试并调整。

    示例代码如下,参照着使用就行了。

    #include <libxml/parser.h>
    #include <libxml/tree.h>
    #include <libxml/xpath.h>
    
    /**
     * @brief xpathxml
    
     * 
     * @param doc xmlָ
     * @param xpath ath
    
     * @return xmlXPathObjectPtr LLָlXPathFreeObject
    
     */
    static xmlXPathObjectPtr xml_get_nodeset(xmlDocPtr doc, const xmlChar *xpath)
    {
        xmlXPathContextPtr context;
        xmlXPathObjectPtr result;
        context = xmlXPathNewContext(doc);
    
        if (context == NULL)
        {
            printf("context is NULL\n");
            return NULL;
        }
    
        result = xmlXPathEvalExpression(xpath, context);
        xmlXPathFreeContext(context);
        if (result == NULL)
        {
            printf("xmlXPathEvalExpression return NULL\n");
            return NULL;
        }
    
        if (xmlXPathNodeSetIsEmpty(result->nodesetval))
        {
            xmlXPathFreeObject(result);
            printf("nodeset is empty\n");
            return NULL;
        }
    
        return result;
    }
    
    int main(int argc, char const *argv[])
    {
        xmlDocPtr doc = xmlReadFile("./test.xml", "utf-8", XML_PARSE_NOBLANKS);
        if (NULL == doc)
        {
            return -1;
        }
        xmlChar *xpath = BAD_CAST "//name";
        xmlXPathObjectPtr result = xml_get_nodeset(doc, xpath);
        if (NULL == result)
        {
            xmlFreeDoc(doc);
            return -1;
        }
    
        xmlNodeSetPtr nodeset = result->nodesetval;
        xmlNodePtr cur = NULL;
    
        for (int i = 0; i < nodeset->nodeNr; i++)
        {
            cur = nodeset->nodeTab[i];
                    xmlChar *name = xmlNodeGetContent(cur);
                    printf("find:%d %s\n", i, name);
                    xmlFree(name);
        }
    
        xmlXPathFreeObject(result);
    
        xmlFreeDoc(doc);
    
        return 0;
    }
    

    值得一提的是xpath有自己的语法,可百度。可参考:https://www.w3school.com.cn/xpath/xpath_syntax.asp

    展开全文
  • libxml2 使用示例

    2012-03-22 20:20:09
    libxml2 使用示例, readNode countNode insertNode updateNode deleteNode
  • libxml2 使用教程

    千次阅读 2015-06-06 11:33:41
    Libxml2支持使用XPath表达式来查找匹配的节点集。简而言之,XPath之于xml,好比SQL之于关系数据库。要在一个复杂的xml文档中查找所需的信息,XPath简直是必不可少的工具。下面代码查询所有keyword元素的内容。 ...
        本文整理自官方使用教程 http://xmlsoft.org/tutorial/index.html

        示例文档story.xml如下:

    [html]  view plain copy
    1. <?xml version="1.0"?>  
    2. <story>  
    3.   <storyinfo>  
    4.     <author>John Fleck</author>  
    5.     <datewritten>June 2, 2002</datewritten>  
    6.     <keyword>example keyword</keyword>  
    7.   </storyinfo>  
    8.   <body>  
    9.     <headline>This is the headline</headline>  
    10.     <para>This is the body text.</para>  
    11.   </body>  
    12. </story>  
         1、解析xml文档
        解析文档时只需要文档名和一个函数调用,再加上错误处理。下面代码查找keyword节点并打印节点下的文本内容,如下:
    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <string.h>  
    3. #include <stdlib.h>  
    4. #include <libxml/xmlmemory.h>  
    5. #include <libxml/parser.h>  
    6.   
    7. /* 解析storyinfo节点,打印keyword节点的内容 */  
    8. void parseStory(xmlDocPtr doc, xmlNodePtr cur){  
    9.     xmlChar* key;  
    10.     cur=cur->xmlChildrenNode;  
    11.     while(cur != NULL){  
    12.         /* 找到keyword子节点 */  
    13.         if(!xmlStrcmp(cur->name, (const xmlChar *)"keyword")){  
    14.             key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);  
    15.             printf("keyword: %s\n", key);  
    16.             xmlFree(key);  
    17.         }  
    18.         cur=cur->next; /* 下一个子节点 */  
    19.     }  
    20.   
    21.     return;  
    22. }  
    23.   
    24. /* 解析文档 */  
    25. static void parseDoc(char *docname){  
    26.     /* 定义文档和节点指针 */  
    27.     xmlDocPtr doc;  
    28.     xmlNodePtr cur;  
    29.       
    30.     /* 进行解析,如果没成功,显示一个错误并停止 */  
    31.     doc = xmlParseFile(docname);  
    32.     if(doc == NULL){  
    33.         fprintf(stderr, "Document not parse successfully. \n");  
    34.         return;  
    35.     }  
    36.   
    37.     /* 获取文档根节点,若无内容则释放文档树并返回 */  
    38.     cur = xmlDocGetRootElement(doc);  
    39.     if(cur == NULL){  
    40.         fprintf(stderr, "empty document\n");  
    41.         xmlFreeDoc(doc);  
    42.         return;  
    43.     }  
    44.   
    45.     /* 确定根节点名是否为story,不是则返回 */  
    46.     if(xmlStrcmp(cur->name, (const xmlChar *)"story")){  
    47.         fprintf(stderr, "document of the wrong type, root node != story");  
    48.         xmlFreeDoc(doc);  
    49.         return;  
    50.     }  
    51.   
    52.     /* 遍历文档树 */  
    53.     cur = cur->xmlChildrenNode;  
    54.     while(cur != NULL){  
    55.         /* 找到storyinfo子节点 */  
    56.         if(!xmlStrcmp(cur->name, (const xmlChar *)"storyinfo")){  
    57.             parseStory(doc, cur); /* 解析storyinfo子节点 */  
    58.         }  
    59.         cur = cur->next; /* 下一个子节点 */  
    60.     }  
    61.   
    62.     xmlFreeDoc(doc); /* 释放文档树 */  
    63.     return;  
    64. }  
    65.   
    66. int main(int argc, char **argv){  
    67.     char *docname;  
    68.     if(argc <= 1){  
    69.         printf("Usage: %s docname\n", argv[0]);  
    70.         return 0;  
    71.     }  
    72.     docname=argv[1];  
    73.     parseDoc(docname);  
    74.     return 1;  
    75. }  
        解析XML文档的基本流程如下:
        (1)定义文档指针和节点指针。
        (2)调用xmlParseFile()解析文档。如果不成功,注册一个错误并停止。一个常见错误是不适当的编码。XML标准文档除了用默认的UTF-8或UTF-16外,还可显式指定用其它编码保存。如果文档是这样,libxml2将自动地为你转换到UTF-8。更多关于XML编码信息包含在XML标准中。
        (3)调用xmlDocGetRootElement()获取文档根节点,若无根节点则释放文档树并返回。
        (4)确认文档是正确的类型,通过检查根节点名称来判断。
        (5)检索节点的内容,这需要遍历文档树。对每个节点,遍历其子节点都需要一个循环。先用cur = cur->xmlChildrenNode获取第一个子节点,然后通过cur = cur->next不断向前遍历,直到cur==NULL。查找找指定节点时使用xmlStrcmp()函数,如果你指定的名称相同,就找到了你要的节点。通常把查找某个子节点的过程封装成函数。
        (6)获取节点中的内容。查找到指定节点后,调用xmlNodeListGetString()获取节点下的文本。注意在XML中,包含在节点中的文本是这个节点的子节点,因此获取的是cur->xmlChildrenNode中的字符串。xmlNodeListGetString()会为返回的字符串分配内存,因此记得要用xmlFree()来释放它。
        (7)调用xmlFreeDoc()释放文档树指针。
         2、使用XPath查询信息
        在xml文档中查询信息是一项核心工作。Libxml2支持使用XPath表达式来查找匹配的节点集。简而言之,XPath之于xml,好比SQL之于关系数据库。要在一个复杂的xml文档中查找所需的信息,XPath简直是必不可少的工具。下面代码查询所有keyword元素的内容。

    [cpp]  view plain copy
    1. #include <libxml/parser.h>  
    2. #include <libxml/xpath.h>  
    3.   
    4. /* 解析文档 */  
    5. xmlDocPtr getdoc(char *docname){  
    6.     xmlDocPtr doc;  
    7.     doc = xmlParseFile(docname);  
    8.     if(doc == NULL){  
    9.         fprintf(stderr, "Document not parsed successfully. \n");  
    10.         return NULL;  
    11.     }  
    12.   
    13.     return doc;  
    14. }  
    15.   
    16. /* 查询节点集 */  
    17. xmlXPathObjectPtr getnodeset(xmlDocPtr doc, xmlChar *xpath){  
    18.     xmlXPathContextPtr context;  
    19.     xmlXPathObjectPtr result; /* 存储查询结果 */  
    20.   
    21.     /* 创建一个xpath上下文 */  
    22.     context = xmlXPathNewContext(doc);  
    23.     if(context == NULL){  
    24.         printf("Error in xmlXPathNewContext\n");  
    25.         return NULL;  
    26.     }  
    27.     /* 查询XPath表达式 */  
    28.     result = xmlXPathEvalExpression(xpath, context);  
    29.     xmlXPathFreeContext(context); /* 释放上下文指针 */  
    30.     if(result == NULL){  
    31.         printf("Error in xmlXPathEvalExpression\n");  
    32.         return NULL;  
    33.     }  
    34.     /* 检查结果集是否为空 */  
    35.     if(xmlXPathNodeSetIsEmpty(result->nodesetval)){  
    36.         xmlXPathFreeObject(result); /* 如为这空就释放 */  
    37.         printf("No result\n");  
    38.         return NULL;  
    39.     }  
    40.     return result;  
    41. }  
    42.   
    43. int main(int argc, char ** argv){  
    44.     char *docname;  
    45.     xmlDocPtr doc;  
    46.     /* 查找所有keyword元素,而不管它们在文档中的位置 */  
    47.     xmlChar *xpath=(xmlChar*)"//keyword";  
    48.     xmlNodeSetPtr nodeset;  
    49.     xmlXPathObjectPtr result;  
    50.     int i;  
    51.     xmlChar *keyword;  
    52.   
    53.     if(argc <= 1){  
    54.         printf("Usage: %s docname\n", argv[0]);  
    55.         return(0);  
    56.     }  
    57.   
    58.     docname = argv[1];  
    59.     doc = getdoc(docname);  
    60.     result = getnodeset(doc, xpath);  
    61.     if(result){  
    62.         /* 得到keyword节点集 */  
    63.         nodeset = result->nodesetval;  
    64.         for(i=0; i < nodeset->nodeNr; i++){ /* 打印每个节点中的内容 */  
    65.             keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);  
    66.             printf("keyword: %s\n", keyword);  
    67.             xmlFree(keyword);  
    68.         }  
    69.         xmlXPathFreeObject(result); /* 释放结果集 */  
    70.     }  
    71.   
    72.     xmlFreeDoc(doc); /* 释放文档树 */  
    73.     xmlCleanupParser(); /* 清除库内存 */  
    74.     return(1);  
    75. }  
        可以在story.xml中多插入几个keyword元素,然后运行一下本程序看看效果。使用XPath查询信息的基本流程如下:
        (1)调用xmlXPathNewContext()给文档树创建一个上下文指针。
        (2)调用xmlXPathEvalExpression(),传入XPath表达式和上下文指针,返回一个xmlXPathObjectPtr结果集指针。nodesetval对象包含keyword节点个数(nodeNr)和节点列表(nodeTab)。在使用之前要和xmlXPathNodeSetIsEmpty()检查nodesetval节点列表是否为空。
        (3)遍历节点列表nodeTab,用xmlNodeListGetString()获取每个keyword节点的内容。
        (4)用xmlXPathFreeObject()释放查询结果,用xmlFreeDoc()释放文档树。
        更多关于Xpath的内容可以参考XPath官方规范http://www.w3.org/TR/xpath/。XPath语法的介绍,可参考w3school上的教程http://www.w3school.com.cn/xpath/index.asp,或者http://w3schools.com/xpath/default.asp。只有掌握XPath,才能掌握使用大型XML文件获取信息的方法,否则每寻找一个节点都要从根节点找起,很耗时耗力。
         3、修改xml文档
        这与上面的过程类似,首先遍历文档树,找到要插入(或删除)的节点处,然后插入(或删除)相关的内容。下面代码在storyinfo节点下插入一个keyword元素。
    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <string.h>  
    3. #include <stdlib.h>  
    4. #include <libxml/xmlmemory.h>  
    5. #include <libxml/parser.h>  
    6.   
    7. void  
    8. parseStory(xmlDocPtr doc, xmlNodePtr cur, const xmlChar* keyword) {  
    9.     /* 在当前节点下插入一个keyword子节点 */  
    10.     xmlNewTextChild(cur, NULL, (const xmlChar*)"keyword", keyword);  
    11.     return;  
    12. }  
    13.   
    14. xmlDocPtr  
    15. parseDoc(char *docname, char *keyword) {  
    16.   
    17.     xmlDocPtr doc;  
    18.     xmlNodePtr cur;  
    19.   
    20.     doc = xmlParseFile(docname);  
    21.       
    22.     if (doc == NULL ) {  
    23.         fprintf(stderr,"Document not parsed successfully. \n");  
    24.         return (NULL);  
    25.     }  
    26.       
    27.     cur = xmlDocGetRootElement(doc);  
    28.       
    29.     if (cur == NULL) {  
    30.         fprintf(stderr,"empty document\n");  
    31.         xmlFreeDoc(doc);  
    32.         return (NULL);  
    33.     }  
    34.       
    35.     if (xmlStrcmp(cur->name, (const xmlChar *) "story")) {  
    36.         fprintf(stderr,"document of the wrong type, root node != story");  
    37.         xmlFreeDoc(doc);  
    38.         return (NULL);  
    39.     }  
    40.       
    41.     cur = cur->xmlChildrenNode;  
    42.     while (cur != NULL) {  
    43.         if ((!xmlStrcmp(cur->name, (const xmlChar *)"storyinfo"))){  
    44.             parseStory (doc, cur, (const xmlChar*)keyword);  
    45.         }  
    46.            
    47.     cur = cur->next;  
    48.     }  
    49.     return(doc);  
    50. }  
    51.   
    52. int  
    53. main(int argc, char **argv) {  
    54.   
    55.     char *docname;  
    56.     char *keyword;  
    57.     xmlDocPtr doc;  
    58.   
    59.     if (argc <= 2) {  
    60.         printf("Usage: %s docname, keyword\n", argv[0]);  
    61.         return(0);  
    62.     }  
    63.   
    64.     docname = argv[1];  
    65.     keyword = argv[2];  
    66.     doc = parseDoc(docname, keyword);  
    67.     if (doc != NULL) {  
    68.         xmlSaveFormatFile(docname, doc, 0);  
    69.         xmlFreeDoc(doc);  
    70.     }  
    71.       
    72.     return (1);  
    73. }  
        这里xmlNewTextChild函数在当前节点指针上添加一个子元素。如果希望元素有名字空间,则可以在这里加上。添加完后,就要用xmlSaveFormatFile()把修改后的文档写入到文件。我们这里使用原来doc文档指针,因此会覆盖原来的文件。第三个参数如果设置为1,则输出的文档会自动缩进。
        若要删除某个节点,可以使用以下代码:
    [cpp]  view plain copy
    1. if(!xmlStrcmp(cur->name, BAD_CAST "keyword")){  
    2.     xmlNodePtr tempNode;  
    3.     tempNode = cur->next;  
    4.     xmlUnlinkNode(cur);  
    5.     xmlFreeNode(cur);  
    6.     cur = tempNode;  
    7.     continue;  
    8. }  
        注意libxml2并没有xmlDelNode或者xmlRemoveNode之类的函数。我们需要将当前节点从文档中断链(unlink),文档就不会再包含这个子节点。这样做需要使用一个临时变量来存储断链节点的后续节点,并记得要手动删除断链节点的内存。
        若要给节点添加属性,可以这样:
    [cpp]  view plain copy
    1. xmlDocPtr  
    2. parseDoc(char *docname, char *uri) {  
    3.     xmlDocPtr doc;  
    4.     xmlNodePtr cur;  
    5.     xmlNodePtr newnode;  
    6.     xmlAttrPtr newattr;  
    7.   
    8.     doc = xmlParseFile(docname);      
    9.     if (doc == NULL ) {  
    10.         fprintf(stderr,"Document not parsed successfully. \n");  
    11.         return (NULL);  
    12.     }  
    13.       
    14.     cur = xmlDocGetRootElement(doc);      
    15.     if (cur == NULL) {  
    16.         fprintf(stderr,"empty document\n");  
    17.         xmlFreeDoc(doc);  
    18.         return (NULL);  
    19.     }  
    20.       
    21.     if (xmlStrcmp(cur->name, (const xmlChar *) "story")) {  
    22.         fprintf(stderr,"document of the wrong type, root node != story");  
    23.         xmlFreeDoc(doc);  
    24.         return (NULL);  
    25.     }  
    26.       
    27.     newnode = xmlNewTextChild(cur, NULL, "reference", NULL);  
    28.     newattr = xmlNewProp(newnode, "uri", uri);  
    29.     return(doc);  
    30. }  
        我们用xmlAttrPtr声明一个属性指针。在找到story元素后,用xmlNewTextChild()新建一个reference子元素,用xmlNewProp()给这个子元素新建一个uri属性。文档修改完后要用xmlSaveFormatFile()写入到磁盘。
        查询属性的过程类似。如下:
    [cpp]  view plain copy
    1. void  
    2. getReference(xmlDocPtr doc, xmlNodePtr cur) {  
    3.     xmlChar *uri;  
    4.     cur = cur->xmlChildrenNode;  
    5.     while (cur != NULL) {  
    6.         if ((!xmlStrcmp(cur->name, (const xmlChar *)"reference"))) {  
    7.             uri = xmlGetProp(cur, "uri");  
    8.             printf("uri: %s\n", uri);  
    9.             xmlFree(uri);  
    10.         }  
    11.         cur = cur->next;  
    12.     }  
    13.     return;  
    14. }  
        关键函数为xmlGetProp(),用来获取节点中的指定属性。注意如果你使用DTD为属性声明一个固定的或默认的值,则该函数也查找这些值。
         4、创建xml文档
        有了上面的基础,创建一个xml文档显得非常简单,就是一个不断插入节点的过程。其流程如下:
        (1)用xmlNewDoc函数创建一个文档指针doc;
        (2)用xmlNewNode函数创建一个节点指针root_node;
        (3)用xmlDocSetRootElement将root_node设置为doc的根结点;
        (4)用xmlAddChild()给root_node添加一系列的子节点,并设置子节点的内容和属性;
        (5)用xmlSaveFile将xml文档存入文件;
        (6)用xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。    
        下面代码创建一个xml文档:
    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <iostream>  
    3. #include <libxml/parser.h>  
    4. #include <libxml/tree.h>  
    5. using namespace std;  
    6.   
    7. int main(int argc, char* argv[]){  
    8.     //定义文档和节点指针  
    9.     xmlDocPtr doc=xmlNewDoc(BAD_CAST"1.0");  
    10.     xmlNodePtr root_node=xmlNewNode(NULL,BAD_CAST"root");  
    11.     //设置根节点  
    12.     xmlDocSetRootElement(doc,root_node);  
    13.     //在根节点中直接创建节点  
    14.     xmlNewTextChild(root_node, NULL, BAD_CAST"newNode1", BAD_CAST"newNode1 content");  
    15.     xmlNewTextChild(root_node, NULL, BAD_CAST"newNode2", BAD_CAST"newNode2 content");  
    16.     xmlNewTextChild(root_node, NULL, BAD_CAST"newNode3", BAD_CAST"newNode3 content");  
    17.     //创建一个节点,设置其内容和属性,然后加入根结点  
    18.     xmlNodePtr node=xmlNewNode(NULL, BAD_CAST"node2");  
    19.     xmlNodePtr content=xmlNewText(BAD_CAST"NODE CONTENT");  
    20.     xmlAddChild(root_node,node);  
    21.     xmlAddChild(node,content);  
    22.     xmlNewProp(node,BAD_CAST"attribute",BAD_CAST"yes");  
    23.     //创建一个儿子和孙子节点  
    24.     node=xmlNewNode(NULL,BAD_CAST"son");  
    25.     xmlAddChild(root_node,node);  
    26.     xmlNodePtr grandson=xmlNewNode(NULL,BAD_CAST"grandson");  
    27.     xmlAddChild(node,grandson);  
    28.     xmlAddChild(grandson,xmlNewText(BAD_CAST"This is a grandson node"));  
    29.     //存储xml文档  
    30.     int nRel=xmlSaveFile("CreatedXml.xml",doc);  
    31.     if(nRel!=-1){  
    32.         cout<<"一个xml文档被创建,写入"<<nRel<<"个字节"<<endl;  
    33.     }  
    34.     //释放文档内节点动态申请的内存  
    35.     xmlFreeDoc(doc);  
    36.     return 1;  
    37. }  
        编译并运行这个程序,将创建CreatedXml.xml文档,内容如下:
    [html]  view plain copy
    1. <root>  
    2.     <newNode1>newNode1 content</newNode1>  
    3.     <newNode2>newNode2 content</newNode2>  
    4.     <newNode3>newNode3 content</newNode3>  
    5.     <node2 attribute="yes">NODE CONTENT</node2>  
    6.     <son>  
    7.         <grandson>This is a grandson node</grandson>  
    8.     </son>  
    9. </root>  
        注意,有多种方式可以添加子节点。第一是用xmlNewTextChild直接添加一个文本子节点;第二是先创建新节点,然后用xmlAddChild将新节点加入上层节点。
         5、编码转换
        数据编码兼容性问题是很多开发人员都会遇到的一大难题,特别是在使用libxml时。libxml内部使用UTF-8格式存储和操作数据。你的应用程序数据如果使用其他格式的编码,例如ISO-8859-1编码,则在传给libxml之前必须转换成UTF-8格式。如果你的应用输出想用非UTF-8格式的编码,也需要进行转换。
        Libxml2本身只支持把UTF-8, UTF-16和ISO-8859-1格式的外部数据转换成内部使用的UTF-8格式,以及处理完后输出成这些格式的数据。对其他的字符编码,需要使用libiconv(当然你也可以使用其他的国际化库,例如ICU)。当前libiconv支持150多种不同的字符编码,libiconv的实现尽量保证支持所有我们听过的编码格式。在使用libxml之前,一般是通过libiconv把数据先转换UTF-8格式。在使用libxml处理完之后,再通过libiconv把数据输出成你要的编码格式。
        一个常见的错误是一份代码的不同部分的数据使用不同的编码格式。例如内部数据使用ISO-8859-1格式的应用程序,联合使用libxml,而它的内部数据格式为UTF-8。这样应用程序在运行不同的代码段时要不同地对待内部数据,这有可能导致解析数据出现错误。
         例子1:使用Libxml内建的编码处理器
        下面的例子创建一个简单的文档,添加从命令行得到的数据到文档根元素,并以合适的编码格式输出到stdout。对提供的数据我们使用ISO-8859-1编码,处理过程为从ISO-8859-1到UTF-8,再到ISO-8859-1。命令行上输入的字符串从ISO-8859-1格式转换成UTF-8格式,以供libxml使用,输出时又重新转换成ISO-8859-1格式。
    [cpp]  view plain copy
    1. #include <string.h>  
    2. #include <libxml/parser.h>  
    3.   
    4. /* 对指定编码格式的外部数据,转换成libxml使用UTF-8格式 */  
    5. unsigned char*  
    6. convert(unsigned char *in, char *encoding){  
    7.     unsigned char *out;  
    8.     int ret,size,out_size,temp;  
    9.     /* 定义一个编码处理器指针 */  
    10.     xmlCharEncodingHandlerPtr handler;  
    11.   
    12.     size = (int)strlen((const char*)in)+1; /* 输入数据长度 */  
    13.     out_size = size*2-1; /* 输出数据长度 */  
    14.     out = (unsigned char*)malloc((size_t)out_size); /* 存放输出数据 */  
    15.   
    16.     if (out) {  
    17.         /* 查找内建的编码处理器 */  
    18.         handler = xmlFindCharEncodingHandler(encoding);  
    19.         if(!handler) {  
    20.             free(out);  
    21.             out = NULL;  
    22.         }  
    23.     }  
    24.     if(out) {  
    25.         temp=size-1;  
    26.         /* 对输入数据进行编码转换 */  
    27.         ret = handler->input(out, &out_size, in, &temp);  
    28.         if(ret || temp-size+1) { /* 转换不成功 */  
    29.             if (ret) { /* 转换失败 */  
    30.                 printf("conversion wasn't successful.\n");  
    31.             } else { /* 只转换了一部分数据 */  
    32.                 printf("conversion wasn't successful. converted: %i octets.\n",temp);  
    33.             }  
    34.             free(out);  
    35.             out = NULL;  
    36.         }else { /* 转换成功 */  
    37.             out = (unsigned char*)realloc(out,out_size+1);  
    38.             out[out_size]=0; /* 输出的末尾加上null终止符 */  
    39.                           
    40.         }  
    41.     } else {  
    42.         printf("no mem\n");  
    43.     }  
    44.     return (out);  
    45. }     
    46.   
    47. int  
    48. main(int argc, char **argv) {  
    49.     unsigned char *content, *out;  
    50.     xmlDocPtr doc;  
    51.     xmlNodePtr rootnode;  
    52.     char *encoding = "ISO-8859-1";  
    53.       
    54.     if (argc <= 1) {  
    55.         printf("Usage: %s content\n", argv[0]);  
    56.         return(0);  
    57.     }  
    58.   
    59.     content = (unsigned char*)argv[1];  
    60.     /* 转换成libxml2使用的UTF-8格式 */  
    61.     out = convert(content, encoding);  
    62.     doc = xmlNewDoc (BAD_CAST "1.0");  
    63.     rootnode = xmlNewDocNode(doc, NULL, (const xmlChar*)"root", out);  
    64.     xmlDocSetRootElement(doc, rootnode);  
    65.     /* 以ISO-8859-1格式输出文档内容 */  
    66.     xmlSaveFormatFileEnc("-", doc, encoding, 1);  
    67.     return (1);  
    68. }  
        编译运行这个程序,假设在命令行上提供的数据"zhou"是ISO-8859-1格式(我的系统中不是),则输出文档为:
    [html]  view plain copy
    1. <?xml version="1.0" encoding="ISO-8859-1"?>  
    2. <root>zhou</root>  
        编码转换的基本流程如下:
        (1)用xmlCharEncodingHandlerPtr定义一个编码处理器指针,用xmlFindCharEncodingHandler()查找libxml2中指定的编码处理器。libxml2内建只支持把UTF-8, UTF-16和ISO-8859-1格式的外部数据转换成内部使用的UTF-8格式。如果要转换其他格式的数据(如中文编码),则要使用独立的libiconv库给libxml2注册新编码处理器。
        (2)调用编码处理器的input()函数,把外部数据转换成libxml2使用的格式。
        (3)进行xml处理,处理完若要保存成非UTF-8格式的文档,使用xmlSaveFormatFileEnc()函数。若保存的编码格式libxml2不支持,则只能用libiconv把保存的文档转换成需要的编码格式。
         例子2:通过iconv库给Libxml注册新的编码处理器     
        下面例子先编写GBK的编码处理器gbk_input()和gbk_output(),前者是GBK到UTF-8输入处理,后者是UTF-8到GBK输出处理,这两个处理器都要用到iconv转换函数。然后调用xmlNewCharEncodingHandler()注册输入输出处理器。对输入输出数据的编码转换由convertToUTF8From()和utf8ConvertTo()来完成,它们都是调用xmlFindCharEncodingHandler()查找已注册的处理器,然后在处理器上调用input()或output()对数据进行编码转换。
    [cpp]  view plain copy
    1. #include <string.h>  
    2. #include <iconv.h>  
    3. #include <libxml/encoding.h>  
    4. #include <libxml/xmlwriter.h>  
    5. #include <libxml/xmlreader.h>  
    6.   
    7. /* 输入编码处理器:GBK到UTF-8 */  
    8. int gbk_input(unsigned char *out, int *outlen,   
    9.         const unsigned char *in, int *inlen){  
    10.   
    11.     char *outbuf = (char *) out;  
    12.     char *inbuf = (char *) in;  
    13.     iconv_t iconv_from; /* gbk到utf-8的转换描述符 */  
    14.     size_t len1, len2, rslt;  
    15.     /* 注意一般不直接从int*到size_t*的转换 
    16.        这在32位平台下是正常的,但到了64平台下size_t为64位, 
    17.        那(size_t*)inlen将是一个未知的数据  
    18.     */  
    19.     len1 = *inlen;  
    20.     len2 = *outlen;  
    21.     /* 分配一个从GBK到UTF-8的转换描述符 */  
    22.     iconv_from = iconv_open("utf-8","gbk");  
    23.     /* 根据转换描述符,对数据进行编码转换 */  
    24.     rslt = iconv(iconv_from, &inbuf, &len1, &outbuf, &len2);  
    25.     if(rslt < 0){  
    26.         return rslt;  
    27.     }  
    28.     iconv_close(iconv_from); /* 释放描述符 */  
    29.     *outlen = ((unsigned char *) outbuf - out);  
    30.     *inlen = ((unsigned char *) inbuf - in);  
    31.     return *outlen;  
    32. }  
    33.   
    34. /* 输出编码处理器:UTF-8到GBK */  
    35. int gbk_output(unsigned char *out, int *outlen,   
    36.                 const unsigned char *in, int *inlen){  
    37.   
    38.     char *outbuf = (char *) out;  
    39.     char *inbuf = (char *) in;  
    40.     iconv_t iconv_to; /* utf-8到gbk的转换描述符 */  
    41.     size_t len1, len2, rslt;  
    42.     /* 注意一般不直接从int*到size_t*的转换 
    43.        这在32位平台下是正常的,但到了64平台下size_t为64位, 
    44.        那(size_t*)inlen将是一个未知的数据  
    45.     */  
    46.     len1 = *inlen;  
    47.     len2 = *outlen;  
    48.     /* 分配一个从UTF-8到GBK的转换描述符 */  
    49.     iconv_to=iconv_open("gbk","utf-8");  
    50.     /* 根据转换描述符,对数据进行编码转换 */  
    51.     rslt = iconv(iconv_to, &inbuf, &len1, &outbuf, &len2);  
    52.     if(rslt < 0){  
    53.         return rslt;  
    54.     }  
    55.     iconv_close(iconv_to); /* 释放描述符 */  
    56.     *outlen = ((unsigned char *) outbuf - out);  
    57.     *inlen = ((unsigned char *) inbuf - in);  
    58.     return *outlen;  
    59. }  
    60.   
    61. /** 
    62.  * convertToUTF8From: 
    63.  * 把encoding编码的输入数据in转换成utf-8格式返回 
    64.  * 出错则返回NULL 
    65.  */  
    66. xmlChar *convertToUTF8From(const char *in, const char *encoding){  
    67.     xmlChar *out;  
    68.     int ret;  
    69.     int size;  
    70.     int out_size;  
    71.     int temp;  
    72.     xmlCharEncodingHandlerPtr handler;  
    73.     if (in == 0)  
    74.         return 0;  
    75.     /* 查找内建的编码处理器 */  
    76.     handler = xmlFindCharEncodingHandler(encoding);  
    77.     if (!handler) {  
    78.         printf("convertToUTF8From: no encoding handler found for '%s'\n",  
    79.                encoding ? encoding : "");  
    80.         return 0;  
    81.     }  
    82.     size = (int)strlen(in) + 1;  /* 输入数据长度 */  
    83.     out_size = size*2 - 1;  /* 输出数据长度 */  
    84.     /* 存放输出数据 */  
    85.     out = (unsigned char *) xmlMalloc((size_t) out_size);  
    86.     memset(out, 0, out_size);  
    87.   
    88.     if(out != NULL) {  
    89.         temp = size - 1;  
    90.         /* 对输入数据进行编码转换,成功后返回0 */  
    91.         ret = handler->input(out, &out_size, (const xmlChar *) in, &temp);  
    92.         if(ret || temp - size + 1) {  /* 转换不成功 */  
    93.             if(ret){  /* 转换失败 */  
    94.                 printf("convertToUTF8From: conversion wasn't successful.\n");  
    95.             }else{  /* 只转换了一部分数据 */  
    96.                 printf("convertToUTF8From: conversion wasn't successful. converted: %i octets.\n", temp);  
    97.             }  
    98.             xmlFree(out); /* 释放输出缓冲区 */  
    99.             out = 0;  
    100.         }else{  /* 转换成功,在输出末尾加上null终止符 */  
    101.             out = (unsigned char *) xmlRealloc(out, out_size + 1);  
    102.             out[out_size] = 0;  
    103.         }  
    104.     } else {  
    105.         printf("convertToUTF8From: no mem\n");  
    106.     }  
    107.     return out;  
    108. }  
    109.   
    110. /** 
    111.  * utf8ConvertTo: 
    112.  * 把utf-8的数据转换成encoding编码返回 
    113.  * 出错则返回NULL 
    114.  */  
    115. char *utf8ConvertTo(xmlChar *in, const char *encoding){  
    116.     char *out;  
    117.     int ret;  
    118.     int size;  
    119.     int out_size;  
    120.     int temp;  
    121.     xmlCharEncodingHandlerPtr handler;  
    122.   
    123.     if (in == 0)  
    124.         return 0;  
    125.   
    126.     handler = xmlFindCharEncodingHandler(encoding);  
    127.   
    128.     if (!handler) {  
    129.         printf("utf8ConvertTo: no encoding handler found for '%s'\n",  
    130.                encoding ? encoding : "");  
    131.         return 0;  
    132.     }  
    133.   
    134.     size = (int) strlen((char*)in) + 1;  /* 输入数据长度 */  
    135.     out_size = size * 2 - 1;  /* 输出数据长度 */  
    136.     out = (char *) malloc((size_t) out_size);  /* 存放输出数据 */  
    137.     memset(out,0,out_size);  
    138.     if(out != NULL) {  
    139.         temp = size - 1;  
    140.         /* 对输入数据进行编码转换,成功后返回0 */  
    141.         ret = handler->output((xmlChar*)out, &out_size, (const xmlChar *) in, &temp);  
    142.         if(ret || temp - size + 1){  
    143.             if(ret){  
    144.                 printf("utf8ConvertTo: conversion wasn't successful.\n");  
    145.             }else{  
    146.                 printf("utf8ConvertTo: conversion wasn't successful. converted: %i octets.\n", temp);  
    147.             }  
    148.             free(out);  
    149.             out = 0;  
    150.         }else{  
    151.             out = (char *) realloc(out, out_size + 1);  
    152.             out[out_size] = 0;  /* 末尾加上null终止符 */  
    153.         }  
    154.     }else{  
    155.         printf("utf8ConvertTo: no mem\n");  
    156.     }  
    157.   
    158.     return out;  
    159. }  
    160.   
    161. int main(int argc, char **argv){  
    162.     const char *content;  
    163.     xmlChar *out;  
    164.     xmlDocPtr doc;  
    165.     xmlNodePtr rootnode;  
    166.       
    167.     if (argc <= 1) {  
    168.         printf("Usage: %s content\n", argv[0]);  
    169.         return(0);  
    170.     }  
    171.     content = (const char*)argv[1];  
    172.   
    173.     /* 添加gbk编码支持 */  
    174.     xmlNewCharEncodingHandler("gbk", gbk_input, gbk_output);  
    175.     /* 添加gb2312编码支持:仍然可以使用GBK的输入输出处理器 */  
    176.     xmlNewCharEncodingHandler("gb2312", gbk_input, gbk_output);  
    177.   
    178.     /* 输入的GBK数据转换成libxml2使用的UTF-8格式 */  
    179.     out = convertToUTF8From(content, "gbk");  
    180.     /* 创建xml文档 */  
    181.     doc = xmlNewDoc(BAD_CAST "1.0");  
    182.     rootnode = xmlNewDocNode(doc, NULL, (const xmlChar*)"root", out);  
    183.     xmlDocSetRootElement(doc, rootnode);  
    184.     /* 以gb2312格式保存文档内容:"-"表示输出到终端 */  
    185.     xmlSaveFormatFileEnc("-", doc, "gb2312", 1);  
    186.       
    187.     xmlCleanupCharEncodingHandlers();/* 释放编码处理器资源 */  
    188.     return (1);  
    189. }  
        这个例子在32位与64位Linux平台下测试通过。iconv库是Linux默认自带的组件,因此在Linux中使用libxml非常方便。我们先建立utf-8编码与gbk编码的转换接口,并将接口插入到libxml2库中,这样xml库就支持对gb2312和gbk编码的支持了。当然,这个转换不会自动完成,我们需要使用从libxml库中查找特定编码的接口,libxml支持一些基本的编码接口,如ISO-8859-1,UTF-16等编码,但不支持gbk,所以在上述代码中,我们定义了gbk_input,与gbk_output两个接口,这两个接口的原型声明是libxml库的标准声明,即xmlCharEncodingInputFunc和xmlCharEncodingOutputFunc。在使用完libxml库之后,我们需要释放libxml库的转换资源。
         例子3:直接使用iconv库进行转换
        下面例子直接使用iconv函数对输入输出进行编码转换,而不是通过注册编码处理器的方式。
    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <string.h>  
    3. #include <iconv.h>  
    4. #include <libxml/parser.h>  
    5. #include <libxml/tree.h>  
    6.   
    7. /* 代码转换:从一种编码转为另一种编码 */  
    8. int encoding_convert(const char *from_charset, const char *to_charset,   
    9.             char *inbuf, int inlen,   
    10.             char* outbuf, int outlen){  
    11.   
    12.     iconv_t cd;  
    13.     size_t len1, len2, rslt;  
    14.   
    15.     /* 注意一般不直接从int*到size_t*的转换 
    16.        这在32位平台下是正常的,但到了64平台下size_t为64位, 
    17.        那(size_t*)inlen将是一个未知的数据  
    18.     */  
    19.     len1 = inlen;  
    20.     len2 = outlen;  
    21.     /* 分配一个转换描述符 */  
    22.     cd = iconv_open(to_charset,from_charset);  
    23.     if(cd == 0)  
    24.        return -1;  
    25.     memset(outbuf,0,len2);   
    26.     /* 执行编码转换 */  
    27.     rslt=iconv(cd, &inbuf, &len1, &outbuf, &len2);  
    28.     if(rslt== -1)  
    29.         return -1;    
    30.   
    31.     iconv_close(cd); /* 释放描述符 */  
    32.     return 0;    
    33.   
    34. }  
    35.   
    36. /* GB2312转换为UTF-8  
    37.  * 成功则返回一个动态分配的char*变量,需要在使用完毕后手动free,失败返回NULL 
    38.  */  
    39. char *gb2312_utf8(char *inbuf){  
    40.     int nOutLen = 2*strlen(inbuf)-1;  
    41.     char *szOut=(char*)xmlMalloc(nOutLen);  
    42.     if(-1 == encoding_convert("gb2312","uft-8",inbuf,strlen(inbuf),szOut,nOutLen)){  
    43.         xmlFree(szOut);  
    44.         szOut=NULL;  
    45.     }  
    46.     return szOut;  
    47. }  
    48.   
    49. /* UTF-8转换为GB2312 
    50.  * 成功则返回一个动态分配的char*变量,需要在使用完毕后手动free,失败返回NULL 
    51.  */  
    52. char *utf8_gb2312(char *inbuf){  
    53.     int nOutLen = 2* strlen(inbuf)-1;  
    54.     char *szOut=(char*)xmlMalloc(nOutLen);  
    55.     if(-1 == encoding_convert("utf-8","gb2312",inbuf,strlen(inbuf),szOut,nOutLen)){  
    56.         xmlFree(szOut);  
    57.         szOut=NULL;  
    58.     }  
    59.     return szOut;  
    60. }  
    61.   
    62. int main(int argc, char **argv){  
    63.     /* 定义文档节点和指针 */  
    64.     xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");  
    65.     xmlNodePtr root_node=xmlNewNode(NULL, BAD_CAST "root");  
    66.     /* 设置根节点 */  
    67.     xmlDocSetRootElement(doc, root_node);  
    68.   
    69.     /* 一个中文字符串转换为UTF-8字符串,然后写入 */  
    70.     char *szOut=gb2312_utf8("节点1的内容");  
    71.     /* 在根节点中直接创建节点 */  
    72.     xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content");  
    73.     xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content");  
    74.     xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content");  
    75.     xmlNewChild(root_node, NULL, BAD_CAST "node1",BAD_CAST szOut);  
    76.     xmlFree(szOut);  
    77.   
    78.     /* 创建一个节点,设置其内容和属性,然后加入根结点 */  
    79.     xmlNodePtr node = xmlNewNode(NULL,BAD_CAST "node2");  
    80.     xmlNodePtr content = xmlNewText(BAD_CAST "NODE CONTENT");  
    81.     xmlAddChild(root_node,node);  
    82.     xmlAddChild(node,content);  
    83.     szOut = gb2312_utf8("属性值");  
    84.     xmlNewProp(node,BAD_CAST "attribute",BAD_CAST szOut);  
    85.     xmlFree(szOut);  
    86.   
    87.     /* 创建一个中文节点 */  
    88.     szOut = gb2312_utf8("中文节点");  
    89.     xmlNewChild(root_node, NULL, BAD_CAST szOut,BAD_CAST "content of chinese node");  
    90.     xmlFree(szOut);  
    91.   
    92.     /* 存储xml文档 */  
    93.     int nRel = xmlSaveFormatFileEnc("CreatedXml_cn.xml",doc,"GB2312",1);  
    94.     if (nRel != -1){  
    95.         printf("一个xml文档被创建,写入%d个字节", nRel);  
    96.     }  
    97.   
    98.     xmlFreeDoc(doc);  
    99.     return 1;  
    100. }  
        这个例子中,当把中文数据写入到XML节点时,使用gb2312_utf8()直接转换成UTF-8格式,这种直接通过iconv转换的方式更高效。编译并运行程序,输出文档如下:
    [html]  view plain copy
    1. <?xml version="1.0" encoding="GB2312"?>  
    2. <root>  
    3.     <newNode1>newNode1 content</newNode1>  
    4.     <newNode2>newNode2 content</newNode2>  
    5.     <newNode3>newNode3 content</newNode3>  
    6.     <node1>节点1的内容</node1>  
    7.     <node2 attribute="属性值">NODE CONTENT</node2>  
    8.     <中文节点>content of chinese node</中文节点>  
    9. </root>     
         6、一个真实的例子
        内容整理自 http://xmlsoft.org/example.html
        下面是一个真实的例子。应用程序数据的内容不使用DOM树,而是使用内部数据结构来保存。这是一个基于XML存储结构的数据库,它保存了与Gnome相关的任务。如下:
    [html]  view plain copy
    1. <?xml version="1.0"?>  
    2. <gjob:Helping xmlns:gjob="http://www.gnome.org/some-location">  
    3.   <gjob:Jobs>  
    4.   
    5.     <gjob:Job>  
    6.       <gjob:Project ID="3"/>  
    7.       <gjob:Application>GBackup</gjob:Application>  
    8.       <gjob:Category>Development</gjob:Category>  
    9.   
    10.       <gjob:Update>  
    11.         <gjob:Status>Open</gjob:Status>  
    12.         <gjob:Modified>Mon, 07 Jun 1999 20:27:45 -0400 MET DST</gjob:Modified>  
    13.         <gjob:Salary>USD 0.00</gjob:Salary>  
    14.       </gjob:Update>  
    15.   
    16.       <gjob:Developers>  
    17.         <gjob:Developer>  
    18.         </gjob:Developer>  
    19.       </gjob:Developers>  
    20.   
    21.       <gjob:Contact>  
    22.         <gjob:Person>Nathan Clemons</gjob:Person>  
    23.         <gjob:Email>nathan@windsofstorm.net</gjob:Email>  
    24.         <gjob:Company>  
    25.         </gjob:Company>  
    26.         <gjob:Organisation>  
    27.         </gjob:Organisation>  
    28.         <gjob:Webpage>  
    29.         </gjob:Webpage>  
    30.         <gjob:Snailmail>  
    31.         </gjob:Snailmail>  
    32.         <gjob:Phone>  
    33.         </gjob:Phone>  
    34.       </gjob:Contact>  
    35.   
    36.       <gjob:Requirements>  
    37.       The program should be released as free software, under the GPL.  
    38.       </gjob:Requirements>  
    39.   
    40.       <gjob:Skills>  
    41.       </gjob:Skills>  
    42.   
    43.       <gjob:Details>  
    44.       A GNOME based system that will allow a superuser to configure   
    45.       compressed and uncompressed files and/or file systems to be backed   
    46.       up with a supported media in the system.  This should be able to   
    47.       perform via find commands generating a list of files that are passed   
    48.       to tar, dd, cpio, cp, gzip, etc., to be directed to the tape machine   
    49.       or via operations performed on the filesystem itself. Email   
    50.       notification and GUI status display very important.  
    51.       </gjob:Details>  
    52.   
    53.     </gjob:Job>  
    54.   
    55.   </gjob:Jobs>  
    56. </gjob:Helping>  
        把XML文件加载到一个内部DOM树中只是调用几个函数的问题,而遍历整个树来收集数据,并生成内部结构则更困难,也更容易出错。
        对输入结构的定义法则是非常宽松的。属性的顺序无关紧要(XML规范清楚地说明了这一点),不要依赖于一个节点的子节点顺序通常是一个好的主意,除非这样做真的使事情变得更困难了。下面是解析person信息的一段代码:
    [cpp]  view plain copy
    1. /* 
    2.  * 一个person记录 
    3.  */  
    4. typedef struct person {  
    5.     char *name;  
    6.     char *email;  
    7.     char *company;  
    8.     char *organisation;  
    9.     char *smail;  
    10.     char *webPage;  
    11.     char *phone;  
    12. } person, *personPtr;  
    13.   
    14. /* 
    15.  * 解析person的代码 
    16.  */  
    17. personPtr parsePerson(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {  
    18.     personPtr ret = NULL;  
    19.   
    20. DEBUG("parsePerson\n");  
    21.     /* 
    22.      * 为结构分配内存 
    23.      */  
    24.     ret = (personPtr) malloc(sizeof(person));  
    25.     if (ret == NULL) {  
    26.         fprintf(stderr,"out of memory\n");  
    27.         return(NULL);  
    28.     }  
    29.     memset(ret, 0, sizeof(person));  
    30.   
    31.     /* 我们不关心顶层的元素名是什么 */  
    32.     cur = cur->xmlChildrenNode;  
    33.     while (cur != NULL) {  
    34.         if ((!strcmp(cur->name, "Person")) && (cur->ns == ns))  
    35.             ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);  
    36.         if ((!strcmp(cur->name, "Email")) && (cur->ns == ns))  
    37.             ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);  
    38.         cur = cur->next;  
    39.     }  
    40.   
    41.     return(ret);  
    42. }  
        下面是要注意的一些事项:
        (1)通常一个递归的解析风格是更方便的:XML数据天然地遵循重复式地构造,并且是高度结构化的。
        (2)两个参数是xmlDocPtr和xmlNsPtr类型,即指向XML文档和应用程序保留的命名空间的指针。文档信息非常广泛,为你的应用程序数据集定义一个命名空间并测试元素和属性是否属性这个空间是一个好的编程实践。这只需一个简单的相等测试(cur->ns == ns)。
        (3)为了查询文本和属性值,你可以使用函数xmlNodeListGetString()来获取所有文本,和由DOM输出生成的引用节点,并生成一个单一的文本字符串。
        下面是解析另外一个结构的代码片段:
    [cpp]  view plain copy
    1. #include <libxml/tree.h>  
    2. /* 
    3.  * 一个Job的描述 
    4.  */  
    5. typedef struct job {  
    6.     char *projectID;  
    7.     char *application;  
    8.     char *category;  
    9.     personPtr contact;  
    10.     int nbDevelopers;  
    11.     personPtr developers[100]; /* using dynamic alloc is left as an exercise */  
    12. } job, *jobPtr;  
    13.   
    14. /* 
    15.  * 解析Job的代码 
    16.  */  
    17. jobPtr parseJob(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {  
    18.     jobPtr ret = NULL;  
    19.   
    20. DEBUG("parseJob\n");  
    21.     /* 
    22.      * 为结构分配内存 
    23.      */  
    24.     ret = (jobPtr) malloc(sizeof(job));  
    25.     if (ret == NULL) {  
    26.         fprintf(stderr,"out of memory\n");  
    27.         return(NULL);  
    28.     }  
    29.     memset(ret, 0, sizeof(job));  
    30.   
    31.     /* 我们不关心顶层元素名是什么 */  
    32.     cur = cur->xmlChildrenNode;  
    33.     while (cur != NULL) {  
    34.           
    35.         if ((!strcmp(cur->name, "Project")) && (cur->ns == ns)) {  
    36.             ret->projectID = xmlGetProp(cur, "ID");  
    37.             if (ret->projectID == NULL) {  
    38.                 fprintf(stderr, "Project has no ID\n");  
    39.             }  
    40.         }  
    41.         if ((!strcmp(cur->name, "Application")) && (cur->ns == ns))  
    42.             ret->application = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);  
    43.         if ((!strcmp(cur->name, "Category")) && (cur->ns == ns))  
    44.             ret->category = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);  
    45.         if ((!strcmp(cur->name, "Contact")) && (cur->ns == ns))  
    46.             ret->contact = parsePerson(doc, ns, cur);  
    47.         cur = cur->next;  
    48.     }  
    49.   
    50.     return(ret);  
    51. }  

        一旦你会使用libxml2,编写这种类型的代码是非常简单的,也很无趣。最终,你可以写一个拥有C数据结构和一组XML文档例子或一个XML DTD的桩模块,并生成在C数据和XML存储之间导入和导出数据的代码。

        7、详细代码示例
        对Libxml2更详细的使用介绍,可参考官方的详细代码示例http://xmlsoft.org/examples/index.html。上面提供了Libxml2各个组件怎么使用的详细代码示例,包括以下部分:
        xmlWriter: 测试xmlWriter的各个API,包括写入到文件、写入到内存缓冲区、写入到新的文档或子树、字符串编码转换、对输出文档进行序列化。
        InputOutput: 演示使用xmlRegisterInputCallbacks来建立一个客户I/O层,这被用在XInclude方法上下文中,以显示怎样构建动态文档。还演示使用xmlDocDumpMemory来输出文档到字符缓冲区中。
        Parsing: 演示使用xmlReadMemory()读取XML文档,xmlFreeDoc()释放文档树;使用xmlCreatePushParserCtxt()和xmlParseChunk()一块一块地读取XML文档到文档树中。演示为XML文档创建一个解析上下文,然后解析并验证这个文档;创建一个文档树,检查并验证结果,最后用xmlFreeDoc()释放文档树。演示使用xmlReadFile()读取XML文档并用xmlFreeDoc()释放它。
        Tree: 演示怎样创建文档和节点,并把数据dump到标准输出或文件中。演示使用xmlDocGetRootElement()获取根元素,然后遍历文档并打印各个元素名。
        XPath: 演示怎样计算XPath表达式,并在XPath上下文注册名称空间,打印结果节点集。演示怎么加载一个文档、用XPath定位到某个子元素、修改这个元素并保存结果。这包含了加载/编辑/保存的一个完整来回。
        xmlReader: 演示使用xmlReaderForFile()解析XML文档,并dump出节点的信息。演示在用xmlReaderForFile()解析时验证文档的内容,激活各种选项,诸如实体替换、DTD属性不一致等。演示使用xmlTextReaderPreservePattern()提取XML文档中某一部分的子文档。演示重用xmlReader对象来解析多个XML文档。

    展开全文
  • libxml2使用

    2013-05-06 09:29:10
    #sudo apt-get install libxml2 #sudo apt-get install libxml2-dev 创建xml文档 /******************************************************************** created: 2007/11/09 created: 9:11:2

    安装

    #sudo apt-get install libxml2

    #sudo apt-get install libxml2-dev


    创建xml文档

    /********************************************************************
        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:   创建一个xml文件
    *********************************************************************/
    #include<stdio.h>
    #include<libxml/parser.h>
    #include<libxml/tree.h>
    #include<iostream>
    using namespace std;
    int main()
    {
        //定义文件和节点指针
        xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");
        xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root");
        //设置根节点
        xmlDocSetRootElement(doc,root_node);
        //在根节点中直接创建节点
        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");
        //创建一个节点,设置其内容和属性,然后加入根结点
        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");
        //创建一个儿子和孙子节点
        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文件被创建,写入"<<nRel<<"个字节"<<endl;
    	}
        //释放文件内节点动态申请的内存
        xmlFreeDoc(doc);
        return 1;
    }
    创建的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>

    解析xml文档


    /********************************************************************
        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>
    using namespace std;
    int main(int argc, char* argv[])
    {
        xmlDocPtr doc;           //定义解析文件指针
        xmlNodePtr curNode;      //定义结点指针(你需要他为了在各个结点间移动) 
        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将指一个注册的错误并停止。
        //一个常见错误是不适当的编码。XML标准文件除了用UTF-8或UTF-16外还可用其他编码保存。
        //如果文件是这样,libxml将自动地为你转换到UTF-8。更多关于XML编码信息包含在XML标准中.
        if (NULL == doc) 
        {  
           fprintf(stderr,"Document not parsed successfully. \n");     
           return -1; 
        } 
        curNode = xmlDocGetRootElement(doc); //确定文件根元素
        /*检查确认当前文件中包含内容*/ 
        if (NULL == curNode)
        { 
           fprintf(stderr,"empty document\n"); 
           xmlFreeDoc(doc); 
           return -1; 
        } 
        /*在这个例子中,我们需要确认文件是正确的类型。“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) 
        {
           //取出节点中的内容
           if ((!xmlStrcmp(curNode->name, (const xmlChar *)"newNode1"))) 
           {
               szKey = xmlNodeGetContent(curNode);
               printf("newNode1: %s \n", szKey); 
               xmlFree(szKey); 
           } 
           //查找带有属性attribute的节点
           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;
    }

    编译

    g++ CreateXmlFile.cpp -lxml2



    展开全文
  • 目录前言一、XML简介1.1 什么是XML1.2 XML 和 HTML 之间的差异1.3...在使用libxml2库的时候,我们有必要先了解一下xml的语法规则。在了解xml的时候顺带又把HTML过了一下。 提示:以下是本篇文章正文内容,下面案例可供
  • libxml2使用示例

    2012-03-20 22:10:06
    libxml2使用示例。 可能有Bug。
  • libxml2-2.9.1.tar.gz

    2020-02-18 16:45:09
    libxml2是一个用来解析XML文档的函数库。它用 C 语言写成,并且能被多种语言所调用,如 C、C++、XSH、C#、Python、Kylix、Delphi、Ruby、PHP 等。 注:先解压得到libxml2-2.9.1.tar.gz文件,然后再拷贝到linux系统...
  • libxml2.so.2

    2019-03-28 20:32:13
    libxml2.so.2
  • Libxml2 (2.9.8)库在Windows下的编译批处理文件。将本文件下载到源码目录win32子目录中,然后点击执行即可完成编译。 在执行之前,需要根据实际情况修改批处理中的文件目录。
  • VS2015编译的libxml2的64位库,版本是2.7.2。libxml2是一个用来解析XML文档的函数库。它用 C 语言写成,并且能被多种语言所调用,如 C、C++、XSH、C#、Python、Kylix、Delphi、Ruby、PHP 等。它最初是为 GNOME 开发...
  • libxml2示例源码

    2018-02-02 18:49:11
    Libxml2是一个C语言的XML程序库,可以简单方便的提供对XML文档的各种操作。Linux, Unix, Windows, CygWin, MacOS, MacOS X, RISC Os, OS/2, VMS, QNX, MVS, VxWorks, ...
  • 写这篇文章的原因有如下几点:1)C++标准库中没有操作...基于以上几点原因,决定写一个在Windows平台下,使用C/C++语言,应用LibXml2库来进行xml文档操作,同时使用ICONV库进行中文编码转换的文档。其中还涉及了Makefil
  • libxml2-2.9.9.tar.gz

    2019-02-14 15:28:22
    The XML C parser and toolkit of Gnome libxml libxml2-2.9.9.tar.gz 安装包
  • 利用libxml2生成,解析,修改xml文件示例,安装libxml2库, sudo apt-...使用libxml2库进行xml文件的操作,取出了平台差异化,便于在不同的平台都可以进行文件的操作,不受平台系统的限制,可以实现一次编码,多次编译
  • 使用函数xmlNewChild新增没有prop的节点时,参数content不能传空字符串,用NULL即可 xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) ...
  • ubuntu12.04 安装libxml2 使用libxml2编译

    千次阅读 2016-10-02 23:52:10
    #sudo apt-get install libxml2 #sudo apt-get install libxml2-dev 默认是安装在/usr/include/libxml2 如果需要编译一个.c文件,命令如下 gcc obj.c -o obj -I /usr/include/libxml2 -L
  • c++ libxml2 简明入门使用教程

    千次阅读 2017-11-27 12:38:53
    libxml2常用库函数详解地址一 : 首先认识一下几个libxml2 中常用的指针 xmlDocPtr用于表示XML 文档的指针 xmlNodePtr用于表示XML 节点的指针 xmlChar用于表示XML 中的字符串(属性值等) ,unsigned char 的重定义 ...
  • libxml2的安装及使用

    万次阅读 2018-09-10 21:24:29
    本文着重介绍解析xml的libxml2库的安装及使用,举例说明创建和解析xml的过程。是针对C语言开发人员使用 你若想详细学习前端的一套东西,即xml html css javascript(JS)等,可以登录这个网站http://www.runoob.com/ ...
  • libxml2-2.9.8源码及编译方法,libxml2-2.9.8源码及编译方法
  • libxml2

    2019-04-12 01:11:19
    NULL 博文链接:https://ssdutliuhaibo.iteye.com/blog/1683204
  • 使用vs2017编译运行,也可以在linux,macOS下使用, 没有使用特定平台的代码。博客https://infoworld.blog.csdn.net/article/details/105507364的项目例子。注意由于库是32位的,而vs2017打开时自动选了x64, 所以要...
  • libxml2.dll

    2019-11-22 13:50:53
    libxml2
  • python3 安装 libxml2

    2022-03-16 12:48:59
    command:pip install libxml2-python3 errors: Collecting libxml2-python3 Using cached libxml2-python3-2.9.5.tar.gz (216 kB) Preparing metadata (setup.py) ... error ERROR: Command errored out ...
  • libxml2使用详解

    千次阅读 2013-07-23 16:26:54
    以下是对minixml分析后做出的例子。希望对大家有用。至于minixml库,大家可google查找。        ....1.   .....2...   .....3..   ....4.   ...5
  • Windows版本的libxml2库,我是根据官网的源码自己编译生成的,网上一般都是32位的,我自己因为需要64位的,就自己编译出来64位的,亲测可用。
  • libxml2 VS库.zip

    2020-05-11 14:58:27
    在机器学习应用中,可能需要将检测到的目标写入xml文件,来辅助生产标记文件;也可能需要读取xml文件显示到图像中,和检测结果进行比对,来辅助确诊标记文件是否有标记错误的情况。这里搬运了libxml2的算法库
  • libxml2-2.9.7.tar.gz

    2018-01-17 15:57:22
    libxml2-2.9.7.tar.gz python下载包 libxml用于解析xml格式文档。 可是用于自定义的html,xml等文档的解析工作
  • 编译好的libxml 2.9.9,包含动态库和链接库文件。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 68,832
精华内容 27,532
关键字:

libxml2使用