OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/libjingle/xmllite/xmlelement.h" | |
12 | |
13 #include <ostream> | |
14 #include <sstream> | |
15 #include <string> | |
16 #include <vector> | |
17 | |
18 #include "webrtc/libjingle/xmllite/qname.h" | |
19 #include "webrtc/libjingle/xmllite/xmlbuilder.h" | |
20 #include "webrtc/libjingle/xmllite/xmlconstants.h" | |
21 #include "webrtc/libjingle/xmllite/xmlparser.h" | |
22 #include "webrtc/libjingle/xmllite/xmlprinter.h" | |
23 #include "webrtc/base/common.h" | |
24 | |
25 namespace buzz { | |
26 | |
27 XmlChild::~XmlChild() { | |
28 } | |
29 | |
30 bool XmlText::IsTextImpl() const { | |
31 return true; | |
32 } | |
33 | |
34 XmlElement* XmlText::AsElementImpl() const { | |
35 return NULL; | |
36 } | |
37 | |
38 XmlText* XmlText::AsTextImpl() const { | |
39 return const_cast<XmlText *>(this); | |
40 } | |
41 | |
42 void XmlText::SetText(const std::string& text) { | |
43 text_ = text; | |
44 } | |
45 | |
46 void XmlText::AddParsedText(const char* buf, int len) { | |
47 text_.append(buf, len); | |
48 } | |
49 | |
50 void XmlText::AddText(const std::string& text) { | |
51 text_ += text; | |
52 } | |
53 | |
54 XmlText::~XmlText() { | |
55 } | |
56 | |
57 XmlElement::XmlElement(const QName& name) : | |
58 name_(name), | |
59 first_attr_(NULL), | |
60 last_attr_(NULL), | |
61 first_child_(NULL), | |
62 last_child_(NULL), | |
63 cdata_(false) { | |
64 } | |
65 | |
66 XmlElement::XmlElement(const XmlElement& elt) : | |
67 XmlChild(), | |
68 name_(elt.name_), | |
69 first_attr_(NULL), | |
70 last_attr_(NULL), | |
71 first_child_(NULL), | |
72 last_child_(NULL), | |
73 cdata_(false) { | |
74 | |
75 // copy attributes | |
76 XmlAttr* attr; | |
77 XmlAttr ** plast_attr = &first_attr_; | |
78 XmlAttr* newAttr = NULL; | |
79 for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) { | |
80 newAttr = new XmlAttr(*attr); | |
81 *plast_attr = newAttr; | |
82 plast_attr = &(newAttr->next_attr_); | |
83 } | |
84 last_attr_ = newAttr; | |
85 | |
86 // copy children | |
87 XmlChild* pChild; | |
88 XmlChild ** ppLast = &first_child_; | |
89 XmlChild* newChild = NULL; | |
90 | |
91 for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) { | |
92 if (pChild->IsText()) { | |
93 newChild = new XmlText(*(pChild->AsText())); | |
94 } else { | |
95 newChild = new XmlElement(*(pChild->AsElement())); | |
96 } | |
97 *ppLast = newChild; | |
98 ppLast = &(newChild->next_child_); | |
99 } | |
100 last_child_ = newChild; | |
101 | |
102 cdata_ = elt.cdata_; | |
103 } | |
104 | |
105 XmlElement::XmlElement(const QName& name, bool useDefaultNs) : | |
106 name_(name), | |
107 first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL), | |
108 last_attr_(first_attr_), | |
109 first_child_(NULL), | |
110 last_child_(NULL), | |
111 cdata_(false) { | |
112 } | |
113 | |
114 bool XmlElement::IsTextImpl() const { | |
115 return false; | |
116 } | |
117 | |
118 XmlElement* XmlElement::AsElementImpl() const { | |
119 return const_cast<XmlElement *>(this); | |
120 } | |
121 | |
122 XmlText* XmlElement::AsTextImpl() const { | |
123 return NULL; | |
124 } | |
125 | |
126 const std::string XmlElement::BodyText() const { | |
127 if (first_child_ && first_child_->IsText() && last_child_ == first_child_) { | |
128 return first_child_->AsText()->Text(); | |
129 } | |
130 | |
131 return std::string(); | |
132 } | |
133 | |
134 void XmlElement::SetBodyText(const std::string& text) { | |
135 if (text.empty()) { | |
136 ClearChildren(); | |
137 } else if (first_child_ == NULL) { | |
138 AddText(text); | |
139 } else if (first_child_->IsText() && last_child_ == first_child_) { | |
140 first_child_->AsText()->SetText(text); | |
141 } else { | |
142 ClearChildren(); | |
143 AddText(text); | |
144 } | |
145 } | |
146 | |
147 const QName XmlElement::FirstElementName() const { | |
148 const XmlElement* element = FirstElement(); | |
149 if (element == NULL) | |
150 return QName(); | |
151 return element->Name(); | |
152 } | |
153 | |
154 XmlAttr* XmlElement::FirstAttr() { | |
155 return first_attr_; | |
156 } | |
157 | |
158 const std::string XmlElement::Attr(const StaticQName& name) const { | |
159 XmlAttr* attr; | |
160 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
161 if (attr->name_ == name) | |
162 return attr->value_; | |
163 } | |
164 return std::string(); | |
165 } | |
166 | |
167 const std::string XmlElement::Attr(const QName& name) const { | |
168 XmlAttr* attr; | |
169 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
170 if (attr->name_ == name) | |
171 return attr->value_; | |
172 } | |
173 return std::string(); | |
174 } | |
175 | |
176 bool XmlElement::HasAttr(const StaticQName& name) const { | |
177 XmlAttr* attr; | |
178 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
179 if (attr->name_ == name) | |
180 return true; | |
181 } | |
182 return false; | |
183 } | |
184 | |
185 bool XmlElement::HasAttr(const QName& name) const { | |
186 XmlAttr* attr; | |
187 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
188 if (attr->name_ == name) | |
189 return true; | |
190 } | |
191 return false; | |
192 } | |
193 | |
194 void XmlElement::SetAttr(const QName& name, const std::string& value) { | |
195 XmlAttr* attr; | |
196 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
197 if (attr->name_ == name) | |
198 break; | |
199 } | |
200 if (!attr) { | |
201 attr = new XmlAttr(name, value); | |
202 if (last_attr_) | |
203 last_attr_->next_attr_ = attr; | |
204 else | |
205 first_attr_ = attr; | |
206 last_attr_ = attr; | |
207 return; | |
208 } | |
209 attr->value_ = value; | |
210 } | |
211 | |
212 void XmlElement::ClearAttr(const QName& name) { | |
213 XmlAttr* attr; | |
214 XmlAttr* last_attr = NULL; | |
215 for (attr = first_attr_; attr; attr = attr->next_attr_) { | |
216 if (attr->name_ == name) | |
217 break; | |
218 last_attr = attr; | |
219 } | |
220 if (!attr) | |
221 return; | |
222 if (!last_attr) | |
223 first_attr_ = attr->next_attr_; | |
224 else | |
225 last_attr->next_attr_ = attr->next_attr_; | |
226 if (last_attr_ == attr) | |
227 last_attr_ = last_attr; | |
228 delete attr; | |
229 } | |
230 | |
231 XmlChild* XmlElement::FirstChild() { | |
232 return first_child_; | |
233 } | |
234 | |
235 XmlElement* XmlElement::FirstElement() { | |
236 XmlChild* pChild; | |
237 for (pChild = first_child_; pChild; pChild = pChild->next_child_) { | |
238 if (!pChild->IsText()) | |
239 return pChild->AsElement(); | |
240 } | |
241 return NULL; | |
242 } | |
243 | |
244 XmlElement* XmlElement::NextElement() { | |
245 XmlChild* pChild; | |
246 for (pChild = next_child_; pChild; pChild = pChild->next_child_) { | |
247 if (!pChild->IsText()) | |
248 return pChild->AsElement(); | |
249 } | |
250 return NULL; | |
251 } | |
252 | |
253 XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) { | |
254 XmlChild* pChild; | |
255 for (pChild = first_child_; pChild; pChild = pChild->next_child_) { | |
256 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) | |
257 return pChild->AsElement(); | |
258 } | |
259 return NULL; | |
260 } | |
261 | |
262 XmlElement * | |
263 XmlElement::NextWithNamespace(const std::string& ns) { | |
264 XmlChild* pChild; | |
265 for (pChild = next_child_; pChild; pChild = pChild->next_child_) { | |
266 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) | |
267 return pChild->AsElement(); | |
268 } | |
269 return NULL; | |
270 } | |
271 | |
272 XmlElement * | |
273 XmlElement::FirstNamed(const QName& name) { | |
274 XmlChild* pChild; | |
275 for (pChild = first_child_; pChild; pChild = pChild->next_child_) { | |
276 if (!pChild->IsText() && pChild->AsElement()->Name() == name) | |
277 return pChild->AsElement(); | |
278 } | |
279 return NULL; | |
280 } | |
281 | |
282 XmlElement * | |
283 XmlElement::FirstNamed(const StaticQName& name) { | |
284 XmlChild* pChild; | |
285 for (pChild = first_child_; pChild; pChild = pChild->next_child_) { | |
286 if (!pChild->IsText() && pChild->AsElement()->Name() == name) | |
287 return pChild->AsElement(); | |
288 } | |
289 return NULL; | |
290 } | |
291 | |
292 XmlElement * | |
293 XmlElement::NextNamed(const QName& name) { | |
294 XmlChild* pChild; | |
295 for (pChild = next_child_; pChild; pChild = pChild->next_child_) { | |
296 if (!pChild->IsText() && pChild->AsElement()->Name() == name) | |
297 return pChild->AsElement(); | |
298 } | |
299 return NULL; | |
300 } | |
301 | |
302 XmlElement * | |
303 XmlElement::NextNamed(const StaticQName& name) { | |
304 XmlChild* pChild; | |
305 for (pChild = next_child_; pChild; pChild = pChild->next_child_) { | |
306 if (!pChild->IsText() && pChild->AsElement()->Name() == name) | |
307 return pChild->AsElement(); | |
308 } | |
309 return NULL; | |
310 } | |
311 | |
312 XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) { | |
313 XmlElement* child = FirstNamed(name); | |
314 if (!child) { | |
315 child = new XmlElement(name); | |
316 AddElement(child); | |
317 } | |
318 | |
319 return child; | |
320 } | |
321 | |
322 const std::string XmlElement::TextNamed(const QName& name) const { | |
323 XmlChild* pChild; | |
324 for (pChild = first_child_; pChild; pChild = pChild->next_child_) { | |
325 if (!pChild->IsText() && pChild->AsElement()->Name() == name) | |
326 return pChild->AsElement()->BodyText(); | |
327 } | |
328 return std::string(); | |
329 } | |
330 | |
331 void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) { | |
332 if (predecessor == NULL) { | |
333 next->next_child_ = first_child_; | |
334 first_child_ = next; | |
335 } | |
336 else { | |
337 next->next_child_ = predecessor->next_child_; | |
338 predecessor->next_child_ = next; | |
339 } | |
340 } | |
341 | |
342 void XmlElement::RemoveChildAfter(XmlChild* predecessor) { | |
343 XmlChild* next; | |
344 | |
345 if (predecessor == NULL) { | |
346 next = first_child_; | |
347 first_child_ = next->next_child_; | |
348 } | |
349 else { | |
350 next = predecessor->next_child_; | |
351 predecessor->next_child_ = next->next_child_; | |
352 } | |
353 | |
354 if (last_child_ == next) | |
355 last_child_ = predecessor; | |
356 | |
357 delete next; | |
358 } | |
359 | |
360 void XmlElement::AddAttr(const QName& name, const std::string& value) { | |
361 ASSERT(!HasAttr(name)); | |
362 | |
363 XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_; | |
364 last_attr_ = (*pprev = new XmlAttr(name, value)); | |
365 } | |
366 | |
367 void XmlElement::AddAttr(const QName& name, const std::string& value, | |
368 int depth) { | |
369 XmlElement* element = this; | |
370 while (depth--) { | |
371 element = element->last_child_->AsElement(); | |
372 } | |
373 element->AddAttr(name, value); | |
374 } | |
375 | |
376 void XmlElement::AddParsedText(const char* cstr, int len) { | |
377 if (len == 0) | |
378 return; | |
379 | |
380 if (last_child_ && last_child_->IsText()) { | |
381 last_child_->AsText()->AddParsedText(cstr, len); | |
382 return; | |
383 } | |
384 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; | |
385 last_child_ = *pprev = new XmlText(cstr, len); | |
386 } | |
387 | |
388 void XmlElement::AddCDATAText(const char* buf, int len) { | |
389 cdata_ = true; | |
390 AddParsedText(buf, len); | |
391 } | |
392 | |
393 void XmlElement::AddText(const std::string& text) { | |
394 if (text == STR_EMPTY) | |
395 return; | |
396 | |
397 if (last_child_ && last_child_->IsText()) { | |
398 last_child_->AsText()->AddText(text); | |
399 return; | |
400 } | |
401 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; | |
402 last_child_ = *pprev = new XmlText(text); | |
403 } | |
404 | |
405 void XmlElement::AddText(const std::string& text, int depth) { | |
406 // note: the first syntax is ambigious for msvc 6 | |
407 // XmlElement* pel(this); | |
408 XmlElement* element = this; | |
409 while (depth--) { | |
410 element = element->last_child_->AsElement(); | |
411 } | |
412 element->AddText(text); | |
413 } | |
414 | |
415 void XmlElement::AddElement(XmlElement *child) { | |
416 if (child == NULL) | |
417 return; | |
418 | |
419 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; | |
420 *pprev = child; | |
421 last_child_ = child; | |
422 child->next_child_ = NULL; | |
423 } | |
424 | |
425 void XmlElement::AddElement(XmlElement *child, int depth) { | |
426 XmlElement* element = this; | |
427 while (depth--) { | |
428 element = element->last_child_->AsElement(); | |
429 } | |
430 element->AddElement(child); | |
431 } | |
432 | |
433 void XmlElement::ClearNamedChildren(const QName& name) { | |
434 XmlChild* prev_child = NULL; | |
435 XmlChild* next_child; | |
436 XmlChild* child; | |
437 for (child = FirstChild(); child; child = next_child) { | |
438 next_child = child->NextChild(); | |
439 if (!child->IsText() && child->AsElement()->Name() == name) | |
440 { | |
441 RemoveChildAfter(prev_child); | |
442 continue; | |
443 } | |
444 prev_child = child; | |
445 } | |
446 } | |
447 | |
448 void XmlElement::ClearAttributes() { | |
449 XmlAttr* attr; | |
450 for (attr = first_attr_; attr; ) { | |
451 XmlAttr* to_delete = attr; | |
452 attr = attr->next_attr_; | |
453 delete to_delete; | |
454 } | |
455 first_attr_ = last_attr_ = NULL; | |
456 } | |
457 | |
458 void XmlElement::ClearChildren() { | |
459 XmlChild* pchild; | |
460 for (pchild = first_child_; pchild; ) { | |
461 XmlChild* to_delete = pchild; | |
462 pchild = pchild->next_child_; | |
463 delete to_delete; | |
464 } | |
465 first_child_ = last_child_ = NULL; | |
466 } | |
467 | |
468 std::string XmlElement::Str() const { | |
469 std::stringstream ss; | |
470 XmlPrinter::PrintXml(&ss, this); | |
471 return ss.str(); | |
472 } | |
473 | |
474 XmlElement* XmlElement::ForStr(const std::string& str) { | |
475 XmlBuilder builder; | |
476 XmlParser::ParseXml(&builder, str); | |
477 return builder.CreateElement(); | |
478 } | |
479 | |
480 XmlElement::~XmlElement() { | |
481 XmlAttr* attr; | |
482 for (attr = first_attr_; attr; ) { | |
483 XmlAttr* to_delete = attr; | |
484 attr = attr->next_attr_; | |
485 delete to_delete; | |
486 } | |
487 | |
488 XmlChild* pchild; | |
489 for (pchild = first_child_; pchild; ) { | |
490 XmlChild* to_delete = pchild; | |
491 pchild = pchild->next_child_; | |
492 delete to_delete; | |
493 } | |
494 } | |
495 | |
496 } // namespace buzz | |
OLD | NEW |