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