• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "talk/xmllite/xmlprinter.h"
29 
30 #include <sstream>
31 #include <string>
32 #include <vector>
33 
34 #include "talk/xmllite/xmlconstants.h"
35 #include "talk/xmllite/xmlelement.h"
36 #include "talk/xmllite/xmlnsstack.h"
37 
38 namespace buzz {
39 
40 class XmlPrinterImpl {
41 public:
42   XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack);
43   void PrintElement(const XmlElement* element);
44   void PrintQuotedValue(const std::string& text);
45   void PrintBodyText(const std::string& text);
46   void PrintCDATAText(const std::string& text);
47 
48 private:
49   std::ostream *pout_;
50   XmlnsStack* ns_stack_;
51 };
52 
PrintXml(std::ostream * pout,const XmlElement * element)53 void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) {
54   XmlnsStack ns_stack;
55   PrintXml(pout, element, &ns_stack);
56 }
57 
PrintXml(std::ostream * pout,const XmlElement * element,XmlnsStack * ns_stack)58 void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element,
59                           XmlnsStack* ns_stack) {
60   XmlPrinterImpl printer(pout, ns_stack);
61   printer.PrintElement(element);
62 }
63 
XmlPrinterImpl(std::ostream * pout,XmlnsStack * ns_stack)64 XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack)
65     : pout_(pout),
66       ns_stack_(ns_stack) {
67 }
68 
PrintElement(const XmlElement * element)69 void XmlPrinterImpl::PrintElement(const XmlElement* element) {
70   ns_stack_->PushFrame();
71 
72   // first go through attrs of pel to add xmlns definitions
73   const XmlAttr* attr;
74   for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
75     if (attr->Name() == QN_XMLNS) {
76       ns_stack_->AddXmlns(STR_EMPTY, attr->Value());
77     } else if (attr->Name().Namespace() == NS_XMLNS) {
78       ns_stack_->AddXmlns(attr->Name().LocalPart(),
79                           attr->Value());
80     }
81   }
82 
83   // then go through qnames to make sure needed xmlns definitons are added
84   std::vector<std::string> new_ns;
85   std::pair<std::string, bool> prefix;
86   prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false);
87   if (prefix.second) {
88     new_ns.push_back(prefix.first);
89     new_ns.push_back(element->Name().Namespace());
90   }
91 
92   for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
93     prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true);
94     if (prefix.second) {
95       new_ns.push_back(prefix.first);
96       new_ns.push_back(attr->Name().Namespace());
97     }
98   }
99 
100   // print the element name
101   *pout_ << '<' << ns_stack_->FormatQName(element->Name(), false);
102 
103   // and the attributes
104   for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
105     *pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\"";
106     PrintQuotedValue(attr->Value());
107     *pout_ << '"';
108   }
109 
110   // and the extra xmlns declarations
111   std::vector<std::string>::iterator i(new_ns.begin());
112   while (i < new_ns.end()) {
113     if (*i == STR_EMPTY) {
114       *pout_ << " xmlns=\"" << *(i + 1) << '"';
115     } else {
116       *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
117     }
118     i += 2;
119   }
120 
121   // now the children
122   const XmlChild* child = element->FirstChild();
123 
124   if (child == NULL)
125     *pout_ << "/>";
126   else {
127     *pout_ << '>';
128     while (child) {
129       if (child->IsText()) {
130         if (element->IsCDATA()) {
131           PrintCDATAText(child->AsText()->Text());
132         } else {
133           PrintBodyText(child->AsText()->Text());
134         }
135       } else {
136         PrintElement(child->AsElement());
137       }
138       child = child->NextChild();
139     }
140     *pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>';
141   }
142 
143   ns_stack_->PopFrame();
144 }
145 
PrintQuotedValue(const std::string & text)146 void XmlPrinterImpl::PrintQuotedValue(const std::string& text) {
147   size_t safe = 0;
148   for (;;) {
149     size_t unsafe = text.find_first_of("<>&\"", safe);
150     if (unsafe == std::string::npos)
151       unsafe = text.length();
152     *pout_ << text.substr(safe, unsafe - safe);
153     if (unsafe == text.length())
154       return;
155     switch (text[unsafe]) {
156       case '<': *pout_ << "&lt;"; break;
157       case '>': *pout_ << "&gt;"; break;
158       case '&': *pout_ << "&amp;"; break;
159       case '"': *pout_ << "&quot;"; break;
160     }
161     safe = unsafe + 1;
162     if (safe == text.length())
163       return;
164   }
165 }
166 
PrintBodyText(const std::string & text)167 void XmlPrinterImpl::PrintBodyText(const std::string& text) {
168   size_t safe = 0;
169   for (;;) {
170     size_t unsafe = text.find_first_of("<>&", safe);
171     if (unsafe == std::string::npos)
172       unsafe = text.length();
173     *pout_ << text.substr(safe, unsafe - safe);
174     if (unsafe == text.length())
175       return;
176     switch (text[unsafe]) {
177       case '<': *pout_ << "&lt;"; break;
178       case '>': *pout_ << "&gt;"; break;
179       case '&': *pout_ << "&amp;"; break;
180     }
181     safe = unsafe + 1;
182     if (safe == text.length())
183       return;
184   }
185 }
186 
PrintCDATAText(const std::string & text)187 void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
188   *pout_ << "<![CDATA[" << text << "]]>";
189 }
190 
191 }  // namespace buzz
192