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 |