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