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 41namespace buzz { 42 43const QName QN_EMPTY(true, STR_EMPTY, STR_EMPTY); 44const QName QN_XMLNS(true, STR_EMPTY, STR_XMLNS); 45 46 47XmlChild::~XmlChild() { 48} 49 50bool 51XmlText::IsTextImpl() const { 52 return true; 53} 54 55XmlElement * 56XmlText::AsElementImpl() const { 57 return NULL; 58} 59 60XmlText * 61XmlText::AsTextImpl() const { 62 return const_cast<XmlText *>(this); 63} 64 65void 66XmlText::SetText(const std::string & text) { 67 text_ = text; 68} 69 70void 71XmlText::AddParsedText(const char * buf, int len) { 72 text_.append(buf, len); 73} 74 75void 76XmlText::AddText(const std::string & text) { 77 text_ += text; 78} 79 80XmlText::~XmlText() { 81} 82 83XmlElement::XmlElement(const QName & name) : 84 name_(name), 85 pFirstAttr_(NULL), 86 pLastAttr_(NULL), 87 pFirstChild_(NULL), 88 pLastChild_(NULL), 89 cdata_(false) { 90} 91 92XmlElement::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 131XmlElement::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 140bool 141XmlElement::IsTextImpl() const { 142 return false; 143} 144 145XmlElement * 146XmlElement::AsElementImpl() const { 147 return const_cast<XmlElement *>(this); 148} 149 150XmlText * 151XmlElement::AsTextImpl() const { 152 return NULL; 153} 154 155const std::string & 156XmlElement::BodyText() const { 157 if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) { 158 return pFirstChild_->AsText()->Text(); 159 } 160 161 return STR_EMPTY; 162} 163 164void 165XmlElement::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 178const QName & 179XmlElement::FirstElementName() const { 180 const XmlElement * element = FirstElement(); 181 if (element == NULL) 182 return QN_EMPTY; 183 return element->Name(); 184} 185 186XmlAttr * 187XmlElement::FirstAttr() { 188 return pFirstAttr_; 189} 190 191const std::string & 192XmlElement::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 201bool 202XmlElement::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 211void 212XmlElement::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 230void 231XmlElement::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 250XmlChild * 251XmlElement::FirstChild() { 252 return pFirstChild_; 253} 254 255XmlElement * 256XmlElement::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 265XmlElement * 266XmlElement::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 275XmlElement * 276XmlElement::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 285XmlElement * 286XmlElement::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 295XmlElement * 296XmlElement::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 305XmlElement * 306XmlElement::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 315XmlElement* 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 325const std::string & 326XmlElement::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 335void 336XmlElement::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 347void 348XmlElement::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 366void 367XmlElement::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 374void 375XmlElement::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 384void 385XmlElement::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 397void 398XmlElement::AddCDATAText(const char * buf, int len) { 399 cdata_ = true; 400 AddParsedText(buf, len); 401} 402 403void 404XmlElement::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 416void 417XmlElement::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 427void 428XmlElement::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 437void 438XmlElement::AddElement(XmlElement *pelChild, int depth) { 439 XmlElement * element = this; 440 while (depth--) { 441 element = element->pLastChild_->AsElement(); 442 } 443 element->AddElement(pelChild); 444} 445 446void 447XmlElement::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 462void 463XmlElement::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 473void 474XmlElement::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 484std::string 485XmlElement::Str() const { 486 std::stringstream ss; 487 Print(&ss, NULL, 0); 488 return ss.str(); 489} 490 491XmlElement * 492XmlElement::ForStr(const std::string & str) { 493 XmlBuilder builder; 494 XmlParser::ParseXml(&builder, str); 495 return builder.CreateElement(); 496} 497 498void 499XmlElement::Print( 500 std::ostream * pout, std::string xmlns[], int xmlnsCount) const { 501 XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount); 502} 503 504XmlElement::~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