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/xmlprinter.h" |
| 12 |
| 13 #include <sstream> |
| 14 #include <string> |
| 15 #include <vector> |
| 16 |
| 17 #include "webrtc/libjingle/xmllite/xmlconstants.h" |
| 18 #include "webrtc/libjingle/xmllite/xmlelement.h" |
| 19 #include "webrtc/libjingle/xmllite/xmlnsstack.h" |
| 20 |
| 21 namespace buzz { |
| 22 |
| 23 class XmlPrinterImpl { |
| 24 public: |
| 25 XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack); |
| 26 void PrintElement(const XmlElement* element); |
| 27 void PrintQuotedValue(const std::string& text); |
| 28 void PrintBodyText(const std::string& text); |
| 29 void PrintCDATAText(const std::string& text); |
| 30 |
| 31 private: |
| 32 std::ostream *pout_; |
| 33 XmlnsStack* ns_stack_; |
| 34 }; |
| 35 |
| 36 void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) { |
| 37 XmlnsStack ns_stack; |
| 38 PrintXml(pout, element, &ns_stack); |
| 39 } |
| 40 |
| 41 void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element, |
| 42 XmlnsStack* ns_stack) { |
| 43 XmlPrinterImpl printer(pout, ns_stack); |
| 44 printer.PrintElement(element); |
| 45 } |
| 46 |
| 47 XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack) |
| 48 : pout_(pout), |
| 49 ns_stack_(ns_stack) { |
| 50 } |
| 51 |
| 52 void XmlPrinterImpl::PrintElement(const XmlElement* element) { |
| 53 ns_stack_->PushFrame(); |
| 54 |
| 55 // first go through attrs of pel to add xmlns definitions |
| 56 const XmlAttr* attr; |
| 57 for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { |
| 58 if (attr->Name() == QN_XMLNS) { |
| 59 ns_stack_->AddXmlns(STR_EMPTY, attr->Value()); |
| 60 } else if (attr->Name().Namespace() == NS_XMLNS) { |
| 61 ns_stack_->AddXmlns(attr->Name().LocalPart(), |
| 62 attr->Value()); |
| 63 } |
| 64 } |
| 65 |
| 66 // then go through qnames to make sure needed xmlns definitons are added |
| 67 std::vector<std::string> new_ns; |
| 68 std::pair<std::string, bool> prefix; |
| 69 prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false); |
| 70 if (prefix.second) { |
| 71 new_ns.push_back(prefix.first); |
| 72 new_ns.push_back(element->Name().Namespace()); |
| 73 } |
| 74 |
| 75 for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { |
| 76 prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true); |
| 77 if (prefix.second) { |
| 78 new_ns.push_back(prefix.first); |
| 79 new_ns.push_back(attr->Name().Namespace()); |
| 80 } |
| 81 } |
| 82 |
| 83 // print the element name |
| 84 *pout_ << '<' << ns_stack_->FormatQName(element->Name(), false); |
| 85 |
| 86 // and the attributes |
| 87 for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { |
| 88 *pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\""; |
| 89 PrintQuotedValue(attr->Value()); |
| 90 *pout_ << '"'; |
| 91 } |
| 92 |
| 93 // and the extra xmlns declarations |
| 94 std::vector<std::string>::iterator i(new_ns.begin()); |
| 95 while (i < new_ns.end()) { |
| 96 if (*i == STR_EMPTY) { |
| 97 *pout_ << " xmlns=\"" << *(i + 1) << '"'; |
| 98 } else { |
| 99 *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"'; |
| 100 } |
| 101 i += 2; |
| 102 } |
| 103 |
| 104 // now the children |
| 105 const XmlChild* child = element->FirstChild(); |
| 106 |
| 107 if (child == NULL) |
| 108 *pout_ << "/>"; |
| 109 else { |
| 110 *pout_ << '>'; |
| 111 while (child) { |
| 112 if (child->IsText()) { |
| 113 if (element->IsCDATA()) { |
| 114 PrintCDATAText(child->AsText()->Text()); |
| 115 } else { |
| 116 PrintBodyText(child->AsText()->Text()); |
| 117 } |
| 118 } else { |
| 119 PrintElement(child->AsElement()); |
| 120 } |
| 121 child = child->NextChild(); |
| 122 } |
| 123 *pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>'; |
| 124 } |
| 125 |
| 126 ns_stack_->PopFrame(); |
| 127 } |
| 128 |
| 129 void XmlPrinterImpl::PrintQuotedValue(const std::string& text) { |
| 130 size_t safe = 0; |
| 131 for (;;) { |
| 132 size_t unsafe = text.find_first_of("<>&\"", safe); |
| 133 if (unsafe == std::string::npos) |
| 134 unsafe = text.length(); |
| 135 *pout_ << text.substr(safe, unsafe - safe); |
| 136 if (unsafe == text.length()) |
| 137 return; |
| 138 switch (text[unsafe]) { |
| 139 case '<': *pout_ << "<"; break; |
| 140 case '>': *pout_ << ">"; break; |
| 141 case '&': *pout_ << "&"; break; |
| 142 case '"': *pout_ << """; break; |
| 143 } |
| 144 safe = unsafe + 1; |
| 145 if (safe == text.length()) |
| 146 return; |
| 147 } |
| 148 } |
| 149 |
| 150 void XmlPrinterImpl::PrintBodyText(const std::string& text) { |
| 151 size_t safe = 0; |
| 152 for (;;) { |
| 153 size_t unsafe = text.find_first_of("<>&", safe); |
| 154 if (unsafe == std::string::npos) |
| 155 unsafe = text.length(); |
| 156 *pout_ << text.substr(safe, unsafe - safe); |
| 157 if (unsafe == text.length()) |
| 158 return; |
| 159 switch (text[unsafe]) { |
| 160 case '<': *pout_ << "<"; break; |
| 161 case '>': *pout_ << ">"; break; |
| 162 case '&': *pout_ << "&"; break; |
| 163 } |
| 164 safe = unsafe + 1; |
| 165 if (safe == text.length()) |
| 166 return; |
| 167 } |
| 168 } |
| 169 |
| 170 void XmlPrinterImpl::PrintCDATAText(const std::string& text) { |
| 171 *pout_ << "<![CDATA[" << text << "]]>"; |
| 172 } |
| 173 |
| 174 } // namespace buzz |
OLD | NEW |