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