• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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