source: tags/arb_5.0/XML/xml.cxx

Last change on this file was 5675, checked in by westram, 15 years ago
  • removed automatic timestamps (the best they were good for, were vc-conflicts)
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
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
21using namespace std;
22
23XML_Document *the_XML_Document = 0;
24
25static 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// ********************************************************************************
34
35//  ---------------------------------------------------------------------------------
36//      static string encodeEntities(const string& str, bool quotedText = false)
37//  ---------------------------------------------------------------------------------
38// if quotedText is true the string is encoded for usage in quotes
39// currently it makes no difference, but this might change
40static string encodeEntities(const string& str, bool quotedText = false) {
41    string neu;
42    neu.reserve(str.length()*4);
43
44
45    for (string::const_iterator s = str.begin(); s != str.end(); ++s) {
46        char        replace = 0;
47        const char *entity  = 0;
48
49        switch (*s) {
50            case '<':  { entity = "lt"; break; }
51            case '>':  { entity = "gt"; break; }
52            case '&':  { entity = "amp"; break; }
53            case '\'':  { entity = "apostr"; break; }
54            case char(0xb4):  { entity = "acute"; break; } // acute (forward)
55            case 'é': { entity = "eacute"; break; }
56            default :  { replace = *s; }
57            }
58
59        if (replace) {
60            neu.append(1, replace);
61        }
62        else {
63            xml_assert(entity);
64            neu.append(1, '&');
65            neu.append(entity);
66            neu.append(1, ';');
67        }
68    }
69
70    return neu;
71}
72
73//  ----------------------------------------------------------------------------------
74//      XML_Attribute::XML_Attribute(const string& name_, const string& content_)
75//  ----------------------------------------------------------------------------------
76XML_Attribute::XML_Attribute(const string& name_, const string& content_)
77    : name(name_), content(content_), next(0)
78{}
79
80//  ----------------------------------------
81//      XML_Attribute::~XML_Attribute()
82//  ----------------------------------------
83XML_Attribute::~XML_Attribute() {
84    delete next;
85}
86//  ----------------------------------------------------------------------
87//      XML_Attribute *XML_Attribute::append_to(XML_Attribute *queue)
88//  ----------------------------------------------------------------------
89XML_Attribute *XML_Attribute::append_to(XML_Attribute *queue) {
90    if (!queue) return this;
91    queue->next = append_to(queue->next);
92    return queue;
93}
94//  ---------------------------------------------------
95//      void XML_Attribute::print(FILE *out) const
96//  ---------------------------------------------------
97void XML_Attribute::print(FILE *out) const {
98    fprintf(out, " %s=\"%s\"", name.c_str(), encodeEntities(content, true).c_str());
99//     out << " " << name << "=\"" << content << "\"";
100    if (next) next->print(out);
101}
102
103// ********************************************************************************
104
105//  ----------------------------------------
106//      XML_Node::XML_Node(bool is_tag)
107//  ----------------------------------------
108XML_Node::XML_Node(bool is_tag) {
109    xml_assert(the_XML_Document);
110
111    father = the_XML_Document->LatestSon();
112    the_XML_Document->set_LatestSon(this);
113    indent = 0;
114
115    if (father) {
116        father->add_son(this, is_tag);
117        indent = father->Indent()+1;
118    }
119
120    opened = false;
121}
122
123//  ------------------------------
124//      XML_Node::~XML_Node()
125//  ------------------------------
126XML_Node::~XML_Node() {
127    if (father) father->remove_son(this);
128    the_XML_Document->set_LatestSon(father);
129}
130
131// ********************************************************************************
132
133inline void to_indent(FILE *out, int indent) { int i = indent*the_XML_Document->indentation_per_level; while (i--) fputc(' ', out); }
134
135//  ---------------------------------------------
136//      XML_Tag::XML_Tag(const string &name_)
137//  ---------------------------------------------
138XML_Tag::XML_Tag(const string &name_)
139    : XML_Node(true), name(name_), son(0), attribute(0), state(0), onExtraLine(true)
140{
141}
142//  ----------------------------
143//      XML_Tag::~XML_Tag()
144//  ----------------------------
145XML_Tag::~XML_Tag() {
146    FILE *out = the_XML_Document->Out();
147    if (son) {
148        throw string("XML_Tag has son in destructor");
149    }
150    close(out);
151}
152
153//  ---------------------------------------------------------------------------------
154//      void XML_Tag::add_attribute(const string& name_, const string& content_)
155//  ---------------------------------------------------------------------------------
156void XML_Tag::add_attribute(const string& name_, const string& content_) {
157    XML_Attribute *newAttr = new XML_Attribute(name_, content_);
158    attribute = newAttr->append_to(attribute);
159}
160// ---------------------------------------------------------------------
161//      void XML_Tag::add_attribute(const string& name_, int value)
162// ---------------------------------------------------------------------
163void XML_Tag::add_attribute(const string& name_, int value) {
164    char buf[30];
165    sprintf(buf, "%i", value);
166    add_attribute(name_, buf);
167}
168//  ---------------------------------------------------------------
169//      void XML_Tag::add_son(XML_Node *son_, bool son_is_tag)
170//  ---------------------------------------------------------------
171void XML_Tag::add_son(XML_Node *son_, bool son_is_tag) {
172    if (son) throw string("Tried to add a second son! Destroy previous son first.");
173    son                           = son_;
174    int wanted_state              = son_is_tag?2:1;
175    if (state<wanted_state) state = wanted_state;
176}
177//  -------------------------------------------------
178//      void XML_Tag::remove_son(XML_Node *son_)
179//  -------------------------------------------------
180void XML_Tag::remove_son(XML_Node *son_) {
181    if (son != son_) throw string("Tried to remove wrong son!");
182    son = 0;
183}
184
185//  --------------------------------------
186//      void XML_Tag::open(FILE *out)
187//  --------------------------------------
188void XML_Tag::open(FILE *out) {
189    if (father && !father->Opened()) father->open(out);
190    if (onExtraLine) {
191        fputc('\n', out);
192        to_indent(out, Indent());
193    }
194    fputc('<', out); fputs(name.c_str(), out);
195    if (attribute) attribute->print(out);
196    fputc('>', out);
197    opened = true;
198}
199//  ----------------------------------------
200//      void XML_Tag::close(FILE *out)
201//  ----------------------------------------
202void XML_Tag::close(FILE *out)  {
203    if (!opened) {
204        if (!the_XML_Document->skip_empty_tags || attribute || !father) {
205            if (father && !father->Opened()) father->open(out);
206            if (onExtraLine) {
207                fputc('\n', out);
208                to_indent(out, Indent());
209            }
210            fputc('<', out); fputs(name.c_str(), out);
211            if (attribute) attribute->print(out);
212            fputs("/>", out);
213        }
214    }
215    else {
216        if (state >= 2 && onExtraLine) { fputc('\n', out); to_indent(out, Indent()); }
217        fprintf(out, "</%s>", name.c_str());
218    }
219}
220
221// ********************************************************************************
222
223// start of implementation of class XML_Text:
224
225//  ------------------------------
226//      XML_Text::~XML_Text()
227//  ------------------------------
228XML_Text::~XML_Text() {
229    FILE *out = the_XML_Document->Out();
230    close(out);
231}
232//  -------------------------------------------------
233//      void XML_Text::add_son(XML_Node *, bool)
234//  -------------------------------------------------
235void XML_Text::add_son(XML_Node *, bool) {
236    throw string("Can't add son to XML_Text-Node");
237}
238//  ------------------------------------------------------
239//      void XML_Text::remove_son(XML_Node */*son_*/)
240//  ------------------------------------------------------
241void XML_Text::remove_son(XML_Node */*son_*/) {
242    throw string("Can't remove son from XML_Text-Node");
243}
244
245// ------------------------------------
246//      void XML_Text::open(FILE *)
247// ------------------------------------
248void XML_Text::open(FILE *)
249{
250}
251
252//  ----------------------------------------
253//      void XML_Text::close(FILE *out)
254//  ----------------------------------------
255void XML_Text::close(FILE *out) {
256    if (father && !father->Opened()) father->open(out);
257    //fputc('\n', out); to_indent(out, Indent());
258//     fputs(content.c_str(), out);
259    fputs(encodeEntities(content).c_str(), out);
260}
261
262// -end- of implementation of class XML_Text.
263
264// start of implementation of class XML_Comment:
265
266// ------------------------------------
267//      XML_Comment::~XML_Comment()
268// ------------------------------------
269XML_Comment::~XML_Comment()
270{
271    FILE *out = the_XML_Document->Out();
272    close(out);
273}
274
275// -----------------------------------------------------
276//      void XML_Comment::add_son(XML_Node *, bool )
277// -----------------------------------------------------
278void XML_Comment::add_son(XML_Node *, bool )
279{
280    throw string("Can't add son to XML_Comment-Node");
281}
282
283// -------------------------------------------------
284//      void XML_Comment::remove_son(XML_Node *)
285// -------------------------------------------------
286void XML_Comment::remove_son(XML_Node *)
287{
288    throw string("Can't remove son from XML_Comment-Node");
289}
290
291// ---------------------------------------
292//      void XML_Comment::open(FILE *)
293// ---------------------------------------
294void XML_Comment::open(FILE *)
295{
296}
297
298// -------------------------------------------
299//      void XML_Comment::close(FILE *out)
300// -------------------------------------------
301void XML_Comment::close(FILE *out)
302{
303    fputc('\n', out); to_indent(out, Indent());
304    fputs("<!--", out);
305    fputs(encodeEntities(content).c_str(), out);
306    fputs("-->", out);
307}
308
309
310
311// -end- of implementation of class XML_Comment.
312
313
314// ********************************************************************************
315
316//  ---------------------------------------------------------------------------------------
317//      XML_Document::XML_Document(const string& name_, const string& dtd_, FILE *out_)
318//  ---------------------------------------------------------------------------------------
319XML_Document::XML_Document(const string& name_, const string& dtd_, FILE *out_)
320    : dtd(dtd_), root(0), out(out_), skip_empty_tags(false), indentation_per_level(1)
321{
322    xml_assert(out);
323    if (the_XML_Document) string Error("You can only have one XML_Document at a time.");
324    the_XML_Document = this;
325    latest_son       = 0;
326    root             = new XML_Tag(name_);
327    xml_assert(latest_son == root);
328
329    fputs("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", out);
330    fprintf(out, "<!DOCTYPE %s SYSTEM '%s' [\n%s]>\n", name_.c_str(), dtd.c_str(), entities);
331}
332
333//  --------------------------------------
334//      XML_Document::~XML_Document()
335//  --------------------------------------
336XML_Document::~XML_Document() {
337    delete root;
338    xml_assert(the_XML_Document == this);
339    the_XML_Document = 0;
340}
341
342
Note: See TracBrowser for help on using the repository browser.