Home | History | Annotate | Download | only in xmllite
      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
    497