acl  3.5.3.0
xml.hpp
浏览该文件的文档.
1 #pragma once
2 #include "../acl_cpp_define.hpp"
3 #include <vector>
4 #include <list>
5 #include "dbuf_pool.hpp"
6 #include "string.hpp"
7 #include "pipe_stream.hpp"
8 
9 struct ACL_TOKEN;
10 struct ACL_ITER;
11 
12 /**
13  * 对 ACL 库中 XML 解析库的封装,方便 C++ 用户使用,如果不太注重性能因素,
14  * 可以直接使用该类,如果在服务端执行且非常注重性能,建议直接使用 ACL 库的
15  * XML 解析器,因为该类也是调用了 ACL 库中的 XML 解析过程,并且有二次拷贝
16  * 过程,可能会稍微影响一些性能,但对于一般的应用这点影响是微不足道的
17  */
18 
19 namespace acl {
20 
21 class xml;
22 class xml_node;
23 class istream;
24 
26 {
27 public:
28  /**
29  * 获得属性名
30  * @return {const char*} 属性名,永远不会返回空指针,返回值
31  * 有可能为 "\0"
32  */
33  virtual const char* get_name(void) const = 0;
34 
35  /**
36  * 获得属性值
37  * @return {const char*} 属性值,永远不会返回空指针,返回值
38  * 有可能为 "\0"
39  */
40  virtual const char* get_value(void) const = 0;
41 
42 protected:
43  friend class xml_node;
44 
45  xml_attr(xml_node* node) : node_(node) {}
46  virtual ~xml_attr(void) {}
47 
49 };
50 
52 {
53 public:
54  /**
55  * 取得本 XML 节点的标签名
56  * @return {const char*} 返回 XML 节点标签名,如果返回空,则说明
57  * 不存在标签 xxxx,以防万一,调用者需要判断返回值
58  */
59  virtual const char* tag_name(void) const = 0;
60 
61  /**
62  * 如果该 XML 节点的 ID 号属性不存在,则返回空指针
63  * @return {const char*} 当 ID 属性存在时返回对应的值,否则返回空
64  */
65  virtual const char* id(void) const = 0;
66 
67  /**
68  * 返回该 XML 节点的正文内容
69  * @return {const char*} 返回空说明没有正文内容
70  */
71  virtual const char* text(void) const = 0;
72 
73  /**
74  * 返回该 XML 节点的某个属性值
75  * @param name {const char*} 属性名
76  * @return {const char*} 属性值,如果返回空则说明该属性不存在
77  */
78  virtual const char* attr_value(const char* name) const = 0;
79 
80  /**
81  * 返回该 XML 节点的某个属性值的便捷写法
82  * @param name {const char*} 属性名
83  * @return {const char*} 属性值,如果返回空则说明该属性不存在
84  */
85  const char* operator[](const char* name) const;
86 
87  /**
88  * 遍历节点的所有属性时,需要调用此函数来获得第一个属性对象
89  * @return {const xml_attr*} 返回第一个属性对象,若为空,则表示
90  * 该节点没有属性
91  */
92  virtual const xml_attr* first_attr(void) const = 0;
93 
94  /**
95  * 遍历节点的所有属性时,调用本函数获得下一个属性对象
96  * @return {const xml_attr*} 返回下一下属性对象,若为空,则表示
97  * 遍历完毕
98  */
99  virtual const xml_attr* next_attr(void) const = 0;
100 
101  /**
102  * 添加 XML 节点属性
103  * @param name {const char*} 属性名
104  * @param value {const char*} 属性值
105  * @return {xml_node&}
106  */
107  virtual xml_node& add_attr(const char* name, const char* value) = 0;
108 
109  /**
110  * 添加 XML 节点属性
111  * @param name {const char*} 属性名
112  * @param n {char} 属性值
113  * @return {xml_node&}
114  */
115  xml_node& add_attr(const char* name, char n);
116 
117  /**
118  * 添加 XML 节点属性
119  * @param name {const char*} 属性名
120  * @param n {int} 属性值
121  * @return {xml_node&}
122  */
123  xml_node& add_attr(const char* name, int n);
124 
125  /**
126  * 添加 XML 节点属性
127  * @param name {const char*} 属性名
128  * @param n {size_t} 属性值
129  * @return {xml_node&}
130  */
131  xml_node& add_attr(const char* name, size_t n);
132 
133  /**
134  * 添加 XML 节点属性
135  * @param name {const char*} 属性名
136  * @param n {acl_int64} 属性值
137  * @return {xml_node&}
138  */
139 #if defined(_WIN32) || defined(_WIN64)
140  xml_node& add_attr(const char* name, __int64 n);
141 #else
142  xml_node& add_attr(const char* name, long long int n);
143 #endif
144 
145  /**
146  * 设置 xml 节点的文本内容
147  * @param str {const char*} 字符串内容
148  * @param append {bool} 添加文本时是采用追加模式还是覆盖模式,如果为追加模式,
149  * 则当原来该节点上有文本内容时,新添加的内容在原文本后面追加,否则则覆盖
150  * @return {xml_node&}
151  */
152  virtual xml_node& set_text(const char* str, bool append = false) = 0;
153 
154  /**
155  * 设置 xml 节点,同时将流对象中的数据做为该节点的文本内容
156  * @param in {istream&} 输入流对象
157  * @param off {size_t} 对于文件流,则指定要拷贝的数据的起始位置
158  * @param len {size_t} 要拷贝的最大数据量,当为 0 时,则一直拷贝到流结束
159  * @return {xml_node&}
160  */
161  virtual xml_node& set_text(istream& in, size_t off = 0,
162  size_t len = 0) = 0;
163 
164  /**
165  * 设置 xml 节点的文本内容
166  * @param number {long long int} 64 位整数
167  * @return {xml_node&}
168  */
169 #if defined(_WIN32) || defined(_WIN64)
170  xml_node& set_text(__int64 number);
171 #else
172  xml_node& set_text(long long int number);
173 #endif
174 
175  /**
176  * 给本 xml 节点添加 xml_node 子节点对象
177  * @param child {xml_node*} 子节点对象
178  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
179  * @return {xml_node&} return_child 为 true 返回子节点的引用,
180  * 否则返回本 xml 节点引用
181  */
182  virtual xml_node& add_child(xml_node* child,
183  bool return_child = false) = 0;
184 
185  /**
186  * 给本 xml 节点添加 xml_node 子节点对象
187  * @param child {xml_node&} 子节点对象
188  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
189  * @return {xml_node&} return_child 为 true 返回子节点的引用,
190  * 否则返回本 xml 节点引用
191  */
192  xml_node& add_child(xml_node& child, bool return_child = false);
193 
194  /**
195  * 给本 xml 节点添加 xml_node 子节点对象
196  * @param tag {const char* tag} 子节点对象的标签名
197  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
198  * @param str {const char*} 文本字符串
199  * @return {xml_node&} return_child 为 true 返回子节点的引用,
200  * 否则返回本 xml 节点引用
201  */
202  xml_node& add_child(const char* tag, bool return_child = false,
203  const char* str = NULL);
204 
205  /**
206  * 给本 xml 节点添加 xml_node 子节点对象
207  * @param tag {const char* tag} 子节点对象的标签名
208  * @param txt {long long int} 节点中的文本内容,非空字符串
209  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
210  * @return {xml_node&} return_child 为 true 返回子节点的引用,
211  * 否则返回本 xml 节点引用
212  */
213  xml_node& add_child(const char* tag, const char* txt,
214  bool return_child = false);
215 
216  /**
217  * 给本 xml 节点添加 xml_node 子节点对象
218  * @param tag {const char* tag} 子节点对象的标签名
219  * @param number {long long int} 64 位整数
220  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
221  * @return {xml_node&} return_child 为 true 返回子节点的引用,
222  * 否则返回本 xml 节点引用
223  */
224 #if defined(_WIN32) || defined(_WIN64)
225  xml_node& add_child(const char* tag, __int64 number,
226  bool return_child = false);
227 #else
228  xml_node& add_child(const char* tag, long long int number,
229  bool return_child = false);
230 #endif
231 
232  /**
233  * 给本 xml 节点添加 xml_node 子节点对象,同时使用输入流中的内容做为节点的文本
234  * @param tag {const char* tag} 子节点对象的标签名
235  * @param in {istream&} 输入流对象
236  * @param off {size_t} 对于文件流,则指定要拷贝的数据的起始位置
237  * @param len {size_t} 要拷贝的最大数据量,当为 0 时,则一直拷贝到流结束
238  * @param return_child {bool} 是否需要本函数返回新创建的子节点的引用
239  * @return {xml_node&} return_child 为 true 返回子节点的引用,
240  * 否则返回本 xml 节点引用
241  */
242  xml_node& add_child(const char* tag, istream& in,
243  size_t off = 0, size_t len = 0, bool return_child = false);
244 
245  /**
246  * 获得本节点的父级节点对象的引用
247  * @return {xml_node&}
248  */
249  virtual xml_node& get_parent(void) const = 0;
250 
251  /**
252  * 设置本节点的父级节点
253  * @param node {xml_node*} 父节点
254  * @return {xml_node&}
255  */
256  virtual xml_node& set_parent(xml_node* node) = 0;
257 
258  /**
259  * 将本节点及其子节点从 xml 树中分离,其内存将由 xml 对象统一释放
260  * @return {int} 返回被释放的节点个数
261  */
262  virtual int detach(void) = 0;
263 
264  /**
265  * 获得本节点的第一个子节点,需要遍历子节点时必须首先调用此函数
266  * @return {xml_node*} 返回空表示没有子节点
267  */
268  virtual xml_node* first_child(void) = 0;
269 
270  /**
271  * 获得本节点的下一个子节点
272  * @return {xml_node*} 返回空表示遍历过程结束
273  */
274  virtual xml_node* next_child(void) = 0;
275 
276  /**
277  * 返回该 XML 节点在整个 XML 树中的深度
278  * @return {int}
279  */
280  virtual int depth(void) const = 0;
281 
282  /**
283  * 判断当前节点是否为 xml 对象中的 root 节点
284  * @return {bool}
285  */
286  virtual bool is_root(void) const = 0;
287 
288  /**
289  * 返回该 xml 节点的下一级子节点的个数
290  * @return {int} 永远 >= 0
291  */
292  virtual int children_count(void) const = 0;
293 
294  /**
295  * 当在遍历该 xml 节点时,内部会动态产生一些临时 xml_node 对象,调用
296  * 此函数可以清空这些对象,一旦调用此函数进行了清除,则由
297  * first_child/next_child 返回的 xml_node 节点对象将不再可用,否则会
298  * 产生内存非法访问
299  */
300  void clear(void);
301 
302  /**
303  * 获得 xml 对象的引用
304  * @return {xml&}
305  */
306  xml& get_xml(void) const;
307 
308 protected:
309  friend class xml;
310  friend class dbuf_guard;
311 
312  /**
313  * xml 节点构造函数
314  * @param xml_ptr {xml*} xml 树对象,非空
315  */
316  xml_node(xml* xml_ptr);
317 
318  /**
319  * 要求该对象必须是动态创建的
320  */
321  virtual ~xml_node(void);
322 
323 protected:
325  std::vector<xml_node*> nodes_tmp_;
326  std::vector<xml_attr*> attrs_tmp_;
327 };
328 
329 class string;
330 
331 class ACL_CPP_API xml : public pipe_stream, public dbuf_obj
332 {
333 public:
334  /**
335  * @param dbuf_nblock {size_t} 内部所用 dbuf_guard 的初始化参数
336  * @param dbuf_capacity {size_t} 内部所用 dbuf_guard 的初始化参数
337  */
338  xml(size_t dbuf_nblock = 2, size_t dbuf_capacity = 100);
339  virtual ~xml(void);
340 
341  /**
342  * 对于非闭合的标签,是否需要忽略闭合字符 '/',缺省为不忽略
343  * @param on {bool}
344  * @return {xml&}
345  */
346  virtual xml& ignore_slash(bool on) = 0;
347 
348  /**
349  * 解析 xml 对象时,是否自动进行 xml 解码,缺省解码
350  * @param on {bool}
351  * @return {xml&}
352  */
353  virtual xml& xml_decode(bool on) = 0;
354 
355  /**
356  * 创建 xml 对象时,是否自动进行 xml 编码,缺省编码
357  * @param on {bool}
358  * @return {xml&}
359  */
360  virtual xml& xml_encode(bool on) = 0;
361 
362  /**
363  * 解析 xml 时是否允许有多个根节点(内部缺省为允许)
364  * @param on {bool}
365  * @retrn {xml&}
366  */
367  virtual xml& xml_multi_root(bool on) = 0;
368 
369  /**
370  * 以流式方式循环调用本函数添加 XML 数据,也可以一次性添加
371  * 完整的 XML 数据,如果是重复使用该 XML 解析器解析多个 XML
372  * 对象,则应该在解析下一个 XML 对象前调用 reset() 方法来清
373  * 除上一次的解析结果
374  * @param data {const char*} xml 数据
375  * @return {const char*} 当解析完毕时还有剩余数据,则该返回值返回
376  * 剩余的数据; 如果 data 为 '\0',则说明已经处理完输入的数据
377  */
378  virtual const char* update(const char* data) = 0;
379 
380  /**
381  * 判断 XML 解析是否完毕
382  * @param root_tag {const char*} 根节点标签名,非 NULL 字符串,用该标签名
383  * 与 xml 对象中最外层的标签名比较是否相同
384  * @return {bool}
385  */
386  virtual bool complete(const char* root_tag) = 0;
387 
388  /**
389  * 重置 XML 解析器状态,该 XML 对象可以用来对多个 XML 数据
390  * 进行解析,在反复使用本 XML 解析器前,需要调用本函数重置
391  * 内部 XML 解析器状态,清除上一次的解析结果
392  */
393  virtual void reset(void) = 0;
394 
395  /**
396  * 从解析的 XML 原始数据中仅提取文本部分
397  * @return {const string&} 返回结果缓冲区的引用,该引用是内
398  * 部变量,用户不需要释放
399  */
400  virtual const string& getText(void);
401 
402  /**
403  * 从 XML 对象中取得某个标签名的所有节点集合
404  * @param tag {const char*} 标签名(不区分大小写)
405  * @return {const std::vector<xml_node*>&} 返回结果集的对象引用,
406  * 如果查询结果为空,则该集合为空,即:empty() == true
407  * 注:返回的数组中的 xml_node 节点数据可以修改,但不能删除该节点,
408  * 因为该库内部有自动删除的机制
409  */
410  virtual const std::vector<xml_node*>&
411  getElementsByTagName(const char* tag) const = 0;
412 
413  /**
414  * 从 xml 对象中获得对应标签名的第一个 xml 节点对象
415  * @param tag {const char*} 标签名(不区分大小写)
416  * @return {xml_node*} 返回空表明该标签对应的 xml 节点不存在
417  */
418  virtual xml_node* getFirstElementByTag(const char* tag) const = 0;
419 
420  /**
421  * 从 xml 对象中获得所有的与给定多级标签名相同的 xml 节点的集合
422  * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据:
423  * <root> <first> <second> <third name="test1"> text1 </third> </second> </first> ...
424  * <root> <first> <second> <third name="test2"> text2 </third> </second> </first> ...
425  * <root> <first> <second> <third name="test3"> text3 </third> </second> </first> ...
426  * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的节点
427  * @return {const std::vector<xml_node*>&} 符合条件的 xml 节点集合,
428  * 如果查询结果为空,则该集合为空,即:empty() == true
429  * 注:返回的数组中的 xml_node 节点数据可以修改,但不能删除该节点,
430  * 因为该库内部有自动删除的机制
431  */
432  virtual const std::vector<xml_node*>&
433  getElementsByTags(const char* tags) const = 0;
434 
435  /**
436  * 从 xml 对象中获得指定多级标签名的第一个 xml 节点
437  * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据:
438  * <root> <first> <second> <third name="test1"> text1 </third> </second> </first> ...
439  * <root> <first> <second> <third name="test2"> text2 </third> </second> </first> ...
440  * <root> <first> <second> <third name="test3"> text3 </third> </second> </first> ...
441  * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的节点
442  * @return {xml_node*} 返回空表示不存在
443  */
444  virtual xml_node* getFirstElementByTags(const char* tags) const = 0;
445 
446  /**
447  * 从 xml 对象中获得所有与给定属性名 name 的属性值相同的 xml 节点集合
448  * @param value {const char*} 属性名为 name 的属性值
449  * @return {const std::vector<xml_node*>&} 返回结果集的对象引用,
450  * 如果查询结果为空,则该集合为空,即:empty() == true
451  * 注:返回的数组中的 xml_node 节点数据可以修改,但不能删除该节点,
452  * 因为该库内部有自动删除的机制
453  */
454  virtual const std::vector<xml_node*>&
455  getElementsByName(const char* value) const = 0;
456 
457  /**
458  * 从 xml 对象中获得所有给定属性名及属性值的 xml 节点元素集合
459  * @param name {const char*} 属性名
460  * @param value {const char*} 属性值
461  * @return {const std::vector<xml_node*>&} 返回结果集的对象引用,
462  * 如果查询结果为空,则该集合为空,即:empty() == true
463  */
464  virtual const std::vector<xml_node*>& getElementsByAttr(
465  const char* name, const char* value) const = 0;
466 
467  /**
468  * 从 xml 对象中获得指定 id 值的 xml 节点元素
469  * @param id {const char*} id 值
470  * @return {const xml_node*} xml 节点元素, 若返回 NULL 则表示没有符合
471  * 条件的 xml 节点, 返回值不需要释放
472  */
473  virtual xml_node* getElementById(const char* id) const = 0;
474 
475  /**
476  * 创建一个 xml_node 节点对象
477  * @param tag {const char*} 标签名
478  * @param txt {const char*} 文本字符串
479  * @return {xml_node*} 新产生的 xml_node 对象不需要用户手工释放,因为
480  * 在 xml 对象被释放时这些节点会自动被释放,当然用户也可以在不用时调
481  * 用 reset 来释放这些 xml_node 节点对象
482  */
483  virtual xml_node& create_node(const char* tag,
484  const char* txt = NULL) = 0;
485 
486  /**
487  * 创建一个 xml_node 节点对象,同时指定输入流中的内容做为节点文本内容
488  * @param tag {const char*} 标签名
489  * @param in {istream&} 输入流对象
490  * @param off {size_t} 对于文件流,则指定要拷贝的数据的起始位置
491  * @param len {size_t} 要拷贝的最大数据量,当为 0 时,则一直拷贝到流结束
492  * @return {xml_node*} 新产生的 xml_node 对象不需要用户手工释放,因为
493  * 在 xml 对象被释放时这些节点会自动被释放,当然用户也可以在不用时调
494  * 用 reset 来释放这些 xml_node 节点对象
495  */
496  virtual xml_node& create_node(const char* tag, istream& in,
497  size_t off = 0, size_t len = 0) = 0;
498 
499  /**
500  * 创建一个 xml_node 节点对象
501  * @param tag {const char*} 标签名
502  * @param number {long long int} 64 位整数
503  * @return {xml_node*} 新产生的 xml_node 对象不需要用户手工释放,因为
504  * 在xml 对象被释放时这些节点会自动被释放,当然用户也可以在不用时调用
505  * reset 来释放这些 xml_node 节点对象
506  */
507 #if defined(_WIN32) || defined(_WIN64)
508  xml_node& create_node(const char* tag, __int64 number);
509 #else
510  xml_node& create_node(const char* tag, long long int number);
511 #endif
512 
513  /**
514  * 获得根节点对象,但需要注意,该节点为虚节点,里面不存放任何数据,
515  * 它是所有 xml 节点对象的最顶层父对象
516  * @return {xml_node&}
517  */
518  virtual xml_node& get_root(void) = 0;
519 
520  /**
521  * 开始遍历该 xml 对象并获得第一个节点
522  * @return {xml_node*} 返回空表示该 xml 对象为空节点
523  * 注:返回的节点对象用户不能手工释放,因为该对象被
524  * 内部库自动释放
525  */
526  virtual xml_node* first_node(void) = 0;
527 
528  /**
529  * 遍历该 xml 对象的下一个 xml 节点
530  * @return {xml_node*} 返回空表示遍历完毕
531  * 注:返回的节点对象用户不能手工释放,因为该对象被
532  * 内部库自动释放
533  */
534  virtual xml_node* next_node(void) = 0;
535 
536  /**
537  * 将 xml 对象树转成字符串
538  * @param out {string&} 存储转换结果的缓冲区
539  */
540  virtual void build_xml(string& out) const { (void) out; };
541 
542  /**
543  * 将 xml 对象转换为字符串
544  * @param len {size_t*} 非 NULL 时存放数据长度
545  * @return {const char*} xml 字符串
546  */
547  virtual const char* to_string(size_t* len = NULL) const = 0;
548 
549  /**
550  * 获得当前 xml 对象已经分配的内存大小总和
551  * @return {size_t}
552  */
553  virtual size_t space(void) const = 0;
554 
555  /**
556  * 将记录 xml 已分配内存大小的变量清 0
557  */
558  virtual void space_clear(void) = 0;
559 
560  /**
561  * 获得当前 xml 对象中 xml 节点的总数
562  * @return {size_t}
563  */
564  virtual size_t node_count(void) const = 0;
565 
566  /**
567  * 获得当前 xml 对象中所有 xml 节点属性的总数
568  * @return {size_t}
569  */
570  virtual size_t attr_count(void) const = 0;
571 
572 public:
573  // pipe_stream 虚函数重载
574 
575  virtual int push_pop(const char* in, size_t len,
576  string* out, size_t max = 0);
577  virtual int pop_end(string* out, size_t max = 0);
578  virtual void clear(void);
579 
580 protected:
582  std::vector<xml_node*> elements_;
583  string* buf_;
584  //bool dummyRootAdded_;
585 
587  //std::list<xml_node*> nodes_tmp_;
588 };
589 
590 } // namespace acl
xml_node * node_
Definition: xml.hpp:48
ACL_TOKEN * m_pTokenTree
Definition: xml.hpp:586
HTTP_API void const char * name
Definition: lib_http.h:620
virtual ~xml_attr(void)
Definition: xml.hpp:46
string * buf_
Definition: xml.hpp:583
xml * xml_
Definition: xml.hpp:324
std::vector< xml_node * > nodes_tmp_
Definition: xml.hpp:325
std::vector< xml_attr * > attrs_tmp_
Definition: xml.hpp:326
dbuf_guard dbuf_
Definition: xml.hpp:581
std::vector< xml_node * > elements_
Definition: xml.hpp:582
virtual void build_xml(string &out) const
Definition: xml.hpp:540
xml_attr(xml_node *node)
Definition: xml.hpp:45
#define ACL_CPP_API