varch/doc/xml.md
2024-07-21 19:02:13 +08:00

273 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 介绍
C语言xml解释器。包含xml文本文件解析和生成适合大部分的C语言平台。
## 使用例子
### 生成
**测试代码**
```c
void test_write(void)
{
xml_t root, x;
root = xml_create("root");
if (!root) return;
x = xml_create("name");
xml_set_text(x, "xml parser");
xml_insert(root, 0, x);
x = xml_create("description");
xml_set_text(x, "This is a C language version of xml parser.");
xml_insert(root, 1, x);
x = xml_create("license");
xml_set_text(x, "GPL3.0");
xml_insert(root, 2, x);
xml_file_dump(root, "write.xml");
xml_delete(root);
}
```
生成文件名: **write.xml**
```xml
<root>
<name>xml parser</name>
<description>This is a C language version of xml parser.</description>
<license>GPL3.0</license>
</root>
```
### 解析
文件名: **read.xml**
```xml
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="CHILDREN">
<title>Harry Potter</title>
<author>J K.Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title>Learning XML</title>
<author>Erik T.Ray</author>
<year>2004</year>
<price>39.95</price>
</book>
</bookstore>
```
**测试代码**
```c
void test_read(void)
{
xml_t root, x;
root = xml_file_load(READ_FILE);
if (!root) return;
printf("load success!\r\n");
x = xml_to(root, "book", 1);
printf("x attr: %s\r\n", xml_get_attribute(x, NULL, 0));
x = xml_to(x, "author", 0);
printf("author: %s\r\n", xml_get_text(x));
xml_delete(root);
}
```
**打印结果**
```
load success!
x attr: WEB
author: Erik T.Ray
```
## xml语法
### xml文档必须有根元素
xml必须包含根元素它是所有其他元素的父元素比如以下实例中 root 就是根元素:
```xml
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
```
### XML声明
XML 声明文件的可选部分,如果存在需要放在文档的第一行,如下所示:
```xml
<?xml version="1.0" encoding="utf-8"?>
```
* 该xml只是支持这个声明的解析没实际应用解析版本和编码
### 所有的 XML 元素都必须有一个关闭标签
在 XML 中,省略关闭标签是非法的。所有元素都必须有关闭标签:
```xml
<p>This is a paragraph.</p>
```
### XML 标签对大小写敏感
XML 标签对大小写敏感。标签 <Letter> 与标签 <letter> 是不同的。
必须使用相同的大小写来编写打开标签和关闭标签:
```xml
<Message>这是错误的</message>
<message>这是正确的</message>
```
### XML 必须正确嵌套
在 XML 中,所有元素都必须彼此正确地嵌套:
```xml
<b><i>This text is bold and italic</i></b>
```
### XML 属性值必须加引号
在 XML 中XML 的属性值必须加引号。
```xml
<note date=12/11/2007>
<to>Tove</to>
<from>Jani</from>
</note>
```
```xml
<note date="12/11/2007">
<to>Tove</to>
<from>Jani</from>
</note>
```
在第一个文档中的错误是note 元素中的 date 属性没有加引号。
### 实体引用
在 XML 中,一些字符拥有特殊的意义。
如果您把字符 "<" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。
这样会产生 XML 错误:
```xml
<message>if salary < 1000 then</message>
```
为了避免这个错误,请用实体引用来代替 "<" 字符:
```xml
<message>if salary &lt; 1000 then</message>
```
在 XML 中,有 5 个预定义的实体引用:
| | | |
|:--------:|:-:|:--------------:|
| `&lt;` | < | less than |
| `&gt;` | > | greater than |
| `&amp;` | & | ampersand |
| `&apos;` | ' | apostrophe |
| `&quot;` | " | quotation mark |
注释:在 XML 中,只有字符 "<" 和 "&" 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。
## 操作方法
### 常用方法
#### xml解析
方法原型
```c
xml_t xml_loads(const char* text);
xml_t xml_file_load(const char* filename);
```
`xml_loads`函数传进xml文本信息则可以返回解析出来的xml对象句柄。 `xml_file_load`函数则是直接传入文件名即可加载文件返回xml对象函数内部通过C语言标准文件操作函数集对文件进行读取然后套用`xml_loads`函数进行解析支持utf8编码文件。
#### xml生成
方法原型
```c
char* xml_dumps(xml_t xml, int preset, int unformat, int* len);
int xml_file_dump(xml_t xml, char* filename);
```
`xml_dumps`函数将xml对象转换成文本信息其中`preset`为预置的文本长度,预置的长度和最终输出文本长度接近则可以减小内存重分配的次数而提高转换效率;`unformat`是否不采用格式化输出,不采用格式化则文本会挤在一行;`len`是转换的输出长度。
`xml_file_dump`函数套用了`xml_dumps`函数将文本信息存储到指定名字的文件。
#### xml创建对象和删除对象
方法原型
```c
xml_t xml_create(void);
void xml_delete(xml_t xml);
```
`xml_create`创建返回一个空xml对象返回NULL即失败。`xml_delete`则是删除xml对象。
#### xml获取子对象
方法原型
```c
xml_t xml_to(xml_t xml, const char *name, int index);
```
在xml对象中name是不查重的也就是在同一个层级的xml中可能存在多个同名的name`xml_to`方法则是可以用于匹配特定的name。此函数当`name`传入NULL时则只有index起作用按照索引来匹配子对象当`name`不为NULL的时候则只会匹配相应key的子对象并通过index来指示匹配第几个名为`name`的对象。
```c
t = xml_to(xml, NULL, 3); // 找索引为3的子对象
t = xml_to(xml, "a", 3); // 找键为"a"索引为3的子对象
```
#### xml设置和获取文本
方法原型
```c
int xml_set_text(xml_t xml, const char *text);
const char* xml_get_text(xml_t xml);
```
这两个方法分别设置xml的文本和获取xml文本。
#### xml添加和移除属性
方法原型
```c
int xml_add_attribute(xml_t xml, const char *name, const char *value);
int xml_remove_attribute(xml_t xml, const char *name, int index);
```
`xml_add_attribute`会在xml的首位置添加一个`name`对应`value`的属性。
`xml_remove_attribute`则类似`xml_to`的匹配逻辑,移除特定的属性。
这两个方法操作成功返回1失败返回0。
### xml获取属性
```c
const char* xml_get_attribute(xml_t xml, const char *name, int index);
```
类似`xml_to`的匹配逻辑获取相应的属性值。
#### xml插入和删除子对象
方法原型
```c
int xml_insert(xml_t xml, int index, xml_t ins);
int xml_remove(xml_t xml, const char *name, int index);
```
`xml_insert`方法是将创建后的对象按照索引插入到另一个对象中。
`xml_remove`方法和`xml_remove_attribute`类似移除特定的子对象。
这两个方法操作成功返回1失败返回0。
#### xml解析报错
错误类型包含以下几种
```c
#define XML_E_OK 0 // ok
#define XML_E_TEXT 1 // empty text
#define XML_E_MEMORY 2 // memory
#define XML_E_LABEL 3 // label
#define XML_E_VERSION 4 // version
#define XML_E_ENCODING 5 // encoding
#define XML_E_ILLEGAL 6 // illegal character
#define XML_E_END 7 // end
#define XML_E_VALUE 8 // missing value
#define XML_E_QUOTE 9 // missing quete
#define XML_E_COMMENT 10 // missing comment tail -->
#define XML_E_NOTES 11 // head notes error
#define XML_E_CDATA 12 // missing comment tail ]]>
```