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

  • 相关阅读:
    Bolero and Data Mining
    2007年3月15日 网站论坛出现以下错误/forum/inc/Dv_ClsMain.asp,行 1344
    A Probabilistic Model for Retrospective News Event
    信息抽取的资料文档
    Textual Data Mining and WEBSOM
    DockPanel Suite更新到2.6了 武胜
    Use Custom Events from your WCF ServiceHost http://www.codeproject.com/Tips/150702/UseCustomEventsfromyourWCFServiceHost 武胜
    Unable to convert MySQL date/time value to System.DateTime 解决方案 转 武胜
    XML 转义字符 武胜
    Using Nini .NET Configuration Library 武胜
  • 原文地址:https://www.cnblogs.com/aini521521/p/6738621.html
Copyright © 2011-2022 走看看