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