1 #include "xutil.hh"
2 #include "xdoc.hh"
3 #include "xbuffer.hh"
4 #include <assert.h>
5 #include <string.h>
6
7 using std::string;
8
add_last(xmlNodePtr leader,xmlNodePtr cur)9 static void add_last(xmlNodePtr leader, xmlNodePtr cur)
10 {
11 assert(leader);
12 assert(cur);
13 assert(leader != cur);
14 assert(cur->type != XML_DOCUMENT_FRAG_NODE);
15
16 xmlNodePtr p = leader->parent;
17 cur->parent = p;
18
19 leader->next = cur;
20 cur->prev = leader;
21
22 if (p) {
23 p->last = cur;
24 }
25 }
26
unlink_node(xmlNodePtr n)27 static void unlink_node(xmlNodePtr n)
28 {
29 assert(n != 0);
30
31 if ( n->prev != NULL ) {
32 n->prev->next = n->next;
33 }
34
35 if ( n->next != NULL ) {
36 n->next->prev = n->prev;
37 }
38
39 if ( n->parent != NULL ) {
40 if ( n == n->parent->last ) {
41 n->parent->last = n->prev;
42 }
43
44 if ( n == n->parent->children ) {
45 n->parent->children = n->next;
46 }
47 }
48
49 n->prev = 0;
50 n->next = 0;
51 n->parent = 0;
52 }
53
equal_to(xmlNsPtr top,xmlNsPtr ns)54 static bool equal_to(xmlNsPtr top, xmlNsPtr ns)
55 {
56 assert(top);
57 assert(top->prefix);
58 assert(top->href);
59 assert(ns);
60
61 return ns->prefix &&
62 !strcmp(reinterpret_cast<const char *>(top->prefix),
63 reinterpret_cast<const char *>(ns->prefix)) &&
64 ns->href &&
65 !strcmp(reinterpret_cast<const char *>(top->href),
66 reinterpret_cast<const char *>(ns->href));
67 }
68
repoint(xmlNsPtr top,xmlNodePtr n)69 static void repoint(xmlNsPtr top, xmlNodePtr n)
70 {
71 assert(n);
72
73 if (n->type != XML_ELEMENT_NODE) {
74 return;
75 }
76
77 if (n->ns && equal_to(top, n->ns)) {
78 n->ns = top;
79 }
80
81 xmlAttrPtr attr = n->properties;
82 while (attr) {
83 if (attr->ns && equal_to(top, attr->ns)) {
84 attr->ns = top;
85 }
86
87 attr = attr->next;
88 }
89
90 xmlNodePtr ch = n->children;
91 while (ch) {
92 repoint(top, ch);
93 ch = ch->next;
94 }
95 }
96
97 // Remove the namespace equivalent to top (which must have both local
98 // name and href and must be declared above n) from the list starting
99 // at ns_head and return the new head.
purge_one(xmlNsPtr top,xmlNsPtr ns_head)100 static xmlNsPtr purge_one(xmlNsPtr top, xmlNsPtr ns_head)
101 {
102 xmlNsPtr ns = ns_head;
103 xmlNsPtr prev = 0;
104 while (ns) {
105 if (equal_to(top, ns)) {
106 if (prev) {
107 prev->next = ns->next;
108 } else {
109 ns_head = ns->next;
110 }
111
112 ns->next = 0; // necessary?
113
114 xmlFreeNs(ns);
115
116 return ns_head;
117 }
118
119 prev = ns;
120 ns = ns->next;
121 }
122
123 return ns_head;
124 }
125
purge(xmlNsPtr top,xmlNodePtr n)126 static void purge(xmlNsPtr top, xmlNodePtr n)
127 {
128 if (n->type != XML_ELEMENT_NODE) {
129 return;
130 }
131
132 // 7Aug2003: Once is enough: the parser won't allow more than 1
133 // equivalent ns declaration in one node.
134 n->nsDef = purge_one(top, n->nsDef);
135
136 xmlNodePtr ch = n->children;
137 while (ch) {
138 purge(top, ch);
139 ch = ch->next;
140 }
141 }
142
get_root_element(xmlDocPtr doc)143 xmlNodePtr xutil::get_root_element(xmlDocPtr doc)
144 {
145 assert(doc);
146
147 xmlNodePtr de = xmlDocGetRootElement(doc);
148 if (!de) {
149 throw string("empty document");
150 }
151
152 return de;
153 }
154
parse_file(const char * fname)155 XDoc xutil::parse_file(const char *fname)
156 {
157 xmlDocPtr doc = xmlParseFile(fname);
158 if (!doc) {
159 string s = "error parsing ";
160 s += fname;
161 throw s;
162 }
163
164 return XDoc(doc);
165 }
166
get_node_name(xmlNodePtr n)167 string xutil::get_node_name(xmlNodePtr n)
168 {
169 string out;
170
171 if (n->ns && n->ns->prefix) {
172 out = reinterpret_cast<const char *>(n->ns->prefix);
173 out += ':';
174 }
175
176 if (n->name)
177 {
178 out += reinterpret_cast<const char *>(n->name);
179 }
180 else // 21Sep2009: does happen, although perhaps only in a buggy
181 // program...
182 {
183 out += "<unnamed>";
184 }
185
186 return out;
187 }
188
append_child(xmlNodePtr ex_parent,xmlNodePtr new_child)189 void xutil::append_child(xmlNodePtr ex_parent, xmlNodePtr new_child)
190 {
191 assert(ex_parent != 0);
192 assert(ex_parent->doc == new_child->doc);
193
194 unlink_node(new_child);
195
196 // 24Jul2003: does this need to be implemented?
197 assert(new_child->type != XML_DOCUMENT_FRAG_NODE);
198
199 if (ex_parent->children) {
200 add_last(ex_parent->last, new_child);
201 } else {
202 ex_parent->children = new_child;
203 ex_parent->last = new_child;
204 new_child->parent= ex_parent;
205 }
206
207 xmlReconciliateNs(ex_parent->doc, new_child);
208 }
209
remove_child(xmlNodePtr parent,xmlNodePtr child)210 void xutil::remove_child(xmlNodePtr parent, xmlNodePtr child)
211 {
212 assert(parent &&
213 child &&
214 (child->type != XML_ATTRIBUTE_NODE) &&
215 (child->type != XML_NAMESPACE_DECL) &&
216 (parent == child->parent));
217
218 unlink_node(child);
219 }
220
remove_children(xmlNodePtr n)221 void xutil::remove_children(xmlNodePtr n)
222 {
223 if (n->children)
224 {
225 xmlFree(n->children);
226 n->children = 0;
227 n->last = 0;
228 }
229 }
230
231 // 10Aug2003: should probably be moved to Target (equal_to is already
232 // duplicated in Merge).
unify_namespace(xmlNsPtr top,xmlNodePtr n)233 void xutil::unify_namespace(xmlNsPtr top, xmlNodePtr n)
234 {
235 repoint(top, n);
236 purge(top, n);
237 }
238
flatten(xmlNodePtr n)239 std::string xutil::flatten(xmlNodePtr n)
240 {
241 assert(n);
242 assert(n->doc);
243
244 XBuffer buf;
245 int rv = xmlNodeDump(buf, n->doc, n, 0, 0);
246 if (rv < 0) {
247 throw std::string("cannot dump node");
248 }
249
250 return std::string(
251 reinterpret_cast<char *>(((xmlBufferPtr)buf)->content));
252 }
253
254