Home | History | Annotate | Download | only in xmllite
      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_ << "&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 
    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 
    170 void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
    171   *pout_ << "<![CDATA[" << text << "]]>";
    172 }
    173 
    174 }  // namespace buzz
    175