ARB
xml.cxx
Go to the documentation of this file.
1 // --------------------------------------------------------------------------------
2 //
3 // Copyright (C) 2000
4 // Ralf Westram
5 //
6 // Permission to use, copy, modify, distribute and sell this software
7 // and its documentation for any purpose is hereby granted without fee,
8 // provided that the above copyright notice appear in all copies and
9 // that both that copyright notice and this permission notice appear
10 // in supporting documentation. Ralf Westram makes no
11 // representations about the suitability of this software for any
12 // purpose. It is provided "as is" without express or implied warranty.
13 //
14 // This code is part of my library.
15 // You may find a more recent version at http://www.reallysoft.de/
16 //
17 // --------------------------------------------------------------------------------
18 
19 #include "xml.hxx"
20 
21 using namespace std;
22 
23 XML_Document *the_XML_Document = NULp;
24 
25 static const char *entities =
26 " <!ENTITY nbsp \"&#160;\">\n"
27 " <!ENTITY acute \"&#180;\">\n" // Acute accent (forward)
28 " <!ENTITY eacute \"&#233;\">\n" // e Acute (forward)
29 " <!ENTITY apostr \"&#39;\">\n" // single quote (vertical)
30 " <!ENTITY semi \"&#59;\">\n"
31 ;
32 
33 static string encodeEntities(const string& str, bool /*quotedText*/) {
34  // if quotedText is true the string is encoded for usage in quotes
35  // currently it makes no difference, but this might change
36 
37  string neu;
38  neu.reserve(str.length()*4);
39 
40 
41  for (string::const_iterator s = str.begin(); s != str.end(); ++s) {
42  char replace = 0;
43  const char *entity = NULp;
44 
45  switch (*s) {
46  case '<': { entity = "lt"; break; }
47  case '>': { entity = "gt"; break; }
48  case '&': { entity = "amp"; break; }
49  case '\'': { entity = "apostr"; break; }
50  case char(0xb4): { entity = "acute"; break; } // acute (forward)
51  case 'é': { entity = "eacute"; break; }
52  default: { replace = *s; }
53  }
54 
55  if (replace) {
56  neu.append(1, replace);
57  }
58  else {
59  xml_assert(entity);
60  neu.append(1, '&');
61  neu.append(entity);
62  neu.append(1, ';');
63  }
64  }
65 
66  return neu;
67 }
68 
69 // ----------------------
70 // XML_Attribute
71 
72 XML_Attribute::XML_Attribute(const string& name_, const string& content_) :
73  name(name_),
74  content(content_),
75  next(NULp)
76 {}
77 
78 XML_Attribute::~XML_Attribute() {
79  delete next;
80 }
81 XML_Attribute *XML_Attribute::append_to(XML_Attribute *queue) {
82  if (!queue) return this;
83  queue->next = append_to(queue->next);
84  return queue;
85 }
86 void XML_Attribute::print(FILE *out) const {
87  fprintf(out, " %s=\"%s\"", name.c_str(), encodeEntities(content, true).c_str());
88  if (next) next->print(out);
89 }
90 
91 // -----------------
92 // XML_Node
93 
94 XML_Node::XML_Node(bool is_tag) {
96 
97  father = the_XML_Document->LatestSon();
98  the_XML_Document->set_LatestSon(this);
99  indent = 0;
100 
101  if (father) {
102  father->add_son(this, is_tag);
103  indent = father->Indent()+1;
104  }
105 
106  opened = false;
107 }
108 
110  if (father) father->remove_son(this);
111  the_XML_Document->set_LatestSon(father);
112 }
113 
114 
115 // ----------------
116 // XML_Tag
117 
118 XML_Tag::XML_Tag(const string &name_) :
119  XML_Node(true),
120  name(name_),
121  son(NULp),
122  attribute(NULp),
123  state(0),
124  onExtraLine(true)
125 {}
126 
127 XML_Tag::~XML_Tag() {
128  FILE *out = the_XML_Document->Out();
129  xml_assert(!son);
130  close(out);
131 
132  delete attribute;
133 }
134 
135 void XML_Tag::add_attribute(const string& name_, const string& content_) {
136  XML_Attribute *newAttr = new XML_Attribute(name_, content_);
137  attribute = newAttr->append_to(attribute);
138 }
139 
140 void XML_Tag::add_attribute(const string& name_, int value) {
141  char buf[30];
142  sprintf(buf, "%i", value);
143  add_attribute(name_, buf);
144 }
145 
146 void XML_Tag::add_son(XML_Node *son_, bool son_is_tag) {
147  if (son) throw string("Tried to add a second son! Destroy previous son first.");
148  son = son_;
149  int wanted_state = son_is_tag ? 2 : 1;
150  if (state<wanted_state) state = wanted_state;
151 }
152 
153 void XML_Tag::remove_son(XML_Node *son_) {
154  if (son != son_) throw string("Tried to remove wrong son!");
155  son = NULp;
156 }
157 
158 inline void to_indent(FILE *out, int indent) { int i = indent*the_XML_Document->indentation_per_level; while (i--) fputc(' ', out); }
159 
160 void XML_Tag::open(FILE *out) {
161  if (father && !father->Opened()) father->open(out);
162  if (onExtraLine) {
163  fputc('\n', out);
164  to_indent(out, Indent());
165  }
166  fputc('<', out); fputs(name.c_str(), out);
167  if (attribute) attribute->print(out);
168  fputc('>', out);
169  opened = true;
170 }
171 
172 void XML_Tag::close(FILE *out) {
173  if (!opened) {
174  if (!the_XML_Document->skip_empty_tags || attribute || !father) {
175  if (father && !father->Opened()) father->open(out);
176  if (onExtraLine) {
177  fputc('\n', out);
178  to_indent(out, Indent());
179  }
180  fputc('<', out); fputs(name.c_str(), out);
181  if (attribute) attribute->print(out);
182  fputs("/>", out);
183  }
184  }
185  else {
186  if (state >= 2 && onExtraLine) { fputc('\n', out); to_indent(out, Indent()); }
187  fprintf(out, "</%s>", name.c_str());
188  }
189 }
190 
191 // -----------------
192 // XML_Text
193 
195  FILE *out = the_XML_Document->Out();
196  close(out);
197 }
198 
200  throw string("Can't add son to XML_Text-Node");
201 }
202 
203 void XML_Text::remove_son(XML_Node * /* son_ */) {
204  throw string("Can't remove son from XML_Text-Node");
205 }
206 
207 void XML_Text::open(FILE *) {}
208 
209 void XML_Text::close(FILE *out) {
210  if (father && !father->Opened()) father->open(out);
211  fputs(encodeEntities(content, false).c_str(), out);
212 }
213 
214 // --------------------
215 // XML_Comment
216 
218  FILE *out = the_XML_Document->Out();
219  close(out);
220 }
221 
223  throw string("Can't add son to XML_Comment-Node");
224 }
225 
227  throw string("Can't remove son from XML_Comment-Node");
228 }
229 
230 void XML_Comment::open(FILE *) {}
231 
232 void XML_Comment::close(FILE *out) {
233  fputc('\n', out); to_indent(out, Indent());
234  fputs("<!--", out);
235  fputs(encodeEntities(content, false).c_str(), out);
236  fputs("-->", out);
237 }
238 
239 // ---------------------
240 // XML_Document
241 
242 XML_Document::XML_Document(const string& name_, const string& dtd_, FILE *out_)
243  : dtd(dtd_),
244  root(NULp),
245  out(out_),
246  skip_empty_tags(false),
247  indentation_per_level(1)
248 {
249  xml_assert(out);
250  if (the_XML_Document) GBK_terminate("You can only have one XML_Document at a time.");
251  the_XML_Document = this;
252  latest_son = NULp;
253  root = new XML_Tag(name_);
254  xml_assert(latest_son == root);
255 
256  fputs("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", out);
257  fprintf(out, "<!DOCTYPE %s SYSTEM '%s' [\n%s]>\n", name_.c_str(), dtd.c_str(), entities);
258 }
259 
260 XML_Document::~XML_Document() {
261  delete root;
262  xml_assert(the_XML_Document == this);
264 }
265 
266 
void close(FILE *out) OVERRIDE
Definition: xml.cxx:232
XML_Node(bool is_tag)
Definition: xml.cxx:94
void remove_son(XML_Node *son_) OVERRIDE __ATTR__NORETURN
Definition: xml.cxx:203
int Indent() const
Definition: xml.hxx:79
return string(buffer, length)
#define xml_assert(bed)
Definition: xml.hxx:37
XML_Node * father
Definition: xml.hxx:71
static string encodeEntities(const string &str, bool)
Definition: xml.cxx:33
virtual ~XML_Node()
Definition: xml.cxx:109
STL namespace.
bool Opened() const
Definition: xml.hxx:80
~XML_Text() OVERRIDE
Definition: xml.cxx:194
POS_TREE1 * father
Definition: probe_tree.h:39
void add_son(XML_Node *son_, bool son_is_tag) OVERRIDE __ATTR__NORETURN
Definition: xml.cxx:199
virtual void add_son(XML_Node *son_, bool son_is_tag)=0
~XML_Comment() OVERRIDE
Definition: xml.cxx:217
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:509
#define true
Definition: ureadseq.h:14
#define false
Definition: ureadseq.h:13
XML_Document * the_XML_Document
Definition: xml.cxx:23
void add_son(XML_Node *son_, bool son_is_tag) OVERRIDE __ATTR__NORETURN
Definition: xml.cxx:222
fputc('\n', stderr)
void open(FILE *) OVERRIDE
Definition: xml.cxx:230
void remove_son(XML_Node *son_) OVERRIDE __ATTR__NORETURN
Definition: xml.cxx:226
fputs(TRACE_PREFIX, stderr)
static const char * entities
Definition: xml.cxx:25
Definition: xml.hxx:69
Definition: output.h:122
void open(FILE *) OVERRIDE
Definition: xml.cxx:207
void to_indent(FILE *out, int indent)
Definition: xml.cxx:158
virtual void remove_son(XML_Node *son_)=0
#define NULp
Definition: cxxforward.h:116
void close(FILE *out) OVERRIDE
Definition: xml.cxx:209
bool opened
Definition: xml.hxx:72
virtual void open(FILE *out)=0
void print(const T &t)
Definition: test_unit.h:359
GB_write_int const char s
Definition: AW_awar.cxx:154