1 // Copyright 2017 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "examples/xml/xml_writer.h"
16
17 #include <algorithm>
18 #include <sstream>
19
20 #include "examples/xml/xml.pb.h"
21
22 namespace protobuf_mutator {
23 namespace xml {
24
25 namespace {
26
27 class XmlWriter {
28 public:
29 XmlWriter();
30 std::string ToXml(const Document& doc);
31
32 private:
33 void ToXml(const std::string& name, const std::string& value);
34 void ToXml(const Element& element);
35 void ToXml(const Content& content);
36 void ToXml(const Misk& misk);
37 void ToXml(const DoctypeDecl& doctype);
38
39 std::ostringstream out_;
40 };
41
XmlWriter()42 XmlWriter::XmlWriter() {}
43
ToXml(const std::string & name,const std::string & value)44 void XmlWriter::ToXml(const std::string& name, const std::string& value) {
45 char quote = (name.size() % 2) ? '"' : '\'';
46 out_ << " " << name << "=" << quote << value << quote;
47 }
48
ToXml(const Misk & misk)49 void XmlWriter::ToXml(const Misk& misk) {
50 if (misk.has_pi()) {
51 out_ << "<?" << misk.pi().target() << misk.pi().data() << "?>";
52 }
53
54 if (misk.has_comment()) {
55 out_ << "<!--" << misk.comment() << "-->";
56 }
57 }
58
ToXml(const DoctypeDecl & doctype)59 void XmlWriter::ToXml(const DoctypeDecl& doctype) {
60 out_ << "<!DOCTYPE " << doctype.name();
61 if (doctype.has_external_id()) out_ << " " << doctype.external_id();
62 if (doctype.has_int_subset()) out_ << " [" << doctype.int_subset() << "]";
63 for (int i = 0; i < doctype.misk_size(); ++i) ToXml(doctype.misk(i));
64 out_ << ">";
65 }
66
ToXml(const Content & content)67 void XmlWriter::ToXml(const Content& content) {
68 if (content.has_char_data()) out_ << content.char_data();
69 if (content.has_element()) ToXml(content.element());
70 if (content.has_reference()) {
71 out_ << (content.reference().entry() ? '&' : '%')
72 << content.reference().name() << ';';
73 }
74 if (content.has_cdsect()) out_ << "<![CDATA[" << content.cdsect() << "]]>";
75
76 if (content.has_misk()) ToXml(content.misk());
77 }
78
ToXml(const Element & element)79 void XmlWriter::ToXml(const Element& element) {
80 std::string tag;
81 std::string name;
82 tag += element.tag().name();
83 out_ << "<" << tag;
84
85 for (int i = 0; i < element.tag().attribute_size(); ++i) {
86 ToXml(element.tag().attribute(i).name(),
87 element.tag().attribute(i).value());
88 }
89
90 if (element.content_size() == 0) {
91 out_ << "/>";
92 } else {
93 out_ << ">";
94 for (int i = 0; i < element.content_size(); ++i) ToXml(element.content(i));
95 out_ << "</" << tag << ">";
96 }
97 }
98
ToXml(const Document & doc)99 std::string XmlWriter::ToXml(const Document& doc) {
100 out_.str("");
101
102 if (doc.has_version() || doc.has_encoding() || doc.has_standalone()) {
103 out_ << "<?xml";
104 if (doc.has_version())
105 ToXml("version", (doc.version().size() == 7) ? "1.0" : doc.version());
106 if (doc.has_encoding()) ToXml("encoding", doc.encoding());
107 if (doc.has_standalone())
108 ToXml("encoding", doc.standalone() ? "yes" : "no");
109 out_ << "?>";
110 }
111
112 for (int i = 0; i < doc.misk1_size(); ++i) ToXml(doc.misk1(i));
113 if (doc.has_doctype()) ToXml(doc.doctype());
114 ToXml(doc.element());
115 for (int i = 0; i < doc.misk2_size(); ++i) ToXml(doc.misk2(i));
116
117 return out_.str();
118 }
119
120 } // namespace
121
MessageToXml(const Document & document)122 std::string MessageToXml(const Document& document) {
123 XmlWriter writer;
124 return writer.ToXml(document);
125 }
126
127 } // namespace xml
128 } // namespace protobuf_mutator
129