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