Imported Upstream version 2.34.2
[platform/upstream/libxml++.git] / libxml++ / parsers / domparser.cc
1 /* domparser.cc
2  * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
3  * are covered by the GNU Lesser General Public License, which should be
4  * included with libxml++ as the file COPYING.
5  */
6
7 #include "libxml++/parsers/domparser.h"
8 #include "libxml++/dtd.h"
9 #include "libxml++/nodes/element.h"
10 #include "libxml++/nodes/textnode.h"
11 #include "libxml++/nodes/commentnode.h"
12 #include "libxml++/keepblanks.h"
13 #include "libxml++/exceptions/internal_error.h"
14 #include <libxml/parserInternals.h>//For xmlCreateFileParserCtxt().
15
16 #include <sstream>
17 #include <iostream>
18
19 namespace xmlpp
20 {
21
22 DomParser::DomParser()
23 : doc_(0)
24 {
25   //Start with an empty document:
26   doc_ = new Document();
27 }
28
29 DomParser::DomParser(const Glib::ustring& filename, bool validate)
30 : doc_(0)
31 {
32   set_validate(validate);
33   parse_file(filename);
34 }
35
36 DomParser::~DomParser()
37
38   release_underlying();
39 }
40
41 void DomParser::parse_file(const Glib::ustring& filename)
42 {
43   release_underlying(); //Free any existing document.
44
45   KeepBlanks k(KeepBlanks::Default);
46
47   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
48   context_ = xmlCreateFileParserCtxt(filename.c_str());
49
50   if(!context_)
51   {
52     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
53     throw internal_error("Couldn't create parsing context");
54     #else
55     return;
56     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
57   }
58
59   if(context_->directory == 0)
60   {
61     char* directory = xmlParserGetDirectory(filename.c_str());
62     context_->directory = (char*) xmlStrdup((xmlChar*) directory);
63   }
64
65   parse_context();
66 }
67
68 void DomParser::parse_memory_raw(const unsigned char* contents, size_type bytes_count)
69 {
70   release_underlying(); //Free any existing document.
71
72   KeepBlanks k(KeepBlanks::Default);
73
74   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
75   context_ = xmlCreateMemoryParserCtxt((const char*)contents, bytes_count);
76
77   if(!context_)
78   {
79     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
80     throw internal_error("Couldn't create parsing context");
81     #else
82     return;
83     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
84   }
85
86   parse_context();
87 }
88
89 void DomParser::parse_memory(const Glib::ustring& contents)
90 {
91   parse_memory_raw((const unsigned char*)contents.c_str(), contents.bytes());
92 }
93
94 void DomParser::parse_context()
95 {
96   KeepBlanks k(KeepBlanks::Default);
97
98   //The following is based on the implementation of xmlParseFile(), in xmlSAXParseFileWithData():
99   //and the implementation of xmlParseMemory(), in xmlSaxParseMemoryWithData().
100   initialize_context();
101
102   if(!context_)
103   {
104     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
105     throw internal_error("Context not initialized");
106     #else
107     return;
108     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
109   }
110
111   xmlParseDocument(context_);
112
113   check_for_exception();
114
115   if(!context_->wellFormed)
116   {
117     release_underlying(); //Free doc_;
118
119     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
120     throw parse_error("Document not well-formed.");
121     #else
122     return;
123     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
124   }
125
126   if(context_->errNo != 0)
127   {
128     std::ostringstream o;
129     o << "libxml error " << context_->errNo;
130
131     release_underlying();
132
133     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
134     throw parse_error(o.str());
135     #else
136     return;
137     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
138   }
139
140   doc_ = new Document(context_->myDoc);
141   // This is to indicate to release_underlying that we took the
142   // ownership on the doc.
143   context_->myDoc = 0;
144
145   //Free the parse context, but keep the document alive so people can navigate the DOM tree:
146   //TODO: Why not keep the context alive too?
147   Parser::release_underlying();
148
149   check_for_exception();
150 }
151
152
153 void DomParser::parse_stream(std::istream& in)
154 {
155   release_underlying(); //Free any existing document.
156
157   KeepBlanks k(KeepBlanks::Default);
158
159   context_ = xmlCreatePushParserCtxt(
160       0, // setting thoses two parameters to 0 force the parser
161       0, // to create a document while parsing.
162       0,
163       0,
164       ""); // here should come the filename. I don't know if it is a problem to let it empty
165
166   if(!context_)
167   {
168     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
169     throw internal_error("Couldn't create parsing context");
170     #else
171     return;
172     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
173   }
174
175   initialize_context();
176
177   //TODO: Shouldn't we use a Glib::ustring here, and some alternative to std::getline()?
178   std::string line;
179   while(std::getline(in, line))
180   {
181     // since getline does not get the line separator, we have to add it since the parser cares
182     // about layout in certain cases.
183     line += '\n';
184
185     xmlParseChunk(context_, line.c_str(), line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */, 0);
186   }
187
188   xmlParseChunk(context_, 0, 0, 1);
189
190   check_for_exception();
191
192   if(!context_->wellFormed)
193   {
194     release_underlying(); //Free doc_;
195
196     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
197     throw parse_error("Document not well-formed.");
198     #else
199     return;
200     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
201   }
202
203   if(context_->errNo != 0)
204   {
205     std::ostringstream o;
206     o << "libxml error " << context_->errNo;
207
208     release_underlying();
209
210     #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
211     throw parse_error(o.str());
212     #else
213     return;
214     #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
215   }
216
217   doc_ = new Document(context_->myDoc);
218   // This is to indicate to release_underlying that we took the
219   // ownership on the doc.
220   context_->myDoc = 0;
221
222
223   //Free the parse context, but keep the document alive so people can navigate the DOM tree:
224   //TODO: Why not keep the context alive too?
225   Parser::release_underlying();
226
227   check_for_exception();
228 }
229
230 void DomParser::release_underlying()
231 {
232   if(doc_)
233   {
234     delete doc_;
235     doc_ = 0;
236   }
237
238   Parser::release_underlying();
239 }
240
241 DomParser::operator bool() const
242 {
243   return doc_ != 0;
244 }
245
246 Document* DomParser::get_document()
247 {
248   return doc_;
249 }
250
251 const Document* DomParser::get_document() const
252 {
253   return doc_;
254 }
255
256 } // namespace xmlpp
257
258