以C之名,解析Xml

这篇具有很好参考价值的文章主要介绍了以C之名,解析Xml。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考文章:
libxml2的安装及使用_阿卡基YUAN的博客-CSDN博客

Xml文件介绍

解析XML文件

libxml2的安装

参考安装:Linux如何安装并配置libxml2库?解决“libxml2 not found“问题_Mintimate的博客-CSDN博客

指令安装

Linux是Debian或Ubuntu:

sudo apt-get install libxml2
sudo apt-get install libxml2-dev

编译安装

可参考libxml2的官方网址: Home · Wiki · GNOME / libxml2 · GitLab
下载最新的libxml2库: Releases · GNOME / libxml2 · GitLab
安装参考: c语言读取xml配置文件-CSDN博客

以C之名,解析Xml,C++基础学习,c语言,xml,开发语言
具体安装步骤:

  1. 解压:$tar zxvf libxml2-2.9.1.tar.gz

  2. 进入解压后的安装目录:$cd libxml2-2.9.1

  3. 配置libxml2库

    1. ./configure
    2. make
    3. make install
  4. 执行配置命令

./configure
  1. 编译过程中出现出错
libxml.c:14:20: fatal error: Python.h: No such file or directory

需要安装python,执行命令:

sudo apt-get install python-dev

安装完python-dev之后,再次编译成功。

  1. 执行make install执行安装

安装完成之后,查看output路径下,增加了相关的文件。
以C之名,解析Xml,C++基础学习,c语言,xml,开发语言

XML文件类型

xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<bmp_para>
  <para id="1">
     <width>1920</width>
     <height>1080</height>
     <bit>3</bit>
     <blue>0</blue>
     <green>0</green>
     <red>255</red>     
  </para>
</bmp_para>

内部字符类型xmlChar

xmlChar是Libxml2中的字符类型,库中所有字符、字符串都是基于这个数据类型。事实上他的定义是:xmlstring.h

#incldue<xmlstring.h>

typedef unsigned char xmlChar;

使用unsigned char作为内部字符格式是考虑到他能非常好适应UTF-8编码,而UTF-8编码正是libxml2的内部编码,其他格式的编码要转换为这个编码才能在libxml2中使用。

xmlChar相关函数

如同标准c中的char类型相同,xmlChar也有动态内存分配、字符串操作等相关函数

  1. xmlMalloc是动态分配内存的函数;
  2. xmlFree是配套的释放内存函数;
  3. xmlStrcmp是字符串比较函数等等。

基本上xmlChar字符串相关函数都在xmlstring.h中定义;而动态内存分配函数在xmlmemory.h中定义

xmlChar*和其他类型之间的转换

另外要注意,因为总是要在xmlChar和char之间进行类型转换,所以定义了一个宏BAD_CAST,其定义如下:xmlstring.h

#include<xmlstring.h>

#define BAD_CAST (xmlChar *)

原则上来说,unsigned char和char之间进行强制类型转换是没有问题的。

文件类型xmlDoc、指针xmlDocPtr

xmlDoc是个struct,保存了一个xml的相关信息,例如文件名、文件类型、子节点等等;xmlDocPtr等于xmlDoc*,他搞成这个样子总让人以为是智能指针,其实不是,要手动删除的。

  • **xmlNewDoc: **创建一个新的文件指针。
  • **xmlParseFile: **以默认方式读入一个UTF-8格式的文件,并返回文件指针
  • **xmlReadFile: **读入一个带有某种编码的xml文件,并返回文件指针;
  • **xmlFreeDoc: **释放文件指针。特别注意,当你调用xmlFreeDoc时,该文件所有包含的节点内存都被释放,所以一般来说不必手动调用xmlFreeNode或xmlFreeNodeList来释放动态分配的节点内存,除非你把该节点从文件中移除了。一般来说,一个文件中所有节点都应该动态分配,然后加入文件,最后调用xmlFreeDoc一次释放所有节点申请的动态内存,这也是为什么我们非常少看见xmlNodeFree的原因。
  • **xmlSaveFile: **将文件以默认方式存入一个文件。
  • **xmlSaveFormatFileEnc: **可将文件以某种编码/格式存入一个文件中。

节点类型xmlNode、指针xmlNodePtr

节点应该是xml中最重要的元素了,xmlNode代表了xml文件中的一个节点,实现为一个struct,内容非常丰富:tree.h

#include<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 */
};

能看到,节点之间是以链表和树两种方式同时组织起来的,next和prev指针能组成链表,而parent和children能组织为树。同时更有以下重要元素:

l 节点中的文字内容:content;
l 节点所属文件:doc;
l 节点名字:name;
l 节点的namespace:ns;
l 节点属性列表:properties;

Xml文件的操作其根本原理就是在节点之间移动、查询节点的各项信息,并进行增加、删除、修改的操作

xmlDocSetRootElement函数能将一个节点设置为某个文件的根节点,这是将文件和节点连接起来的重要手段,当有了根结点以后,所有子节点就能依次连接上根节点,从而组织成为一个xml树。

节点集合类型xmlNodeSet、指针xmlNodeSetPtr

节点集合代表一个由节点组成的变量,节点集合只作为Xpath的查询结果而出现(XPATH的介绍见后面),因此被定义在xpath.h中,其定义如下:

#include<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 @@ */
};

节点集合有三个成员,分别是节点集合的节点数nodeNr最大可容纳的节点数nodeMax,及节点数组头指针nodeTab

对节点集合中各个节点的访问方式非常简单,如下:

xmlNodeSetPtr nodeset = XPATH查询结果;
for (int i = 0; i < nodeNr; i++) 
{
	nodeset->nodeTab;
}

注意:libxml2是个c函数库,因此其函数和数据类型都使用c语言的方式来处理。

xml文档结构

xml按照树形结构进行存储,节点分为元素和文本,必须有根节点。如下的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<phone_books>
  <phone id="1">
     <name>Anker</name>
     <tel>18923873456</tel>
     <address>Shenzheng</address>
  </phone>
  <phone id="2">
    <name>Jermey</name>
    <tel>18623873456</tel>
    <address>Beijing</address>
  </phone>
  <phone id="3">
    <name>Lili</name>
    <tel>13223873456</tel>
    <address>Shanghai</address>
  </phone>
</phone_books>

实操练习

libxml2常用的接口如下:

内部字符类型:xmlChar,用无符号型的char方便表示utf-8编码。libxml2提供了一个宏进行转换,#define BAD_CAST (xmlChar *)

文档类型xmlDoc,指针类型xmlDocPtr。
xmlDoc是个struct,保存了一个xml的相关信息,例如文件名、文件类型、子节点等等;xmlDocPtr等于xmlDoc*。

xmlNewDoc函数创建一个新的文件指针。
xmlParseFile函数以默认方式读入一个UTF-8格式的文件,并返回文件指针。
xmlReadFile函数读入一个带有某种编码的xml文件,并返回文件指针
xmlFreeDoc释放文件指针。特别注意,当你调用xmlFreeDoc时,该文件所有包含的节点内存都被释放
xmlFreeNodeList来释放动态分配的节点内存,除非你把该节点从文件中移除了。
xmlSaveFile将文件以默认方式存入一个文件。
xmlSaveFormatFileEnc可将文件以某种编码/格式存入一个文件中。

节点类型xmlNode、指针xmlNodePtr
xmlDocSetRootElement函数能将一个节点设置为某个文件的根节点

创建xml文件

创建流程:

  1. 用xmlNewDoc函数创建一个文件指针doc;
  2. 用xmlNewNode函数创建一个节点指针root_node;
  3. 用xmlDocSetRootElement函数讲root_node设置为doc的根节点;
  4. 给root_node添加一系列的子节点, 并设置子节点的内容和属性;
  5. 用xmlSaveFile函数讲xml文件存入文件
  6. 用xmlFreeDoc函数关闭文件指针, 并清除本文件中所有节点动态申请的内存

可以有多种方式添加子节点:

  1. 用xmlNewTextChild函数直接添加一个文本子节点
  2. 先创建新节点, 然后用xmlAddChild将新节点加入上层节点

源码分析:

#include<stdio.h>
#include<stdlib.h>

#include<libxml/parser.h>
#include<libxml/tree.h>
#include<libxml/xmlmemory.h>

int main(int argc, char *argv[]){
    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(root_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 grandson Node"));

    //存储xml文件
    int nRet = xmlSaveFile("CreatedXml.xml",doc);
    if(nRet != -1){
        printf("xml creat success\n");
        xmlFreeDoc(doc);
    }
    return 0;
}

参考学习: “libxml/parser.h: 没有那个文件或目录”解决方案_iamlate的博客-CSDN博客

  1. make编译,你应该会报错, “找不到parser.h等头文件”
  2. 然后你去查找一下你会发现, 头文件竟然在src里找到了

以C之名,解析Xml,C++基础学习,c语言,xml,开发语言

  1. 进入/usr/include目录, 你会发现你要找的头文件都是在该路径下,**/usr/include/libxml2/libxml/…h. **
  2. 因为安装好的库,头文件默认是在libxml2的目录下, 所以我们需要做一个软链接.
	sudo ln -s /usr/include/libxml2/libxml  /usr/include/libxml
  1. 然后重新make编译, 你会发现又报错. 哈哈

以C之名,解析Xml,C++基础学习,c语言,xml,开发语言
这里是报错的原因是你一些文件没有链接成功, 加上libxml2.so的动态库就行了.

  1. 加上动态库,重新编译
gcc xml.c -o xml -I/usr/include/libxml -lxml2
  1. 运行成功,

以C之名,解析Xml,C++基础学习,c语言,xml,开发语言

  1. 此时会生成一个CreateXml.xml文件

以C之名,解析Xml,C++基础学习,c语言,xml,开发语言

<?xml version="1.0"?>
<root>
  <newNode1>
    newNode1 content
  </newNode1>
  <newNode2>
    newNode2 content
  </newNode2>
  <newNode3>
    newNode3 content
  </newNode3>
  <node2 attribute="yes"/>NODE CONTENT
  <son>
    <grandson>This is grandson Node</grandson>
  </son>
</root>

附上Makefile文件, 供大家查看, 也正好锻炼一下Makefile

CC := gcc
SRC := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o, ${SRC})
TARGET := $(basename ${OBJS})
INCLUDE_DIR := /usr/include/libxml

CFLAGS+= -I$(INCLUDE_DIR)/
LIBS+= -lxml2

add: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $^ -o $@ $(CFLAGS) $(LIBS)

%.o: %.c
	$(CC) -c $< -o $@

clean:
	-rm -rf $(OBJS)
	-rm -rf $(TARGET)

解析xml文档

在上面,我们学会了如何创建xml文件. 这节学习如何解析已存在的xml文件
解析一个xml文件,从中读取信息, 例如节点中的文字, 或某个节点的属性…

解析流程如下:

  1. xmlReadFile函数读出一个文件指针doc;
  2. xmlDocGetRootElement函数得到根节点curNode;
  3. curNode->xmlChildrenNode就是根节点的子节点集合;
  4. 轮询子节点集合, 找到所需要的节点, 用xmlNodeGetContent取出内容;
  5. xmlHasProp查找含有某个属性的节点;
  6. 取出该节点的属性集合, 用xmlGetProp取出其属性值;
  7. xmlFreeDoc函数关闭文件指针, 并清除本文中的所有节点申请的动态内存;
<?xml version="1.0"?>
<root>
  <newNode1>
    newNode1 content
  </newNode1>
  <newNode2>
    newNode2 content
  </newNode2>
  <newNode3>
    newNode3 content
  </newNode3>
  <node2 attribute="yes"/>NODE CONTENT
  <son>
    <grandson>This is grandson Node</grandson>
  </son>
</root>

源码解析:

#include<stdio.h>
#include<stdlib.h>

#include<libxml/parser.h>
#include<libxml/tree.h>
#include<libxml/xmlmemory.h>
#include<libxml/xmlstring.h>

int main(int argc, char* argv[]){
    xmlDocPtr doc;                      //定义解析文件指针
    xmlNodePtr curNode;                 //定义根节点指针
    xmlChar *szKey;                     //临时字符串变量
    char *szDocName;

    if(argc < 2){
        printf("Usage: %s <xml>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    szDocName = argv[1];                //保存xml文件名
    doc = xmlReadFile(szDocName, "GB2312", XML_PARSE_RECOVER);  //解析文件
    //检查是否解析成功
    if(doc == NULL){
        fprintf(stderr, "Document parse failure\n");
        exit(EXIT_FAILURE);
    }

    curNode = xmlDocGetRootElement(doc);   //确定根节点
    //先检查当前xml文件里是否是空
    if(curNode == NULL){
        fprintf(stderr, "empty xml file\n");
        exit(EXIT_FAILURE);
    }
    if(xmlStrcmp(curNode->name, "root") != 0){  //判断是否是根节点
        fprintf(stderr, "Type error\n");
        exit(EXIT_FAILURE);
    }

    curNode = curNode->xmlChildrenNode;         //遍历子节点 next
    xmlNodePtr propNodeptr = curNode;

    while(curNode != NULL){
        if((xmlStrcmp(curNode->name, (const xmlChar *)"newNode2")) == 0){   //取出子节点的名字
            szKey = xmlNodeGetContent(curNode);                     //保存子节点的名字
            printf("newNode1: %s\n", szKey);
            xmlFree(szKey);                     //清空xmlChar类型
        }

        if(xmlHasProp(curNode, BAD_CAST"attribute") != 0){  //查看属性是attribute的子节点
            propNodeptr = curNode;                  //如果没有就下一个字节点
        }
        curNode = curNode->next;
    }

    //查找属性
    xmlAttrPtr attPtr = propNodeptr->properties;
    while(attPtr != NULL){
        if(!xmlStrcmp(attPtr->name, BAD_CAST"attribute")){
            xmlChar *szAttr = xmlGetProp(propNodeptr, BAD_CAST"attribute");
            printf("szAttr: %s\n", szAttr);
            xmlFree(szAttr);     
        }
        attPtr = attPtr->next;
    }
    xmlFreeDoc(doc);
    return 0;

}

输出结果
以C之名,解析Xml,C++基础学习,c语言,xml,开发语言
文章来源地址https://www.toymoban.com/news/detail-712614.html

到了这里,关于以C之名,解析Xml的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring MVC学习随笔-控制器(Controller)开发详解:调用业务对象、父子工厂拆分(applicationContext.xml、dispatcher.xml)

    学习视频:孙哥说SpringMVC:结合Thymeleaf,重塑你的MVC世界!|前所未有的Web开发探索之旅 💡 1. 接收客户端(Client)请求参数【讲解完毕】2. 调用业务对象【讲解】3. 页面跳转 dispatcher.xml DAO Service Controller 现有SSM开发中存在的问题 MVC层的对象(Controller, mvc:annotation-driven/,视图解

    2024年02月05日
    浏览(47)
  • xml系列篇之xml解析

    接下来看看由辉辉所写的关于xml的相关操作吧 目录 🥳🥳Welcome Huihui\\\'s Code World ! !🥳🥳 是什么 为什么要使用 优点 💡辉辉小贴士:xml在数据库辅助类中的应用 💡辉辉小贴士:怎么获取不同位置下的配置文件呢? 怎么使用 1.DOM4J 代码示例 2. XPath 代码示例 3. SAX 4. StAX 5. JAXB

    2024年02月10日
    浏览(52)
  • 38.Python从入门到精通—Python3 XML 解析 什么是 XML Python 对 XML 的解析

    XML(可扩展标记语言)是一种用于描述数据的标记语言,它可以用于表示各种类型的数据,包括文本、图像、音频、视频等。XML 的语法类似于HTML,但它更加灵活,可以自定义标记,并且不依赖于任何特定的应用程序或操作系统。 XML的基本结构由元素、属性和文本组成。元素

    2024年04月11日
    浏览(36)
  • 【JAVA】XML及其解析技术、XML检索技术、设计模式

    XML(Extensible Markup Language)是可扩展标记语言的缩写,它是一种数据表示格式,可以描述复杂的数据结构,常用于传输和存储数据 作用: 用于进行存储数据和传输数据 作为软件的配置文件 第一行是文档声明 ? xml version =\\\"1.0\\\" encoding =\\\"UTF-8\\\" ? version:XML默认的版本号码、该属性是必

    2024年02月11日
    浏览(43)
  • Java实现接收xml格式数据并解析,返回xml格式数据

    需求描述:后端接受xml格式数据,解析出相应数据,并返回xml格式数据。

    2024年02月10日
    浏览(39)
  • QT解析xml文件

    mainwindow.cpp  mainwindow.h

    2024年02月14日
    浏览(35)
  • 解析XML文件

    什么是XML? xml指可扩展语言(extendsible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 xml被设计用来传输和存储数据。 xml是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。 它也是元标记语言,

    2024年02月06日
    浏览(52)
  • Mapper.xml文件解析

     最近在做一个分布式项目,看到xml文件原先只是上网CV,还是要搞清楚吧! 下面是一个Mybatis的SQL映射文件的配置 这个元素定义了命名空间,用于标识这个映射文件对应的接口。在这里,命名空间指向了 cn.itedus.lottery.infrastructure.dao.IActivityDao 这个接口,表示这个映射文件用

    2024年02月10日
    浏览(40)
  • java解析xml文件

    MyContentHandler类继承自DefaultHandler,是一个自定义的内容处理器。在该类中重写了startElement()、endElement()和characters()方法,以处理XML解析的不同事件。

    2024年02月13日
    浏览(46)
  • Jacoco XML 解析

    1. DOM解析器: ○ 优点:易于使用,提供完整的文档树,可以方便地修改和遍历XML文档。 ○ 缺点:对大型文档消耗内存较多,加载整个文档可能会变慢。 ○ 适用场景:适合小型XML文档或需要多次访问和修改XML内容的情况。 2. SAX解析器: ○ 优点:逐个处理XML元素,节省内存

    2024年02月11日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包