Home | History | Annotate | Download | only in xmllite
      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 
     44 XmlChild::~XmlChild() {
     45 }
     46 
     47 bool XmlText::IsTextImpl() const {
     48   return true;
     49 }
     50 
     51 XmlElement* XmlText::AsElementImpl() const {
     52   return NULL;
     53 }
     54 
     55 XmlText* XmlText::AsTextImpl() const {
     56   return const_cast<XmlText *>(this);
     57 }
     58 
     59 void XmlText::SetText(const std::string& text) {
     60   text_ = text;
     61 }
     62 
     63 void XmlText::AddParsedText(const char* buf, int len) {
     64   text_.append(buf, len);
     65 }
     66 
     67 void XmlText::AddText(const std::string& text) {
     68   text_ += text;
     69 }
     70 
     71 XmlText::~XmlText() {
     72 }
     73 
     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 
     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 
    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 
    131 bool XmlElement::IsTextImpl() const {
    132   return false;
    133 }
    134 
    135 XmlElement* XmlElement::AsElementImpl() const {
    136   return const_cast<XmlElement *>(this);
    137 }
    138 
    139 XmlText* XmlElement::AsTextImpl() const {
    140   return NULL;
    141 }
    142 
    143 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 
    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 
    164 const QName XmlElement::FirstElementName() const {
    165   const XmlElement* element = FirstElement();
    166   if (element == NULL)
    167     return QName();
    168   return element->Name();
    169 }
    170 
    171 XmlAttr* XmlElement::FirstAttr() {
    172   return first_attr_;
    173 }
    174 
    175 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 
    184 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 
    193 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 
    202 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 
    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 
    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 
    248 XmlChild* XmlElement::FirstChild() {
    249   return first_child_;
    250 }
    251 
    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 
    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 
    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 *
    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 *
    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 *
    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 *
    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 *
    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 
    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 
    339 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 
    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 
    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 
    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 
    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 
    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 
    405 void XmlElement::AddCDATAText(const char* buf, int len) {
    406   cdata_ = true;
    407   AddParsedText(buf, len);
    408 }
    409 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    485 std::string XmlElement::Str() const {
    486   std::stringstream ss;
    487   XmlPrinter::PrintXml(&ss, this);
    488   return ss.str();
    489 }
    490 
    491 XmlElement* XmlElement::ForStr(const std::string& str) {
    492   XmlBuilder builder;
    493   XmlParser::ParseXml(&builder, str);
    494   return builder.CreateElement();
    495 }
    496 
    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