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