zoukankan      html  css  js  c++  java
  • xml

    1.   创建XML文档

    (1)创建一个XML文档非常简单,其流程如下:

    ①    用xmlNewDoc函数创建一个文档指针doc。

    ②    用xmlNewNode函数创建一个节点指针root_node。

    ③    用xmlDocSetRootElement将root_node设置为doc的根结点。

    ④    给root_node添加一系列的子节点,并设置子节点的内容和属性。

    ⑤    用xmlSaveFile将XML文档存入文件。

    ⑥    用xmlFreeDoc关闭文档指针,并清除本文档中所有节点动态申请的内存。

    有多种方式可以添加子节点,如可以用xmlNewTextChild直接添加一个文本子节点。也可以先创建新节点,然后用xmlAddChild将新节点加入到上层节点中。

     

    (2)创建xml文件举例

    CreateXmlFile.c源代码如下:

    #include <stdio.h>

    #include <libxml/parser.h>

    #include <libxml/tree.h>

    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("CreateXml.xml",doc);

         if (nRel != -1)

         {

            printf("一个xml文档被创建,写入%d个字节 ", nRel);

         }

         //释放文档内节点动态申请的内存

         xmlFreeDoc(doc);

         return 1;

    }

    编译 gcc CreateXmlFile.c -o CreateXmlFile -I/usr/local/include/libxml2       -lxml2。

    执行./CreateXmlFile,会生成一个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文件,可读性较差。

    2.   解析XML文档

    (1)XML解析流程

    解析一个XML文档,从中取出想要的信息,例如节点中包含的文字,或者某个节点的属性。其流程如下:

    ①    用xmlReadFile函数读入一个文件,并返回一个文档指针doc。

    ②    用xmlDocGetRootElement函数得到根节点curNode。

    ③    此时curNode->xmlChildrenNode就是根节点的首个儿子节点,该儿子节点的兄弟节点可用next指针进行轮询。

    ④    轮询所有子节点,找到所需的节点,用xmlNodeGetContent取出其内容。

    ⑤    用xmlHasProp查找含有某个属性的节点,属性列表指针xmlAttrPtr将指向该节点的属性列表。

    ⑥    取出该节点的属性,用xmlGetProp取出其属性值。

    ⑦    xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。

     

    (2)XML解析举例

    ParseXmlFile.c源代码如下:

    #include <stdio.h>

    #include <libxml/parser.h>

    #include <libxml/tree.h>

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

    {

        xmlDocPtr doc;           //定义解析文件指针

        xmlNodePtr curNode;      //定义结点指针

        xmlChar *szKey;          //临时字符串变量

        char *szDocName;

        if (argc <= 1)

        {

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

            return(0);

        }

        szDocName = argv[1];

        doc = xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER);

        //解析文件

        //检查解析文档是否成功,如果不成功,libxml将报错并停止解析。

        //一个常见错误是不适当的编码,XML标准文档除了用UTF-8或UTF-16外还可用其它编码保存

        if (NULL == doc)

        { 

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

            return -1;

        }

        //获取根节点

        curNode = xmlDocGetRootElement(doc);

        if (NULL == curNode)

        {

            fprintf(stderr,"empty document");

            xmlFreeDoc(doc);

            return -1;

        }

        //确认根元素名字是否符合

        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 ", 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");

                printf("get attribute=%s ", szAttr) ;

                xmlFree(szAttr);

            }

            attrPtr = attrPtr->next;

        }

        xmlFreeDoc(doc);

        return 0;

    }

    编译 gcc ParseXmlFile.c -o ParseXmlFile -I/usr/local/include/libxml2  -lxml2。

    执行 ./ParseXmlFile CreateXml.xml,执行结果如下:

    newNode1: newNode1 content

    get attribute=yes

    3.   修改XML文档

    有了上面的基础,修改XML文档的内容就简单了。首先打开一个已经存在的XML文档,顺着根结点找到需要添加、删除、修改的地方,调用相应的XML函数对节点进行增、删、改操作。

    需要注意的是,并没有xmlDelNode或者xmlRemoveNode函数,删除节点需使用以下一段代码:

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

           {

               xmlNodePtr tempNode;

               tempNode = curNode->next;

               xmlUnlinkNode(curNode);

               xmlFreeNode(curNode);

               curNode = tempNode;

               continue;

           }

    此段代码完成将当前节点从文档中断链(unlink),这样此XML文档就不会再包含这个节点,该节点断链后需使用xmlFreeNode来释放该节点申请的动态内存空间。

    4.   使用XPath查找XML文档

    在libxml2中使用XPath非常简单,其流程如下:

    ①    定义一个XPath上下文指针xmlXPathContextPtr context,并且使用xmlXPathNewContext函数来初始化这个指针。

    ②    定义一个XPath对象指针xmlXPathObjectPtr result,并且使用xmlXPathEvalExpression函数来计算XPath表达式,得到查询结果,将结果存入对象指针中。

    ③    使用result->nodesetval得到节点集合指针,其中包含了所有符合XPath查询结果的节点。

    ④    使用xmlXPathFreeContext释放上下文指针。

    ⑤    使用xmlXPathFreeObject释放XPath对象指针。

    XPath操作代码示例如下:

    xmlXPathObjectPtr getNodeSet(xmlDocPtr doc, const xmlChar *szXpath)

    {

        xmlXPathContextPtr context;    //XPath上下文指针

        xmlXPathObjectPtr result;       //XPath对象指针,用来存储查询结果

        context = xmlXPathNewContext(doc);     //创建一个XPath上下文指针

        if (context == NULL)

        {  

           printf("context is NULL"n");

           return NULL;

        }

        result = xmlXPathEvalExpression(szXpath, context); //查询XPath表达式,得到一个查询结果

        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;   

    }

    5.   用iconv解决XML中字符集问题

    libxml2中默认的内码是UTF-8,所有使用libxml2进行处理的xml文件,必须首先显式或者默认转换为UTF-8编码才能被处理。

    要在XML中使用中文,就必须能够在UTF-8和GB2312之间进行转换。libxml2提供了默认的内码转换机制,并且在libxml2的Tutorial中有一个例子,事实证明这个例子并不很适合用来转换中文。

    有些场合需要使用iconv来进行编码转换,libxml2本身也是使用iconv进行编码转换的。iconv是一个专门用来进行编码转换的库,基本上支持目前所有常用的编码,它是glibc库的一个部分。

    本节其实和libxml没有太大关系,可以把它简单看作是一个编码转换方面的专题。下文提供了一个通用转码函数,并在此基础上实现了两个转码封装函数,即从UTF-8转换到GB2312的函数u2g,以及反向转换的函数g2u。其代码如下:

    #include <iconv.h>

    #include <string.h>

    //代码转换,从一种编码转为另一种编码  

    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码转为GB2312码  

    //成功则返回一个动态分配的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码转为UNICODE码  

    //成功则返回一个动态分配的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;

    }

    下面以UTF-8到GB2312转码流程说明上文中转码函数的使用,使用流程如下:

    ①    得到一个UTF-8的字符串szSrc。

    ②    定义一个char *的字符指针szDes,并不需要给它动态申请内存。

    ③    调用szDes = u2g(szSrc),这样szDes就指向转换后GB2312编码的字符串。

    ④    使用完这个字符串后使用free(szDes)来释放内存。

    如果转码文件可以选择系统调用来进行文件转码。下文中f表示from,t表示to,其转码方法如下:

    system("iconv –f 源格式 –t 目标格式 源文件 >目标文件")

    system("iconv –f  GB18030 –t UTF-8  test_gb.txt > test_utf.txt")

  • 相关阅读:
    数据库字段太多,批量快速建立实体类方法(适合大量字段建立实体类)
    SQL service 中的 ”输入SQL命令窗口“ 打开了 “属性界面” 回到 ”输入SQL命令窗口“
    计算机软件编程英语词汇集锦
    编程常用英语词汇
    svn上传和下载项目
    当启动tomcat时出现tomcat setting should be set in tomcat preference page
    Implicit super constructor Object() is undefined for default constructor. Must define an explicit constructor
    eclipse中选中一个单词 其他相同的也被选中 怎么设置
    Spring Boot的@SpringBootApplication无法引入的问题
    最全的SpringCloud视频教程
  • 原文地址:https://www.cnblogs.com/aini521521/p/6738621.html
Copyright © 2011-2022 走看看