acl  3.5.3.0
acl_xml.h
浏览该文件的文档.
1 #ifndef ACL_XML_INCLUDE_H
2 #define ACL_XML_INCLUDE_H
3 
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7 
8 #include "../stdlib/acl_array.h"
9 #include "../stdlib/acl_ring.h"
10 #include "../stdlib/acl_vstream.h"
11 #include "../stdlib/acl_htable.h"
12 #include "../stdlib/acl_vstring.h"
13 #include "../stdlib/acl_iterator.h"
14 #include "../stdlib/acl_dbuf_pool.h"
15 
16 typedef struct ACL_XML ACL_XML;
17 typedef struct ACL_XML_NODE ACL_XML_NODE;
18 typedef struct ACL_XML_ATTR ACL_XML_ATTR;
19 
20 struct ACL_XML_ATTR {
21  ACL_XML_NODE *node; /**< 所属节点 */
22  ACL_VSTRING *name; /**< 属性名 */
23  ACL_VSTRING *value; /**< 属性值 */
24 
25  /* private */
26  int quote; /**< 非 0 表示 ' 或 " */
27  int backslash; /**< 转义字符 \ */
28  int slash; /**< 是否有 '/' 标志位设定 */
29 };
30 
31 struct ACL_XML_NODE {
32  ACL_VSTRING *ltag; /**< 左标签名 */
33  ACL_VSTRING *rtag; /**< 右标签名 */
34  const ACL_VSTRING *id; /**< ID标识符, 只有 xml->id_table
35  存在的节点的 id 才非空 */
36  ACL_VSTRING *text; /**< 文本显示内容 */
37  ACL_ARRAY *attr_list; /**< 属性(ACL_XML_ATTR)列表 */
38  ACL_XML_NODE *parent; /**< 父节点 */
39  ACL_RING children; /**< 子节点集合 */
40  int depth; /**< 当前节点的深度 */
41 
42  /* private */
43  ACL_XML *xml; /**< xml 对象 */
44  ACL_RING node; /**< 当前节点 */
45  ACL_XML_ATTR *curr_attr; /**< 当前正在解析的属性 */
46  int quote; /**< 非 0 表示 ' 或 " */
47  int last_ch; /**< 所记录本节点的前一个字节值 */
48  int nlt; /**< '<' 个数 */
49  char meta[3]; /**< 元数据临时缓冲区 */
50  unsigned int flag;
51 #define ACL_XML_F_META_QM (1 << 0) /**< '?' flag */
52 #define ACL_XML_F_META_CM (1 << 1) /**< '!--' flag */
53 #define ACL_XML_F_META_EM (1 << 2) /**< only '!' flag */
54 #define ACL_XML_F_SELF_CL (1 << 3) /**< self closed flag */
55 #define ACL_XML_F_LEAF (1 << 4) /**< leaf node has no child node */
56 #define ACL_XML_F_CDATA (1 << 5) /**< CDATA data */
57 
58 /**< 是否是元数据 */
59 #define ACL_XML_F_META \
60  (ACL_XML_F_META_QM | ACL_XML_F_META_CM | ACL_XML_F_META_EM)
61 
62 #define ACL_XML_IS_COMMENT(x) (((x)->flag & ACL_XML_F_META_CM))
63 
64 #define ACL_XML_IS_CDATA(x) (((x)->flag & ACL_XML_F_CDATA))
65 
66  int status; /**< 状态机当前解析状态 */
67 #define ACL_XML_S_NXT 0 /**< 下一个节点 */
68 #define ACL_XML_S_LLT 1 /**< 左边 '<' */
69 #define ACL_XML_S_LGT 2 /**< 右边 '>' */
70 #define ACL_XML_S_LCH 3 /**< 左边 '<' 后第一个字节 */
71 #define ACL_XML_S_LEM 4 /**< 左边 '<' 后的 '!' */
72 #define ACL_XML_S_LTAG 5 /**< 左边的标签名 */
73 #define ACL_XML_S_RLT 6 /**< 右边的 '<' */
74 #define ACL_XML_S_RGT 7 /**< 右边的 '>' */
75 #define ACL_XML_S_RTAG 8 /**< 右边的标签名 */
76 #define ACL_XML_S_ATTR 9 /**< 标签属性名 */
77 #define ACL_XML_S_AVAL 10 /**< 标签属性值 */
78 #define ACL_XML_S_TXT 11 /**< 节点文本 */
79 #define ACL_XML_S_MTAG 12 /**< 元数据标签 */
80 #define ACL_XML_S_MTXT 13 /**< 元数据文本 */
81 #define ACL_XML_S_MCMT 14 /**< 元数据注释 */
82 #define ACL_XML_S_MEND 15 /**< 元数据结束 */
83 #define ACL_XML_S_CDATA 16 /**< CDATA 数据 */
84 
85  /* public: for acl_iterator, 通过 acl_foreach 列出该节点的一级子节点 */
86 
87  /* 取迭代器头函数 */
88  ACL_XML_NODE *(*iter_head)(ACL_ITER*, ACL_XML_NODE*);
89  /* 取迭代器下一个函数 */
90  ACL_XML_NODE *(*iter_next)(ACL_ITER*, ACL_XML_NODE*);
91  /* 取迭代器尾函数 */
92  ACL_XML_NODE *(*iter_tail)(ACL_ITER*, ACL_XML_NODE*);
93  /* 取迭代器上一个函数 */
94  ACL_XML_NODE *(*iter_prev)(ACL_ITER*, ACL_XML_NODE*);
95 };
96 
97 struct ACL_XML {
98  /* public */
99  int depth; /**< 最大深度 */
100  int node_cnt; /**< 节点总数, 包括 root 节点 */
101  int root_cnt; /**< 根节点个数 */
102  int attr_cnt; /**< 属性总数 */
103  ACL_XML_NODE *root; /**< XML 根节点 */
104 
105  /* private */
106  ACL_HTABLE *id_table; /**< id 标识符哈希表 */
107  ACL_XML_NODE *curr_node; /**< 当前正在处理的 XML 节点 */
108  ACL_DBUF_POOL *dbuf; /**< 内存池对象 */
109  ACL_DBUF_POOL *dbuf_inner; /**< 内部分布的内存池对象 */
110  size_t dbuf_keep; /**< 内存池中保留的长度 */
111  size_t space; /**< 在创建 xml 对象时已分配的内存大小 */
112 
113  unsigned flag; /**< 标志位: ACL_XML_FLAG_xxx */
114 
115  /**< 是否允许一个 xml 文档中有多个根节点,内部缺省为允许 */
116 #define ACL_XML_FLAG_MULTI_ROOT (1 << 0)
117 
118  /**< 是否兼容单节点中没有 '/' 情况 */
119 #define ACL_XML_FLAG_IGNORE_SLASH (1 << 1)
120 
121  /**< 是否需要对文本数据进行 xml 解码 */
122 #define ACL_XML_FLAG_XML_DECODE (1 << 2)
123 
124  /**< 创建 xml 对象时是否需要对数据进行 xml 编码 */
125 #define ACL_XML_FLAG_XML_ENCODE (1 << 3)
126 
127  ACL_VSTRING *decode_buf; /**< 当需要进行 xml 解码时非空 */
128 
129  /* public: for acl_iterator, 通过 acl_foreach 可以列出所有子节点 */
130 
131  /* 取迭代器头函数 */
132  ACL_XML_NODE *(*iter_head)(ACL_ITER*, ACL_XML*);
133  /* 取迭代器下一个函数 */
134  ACL_XML_NODE *(*iter_next)(ACL_ITER*, ACL_XML*);
135  /* 取迭代器尾函数 */
136  ACL_XML_NODE *(*iter_tail)(ACL_ITER*, ACL_XML*);
137  /* 取迭代器上一个函数 */
138  ACL_XML_NODE *(*iter_prev)(ACL_ITER*, ACL_XML*);
139 };
140 
141 /***************************************************************************/
142 /* 公共函数接口,用户可以放心使用该接口集 */
143 /***************************************************************************/
144 
145 /*----------------------------- in acl_xml.c ------------------------------*/
146 
147 /**
148  * 判断 xml 对象是否闭合的, 即是否所解析的数据是否完整, 如果该 xml 对象里的
149  * xml 节点元素为空, 则也认为不是闭合的
150  * @param xml {ACL_XML*} xml 对象
151  * @return {int} 0: 否; 1: 是
152  */
153 ACL_API int acl_xml_is_closure(ACL_XML *xml);
154 
155 /**
156  * 根据指定标签名判断 xml 解析已经完成, 当该标签与 xml 对象中 root 一级子节点
157  * 中的最后一个 xml 节点的标签相同时, 则认为 xml 解析完成, 为保证判断的正确性,
158  * 数据源应保证最外层的根节点只有一个, 即 xml->root 的一级子节点只有一个, 否则
159  * 会造成误判
160  * @param xml {ACL_XML*} xml 对象
161  * @param tag {const char*} 用户给定标签名, 内部在匹配时不区分大小写
162  * @return {int} 0: 否; 1: 是
163  */
164 ACL_API int acl_xml_is_complete(ACL_XML *xml, const char *tag);
165 
166 /**
167  * 创建一个 xml 对象
168  * @return {ACL_XML*} 新创建的 xml 对象
169  */
170 ACL_API ACL_XML *acl_xml_alloc(void);
171 
172 /**
173  * 创建一个 xml 对象,该 xml 对象及所有的内部内存分配都在该内存池上进行分配
174  * @param dbuf {ACL_DBUF_POOL*} 内存池对象,当该针对非 NULL 时,则 xml 对象
175  * 及所属节点内存在其基础上进行分配,否则,内部自动创建隶属于 xml 的内存池
176  * @return {ACL_XML*} 新创建的 xml 对象
177  */
179 
180 /**
181  * 获得当前 xml 对象内部已经分配的内存空间大小
182  * @param xml {ACL_XML*}
183  * @return {size_t} 当前 xml 对象内部已分配的内存大小
184  */
185 ACL_API size_t acl_xml_space(ACL_XML *xml);
186 
187 /**
188  * 将 xml 对象内部记录内存大小的变量清 0
189  * @param xml {ACL_XML*}
190  */
191 ACL_API void acl_xml_space_clear(ACL_XML *xml);
192 
193 /**
194  * 将某一个 ACL_XML_NODE 节点作为一个 XML 对象的根节点,从而可以方便地遍历出该
195  * 节点各级子节点(在遍历过程中的所有节点不含本节点自身),该遍历方式有别于单独
196  * 遍历某一个 ACL_XML_NODE 节点时仅能遍历其一级子节点的情形
197  * @param xml {ACL_XML*} xml 对象
198  * @param node {ACL_XML_NODE*} AXL_XML_NODE 节点
199  */
200 ACL_API void acl_xml_foreach_init(ACL_XML *xml, ACL_XML_NODE *node);
201 
202 /**
203  * 设置一个 xml 文档中是否允许有多个根 xml 节点,内部缺省支持多个根节点
204  * @param xml {ACL_XML*} xml 对象
205  * @param on {int} 非 0 则允许,为 0 表示不允许,当禁止有多个根 xml 节点时,
206  * 则在解析时当遇到第一个根节点结束时便返回剩余的数据
207  */
208 ACL_API void acl_xml_multi_root(ACL_XML *xml, int on);
209 
210 /**
211  * 对于 XML 单节点的情况, 是否允许可以没有 /, 如:
212  * <test id=111>, <test id=111 />, 当可以允许没有 / 则这两种写法
213  * 都是合法的,否则只有第二个写法是合法的,如果允许这种兼容性,则
214  * 会造成一定的性能损失
215  * @param xml {ACL_XML*} xml 对象
216  * @param ignore {int} 如果非 0 表示单节点必须有 /
217  */
218 ACL_API void acl_xml_slash(ACL_XML *xml, int ignore);
219 
220 /**
221  * 解析 xml 对象时是否对属性值及文本值进行 xml 解码,内部缺省解码
222  * @param xml {ACL_XML*}
223  * @param on {int} 非 0 表示进行 xml 解码
224  */
225 ACL_API void acl_xml_decode_enable(ACL_XML *xml, int on);
226 
227 /**
228  * 创建 xml 对象时是否对属性值及文本值进行 xml 编码,内部缺省编码
229  */
230 ACL_API void acl_xml_encode_enable(ACL_XML *xml, int on);
231 
232 /**
233  * 释放一个 xml 对象, 同时释放该对象里容纳的所有 xml 节点
234  * @param xml {ACL_XML*} xml 对象
235  * @return {int} 返回释放的 xml 节点个数
236  */
237 ACL_API int acl_xml_free(ACL_XML *xml);
238 
239 /**
240  * 重置 XML 解析器对象
241  * @param xml {ACL_XML*} xml 对象
242  */
243 ACL_API void acl_xml_reset(ACL_XML *xml);
244 
245 /*------------------------- in acl_xml_parse.c ----------------------------*/
246 
247 /**
248  * 解析 xml 数据, 并持续地自动生成 xml 节点树
249  * @param xml {ACL_XML*} xml 对象
250  * @param data {const char*} 以 '\0' 结尾的数据字符串, 可以是完整的 xml 数据;
251  * 也可以是不完整的 xml 数据, 允许循环调用此函数, 将不完整数据持续地输入
252  * @return {const char*} 当通过 acl_xml_multi_root 允许一个 xml 文档中在在
253  * 多个根 xml 节点时,该函数返回的地址的字节为 '\0'; 否则返回剩余的数据地址
254  * 包含非空字符串
255  * 注:也可以通过 acl_xml_is_complete 判断是否解析完毕
256  */
257 ACL_API const char *acl_xml_update(ACL_XML *xml, const char *data);
258 #define acl_xml_parse acl_xml_update
259 
260 /*------------------------- in acl_xml_util.c -----------------------------*/
261 
262 /**
263  * 初始化类似于 input, br, hr 等的自闭合标签, 形成自闭合标签树, 以便于
264  * acl_xml_tag_selfclosed 查询该树, 检查所给标签是否是保留的自闭合标签,
265  * 该函数只能被初始化一次, 也可以不初始化
266  */
267 ACL_API void acl_xml_tag_init(void);
268 
269 /**
270  * 允许用户自己添加一些非自闭合的标签
271  * @param tag {const char*} 标签名,注意标签长度不得大于 254 个字节
272  */
273 ACL_API void acl_xml_tag_add(const char *tag);
274 
275 /**
276  * 当调用 acl_xml_tag_init 初始化保留的自闭合标签树后, 可以调用此函数判断所给
277  * 标签是否属于自闭合标签, 如果未调用 acl_xml_tag_init, 则该函数永远返回 0
278  * @parma tag {const char*} 标签名称
279  * @return {int} 0: 表示否, 1: 表示是
280  */
281 ACL_API int acl_xml_tag_selfclosed(const char *tag);
282 
283 /**
284  * 判断标签所属 xml 节点是否是叶节点, 叶节点没有子节点
285  * @param tag {const char*} 标签名
286  * @return {int} 0: 不是叶节点; 1: 是叶节点
287  */
288 ACL_API int acl_xml_tag_leaf(const char *tag);
289 
290 /**
291  * 释放由 acl_xml_getElementsByTagName, acl_xml_getElementsByName,
292  * acl_xml_getElementsByAttr 等函数返回的动态数组对象, 因为该动态数组中的
293  * 元素都是 ACL_XML 对象中元素的引用, 所以释放掉该动态数组后, 只要 ACL_XML
294  * 对象不释放, 则原来存于该数组中的元素依然可以使用.
295  * 但并不释放里面的 xml 节点元素
296  * @param a {ACL_ARRAY*} 动态数组对象
297  */
298 ACL_API void acl_xml_free_array(ACL_ARRAY *a);
299 
300 /**
301  * 从 xml 对象中获得与所给标签名相同的 xml 第一个节点
302  * @param xml {ACL_XML*} xml 对象
303  * @param tag {const char*} 标签名称
304  * @return {ACL_XML_NODE*} 符合条件的 xml 节点, 若返回 NULL 则
305  * 表示没有符合条件的 xml 节点
306  */
308  ACL_XML *xml, const char *tag);
309 
310 /**
311  * 从 xml 对象中获得所有的与所给标签名相同的 xml 节点的集合
312  * @param xml {ACL_XML*} xml 对象
313  * @param tag {const char*} 标签名称
314  * @return {ACL_ARRAY*} 符合条件的 xml 节点集合, 存于 动态数组中, 若返回 NULL 则
315  * 表示没有符合条件的 xml 节点, 非空值需要调用 acl_xml_free_array 释放
316  */
318  ACL_XML *xml, const char *tag);
319 
320 /**
321  * 从 xml 对象中获得所有的与给定多级标签名相同的 xml 节点的集合
322  * @param xml {ACL_XML*} xml 对象
323  * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据:
324  * <root> <first> <second> <third name="test1"> text1 </third> </second> </first>
325  * <root> <first> <second> <third name="test2"> text2 </third> </second> </first>
326  * <root> <first> <second> <third name="test3"> text3 </third> </second> </first>
327  * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的节点
328  * @return {ACL_ARRAY*} 符合条件的 xml 节点集合, 存于 动态数组中, 若返回 NULL 则
329  * 表示没有符合条件的 xml 节点, 非空值需要调用 acl_xml_free_array 释放
330  */
331 ACL_API ACL_ARRAY *acl_xml_getElementsByTags(ACL_XML *xml, const char *tags);
332 
333 /**
334  * 从 xml 对象中获得所有的与给定属性名 name 的属性值相同的 xml 节点元素集合
335  * @param xml {ACL_XML*} xml 对象
336  * @param value {const char*} 属性名为 name 的属性值
337  * @return {ACL_ARRAY*} 符合条件的 xml 节点集合, 存于 动态数组中, 若返回 NULL 则
338  * 表示没有符合条件的 xml 节点, 非空值需要调用 acl_xml_free_array 释放
339  */
340 ACL_API ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value);
341 
342 /**
343  * 从 xml 对象中获得所有给定属性名及属性值的 xml 节点元素集合
344  * @param xml {ACL_XML*} xml 对象
345  * @param name {const char*} 属性名
346  * @param value {const char*} 属性值
347  * @return {ACL_ARRAY*} 符合条件的 xml 节点集合, 存于 动态数组中, 若返回 NULL 则
348  * 表示没有符合条件的 xml 节点, 非空值需要调用 acl_xml_free_array 释放
349  */
351  const char *name, const char *value);
352 
353 /**
354  * 从 xml 对象中获得指定 id 值的 xml 节点元素的某个属性对象
355  * @param xml {ACL_XML*} xml 对象
356  * @param id {const char*} id 值
357  * @return {ACL_XML_ATTR*} 某 xml 节点的某个属性对象, 若返回 NULL 则表示
358  * 没有符合条件的属性, 返回值不需要释放
359  */
360 ACL_API ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id);
361 
362 /**
363  * 从 xml 对象中获得指定 id 值的 xml 节点元素的某个属性值
364  * @param xml {ACL_XML*} xml 对象
365  * @param id {const char*} id 值
366  * @return {const char*} 某 xml 节点的某个属性值, 若返回 NULL 则表示没有符合
367  * 条件的属性
368  */
369 ACL_API const char *acl_xml_getAttrValueById(ACL_XML *xml, const char *id);
370 
371 /**
372  * 从 xml 对象中获得指定 id 值的 xml 节点元素
373  * @param xml {ACL_XML*} xml 对象
374  * @param id {const char*} id 值
375  * @return {ACL_XML_NODE*} xml 节点元素, 若返回 NULL 则表示没有符合
376  * 条件的 xml 节点, 返回值不需要释放
377  */
378 ACL_API ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id);
379 
380 /**
381  * 从 xml 对象中提取有在 ? ! 等开头的节点
382  * @param xml {ACL_XML*} xml 对象
383  * @param tag {const char*} 标签名
384  * @return {ACL_XML_NODE*} xml 节点元素, 若返回 NULL 则表示没有符合
385  * 条件的 xml 节点, 返回值不需要释放
386  */
387 ACL_API ACL_XML_NODE *acl_xml_getElementMeta(ACL_XML *xml, const char *tag);
388 
389 /**
390  * 获得 xml 的字符集编码格式
391  * @param xml {ACL_XML*} xml 对象
392  * @return {const char*} 返回字符集编码格式,返回 NULL 时表示没有该属性
393  */
394 ACL_API const char *acl_xml_getEncoding(ACL_XML *xml);
395 
396 /**
397  * 获得 xml 数据的类型,如:text/xsl
398  * @param xml {ACL_XML*} xml 对象
399  * @return {const char*} 返回 NULL 表示没有该属性
400  */
401 ACL_API const char *acl_xml_getType(ACL_XML *xml);
402 
403 /**
404  * 从 xml 节点中获得指定属性名的属性对象
405  * @param node {ACL_XML_NODE*} xml 节点
406  * @param name {const char*} 属性名称
407  * @return {ACL_XML_ATTR*} 属性对象, 为空表示不存在, 返回值不需要释放
408  */
409 ACL_API ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name);
410 
411 /**
412  * 从 xml 节点中获得指定属性名的属性值
413  * @param node {ACL_XML_NODE*} xml 节点
414  * @param name {const char*} 属性名称
415  * @return {const char*} 属性值, 为空表示不存在
416  */
417 ACL_API const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name);
418 
419 /**
420  * 从 xml 节点删除某个属性对象, 如果该属性为 id 属性, 则同时会从 xml->id_table 中删除
421  * @param node {ACL_XML_NODE*} xml 节点
422  * @param name {const char*} 属性名称
423  * @return {int} 0 表示删除成功, -1: 表示删除失败(有可能是该属性不存在)
424  */
425 ACL_API int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name);
426 
427 /**
428  * 给 xml 节点添加属性, 如果该属性名已存在, 则用新的属性值替换其属性值, 否则
429  * 创建并添加新的属性对象
430  * @param node {ACL_XML_NODE*} xml 节点
431  * @param name {const char*} 属性名称
432  * @param value {const char*} 属性值
433  * @return {ACL_XML_ATTR*} 返回该属性对象(有可能是原来的, 也有可能是新的),
434  * 返回值不需释放
435  */
437  const char *name, const char *value);
438 
439 /**
440  * 将标签名及节点文本做为参数创建 xml 节点,该函数主要用在构建 xml 对象时
441  * @param xml {ACL_XML*} xml 对象,该对象应该是由 acl_xml_alloc 创建的
442  * @param tagname {const char*} 标签名,必须非空且字符串长度大于 0
443  * @param text {const char*} 节点的文本内容,可以为空
444  * @return {ACL_XML_NODE*} 新创建的 xml 节点,该返回永远返回非空,如果输入
445  * 参数非法则会导致内部自动产生断言
446  */
448  const char* tagname, const char* text);
449 
450 /**
451  * 创建 xml 节点,使用文件流做为节点的文本内容项,同时会自动进行 XML 编码处理
452  * @param xml {ACL_XML*} xml 对象
453  * @param tag {const char*} 标签名,非 NULL 字符串
454  * @param in {ACL_VSTREAM *} 输入流,非 NULL 时,其中内容将做为 xml 节点的文本内容
455  * @param off {size_t} 当 in 为文件流时指定所拷贝内容在文件中的起始位置
456  * @param len {size_t} 指定从输入流中拷贝的最大数据长度,当为 0 时则一直拷贝至流结束
457  * @return {ACL_XML_NODE*} 返回新创建的 xml 节点,永远返回非 NULL 对象,
458  * 如果输入参数非法则内部产生断言
459  */
461  const char *tag, ACL_VSTREAM *in, size_t off, size_t len);
462 
463 /**
464  * 给一个 xml 节点添加属性,该函数主要用在构建 xml 对象时
465  * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的节点
466  * @param name {const char*} 属性名,必须为非空字符串且字符串长度大于 0
467  * @param value {const char*} 属性值,可以为空
468  * @return {ACL_XML_ATTR*} xml 节点的属性对象,当输入参数非法时该函数
469  * 内部自动产生断言
470  */
472  const char *name, const char *value);
473 
474 /**
475  * 给一个 xml 节点添加一组属性,该函数主要用在构建 xml 对象时
476  * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的节点
477  * @param ... 一组属性,遇到 NULL 时表示结束,如:
478  * {name1}, {value1}, {name2}, {value2}, ... NULL
479  */
480 ACL_API void acl_xml_node_add_attrs(ACL_XML_NODE *node, ...);
481 
482 /**
483  * 给一个 xml 节点添加文本内容,该函数主要用在构建 xml 对象时,当该节点之前有文本内容时
484  * 则用新文本覆盖原文本
485  * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的节点
486  * @param text {const char*} 文本内容
487  */
488 ACL_API void acl_xml_node_set_text(ACL_XML_NODE *node, const char *text);
489 
490 /**
491 * 给一个 xml 节点的文本追加内容,该函数主要用在构建 xml 对象时,在该节点的文本内容上
492 * 追加新的文本内容
493 * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的节点
494 * @param text {const char*} 文本内容
495  */
496 ACL_API void acl_xml_node_add_text(ACL_XML_NODE *node, const char *text);
497 
498 /**
499  * 用文件流中的内容给一个 xml 节点添加文本内容
500  * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的节点
501  * @param fp {ACL_VSTREAM*} 输入流对象
502  * @param off {size_t} 当 in 为文件流,指定在文件中的起始位置
503  * @param len {size_t} 要拷贝的最大数据长度,当为 0 时则一直拷贝至流结束
504  */
505 ACL_API void acl_xml_node_set_text_stream(ACL_XML_NODE *node,
506  ACL_VSTREAM *fp, size_t off, size_t len);
507 
508 /**
509  * 将 xml 对象转成字符串内容
510  * @param xml {ACL_XML*} xml 对象
511  * @param buf {ACL_VSTRING*} 存储结果集的缓冲区,当该参数为空时则函数内部会
512  * 自动分配一段缓冲区,应用用完后需要释放掉;非空函数内部会直接将结果存储其中
513  * @return {ACL_VSTRING*} xml 对象转换成字符串后的存储缓冲区,该返回值永远非空,
514  * 使用者可以通过 ACL_VSTRING_LEN(x) 宏来判断内容是否为空,返回的 ACL_VSTRING
515  * 指针如果为该函数内部创建的,则用户名必须用 acl_vstring_free 进行释放
516  */
517 ACL_API ACL_VSTRING* acl_xml_build(ACL_XML* xml, ACL_VSTRING *buf);
518 
519 /**
520  * 将 xml 对象转储于指定流中,注:该转储信息仅为调试用的数据
521  * @param xml {ACL_XML*} xml 对象
522  * @param fp {ACL_VSTREAM*} 流对象
523  */
524 ACL_API void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp);
525 
526 /**
527  * 将 xml 对象转存于指定缓冲区中,注:该转储信息仅为调试用的数据
528  * @param xml {ACL_XML*} xml 对象
529  * @param buf {ACL_VSTRING*} 缓冲区, 需要用户自己分配空间
530  */
531 ACL_API void acl_xml_dump2(ACL_XML *xml, ACL_VSTRING *buf);
532 
533 /***************************************************************************/
534 /* 以下为更为低级的接口, 用户可以根据需要调用以下接口 */
535 /***************************************************************************/
536 
537 /*----------------------------- in acl_xml.c ------------------------------*/
538 
539 /**
540  * 创建 xml 节点的属性
541  * @param node {ACL_XML_NODE*} xml 节点
542  * @return {ACL_XML_ATTR*} 新创建的节点属性
543  */
545 
546 /**
547  * 创建一个 xml 节点
548  * @param xml {ACL_XML*} xml 对象
549  * @return {ACL_XML_NODE*} xml 节点对象
550  */
552 
553 /**
554  * 将某个 xml 节点及其子节点从 xml 对象中删除, 并释放该节点及其子节点所占空间
555  * 函数来释放该 xml 节点所占内存
556  * @param node {ACL_XML_NODE*} xml 节点
557  * @return {int} 返回删除的节点个数
558  */
559 ACL_API int acl_xml_node_delete(ACL_XML_NODE *node);
560 
561 /**
562  * 向某个 xml 节点添加兄弟节点(该兄弟节点必须是独立的 xml 节点)
563  * @param node1 {ACL_XML_NODE*} 向本节点添加 xml 节点
564  * @param node2 {ACL_XML_NODE*} 新添加的兄弟 xml 节点
565  */
566 ACL_API void acl_xml_node_append(ACL_XML_NODE *node1, ACL_XML_NODE *node2);
567 
568 /**
569  * 将某个 xml 节点作为子节点加入某父 xml 节点中
570  * @param parent {ACL_XML_NODE*} 父节点
571  * @param child {ACL_XML_NODE*} 子节点
572  */
573 ACL_API void acl_xml_node_add_child(ACL_XML_NODE *parent, ACL_XML_NODE *child);
574 
575 /**
576  * 获得某个 xml 节点的父节点
577  * @param node {ACL_XML_NODE*} xml 节点
578  * @return {ACL_XML_NODE*} 父节点, 如果为 NULL 则表示其父节点不存在
579  */
581 
582 /**
583  * 获得某个 xml 节点的后一个兄弟节点
584  * @param node {ACL_XML_NODE*} xml 节点
585  * @return {ACL_XML_NODE*} 给定 xml 节点的后一个兄弟节点, 若为NULL则表示不存在
586  */
588 
589 /**
590  * 获得某个 xml 节点的前一个兄弟节点
591  * @param node {ACL_XML_NODE*} xml 节点
592  * @return {ACL_XML_NODE*} 给定 xml 节点的前一个兄弟节点, 若为NULL则表示不存在
593  */
595 
596 #ifdef __cplusplus
597 }
598 #endif
599 #endif
ACL_XML_ATTR * curr_attr
Definition: acl_xml.h:45
ACL_DBUF_POOL * dbuf
Definition: acl_xml.h:108
ACL_API ACL_XML_ATTR * acl_xml_addElementAttr(ACL_XML_NODE *node, const char *name, const char *value)
ACL_API void acl_xml_decode_enable(ACL_XML *xml, int on)
int quote
Definition: acl_xml.h:26
int attr_cnt
Definition: acl_xml.h:102
ACL_API int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name)
ACL_API void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp)
ACL_API void acl_xml_dump2(ACL_XML *xml, ACL_VSTRING *buf)
HTTP_API void const char * name
Definition: lib_http.h:620
unsigned flag
Definition: acl_xml.h:113
ACL_API ACL_XML_NODE * acl_xml_node_parent(ACL_XML_NODE *node)
ACL_API void acl_xml_tag_init(void)
ACL_API ACL_XML_ATTR * acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name)
size_t space
Definition: acl_xml.h:111
ACL_DBUF_POOL * dbuf_inner
Definition: acl_xml.h:109
ACL_API void acl_xml_encode_enable(ACL_XML *xml, int on)
const ACL_VSTRING * id
Definition: acl_xml.h:34
ACL_API void acl_xml_node_add_attrs(ACL_XML_NODE *node,...)
int quote
Definition: acl_xml.h:46
ACL_API void acl_xml_free_array(ACL_ARRAY *a)
ACL_RING node
Definition: acl_xml.h:44
ACL_HTABLE * id_table
Definition: acl_xml.h:106
ACL_API ACL_XML_NODE * acl_xml_create_node(ACL_XML *xml, const char *tagname, const char *text)
ACL_XML * xml
Definition: acl_xml.h:43
int depth
Definition: acl_xml.h:99
ACL_API ACL_ARRAY * acl_xml_getElementsByName(ACL_XML *xml, const char *value)
ACL_API int acl_xml_is_complete(ACL_XML *xml, const char *tag)
ACL_API ACL_XML_NODE * acl_xml_getElementById(ACL_XML *xml, const char *id)
ACL_XML_NODE * root
Definition: acl_xml.h:103
ACL_API void acl_xml_node_set_text(ACL_XML_NODE *node, const char *text)
ACL_VSTRING * name
Definition: acl_xml.h:22
ACL_API ACL_VSTRING * acl_xml_build(ACL_XML *xml, ACL_VSTRING *buf)
ACL_XML_NODE * curr_node
Definition: acl_xml.h:107
ACL_API size_t acl_xml_space(ACL_XML *xml)
int slash
Definition: acl_xml.h:28
ACL_API ACL_XML * acl_xml_alloc(void)
ACL_API void acl_xml_multi_root(ACL_XML *xml, int on)
int status
Definition: acl_xml.h:66
ACL_API const char * acl_xml_update(ACL_XML *xml, const char *data)
ACL_API const char * acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name)
ACL_API int acl_xml_is_closure(ACL_XML *xml)
unsigned int flag
Definition: acl_xml.h:50
ACL_VSTRING * text
Definition: acl_xml.h:36
ACL_API ACL_XML_NODE * acl_xml_getFirstElementByTagName(ACL_XML *xml, const char *tag)
int node_cnt
Definition: acl_xml.h:100
ACL_API ACL_XML_NODE * acl_xml_getElementMeta(ACL_XML *xml, const char *tag)
ACL_ARRAY * attr_list
Definition: acl_xml.h:37
ACL_API void acl_xml_node_add_text(ACL_XML_NODE *node, const char *text)
int backslash
Definition: acl_xml.h:27
ACL_API ACL_ARRAY * acl_xml_getElementsByTags(ACL_XML *xml, const char *tags)
ACL_API ACL_XML_ATTR * acl_xml_node_add_attr(ACL_XML_NODE *node, const char *name, const char *value)
ACL_API int acl_xml_tag_selfclosed(const char *tag)
ACL_XML_NODE * node
Definition: acl_xml.h:21
ACL_API ACL_XML_NODE * acl_xml_node_alloc(ACL_XML *xml)
int last_ch
Definition: acl_xml.h:47
struct ACL_DBUF_POOL ACL_DBUF_POOL
Definition: acl_dbuf_pool.h:8
ACL_API const char * acl_xml_getAttrValueById(ACL_XML *xml, const char *id)
ACL_API void acl_xml_slash(ACL_XML *xml, int ignore)
ACL_API ACL_ARRAY * acl_xml_getElementsByAttr(ACL_XML *xml, const char *name, const char *value)
int root_cnt
Definition: acl_xml.h:101
ACL_VSTRING * decode_buf
Definition: acl_xml.h:127
ACL_API void acl_xml_space_clear(ACL_XML *xml)
size_t dbuf_keep
Definition: acl_xml.h:110
ACL_API int acl_xml_tag_leaf(const char *tag)
ACL_API int acl_xml_free(ACL_XML *xml)
ACL_API void acl_xml_tag_add(const char *tag)
ACL_API void acl_xml_node_append(ACL_XML_NODE *node1, ACL_XML_NODE *node2)
ACL_API const char * acl_xml_getEncoding(ACL_XML *xml)
ACL_API void acl_xml_node_add_child(ACL_XML_NODE *parent, ACL_XML_NODE *child)
ACL_API void acl_xml_node_set_text_stream(ACL_XML_NODE *node, ACL_VSTREAM *fp, size_t off, size_t len)
ACL_API int acl_xml_node_delete(ACL_XML_NODE *node)
ACL_API ACL_XML_NODE * acl_xml_create_node_with_text_stream(ACL_XML *xml, const char *tag, ACL_VSTREAM *in, size_t off, size_t len)
ACL_API ACL_XML_ATTR * acl_xml_getAttrById(ACL_XML *xml, const char *id)
ACL_VSTRING * ltag
Definition: acl_xml.h:32
ACL_API ACL_XML * acl_xml_dbuf_alloc(ACL_DBUF_POOL *dbuf)
ACL_RING children
Definition: acl_xml.h:39
ACL_API void acl_xml_foreach_init(ACL_XML *xml, ACL_XML_NODE *node)
ACL_VSTRING * rtag
Definition: acl_xml.h:33
ACL_API ACL_XML_ATTR * acl_xml_attr_alloc(ACL_XML_NODE *node)
ACL_API ACL_ARRAY * acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag)
ACL_API ACL_XML_NODE * acl_xml_node_next(ACL_XML_NODE *node)
char meta[3]
Definition: acl_xml.h:49
ACL_XML_NODE * parent
Definition: acl_xml.h:38
ACL_API const char * acl_xml_getType(ACL_XML *xml)
ACL_VSTRING * value
Definition: acl_xml.h:23
ACL_API ACL_XML_NODE * acl_xml_node_prev(ACL_XML_NODE *node)
ACL_API void acl_xml_reset(ACL_XML *xml)
int depth
Definition: acl_xml.h:40