8
8
# define __BOOST_NETWORK_DETAIL_XML_WRAPPERS_PARSER_BACKENDS_EXPAT_PARSER_INC__
9
9
10
10
11
- # include < boost/network/detail/xml_wrappers/parser_backends/expat/element_parser.hpp>
11
+ # include < boost/network/traits/string.hpp>
12
+ # include < boost/network/detail/xml_wrappers/element.hpp>
13
+ # include < boost/noncopyable.hpp>
14
+ # include < expat.h>
15
+ # include < cstring>
16
+ # include < stack>
12
17
13
18
14
19
namespace boost {
@@ -17,11 +22,122 @@ namespace detail {
17
22
template <
18
23
class Tag
19
24
>
20
- class basic_expat_parser
21
- : public basic_expat_element_parser<Tag> {
22
-
25
+ class basic_expat_parser : boost::noncopyable {
23
26
public:
24
27
28
+ typedef typename string<Tag>::type string_type;
29
+
30
+ typedef basic_element<Tag> element_type;
31
+
32
+ basic_expat_parser ()
33
+ : parser_(XML_ParserCreate(NULL )), depth_(0 ) {
34
+ assert (parser_);
35
+ XML_SetUserData (parser_, this );
36
+ XML_SetElementHandler (parser_, start_element, end_element);
37
+ XML_SetCharacterDataHandler (parser_, cdata);
38
+ }
39
+
40
+ ~basic_expat_parser () {
41
+ XML_ParserFree (parser_);
42
+ }
43
+
44
+ bool feed (const string_type &chunk) {
45
+ while (!elements_.empty ()) {
46
+ elements_.pop ();
47
+ }
48
+ elements_.push (0 );
49
+ depth_ = 0 ;
50
+ return XML_Parse (parser_, chunk.c_str (), chunk.size (), 0 ) != 0 ;
51
+ }
52
+
53
+ bool feed (const string_type &chunk, element_type &element) {
54
+ while (!elements_.empty ()) {
55
+ elements_.pop ();
56
+ }
57
+ elements_.push (&element);
58
+ depth_ = 0 ;
59
+ return XML_Parse (parser_, chunk.c_str (), chunk.size (), 0 ) != 0 ;
60
+ }
61
+
62
+ private:
63
+
64
+ static void set_name (element_type *element, const XML_Char *name) {
65
+ const XML_Char *name_begin = name;
66
+ const XML_Char *name_end = name_begin + std::strlen (name_begin);
67
+
68
+ element->set_name (string_type (name_begin, name_end));
69
+ }
70
+
71
+ static void set_attributes (element_type *element, const XML_Char **attrs) {
72
+ if (attrs) {
73
+ for (int i = 0 ; attrs[i]; i += 2 ) {
74
+ const XML_Char *key_begin = attrs[i];
75
+ const XML_Char *key_end = key_begin + std::strlen (key_begin);
76
+
77
+ const XML_Char *val_begin = attrs[i + 1 ];
78
+ const XML_Char *val_end = val_begin + std::strlen (val_begin);
79
+
80
+ element->set_attribute (string_type (key_begin, key_end),
81
+ string_type (val_begin, val_end));
82
+ }
83
+ }
84
+ }
85
+
86
+ static void start_element (void *userdata,
87
+ const XML_Char *name,
88
+ const XML_Char **attrs) {
89
+ basic_expat_parser<Tag> *parser
90
+ = static_cast <basic_expat_parser<Tag> *>(userdata);
91
+
92
+ if (!parser->elements_ .top ()) {
93
+ return ;
94
+ }
95
+
96
+ if (parser->depth_ > 0 ) {
97
+ element_type *child = new element_type;
98
+ parser->elements_ .top ()->add_child (child);
99
+ parser->elements_ .push (child);
100
+ }
101
+ set_name (parser->elements_ .top (), name);
102
+ set_attributes (parser->elements_ .top (), attrs);
103
+
104
+ ++parser->depth_ ;
105
+ }
106
+
107
+ static void end_element (void *userdata,
108
+ const XML_Char *name) {
109
+ basic_expat_parser<Tag> *parser
110
+ = static_cast <basic_expat_parser<Tag> *>(userdata);
111
+
112
+ if (!parser->elements_ .top ()) {
113
+ return ;
114
+ }
115
+
116
+ if (parser->depth_ > 0 ) {
117
+ parser->elements_ .pop ();
118
+ }
119
+
120
+ --parser->depth_ ;
121
+ }
122
+
123
+ static void cdata (void *userdata,
124
+ const XML_Char *s,
125
+ int len) {
126
+ basic_expat_parser<Tag> *parser
127
+ = static_cast <basic_expat_parser<Tag> *>(userdata);
128
+
129
+ if (!parser->elements_ .top ()) {
130
+ return ;
131
+ }
132
+
133
+ parser->elements_ .top ()->add_child (
134
+ new element_type (typename element_type::text (), string_type (s, s + len)));
135
+ }
136
+
137
+ XML_Parser parser_;
138
+ std::stack<element_type *> elements_;
139
+ int depth_;
140
+
25
141
};
26
142
} // namespace detail
27
143
} // namespace network
0 commit comments