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 25namespace buzz { 26 27XmlChild::~XmlChild() { 28} 29 30bool XmlText::IsTextImpl() const { 31 return true; 32} 33 34XmlElement* XmlText::AsElementImpl() const { 35 return NULL; 36} 37 38XmlText* XmlText::AsTextImpl() const { 39 return const_cast<XmlText *>(this); 40} 41 42void XmlText::SetText(const std::string& text) { 43 text_ = text; 44} 45 46void XmlText::AddParsedText(const char* buf, int len) { 47 text_.append(buf, len); 48} 49 50void XmlText::AddText(const std::string& text) { 51 text_ += text; 52} 53 54XmlText::~XmlText() { 55} 56 57XmlElement::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 66XmlElement::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 105XmlElement::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 114bool XmlElement::IsTextImpl() const { 115 return false; 116} 117 118XmlElement* XmlElement::AsElementImpl() const { 119 return const_cast<XmlElement *>(this); 120} 121 122XmlText* XmlElement::AsTextImpl() const { 123 return NULL; 124} 125 126const 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 134void 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 147const QName XmlElement::FirstElementName() const { 148 const XmlElement* element = FirstElement(); 149 if (element == NULL) 150 return QName(); 151 return element->Name(); 152} 153 154XmlAttr* XmlElement::FirstAttr() { 155 return first_attr_; 156} 157 158const 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 167const 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 176bool 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 185bool 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 194void 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 212void 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 231XmlChild* XmlElement::FirstChild() { 232 return first_child_; 233} 234 235XmlElement* 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 244XmlElement* 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 253XmlElement* 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 262XmlElement * 263XmlElement::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 272XmlElement * 273XmlElement::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 282XmlElement * 283XmlElement::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 292XmlElement * 293XmlElement::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 302XmlElement * 303XmlElement::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 312XmlElement* 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 322const 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 331void 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 342void 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 360void 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 367void 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 376void 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 388void XmlElement::AddCDATAText(const char* buf, int len) { 389 cdata_ = true; 390 AddParsedText(buf, len); 391} 392 393void 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 405void 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 415void 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 425void 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 433void 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 448void 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 458void 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 468std::string XmlElement::Str() const { 469 std::stringstream ss; 470 XmlPrinter::PrintXml(&ss, this); 471 return ss.str(); 472} 473 474XmlElement* XmlElement::ForStr(const std::string& str) { 475 XmlBuilder builder; 476 XmlParser::ParseXml(&builder, str); 477 return builder.CreateElement(); 478} 479 480XmlElement::~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