Imported Upstream version 2.91.2
[platform/upstream/libxml++.git] / docs / manual / libxml++.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
3   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
4   <!ENTITY date "February 2002">
5   <!ENTITY url_examples_base "http://git.gnome.org/browse/libxml++/tree/examples/">
6 ]>
7
8 <book id="index" lang="en">
9   <bookinfo>
10     <title>libxml++ - An XML Parser for C++</title>
11     <author>
12       <firstname>Murray</firstname>
13       <surname>Cumming</surname>
14       <affiliation>
15               <address><email>murrayc@murrayc.com</email></address>
16       </affiliation>
17     </author>
18     <date>12th September 2004</date>
19     <abstract>
20       <para>This is an introduction to libxml2's C++ binding, with simple examples.</para>
21     </abstract>
22   </bookinfo>
23   <chapter id="chapter-introduction">
24     <title>libxml++</title>
25     <para>
26       libxml++ is a C++ API for the popular <ulink url="http://www.xmlsoft.org">libxml2</ulink> XML parser, written in C.
27       libxml2 is famous for its high performance and compliance to standard specifications, but its C API is quite difficult even for common tasks.
28     </para>
29
30     <para>
31       libxml++ presents a simple C++-like API that can achieve common tasks with less code.
32       Unlike some other C++ parsers, it does not try to avoid the advantages of standard C++ features
33       such as namespaces, STL containers or runtime type identification, and it does not try
34       to conform to standard API specifications meant for Java. Therefore libxml++ requires
35       a fairly modern C++ compiler such as g++ 4.9 or g++ 5. libxml++ 2.39.1 and later require
36       a C++11-compliant compiler.
37     </para>
38
39     <para>But libxml++ was created mainly to fill the need for an API-stable and ABI-stable C++ XML parser which could be used as a shared library dependency by C++ applications that are distributed widely in binary form. That means that installed applications will not break when new versions of libxml++ are installed on a user's computer. Gradual improvement of the libxml++ API is still possible via non-breaking API additions, and new independent versions of the ABI that can be installed in parallel with older versions. These are the general techniques and principles followed by the <ulink
40 url="http://www.gnome.org">GNOME</ulink> project, of which libxml++ is a part.</para>
41
42     <sect1>
43     <title>Installation</title>
44     <para>libxml++ is packaged by major Linux and *BSD distributions and can be installed from source on Linux and Windows, using any modern compiler, such as g++, SUN Forte, or MSVC++.</para>
45     <para>For instance, to install libxml++ and its documentation on debian, use apt-get or synaptic like so:
46     <programlisting>
47     # apt-get install libxml++3.0-dev libxml++3.0-doc
48     </programlisting>
49     </para>
50     <para>To check that you have the libxml++ development packages installed, and that your environment is working properly, try <command>pkg-config libxml++-3.0 --modversion</command>.</para>
51     <para>Links for downloading and more documentation can be found at <ulink
52 url="http://libxmlplusplus.sourceforge.net">libxmlplusplus.sourceforge.net</ulink>.
53     libxml++ is licensed under the LGPL, which allows its use via dynamic linking in both open source and closed-source software. The underlying libxml2 library uses the even more generous MIT licence.</para>
54     </sect1>
55
56     <sect1>
57     <title>UTF-8 and Glib::ustring</title>
58     <para>The libxml++ API takes, and gives, strings in the UTF-8 Unicode encoding, which can support all known languages and locales. This choice was made because, of the encodings that have this capability, UTF-8 is the most commonly accepted choice. UTF-8 is a multi-byte encoding, meaning that some characters use more than 1 byte. But for compatibility, old-fashioned 7-bit ASCII strings are unchanged when encoded as UTF-8, and UTF-8 strings do not contain null bytes which would cause old code to misjudge the number of bytes. For these reasons, you can store a UTF-8 string in a std::string object. However, the std::string API will operate on that string in terms of bytes, instead of characters.</para>
59     <para>Because Standard C++ has no string class that can fully handle UTF-8, libxml++ uses the Glib::ustring class from the glibmm library. Glib::ustring has almost exactly the same API as std::string, but methods such as length() and operator[] deal with whole UTF-8 characters rather than raw bytes.</para>
60     <para>There are implicit conversions between std::string and Glib::ustring, so you can use std::string wherever you see a Glib::ustring in the API, if you really don't care about any locale other than English. However, that is unlikely in today's connected world.</para>
61     <para>glibmm also provides useful API to convert between encodings and locales.</para>
62     </sect1>
63
64     <sect1>
65     <title>Compilation and Linking</title>
66     <para>To use libxml++ in your application, you must tell the compiler where to find the include headers and where to find the libxml++ library. libxml++ provides a pkg-config .pc file to make this easy. For instance, the following command will provide the necessary compiler options:
67     <command>pkg-config libxml++-3.0 --cflags --libs</command>
68     </para>
69     <para>When using autoconf and automake, this is even easier with the PKG_CHECK_MODULES macro in your configure.ac file. For instance:
70     <programlisting>
71     PKG_CHECK_MODULES(SOMEAPP, libxml++-3.0 >= 3.0.0)
72     AC_SUBST(SOMEAPP_CFLAGS)
73     AC_SUBST(SOMEAPP_LIBS)
74     </programlisting>
75     </para>
76     </sect1>
77
78     </chapter>
79
80   <chapter id="chapter-parsers">
81     <title>Parsers</title>
82     <para>Like the underlying libxml2 library, libxml++ allows the use of 3 parsers, depending on your needs - the DOM, SAX, and TextReader parsers. The relative advantages and behaviour of these parsers will be explained here.</para>
83     <para>All of the parsers may parse XML documents directly from disk, a string, or a C++ std::istream. Although the libxml++ API uses only Glib::ustring, and therefore the UTF-8 encoding, libxml++ can parse documents in any encoding, converting to UTF-8 automatically. This conversion will not lose any information because UTF-8 can represent any locale.</para>
84     <para>Remember that white space is usually significant in XML documents, so the parsers might provide unexpected text nodes that contain only spaces and new lines. The parser does not know whether you care about these text nodes, but your application may choose to ignore them.</para> 
85   
86     <sect1>
87       <title>DOM Parser</title>
88       <para>The DOM (Document Object Model) parser parses the whole document at once and stores the structure in memory, available via <methodname>DomParser::get_document()</methodname>. With methods such as <methodname>Document::get_root_node()</methodname> and <methodname>Node::get_children()</methodname>, you may then navigate into the hierarchy of XML nodes without restriction, jumping forwards or backwards in the document based on the information that you encounter. Therefore the DOM parser uses a relatively large amount of memory.</para>
89       <para>You should use C++ RTTI (via <literal>dynamic_cast&lt;&gt;</literal>) to identify the specific node type and to perform actions which are not possible with all node types. For instance, only <classname>Element</classname>s have attributes. Here is the inheritance hierarchy of node types:</para>
90
91       <para>
92       <itemizedlist>
93       <listitem><para>xmlpp::Node
94         <itemizedlist>
95           <listitem><para>xmlpp::Attribute
96           <itemizedlist>
97             <listitem><para>xmlpp::AttributeDeclaration</para></listitem>
98             <listitem><para>xmlpp::AttributeNode</para></listitem>
99           </itemizedlist>
100           </para></listitem>
101           <listitem><para>xmlpp::ContentNode
102           <itemizedlist>
103             <listitem><para>xmlpp::CdataNode</para></listitem>
104             <listitem><para>xmlpp::CommentNode</para></listitem>
105             <listitem><para>xmlpp::EntityDeclaration</para></listitem>
106             <listitem><para>xmlpp::ProcessingInstructionNode</para></listitem>
107             <listitem><para>xmlpp::TextNode</para></listitem>
108           </itemizedlist>
109           </para></listitem>
110           <listitem><para>xmlpp::Element</para></listitem>
111           <listitem><para>xmlpp::EntityReference</para></listitem>
112           <listitem><para>xmlpp::XIncludeEnd</para></listitem>
113           <listitem><para>xmlpp::XIncludeStart</para></listitem>
114         </itemizedlist>
115         </para></listitem>
116  
117       </itemizedlist>
118     </para>
119
120     <para>All <classname>Node</classname>s created by the DOM parser are leaves
121       in the node type tree. For instance, the DOM parser can create
122       <classname>TextNode</classname>s and <classname>Element</classname>s, but it
123       does not create objects whose exact type is <classname>ContentNode</classname>
124       or <classname>Node</classname>.
125     </para>
126     <para>Although you may obtain pointers to the <classname>Node</classname>s, these <classname>Node</classname>s are always owned by their parent <classname>Node</classname>. In most cases that means that the <classname>Node</classname> will exist, and your pointer will be valid, as long as the <classname>Document</classname> instance exists.</para>
127     <para>There are also several methods which can create new child <classname>Node</classname>s. By using these, and one of the <methodname>Document::write_*()</methodname> methods, you can use libxml++ to build a new XML document.</para>
128
129 <sect2>
130 <title>Example</title>
131 <para>This example looks in the document for expected elements and then examines them. All these examples are included in the libxml++ source distribution.</para>
132 <para><ulink url="&url_examples_base;dom_parser">Source Code</ulink></para>
133 <!-- start inserted example code -->
134 <para>File: main.cc
135 <programlisting>
136 #ifdef HAVE_CONFIG_H
137 #include &lt;config.h&gt;
138 #endif
139
140 #include &quot;../testutilities.h&quot;
141 #include &lt;libxml++/libxml++.h&gt;
142 #include &lt;iostream&gt;
143 #include &lt;cstdlib&gt;
144
145 void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
146 {
147   const Glib::ustring indent(indentation, ' ');
148   std::cout &lt;&lt; std::endl; //Separate nodes by an empty line.
149   
150   const auto nodeContent = dynamic_cast&lt;const xmlpp::ContentNode*&gt;(node);
151   const auto nodeText = dynamic_cast&lt;const xmlpp::TextNode*&gt;(node);
152   const auto nodeComment = dynamic_cast&lt;const xmlpp::CommentNode*&gt;(node);
153
154   if(nodeText &amp;&amp; nodeText-&gt;is_white_space()) //Let's ignore the indenting - you don't always want to do this.
155     return;
156     
157   const auto nodename = node-&gt;get_name();
158
159   if(!nodeText &amp;&amp; !nodeComment &amp;&amp; !nodename.empty()) //Let's not say &quot;name: text&quot;.
160   {
161     const auto namespace_prefix = node-&gt;get_namespace_prefix();
162
163     std::cout &lt;&lt; indent &lt;&lt; &quot;Node name = &quot;;
164     if(!namespace_prefix.empty())
165       std::cout &lt;&lt; CatchConvertError(namespace_prefix) &lt;&lt; &quot;:&quot;;
166     std::cout &lt;&lt; CatchConvertError(nodename) &lt;&lt; std::endl;
167   }
168   else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is.
169   {
170     std::cout &lt;&lt; indent &lt;&lt; &quot;Text Node&quot; &lt;&lt; std::endl;
171   }
172
173   //Treat the various node types differently: 
174   if(nodeText)
175   {
176     std::cout &lt;&lt; indent &lt;&lt; &quot;text = \&quot;&quot; &lt;&lt; CatchConvertError(nodeText-&gt;get_content()) &lt;&lt; &quot;\&quot;&quot; &lt;&lt; std::endl;
177   }
178   else if(nodeComment)
179   {
180     std::cout &lt;&lt; indent &lt;&lt; &quot;comment = &quot; &lt;&lt; CatchConvertError(nodeComment-&gt;get_content()) &lt;&lt; std::endl;
181   }
182   else if(nodeContent)
183   {
184     std::cout &lt;&lt; indent &lt;&lt; &quot;content = &quot; &lt;&lt; CatchConvertError(nodeContent-&gt;get_content()) &lt;&lt; std::endl;
185   }
186   else if(const xmlpp::Element* nodeElement = dynamic_cast&lt;const xmlpp::Element*&gt;(node))
187   {
188     //A normal Element node:
189
190     //line() works only for ElementNodes.
191     std::cout &lt;&lt; indent &lt;&lt; &quot;     line = &quot; &lt;&lt; node-&gt;get_line() &lt;&lt; std::endl;
192
193     //Print attributes:
194     for (const auto&amp; attribute : nodeElement-&gt;get_attributes())
195     {
196       const auto namespace_prefix = attribute-&gt;get_namespace_prefix();
197
198       std::cout &lt;&lt; indent &lt;&lt; &quot;  Attribute &quot;;
199       if(!namespace_prefix.empty())
200         std::cout &lt;&lt; CatchConvertError(namespace_prefix) &lt;&lt; &quot;:&quot;;
201       std::cout &lt;&lt; CatchConvertError(attribute-&gt;get_name()) &lt;&lt; &quot; = &quot;
202                 &lt;&lt; CatchConvertError(attribute-&gt;get_value()) &lt;&lt; std::endl;
203     }
204
205     const auto attribute = nodeElement-&gt;get_attribute(&quot;title&quot;);
206     if(attribute)
207     {
208       std::cout &lt;&lt; indent;
209       if (dynamic_cast&lt;const xmlpp::AttributeNode*&gt;(attribute))
210         std::cout &lt;&lt; &quot;AttributeNode &quot;;
211       else if (dynamic_cast&lt;const xmlpp::AttributeDeclaration*&gt;(attribute))
212         std::cout &lt;&lt; &quot;AttributeDeclaration &quot;;
213       std::cout &lt;&lt; &quot;title = &quot; &lt;&lt; CatchConvertError(attribute-&gt;get_value()) &lt;&lt; std::endl;
214     }
215   }
216   
217   if(!nodeContent)
218   {
219     //Recurse through child nodes:
220     for(const auto&amp; child : node-&gt;get_children())
221     {
222       print_node(child, indentation + 2); //recursive
223     }
224   }
225 }
226
227 int main(int argc, char* argv[])
228 {
229   // Set the global C++ locale to the user-specified locale. Then we can
230   // hopefully use std::cout with UTF-8, via Glib::ustring, without exceptions.
231   std::locale::global(std::locale(&quot;&quot;));
232
233   bool validate = false;
234   bool set_throw_messages = false;
235   bool throw_messages = false;
236   bool substitute_entities = true;
237   bool include_default_attributes = false;
238
239   int argi = 1;
240   while (argc &gt; argi &amp;&amp; *argv[argi] == '-') // option
241   {
242     switch (*(argv[argi]+1))
243     {
244       case 'v':
245         validate = true;
246         break;
247       case 't':
248         set_throw_messages = true;
249         throw_messages = true;
250         break;
251       case 'e':
252         set_throw_messages = true;
253         throw_messages = false;
254         break;
255       case 'E':
256         substitute_entities = false;
257         break;
258       case 'a':
259         include_default_attributes = true;
260         break;
261      default:
262        std::cout &lt;&lt; &quot;Usage: &quot; &lt;&lt; argv[0] &lt;&lt; &quot; [-v] [-t] [-e] [filename]&quot; &lt;&lt; std::endl
263                  &lt;&lt; &quot;       -v  Validate&quot; &lt;&lt; std::endl
264                  &lt;&lt; &quot;       -t  Throw messages in an exception&quot; &lt;&lt; std::endl
265                  &lt;&lt; &quot;       -e  Write messages to stderr&quot; &lt;&lt; std::endl
266                  &lt;&lt; &quot;       -E  Do not substitute entities&quot; &lt;&lt; std::endl
267                  &lt;&lt; &quot;       -a  Include default attributes in the node tree&quot; &lt;&lt; std::endl;
268        return EXIT_FAILURE;
269      }
270      argi++;
271   }
272   std::string filepath;
273   if(argc &gt; argi)
274     filepath = argv[argi]; //Allow the user to specify a different XML file to parse.
275   else
276     filepath = &quot;example.xml&quot;;
277  
278   try
279   {
280     xmlpp::DomParser parser;
281     if (validate)
282       parser.set_validate();
283     if (set_throw_messages)
284       parser.set_throw_messages(throw_messages);
285     //We can have the text resolved/unescaped automatically.
286     parser.set_substitute_entities(substitute_entities);
287     parser.set_include_default_attributes(include_default_attributes);
288     parser.parse_file(filepath);
289     if(parser)
290     {
291       //Walk the tree:
292       const auto pNode = parser.get_document()-&gt;get_root_node(); //deleted by DomParser.
293       print_node(pNode);
294     }
295   }
296   catch(const std::exception&amp; ex)
297   {
298     std::cerr &lt;&lt; &quot;Exception caught: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
299     return EXIT_FAILURE;
300   }
301
302   return EXIT_SUCCESS;
303 }
304 </programlisting>
305 </para>
306 <!-- end inserted example code -->
307 </sect2>
308
309
310     </sect1>
311
312
313     <sect1>
314       <title>SAX Parser</title>
315       <para>The SAX (Simple API for XML) parser presents each node of the XML document in sequence. So when you process one node, you must have already stored information about any relevant previous nodes, and you have no information at that time about subsequent nodes. The SAX parser uses less memory than the DOM parser and it is a suitable abstraction for documents that can be processed sequentially rather than as a whole.</para>
316
317       <para>By using the <literal>parse_chunk()</literal> method instead of <literal>parse()</literal>, you can even parse parts of the XML document before you have received the whole document.</para>
318
319       <para>As shown in the example, you should derive your own class from SaxParser and override some of the virtual methods. These &quot;handler&quot; methods will be called while the document is parsed.</para>
320  
321 <sect2>
322 <title>Example</title>
323 <para>This example shows how the handler methods are called during parsing.</para>
324 <para><ulink url="&url_examples_base;sax_parser">Source Code</ulink></para>
325 <!-- start inserted example code -->
326 <para>File: myparser.h
327 <programlisting>
328 #ifndef __LIBXMLPP_EXAMPLES_MYPARSER_H
329 #define __LIBXMLPP_EXAMPLES_MYPARSER_H
330
331 #include &lt;libxml++/libxml++.h&gt;
332
333 class MySaxParser : public xmlpp::SaxParser
334 {
335 public:
336   MySaxParser();
337   ~MySaxParser() override;
338
339 protected:
340   //overrides:
341   void on_start_document() override;
342   void on_end_document() override;
343   void on_start_element(const Glib::ustring&amp; name,
344                                 const AttributeList&amp; properties) override;
345   void on_end_element(const Glib::ustring&amp; name) override;
346   void on_characters(const Glib::ustring&amp; characters) override;
347   void on_comment(const Glib::ustring&amp; text) override;
348   void on_warning(const Glib::ustring&amp; text) override;
349   void on_error(const Glib::ustring&amp; text) override;
350   void on_fatal_error(const Glib::ustring&amp; text) override;
351 };
352
353
354 #endif //__LIBXMLPP_EXAMPLES_MYPARSER_H
355 </programlisting>
356 </para>
357 <para>File: main.cc
358 <programlisting>
359 #ifdef HAVE_CONFIG_H
360 #include &lt;config.h&gt;
361 #endif
362
363 #include &lt;fstream&gt;
364 #include &lt;iostream&gt;
365 #include &lt;stdlib.h&gt;
366 #include &lt;cstring&gt; // std::memset()
367
368 #include &quot;myparser.h&quot;
369
370 int
371 main(int argc, char* argv[])
372 {
373   // Set the global C and C++ locale to the user-configured locale,
374   // so we can use std::cout with UTF-8, via Glib::ustring, without exceptions.
375   std::locale::global(std::locale(&quot;&quot;));
376
377   std::string filepath;
378   if(argc &gt; 1 )
379     filepath = argv[1]; //Allow the user to specify a different XML file to parse.
380   else
381     filepath = &quot;example.xml&quot;;
382     
383   // Parse the entire document in one go:
384   auto return_code = EXIT_SUCCESS;
385   try
386   {
387     MySaxParser parser;
388     parser.set_substitute_entities(true);
389     parser.parse_file(filepath);
390   }
391   catch(const xmlpp::exception&amp; ex)
392   {
393     std::cerr &lt;&lt; &quot;libxml++ exception: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
394     return_code = EXIT_FAILURE;
395   }
396
397   // Incremental parsing, sometimes useful for network connections:
398   try
399   {
400     std::cout &lt;&lt; std::endl &lt;&lt; &quot;Incremental SAX Parser:&quot; &lt;&lt; std::endl;
401     
402     std::ifstream is(filepath.c_str());
403     if (!is)
404       throw xmlpp::exception(&quot;Could not open file &quot; + filepath);
405
406     char buffer[64];
407     const size_t buffer_size = sizeof(buffer) / sizeof(char);
408
409     //Parse the file:
410     MySaxParser parser;
411     parser.set_substitute_entities(true);
412     do
413     {
414       std::memset(buffer, 0, buffer_size);
415       is.read(buffer, buffer_size-1);
416       if(is.gcount())
417       {
418         // We use Glib::ustring::ustring(InputIterator begin, InputIterator end)
419         // instead of Glib::ustring::ustring( const char*, size_type ) because it
420         // expects the length of the string in characters, not in bytes.
421         Glib::ustring input(buffer, buffer+is.gcount());
422         parser.parse_chunk(input);
423       }
424     }
425     while(is);
426
427     parser.finish_chunk_parsing();
428   }
429   catch(const xmlpp::exception&amp; ex)
430   {
431     std::cerr &lt;&lt; &quot;Incremental parsing, libxml++ exception: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
432     return_code = EXIT_FAILURE;
433   }
434
435   return return_code;
436 }
437
438 </programlisting>
439 </para>
440 <para>File: myparser.cc
441 <programlisting>
442 #include &quot;myparser.h&quot;
443 #include &lt;glibmm/convert.h&gt; //For Glib::ConvertError
444
445 #include &lt;iostream&gt;
446
447 MySaxParser::MySaxParser()
448   : xmlpp::SaxParser()
449 {
450 }
451
452 MySaxParser::~MySaxParser()
453 {
454 }
455
456 void MySaxParser::on_start_document()
457 {
458   std::cout &lt;&lt; &quot;on_start_document()&quot; &lt;&lt; std::endl;
459 }
460
461 void MySaxParser::on_end_document()
462 {
463   std::cout &lt;&lt; &quot;on_end_document()&quot; &lt;&lt; std::endl;
464 }
465
466 void MySaxParser::on_start_element(const Glib::ustring&amp; name,
467                                    const AttributeList&amp; attributes)
468 {
469   std::cout &lt;&lt; &quot;node name=&quot; &lt;&lt; name &lt;&lt; std::endl;
470
471   // Print attributes:
472   for(const auto&amp; attr_pair : attributes)
473   {
474     try
475     {
476       std::cout &lt;&lt; &quot;  Attribute name=&quot; &lt;&lt;  attr_pair.name &lt;&lt; std::endl;
477     }
478     catch(const Glib::ConvertError&amp; ex)
479     {
480       std::cerr &lt;&lt; &quot;MySaxParser::on_start_element(): Exception caught while converting name for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
481     }
482
483     try
484     {
485       std::cout &lt;&lt; &quot;    , value= &quot; &lt;&lt;  attr_pair.value &lt;&lt; std::endl;
486     }
487     catch(const Glib::ConvertError&amp; ex)
488     {
489       std::cerr &lt;&lt; &quot;MySaxParser::on_start_element(): Exception caught while converting value for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
490     }
491   }
492 }
493
494 void MySaxParser::on_end_element(const Glib::ustring&amp; /* name */)
495 {
496   std::cout &lt;&lt; &quot;on_end_element()&quot; &lt;&lt; std::endl;
497 }
498
499 void MySaxParser::on_characters(const Glib::ustring&amp; text)
500 {
501   try
502   {
503     std::cout &lt;&lt; &quot;on_characters(): &quot; &lt;&lt; text &lt;&lt; std::endl;
504   }
505   catch(const Glib::ConvertError&amp; ex)
506   {
507     std::cerr &lt;&lt; &quot;MySaxParser::on_characters(): Exception caught while converting text for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
508   }
509 }
510
511 void MySaxParser::on_comment(const Glib::ustring&amp; text)
512 {
513   try
514   {
515     std::cout &lt;&lt; &quot;on_comment(): &quot; &lt;&lt; text &lt;&lt; std::endl;
516   }
517   catch(const Glib::ConvertError&amp; ex)
518   {
519     std::cerr &lt;&lt; &quot;MySaxParser::on_comment(): Exception caught while converting text for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
520   }
521 }
522
523 void MySaxParser::on_warning(const Glib::ustring&amp; text)
524 {
525   try
526   {
527     std::cout &lt;&lt; &quot;on_warning(): &quot; &lt;&lt; text &lt;&lt; std::endl;
528   }
529   catch(const Glib::ConvertError&amp; ex)
530   {
531     std::cerr &lt;&lt; &quot;MySaxParser::on_warning(): Exception caught while converting text for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
532   }
533 }
534
535 void MySaxParser::on_error(const Glib::ustring&amp; text)
536 {
537   try
538   {
539     std::cout &lt;&lt; &quot;on_error(): &quot; &lt;&lt; text &lt;&lt; std::endl;
540   }
541   catch(const Glib::ConvertError&amp; ex)
542   {
543     std::cerr &lt;&lt; &quot;MySaxParser::on_error(): Exception caught while converting text for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
544   }
545 }
546
547 void MySaxParser::on_fatal_error(const Glib::ustring&amp; text)
548 {
549   try
550   {
551     std::cout &lt;&lt; &quot;on_fatal_error(): &quot; &lt;&lt; text &lt;&lt; std::endl;
552   }
553   catch(const Glib::ConvertError&amp; ex)
554   {
555     std::cerr &lt;&lt; &quot;MySaxParser::on_characters(): Exception caught while converting value for std::cout: &quot; &lt;&lt; ex.what() &lt;&lt; std::endl;
556   }
557 }
558
559 </programlisting>
560 </para>
561 <!-- end inserted example code -->
562 </sect2>
563
564     </sect1>
565
566     <sect1>
567       <title>TextReader Parser</title>
568       <para>Like the SAX parser, the TextReader parser is suitable for sequential parsing, but instead of implementing handlers for specific parts of the document, it allows you to detect the current node type, process the node accordingly, and skip forward in the document as much as necessary. Unlike the DOM parser, you may not move backwards in the XML document. And unlike the SAX parser, you must not waste time processing nodes that do not interest you. </para>
569       <para>All methods are on the single parser instance, but their result depends on the current context. For instance, use <literal>read()</literal> to move to the next node, and <literal>move_to_element()</literal> to navigate to child nodes. These methods will return false when no more nodes are available. Then use methods such as <literal>get_name()</literal> and <literal>get_value()</literal> to examine the elements and their attributes.</para> 
570
571 <sect2>
572 <title>Example</title>
573 <para>This example examines each node in turn, then moves to the next node.</para>
574 <para><ulink url="&url_examples_base;textreader">Source Code</ulink></para>
575 <!-- start inserted example code -->
576 <para>File: main.cc
577 <programlisting>
578 #ifdef HAVE_CONFIG_H
579 #include &lt;config.h&gt;
580 #endif
581
582 #include &lt;libxml++/libxml++.h&gt;
583 #include &lt;libxml++/parsers/textreader.h&gt;
584
585 #include &lt;iostream&gt;
586 #include &lt;stdlib.h&gt;
587
588 struct indent {
589   int depth_;
590   indent(int depth): depth_(depth) {};
591 };
592
593 std::ostream &amp; operator&lt;&lt;(std::ostream &amp; o, indent const &amp; in)
594 {
595   for(int i = 0; i != in.depth_; ++i)
596   {
597     o &lt;&lt; &quot;  &quot;;
598   }
599   return o;
600 }
601
602 int main(int /* argc */, char** /* argv */)
603 {
604   // Set the global C and C++ locale to the user-configured locale,
605   // so we can use std::cout with UTF-8, via Glib::ustring, without exceptions.
606   std::locale::global(std::locale(&quot;&quot;));
607
608   try
609   {
610     xmlpp::TextReader reader(&quot;example.xml&quot;);
611
612     while(reader.read())
613     {
614       int depth = reader.get_depth();
615       std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;--- node ---&quot; &lt;&lt; std::endl;
616       std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;name: &quot; &lt;&lt; reader.get_name() &lt;&lt; std::endl;
617       std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;depth: &quot; &lt;&lt; reader.get_depth() &lt;&lt; std::endl;
618
619       if(reader.has_attributes())
620       {
621         std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;attributes: &quot; &lt;&lt; std::endl;
622         reader.move_to_first_attribute();
623         do
624         {
625           std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;  &quot; &lt;&lt; reader.get_name() &lt;&lt; &quot;: &quot; &lt;&lt; reader.get_value() &lt;&lt; std::endl;
626         } while(reader.move_to_next_attribute());
627         reader.move_to_element();
628       }
629       else
630       {
631         std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;no attributes&quot; &lt;&lt; std::endl;
632       }
633
634       if(reader.has_value())
635         std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;value: '&quot; &lt;&lt; reader.get_value() &lt;&lt; &quot;'&quot; &lt;&lt; std::endl;
636       else
637         std::cout &lt;&lt; indent(depth) &lt;&lt; &quot;novalue&quot; &lt;&lt; std::endl;
638
639     }
640   }
641   catch(const std::exception&amp; e)
642   {
643     std::cerr &lt;&lt; &quot;Exception caught: &quot; &lt;&lt; e.what() &lt;&lt; std::endl;
644     return EXIT_FAILURE;
645   }
646   return EXIT_SUCCESS;
647 }
648
649 </programlisting>
650 </para>
651 <!-- end inserted example code -->
652 </sect2>
653
654
655     </sect1>
656
657   
658   </chapter>
659
660
661 </book>