• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PrintXml(std::ostream * pout,const XmlElement * element)36 void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) {
37   XmlnsStack ns_stack;
38   PrintXml(pout, element, &ns_stack);
39 }
40 
PrintXml(std::ostream * pout,const XmlElement * element,XmlnsStack * ns_stack)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 
XmlPrinterImpl(std::ostream * pout,XmlnsStack * ns_stack)47 XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack)
48     : pout_(pout),
49       ns_stack_(ns_stack) {
50 }
51 
PrintElement(const XmlElement * element)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 
PrintQuotedValue(const std::string & text)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_ << "&lt;"; break;
140       case '>': *pout_ << "&gt;"; break;
141       case '&': *pout_ << "&amp;"; break;
142       case '"': *pout_ << "&quot;"; break;
143     }
144     safe = unsafe + 1;
145     if (safe == text.length())
146       return;
147   }
148 }
149 
PrintBodyText(const std::string & text)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_ << "&lt;"; break;
161       case '>': *pout_ << "&gt;"; break;
162       case '&': *pout_ << "&amp;"; break;
163     }
164     safe = unsafe + 1;
165     if (safe == text.length())
166       return;
167   }
168 }
169 
PrintCDATAText(const std::string & text)170 void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
171   *pout_ << "<![CDATA[" << text << "]]>";
172 }
173 
174 }  // namespace buzz
175