1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/xmllite/xmlelement.h"
29
30 #include <ostream>
31 #include <sstream>
32 #include <string>
33 #include <vector>
34
35 #include "talk/base/common.h"
36 #include "talk/xmllite/qname.h"
37 #include "talk/xmllite/xmlparser.h"
38 #include "talk/xmllite/xmlbuilder.h"
39 #include "talk/xmllite/xmlprinter.h"
40 #include "talk/xmllite/xmlconstants.h"
41
42 namespace buzz {
43
~XmlChild()44 XmlChild::~XmlChild() {
45 }
46
IsTextImpl() const47 bool XmlText::IsTextImpl() const {
48 return true;
49 }
50
AsElementImpl() const51 XmlElement* XmlText::AsElementImpl() const {
52 return NULL;
53 }
54
AsTextImpl() const55 XmlText* XmlText::AsTextImpl() const {
56 return const_cast<XmlText *>(this);
57 }
58
SetText(const std::string & text)59 void XmlText::SetText(const std::string& text) {
60 text_ = text;
61 }
62
AddParsedText(const char * buf,int len)63 void XmlText::AddParsedText(const char* buf, int len) {
64 text_.append(buf, len);
65 }
66
AddText(const std::string & text)67 void XmlText::AddText(const std::string& text) {
68 text_ += text;
69 }
70
~XmlText()71 XmlText::~XmlText() {
72 }
73
XmlElement(const QName & name)74 XmlElement::XmlElement(const QName& name) :
75 name_(name),
76 first_attr_(NULL),
77 last_attr_(NULL),
78 first_child_(NULL),
79 last_child_(NULL),
80 cdata_(false) {
81 }
82
XmlElement(const XmlElement & elt)83 XmlElement::XmlElement(const XmlElement& elt) :
84 XmlChild(),
85 name_(elt.name_),
86 first_attr_(NULL),
87 last_attr_(NULL),
88 first_child_(NULL),
89 last_child_(NULL),
90 cdata_(false) {
91
92 // copy attributes
93 XmlAttr* attr;
94 XmlAttr ** plast_attr = &first_attr_;
95 XmlAttr* newAttr = NULL;
96 for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) {
97 newAttr = new XmlAttr(*attr);
98 *plast_attr = newAttr;
99 plast_attr = &(newAttr->next_attr_);
100 }
101 last_attr_ = newAttr;
102
103 // copy children
104 XmlChild* pChild;
105 XmlChild ** ppLast = &first_child_;
106 XmlChild* newChild = NULL;
107
108 for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) {
109 if (pChild->IsText()) {
110 newChild = new XmlText(*(pChild->AsText()));
111 } else {
112 newChild = new XmlElement(*(pChild->AsElement()));
113 }
114 *ppLast = newChild;
115 ppLast = &(newChild->next_child_);
116 }
117 last_child_ = newChild;
118
119 cdata_ = elt.cdata_;
120 }
121
XmlElement(const QName & name,bool useDefaultNs)122 XmlElement::XmlElement(const QName& name, bool useDefaultNs) :
123 name_(name),
124 first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
125 last_attr_(first_attr_),
126 first_child_(NULL),
127 last_child_(NULL),
128 cdata_(false) {
129 }
130
IsTextImpl() const131 bool XmlElement::IsTextImpl() const {
132 return false;
133 }
134
AsElementImpl() const135 XmlElement* XmlElement::AsElementImpl() const {
136 return const_cast<XmlElement *>(this);
137 }
138
AsTextImpl() const139 XmlText* XmlElement::AsTextImpl() const {
140 return NULL;
141 }
142
BodyText() const143 const std::string XmlElement::BodyText() const {
144 if (first_child_ && first_child_->IsText() && last_child_ == first_child_) {
145 return first_child_->AsText()->Text();
146 }
147
148 return std::string();
149 }
150
SetBodyText(const std::string & text)151 void XmlElement::SetBodyText(const std::string& text) {
152 if (text.empty()) {
153 ClearChildren();
154 } else if (first_child_ == NULL) {
155 AddText(text);
156 } else if (first_child_->IsText() && last_child_ == first_child_) {
157 first_child_->AsText()->SetText(text);
158 } else {
159 ClearChildren();
160 AddText(text);
161 }
162 }
163
FirstElementName() const164 const QName XmlElement::FirstElementName() const {
165 const XmlElement* element = FirstElement();
166 if (element == NULL)
167 return QName();
168 return element->Name();
169 }
170
FirstAttr()171 XmlAttr* XmlElement::FirstAttr() {
172 return first_attr_;
173 }
174
Attr(const StaticQName & name) const175 const std::string XmlElement::Attr(const StaticQName& name) const {
176 XmlAttr* attr;
177 for (attr = first_attr_; attr; attr = attr->next_attr_) {
178 if (attr->name_ == name)
179 return attr->value_;
180 }
181 return std::string();
182 }
183
Attr(const QName & name) const184 const std::string XmlElement::Attr(const QName& name) const {
185 XmlAttr* attr;
186 for (attr = first_attr_; attr; attr = attr->next_attr_) {
187 if (attr->name_ == name)
188 return attr->value_;
189 }
190 return std::string();
191 }
192
HasAttr(const StaticQName & name) const193 bool XmlElement::HasAttr(const StaticQName& name) const {
194 XmlAttr* attr;
195 for (attr = first_attr_; attr; attr = attr->next_attr_) {
196 if (attr->name_ == name)
197 return true;
198 }
199 return false;
200 }
201
HasAttr(const QName & name) const202 bool XmlElement::HasAttr(const QName& name) const {
203 XmlAttr* attr;
204 for (attr = first_attr_; attr; attr = attr->next_attr_) {
205 if (attr->name_ == name)
206 return true;
207 }
208 return false;
209 }
210
SetAttr(const QName & name,const std::string & value)211 void XmlElement::SetAttr(const QName& name, const std::string& value) {
212 XmlAttr* attr;
213 for (attr = first_attr_; attr; attr = attr->next_attr_) {
214 if (attr->name_ == name)
215 break;
216 }
217 if (!attr) {
218 attr = new XmlAttr(name, value);
219 if (last_attr_)
220 last_attr_->next_attr_ = attr;
221 else
222 first_attr_ = attr;
223 last_attr_ = attr;
224 return;
225 }
226 attr->value_ = value;
227 }
228
ClearAttr(const QName & name)229 void XmlElement::ClearAttr(const QName& name) {
230 XmlAttr* attr;
231 XmlAttr* last_attr = NULL;
232 for (attr = first_attr_; attr; attr = attr->next_attr_) {
233 if (attr->name_ == name)
234 break;
235 last_attr = attr;
236 }
237 if (!attr)
238 return;
239 if (!last_attr)
240 first_attr_ = attr->next_attr_;
241 else
242 last_attr->next_attr_ = attr->next_attr_;
243 if (last_attr_ == attr)
244 last_attr_ = last_attr;
245 delete attr;
246 }
247
FirstChild()248 XmlChild* XmlElement::FirstChild() {
249 return first_child_;
250 }
251
FirstElement()252 XmlElement* XmlElement::FirstElement() {
253 XmlChild* pChild;
254 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
255 if (!pChild->IsText())
256 return pChild->AsElement();
257 }
258 return NULL;
259 }
260
NextElement()261 XmlElement* XmlElement::NextElement() {
262 XmlChild* pChild;
263 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
264 if (!pChild->IsText())
265 return pChild->AsElement();
266 }
267 return NULL;
268 }
269
FirstWithNamespace(const std::string & ns)270 XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) {
271 XmlChild* pChild;
272 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
273 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
274 return pChild->AsElement();
275 }
276 return NULL;
277 }
278
279 XmlElement *
NextWithNamespace(const std::string & ns)280 XmlElement::NextWithNamespace(const std::string& ns) {
281 XmlChild* pChild;
282 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
283 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
284 return pChild->AsElement();
285 }
286 return NULL;
287 }
288
289 XmlElement *
FirstNamed(const QName & name)290 XmlElement::FirstNamed(const QName& name) {
291 XmlChild* pChild;
292 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
293 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
294 return pChild->AsElement();
295 }
296 return NULL;
297 }
298
299 XmlElement *
FirstNamed(const StaticQName & name)300 XmlElement::FirstNamed(const StaticQName& name) {
301 XmlChild* pChild;
302 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
303 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
304 return pChild->AsElement();
305 }
306 return NULL;
307 }
308
309 XmlElement *
NextNamed(const QName & name)310 XmlElement::NextNamed(const QName& name) {
311 XmlChild* pChild;
312 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
313 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
314 return pChild->AsElement();
315 }
316 return NULL;
317 }
318
319 XmlElement *
NextNamed(const StaticQName & name)320 XmlElement::NextNamed(const StaticQName& name) {
321 XmlChild* pChild;
322 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
323 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
324 return pChild->AsElement();
325 }
326 return NULL;
327 }
328
FindOrAddNamedChild(const QName & name)329 XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
330 XmlElement* child = FirstNamed(name);
331 if (!child) {
332 child = new XmlElement(name);
333 AddElement(child);
334 }
335
336 return child;
337 }
338
TextNamed(const QName & name) const339 const std::string XmlElement::TextNamed(const QName& name) const {
340 XmlChild* pChild;
341 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
342 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
343 return pChild->AsElement()->BodyText();
344 }
345 return std::string();
346 }
347
InsertChildAfter(XmlChild * predecessor,XmlChild * next)348 void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) {
349 if (predecessor == NULL) {
350 next->next_child_ = first_child_;
351 first_child_ = next;
352 }
353 else {
354 next->next_child_ = predecessor->next_child_;
355 predecessor->next_child_ = next;
356 }
357 }
358
RemoveChildAfter(XmlChild * predecessor)359 void XmlElement::RemoveChildAfter(XmlChild* predecessor) {
360 XmlChild* next;
361
362 if (predecessor == NULL) {
363 next = first_child_;
364 first_child_ = next->next_child_;
365 }
366 else {
367 next = predecessor->next_child_;
368 predecessor->next_child_ = next->next_child_;
369 }
370
371 if (last_child_ == next)
372 last_child_ = predecessor;
373
374 delete next;
375 }
376
AddAttr(const QName & name,const std::string & value)377 void XmlElement::AddAttr(const QName& name, const std::string& value) {
378 ASSERT(!HasAttr(name));
379
380 XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_;
381 last_attr_ = (*pprev = new XmlAttr(name, value));
382 }
383
AddAttr(const QName & name,const std::string & value,int depth)384 void XmlElement::AddAttr(const QName& name, const std::string& value,
385 int depth) {
386 XmlElement* element = this;
387 while (depth--) {
388 element = element->last_child_->AsElement();
389 }
390 element->AddAttr(name, value);
391 }
392
AddParsedText(const char * cstr,int len)393 void XmlElement::AddParsedText(const char* cstr, int len) {
394 if (len == 0)
395 return;
396
397 if (last_child_ && last_child_->IsText()) {
398 last_child_->AsText()->AddParsedText(cstr, len);
399 return;
400 }
401 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
402 last_child_ = *pprev = new XmlText(cstr, len);
403 }
404
AddCDATAText(const char * buf,int len)405 void XmlElement::AddCDATAText(const char* buf, int len) {
406 cdata_ = true;
407 AddParsedText(buf, len);
408 }
409
AddText(const std::string & text)410 void XmlElement::AddText(const std::string& text) {
411 if (text == STR_EMPTY)
412 return;
413
414 if (last_child_ && last_child_->IsText()) {
415 last_child_->AsText()->AddText(text);
416 return;
417 }
418 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
419 last_child_ = *pprev = new XmlText(text);
420 }
421
AddText(const std::string & text,int depth)422 void XmlElement::AddText(const std::string& text, int depth) {
423 // note: the first syntax is ambigious for msvc 6
424 // XmlElement* pel(this);
425 XmlElement* element = this;
426 while (depth--) {
427 element = element->last_child_->AsElement();
428 }
429 element->AddText(text);
430 }
431
AddElement(XmlElement * child)432 void XmlElement::AddElement(XmlElement *child) {
433 if (child == NULL)
434 return;
435
436 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
437 *pprev = child;
438 last_child_ = child;
439 child->next_child_ = NULL;
440 }
441
AddElement(XmlElement * child,int depth)442 void XmlElement::AddElement(XmlElement *child, int depth) {
443 XmlElement* element = this;
444 while (depth--) {
445 element = element->last_child_->AsElement();
446 }
447 element->AddElement(child);
448 }
449
ClearNamedChildren(const QName & name)450 void XmlElement::ClearNamedChildren(const QName& name) {
451 XmlChild* prev_child = NULL;
452 XmlChild* next_child;
453 XmlChild* child;
454 for (child = FirstChild(); child; child = next_child) {
455 next_child = child->NextChild();
456 if (!child->IsText() && child->AsElement()->Name() == name)
457 {
458 RemoveChildAfter(prev_child);
459 continue;
460 }
461 prev_child = child;
462 }
463 }
464
ClearAttributes()465 void XmlElement::ClearAttributes() {
466 XmlAttr* attr;
467 for (attr = first_attr_; attr; ) {
468 XmlAttr* to_delete = attr;
469 attr = attr->next_attr_;
470 delete to_delete;
471 }
472 first_attr_ = last_attr_ = NULL;
473 }
474
ClearChildren()475 void XmlElement::ClearChildren() {
476 XmlChild* pchild;
477 for (pchild = first_child_; pchild; ) {
478 XmlChild* to_delete = pchild;
479 pchild = pchild->next_child_;
480 delete to_delete;
481 }
482 first_child_ = last_child_ = NULL;
483 }
484
Str() const485 std::string XmlElement::Str() const {
486 std::stringstream ss;
487 XmlPrinter::PrintXml(&ss, this);
488 return ss.str();
489 }
490
ForStr(const std::string & str)491 XmlElement* XmlElement::ForStr(const std::string& str) {
492 XmlBuilder builder;
493 XmlParser::ParseXml(&builder, str);
494 return builder.CreateElement();
495 }
496
~XmlElement()497 XmlElement::~XmlElement() {
498 XmlAttr* attr;
499 for (attr = first_attr_; attr; ) {
500 XmlAttr* to_delete = attr;
501 attr = attr->next_attr_;
502 delete to_delete;
503 }
504
505 XmlChild* pchild;
506 for (pchild = first_child_; pchild; ) {
507 XmlChild* to_delete = pchild;
508 pchild = pchild->next_child_;
509 delete to_delete;
510 }
511 }
512
513 } // namespace buzz
514