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