pugixml 0.1: sources and documentation
git-svn-id: http://pugixml.googlecode.com/svn/trunk@2 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
41b24d0905
commit
69cc3fcb3a
993
docs/index.html
Normal file
993
docs/index.html
Normal file
@ -0,0 +1,993 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>pugixml documentation</title>
|
||||
</head>
|
||||
<body link="#0000ff" vlink="#800080">
|
||||
<table border="0" cellpadding="4" cellspacing="0" width="100%" summary="header">
|
||||
<tr>
|
||||
<td valign="top" bgcolor="#eeeeeee">
|
||||
<h2 align="left">pugixml documentation</h2>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<h2>Contents</h2>
|
||||
<dl class="index">
|
||||
<dt><a href="#Introduction">Introduction</a></dt>
|
||||
<dt><a href="#DOM">Document Object Model</a></dt>
|
||||
<dt><a href="#Documentation">Documentation</a>
|
||||
<dd><a href="#Doc_Introduction">Introduction</a></dd>
|
||||
<dd><a href="#Doc_Parser">xml_parser class</a></dd>
|
||||
<dd><a href="#Doc_Node">xml_node class</a></dd>
|
||||
<dd><a href="#Doc_Attribute">xml_attribute class</a></dd>
|
||||
<dd><a href="#Doc_Iterators">Iterators</a></dd>
|
||||
<dd><a href="#Doc_Misc">Miscellaneous</a></dd>
|
||||
<dd><a href="#Doc_Lifetime">Lifetime issues and memory management</a></dd>
|
||||
</dt>
|
||||
<dt><a href="#Parsing">Parsing process</a></dt>
|
||||
<dt><a href="#Compliance">W3C compliance</a></dt>
|
||||
<dt><a href="#FAQ">FAQ</a></dt>
|
||||
<dt><a href="#Bugs">Bugs</a></dt>
|
||||
<dt><a href="#Future_work">Future work</a></dt>
|
||||
<dt><a href="#Changelog">Changelog</a></dt>
|
||||
<dt><a href="#Acknowledgements">Acknowledgements</a></dt>
|
||||
<dt><a href="#License">License</a></dt>
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Introduction">
|
||||
<h2>Introduction</h2>
|
||||
<p><i>pugixml</i> is just another XML parser. This is a successor to
|
||||
<a href="http://www.codeproject.com/soap/pugxml.asp">pugxml</a> (well, to be honest, the only part
|
||||
that is left as is is wildcard matching code, the rest was either heavily refactored or rewritten
|
||||
from scratch). The main features (call it USP) are:</p>
|
||||
|
||||
<ul>
|
||||
<li>low memory consumption and fragmentation (the win over <i>pugxml</i> is ~1.5 times, <i>TinyXML</i>
|
||||
- ~4.5 times, <i>Xerces (DOM)</i> - ~7 times <a href="#annot-1"><sup>1</sup></a>)</li>
|
||||
<li>extremely high parsing speed (the win over <i>pugxml</i> is ~11.8 times, <i>TinyXML</i> - ~13.6
|
||||
times, <i>Xerces-DOM</i> - ~20 times <a href="#annot-1"><sup>1</sup></a></li>
|
||||
<li>extremely high parsing speed (well, I'm repeating myself, but it's so fast, that it outperforms
|
||||
<i>expat</i> by <b>2 times</b> on test XML) <a href="#annot-2"><sup>2</sup></a></li>
|
||||
<li>more or less standard-conformant (it will parse any standard-compliant file correctly in w3c-
|
||||
compliance mode, with the exception of DTD related issues and XML namespaces)</li>
|
||||
<li>pretty much error-ignorant (it will not choke on something like <text>You & Me</text>,
|
||||
like <i>expat</i> will; it will try to recover the state even if meeting an error (like finding matching
|
||||
tags for closing ones); it will parse files with data in wrong encoding; and so on)</li>
|
||||
<li>clean interface (a heavily refactored pugxml's one)</li>
|
||||
<li>more or less unicode-aware (actually, it assumes UTF-8 encoding of the input data, though
|
||||
it will readily work with ANSI - no UTF-16 for now (see <a href="#Future_work">Future work</a>), with
|
||||
helper conversion functions (UTF-8 <-> UTF-16/32 (whatever is the default for std::wstring & wchar_t))</li>
|
||||
<li>fully standard compliant code (approved by <a href="http://www.comeaucomputing.com/tryitout/">Comeau</a>
|
||||
strict mode), multiplatform (tested on win32 only ^_^)</li>
|
||||
<li>high flexibility. You can control many aspects of file parsing and DOM tree building via parsing
|
||||
options.
|
||||
</ul>
|
||||
|
||||
<p>Okay, you might ask - what's the catch? Everything is so cute - it's small, fast, robust, clean solution
|
||||
for parsing XML. What is missing? Ok, we are fair developers - so here is a misfeature list:</p>
|
||||
|
||||
<ul>
|
||||
<li>memory consumption. It beats every DOM-based parser that I know of - but when SAX parser comes,
|
||||
there is no chance. You can't process a 2 Gb XML file with less than 4 Gb of memory - and do it fast.
|
||||
Though <i>pugixml</i> behaves better, than all other DOM-based parser, so if you're stuck with DOM,
|
||||
it's not a problem.</li>
|
||||
<li>memory consumption. Ok, I'm repeating myself. Again. When other parsers will allow you to provide
|
||||
XML file in a constant storage (or even as a memory mapped area), <i>pugixml</i> will not. So you'll
|
||||
have to copy the entire data into a non-constant storage. Moreover, it should persist during the
|
||||
parser's lifetime (the reasons for that and more about lifetimes is written below). Again, if you're
|
||||
ok with DOM - it should not be a problem, because the overall memory consumption is less (well, though
|
||||
you'll need a contiguous chunk of memory, which can be a problem).</li>
|
||||
<li>lack of validation, DTD processing, XML namespaces, proper handling of encoding. If you need those -
|
||||
go take MSXML or XercesC or anything like that.</li>
|
||||
<li>lack of XPath & UTF-16/32 parsing. These are not implemented for now, but they are the features
|
||||
for the next release.</li>
|
||||
<li>immutability of DOM tree. It's constant. You can't change it. There are good reasons for prohibiting
|
||||
that, though it is a thing that will likely be in the next release.</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="annot-1"><sup>1</sup><small> The tests were done on a 1 mb XML file with a 4 levels deep tree
|
||||
with a small amount of text. The times are that of building DOM tree.</small> <br>
|
||||
<a name="annot-2"><sup>2</sup><small> Obviously, you can't estimate time of building DOM tree for a
|
||||
SAX parser, so the times of reading the data into storage that closely represented the structure of
|
||||
an XML file were measured.</small>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="DOM">
|
||||
<h2>Document Object Model</h2>
|
||||
|
||||
<p><i>pugixml</i> is a DOM-based parser. This means, that the XML document is converted to a tree.
|
||||
Each XML tag is converted to a node in DOM tree. If a tag is contained in some other tag, its node
|
||||
is a child to the outer tag's one. Comments, CDATA sections and PIs (Processing Instructions) also are
|
||||
transformed into tree nodes, as is the standalone text. Each node has its type.</p>
|
||||
|
||||
<p>Here is an example of an XML document:
|
||||
|
||||
<pre>
|
||||
<span style='color:#004a43; '><?</span><span style='color:#004a43; '>xml</span> <span style='color:#004a43; '>version</span><span style='color:#808030; '>=</span><span style='color:#008c00; '>"1.0"</span><span style='color:#004a43; '>?></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>mesh</span> <span style='color:#274796; '>name</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>mesh_root</span><span style='color:#0000e6; '>"</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#696969; '><!--</span><span style='color:#696969; '> here is a mesh node </span><span style='color:#696969; '>--></span>
|
||||
some text
|
||||
<span style='color:#606060; '><![CDATA[</span>[someothertext<span style='color:#606060; '>]]></span>
|
||||
some more text
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>node</span> <span style='color:#274796; '>attr1</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>value1</span><span style='color:#0000e6; '>"</span> <span style='color:#a65700; '>/></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>node</span> <span style='color:#274796; '>attr1</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>value2</span><span style='color:#0000e6; '>"</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#004a43; '><?</span><span style='color:#004a43; '>TARGET</span><span style='color:#004a43; '> somedata</span><span style='color:#004a43; '>?></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>innernode</span><span style='color:#a65700; '>/></span>
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>node</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>mesh</span><span style='color:#a65700; '>></span>
|
||||
</pre>
|
||||
|
||||
It gets converted to the following tree (note, that with some parsing options comments, PIs and CDATA
|
||||
sections are not stored in the tree, and with some options there are also nodes with whitespaces
|
||||
and the contents of PCDATA sections is a bit different (with trailing/leading whitespaces). So generally
|
||||
the resulting DOM tree depends on the parsing options):</p>
|
||||
|
||||
<p><img src="tree.png"></p>
|
||||
|
||||
<p>The parent-children relations are shown with lines. Some nodes have previous and next siblings
|
||||
(for example, the next sibling for node_comment node is node_pcdata with value "some text", and the
|
||||
previous sibling for node_element with name "mesh" is node_pi with target "xml" (target for PI nodes
|
||||
is stored in the node name)).</p>
|
||||
<hr>
|
||||
|
||||
<a name="Documentation">
|
||||
<h2>Documentation</h2>
|
||||
|
||||
<a name="Doc_Introduction">
|
||||
<h3>Introduction</h3>
|
||||
|
||||
<p><i>pugixml</i> is a library for parsing XML files, which means that you give it XML data some way,
|
||||
and it gives you the DOM tree and the ways to traverse it and to get some useful information from it.
|
||||
The library source consist of two files, the header <b>pugixml.hpp</b>, and the source code <b>pugixml.cpp</b>.
|
||||
You can either compile cpp file in your project, or build a static library (or perhaps even a DLL),
|
||||
or make the whole code use inline linkage and make one big file (as it was done in <i>pugxml</i>).
|
||||
All library classes reside in namespace <b>pugi</b>, so you can either use fully qualified
|
||||
names (<b>pugi::xml_node</b>) or write a using declaration (<b>using namespace pugi;</b>, <b>using
|
||||
pugi::xml_node</b>) and use plain names. All classes have the <b>xml_</b> prefix.</p>
|
||||
|
||||
<p>By default it's supposed that you compile the source file with your project (add it into your
|
||||
project, or add relevant entry in your Makefile, or do whatever you need to do with your compilation
|
||||
environment). The library is written in standard-conformant C++ and was tested on win32 platform
|
||||
(MSVC 7.1 (2003), MSVC 8.0 (2005)).</p>
|
||||
|
||||
<a name="Doc_Parser">
|
||||
<h3>xml_parser class</h3>
|
||||
|
||||
<p><b>xml_parser</b> class is the core of parsing process; you initiate parsing with it, you get DOM
|
||||
tree from it, the nodes and attributes are stored in it. You have two ways to load a file: either
|
||||
provide a string with XML-data (it has to be null-terminated, and it will be modified during parsing
|
||||
process, so it can not be a piece of read-only memory), or with an <b>std::istream</b> object (any input
|
||||
stream, like <b>std::ifstream</b>, <b>std::istringstream</b>, etc.) - in this case the parser will allocate
|
||||
the necessary amount of memory (equivalent to stream's size) and read everything from the stream.</p>
|
||||
|
||||
<p>The functions for parsing are:
|
||||
<dl>
|
||||
<dt>
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >void</font></b> <font color="#000000" >parse(std::istream&</font> <font color="#000000" >stream,</font> <b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >optmsk</font> <font color="#000000" >=</font> <font color="#000000" >parse_noset);</font></font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
<dd>This function will create a buffer with the size equal to that of provided <code>stream</code>,
|
||||
read the chunk of data from the stream and parse it with provided options (<code>optmsk</code>).
|
||||
The stream does not have to persist after the call to the function, the lifetime of internal buffer
|
||||
with stream's data is managed by <i>pugixml</i>.
|
||||
</dd>
|
||||
</dt>
|
||||
<dt> </dt>
|
||||
<dt>
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >parse(</font><b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >xmlstr,</font> <b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >optmsk</font> <font color="#000000" >=</font> <font color="#000000" >parse_noset);</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
<dd>This function parses the provided string with provided options, and returns the position where the
|
||||
parsing stopped (do not expect, that parsing will stop on every error, or on most of them - as I've
|
||||
said, <i>pugixml</i> is error ignorant). The input string is modified. The string must persist for the
|
||||
lifetime of the parser.
|
||||
</dt>
|
||||
<dt> </dt>
|
||||
<dt>
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_parser(std::istream&</font> <font color="#000000" >stream,</font> <b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >optmsk</font> <font color="#000000" >=</font> <font color="#000000" >parse_default);</font></font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
<dd>Just a convenience ctor, that calls the corresponding parse() function.</dd>
|
||||
</dt>
|
||||
<dt> </dt>
|
||||
<dt>
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_parser(</font><b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >xmlstr,</font> <b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >optmsk</font> <font color="#000000" >=</font> <font color="#000000" >parse_default);</font></font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
<dd>Just a convenience ctor, that calls the corresponding parse() function.</dd>
|
||||
</dt>
|
||||
</dl>
|
||||
|
||||
<p>If you want to provide XML data after the creation of the parser, use the default ctor. Otherwise
|
||||
you are free to use either parsing ctors or default ctor and later - parsing function.</p>
|
||||
|
||||
<p>After parsing an XML file, you'll get a DOM tree. To get access to it (or, more precisely, to its
|
||||
root), call either <b>document()</b> function or cast <b>xml_parser</b> object to <b>xml_node</b> by
|
||||
using the following functions:</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >operator</font></b> <font color="#000000" >xml_node()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >document()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Ok, easy part behind - now let's dive into parsing options. There is a variety of them, and you
|
||||
must choose them wisely to get the needed results and the best speed/least memory overhead. At first,
|
||||
there are flags that determine which parts of the document will be put into DOM tree, and which will
|
||||
be just skipped:</p>
|
||||
|
||||
<ul>
|
||||
<li>If <b>parse_pi</b> is on, then processing instructions (<b><? ... ?></b>) are put into DOM
|
||||
tree (with node type <b>node_pi</b>, otherwise they are discarded. Note that for now the prolog
|
||||
(<?xml ... ?>) is parsed as a processing instruction.
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_comments</b> is on, then comments (<b><!-- ... --></b>) are put into DOM
|
||||
tree (with node type <b>node_comment</b>, otherwise they are discarded.
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_cdata</b> is on, then the content of CDATA section (<b><![CDATA[[ ... ]]></b>)
|
||||
is put into DOM tree (with node type <b>node_cdata</b>, otherwise it is discarded.
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_ws_pcdata</b> is off, then the content of PCDATA section (it's the plain text
|
||||
in the node, like in <b><some_tag>Hello!</some_tag></b>) is discarded if it consists only
|
||||
of space-like characters (spaces, tabs and newlines).
|
||||
<br>Default value: off
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_ext_pcdata</b> is off, then the content of PCDATA section is discarded if it belongs
|
||||
to root (document) node, that is it does not have a parent tag.
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: off</li>
|
||||
</ul>
|
||||
|
||||
<p>Then there are flags that determine how the processing of the retrieved data is done. There are
|
||||
several reasons for these flags, mainly:
|
||||
<ul>
|
||||
<li>parsing speed. The less processing - the more speed.</li>
|
||||
<li>data fetching comfort. Sometimes you're ok with messed linefeeds, sometimes you're not. Sometimes
|
||||
you want your PCDATA trimmed, sometimes you do not. Sometimes you want your attribute values normalized,
|
||||
sometimes you do not. Some of these are normally specified in DOCTYPE, though...
|
||||
<li>...parser is not DOCTYPE aware (and will never be), so you need a way to set those properties -
|
||||
if not on per-node basis, then on per-document</li>
|
||||
</ul>
|
||||
So, these are the processing flags:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>If <b>parse_trim_pcdata</b> is on, then the trimming of leading/trailing space-like characters
|
||||
is performed for PCDATA content
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: off</li>
|
||||
<li>If <b>parse_trim_attribute</b> is on, then the trimming of leading/trailing space-like characters
|
||||
is performed for attribute values
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: off</li>
|
||||
<li>If <b>parse_escapes_pcdata</b> is on, then the character reference expansion is done for PCDATA
|
||||
content (replacing <lt; with <, &#4c; with L, etc.).
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_escapes_attribute</b> is on, then the character reference expansion is done for
|
||||
attribute values (replacing <lt; with <, &#4c; with L, etc.).
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_wnorm_pcdata</b> is on, then the whitespace normalisation is done for PCDATA content
|
||||
(this includes replacing any space-like character by a space character and converting sequences of
|
||||
spaces into a single space)
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: off</li>
|
||||
<li>If <b>parse_wnorm_attribute</b> is on, then the whitespace normalisation is done for attribute
|
||||
values
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: off</li>
|
||||
<li>If <b>parse_wconv_attribute</b> is on, then the whitespace conversion is done for attribute
|
||||
values (this is a subset of whitespace normalization, and includes only replacing space-like characters
|
||||
with spaces). If <b>parse_wnorm_attribute</b> is on, this flag has no effect.
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
<li>If <b>parse_eol_cdata</b> is on, then the end-of-line handling is done for CDATA content (this
|
||||
includes converting any pair of 0x0d 0x0a characters to a single 0x0a and converting any standalone
|
||||
0x0d to 0x0a). Note, that end-of-line handling is done for all content (PCDATA, attribute values)
|
||||
except CDATA sections (if this flag is off).
|
||||
<br>Default value: on
|
||||
<br>In W3C mode: on</li>
|
||||
</ul>
|
||||
|
||||
<p>Finally, there are two more flags, that indicate closing tag parsing. When <i>pugixml</i> meets a
|
||||
close tags, there are three ways:
|
||||
<ul>
|
||||
<li>check that the tag name matches the opening tag, return an error if it does not. This is a
|
||||
standard-compliant way, is controlled by <b>parse_check_end_tags</b> flag, which is on in W3C mode</li>
|
||||
<li>try to find the corresponding tag name (so that <b><foo> <bar> </foo></b> will be parsed
|
||||
correctly). This is controlled by <b>parse_match_end_tags</b>, which is on by default</li>
|
||||
<li>just treat the tag as a closing tag for the node (so that <b><foo> ... </bar></b> will
|
||||
be parsed as <b><foo> ... </foo></b>). This is the fastest way, and this is what <i>pugxml</i>
|
||||
is doing, but it can corrupt your DOM tree. This way is chosen if both <b>parse_check_end_tags</b> and
|
||||
<b>parsse_match_end_tags</b> are off.
|
||||
</ul>
|
||||
Note, that these 2 flags are mutually exclusive.
|
||||
</p>
|
||||
|
||||
<p>Did I say finally? Ok, so <b>finally</b> there are some helper flags, or better groups of flags.
|
||||
These are:
|
||||
<ul>
|
||||
<li><b>parse_minimal</b> - no flag is set (this also means the fastest parsing)</li>
|
||||
<li><b>parse_default</b> - default set of flags</li>
|
||||
<li><b>parse_noset</b> - use the current parser options (see below)</li>
|
||||
<li><b>parse_w3c</b> - use the W3C compliance mode</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>A couple of words on flag usage. The parsing options are just a set of bits, with each bit corresponding
|
||||
to one flag. You can turn the flag on by OR-ing the options value with this flag's constant:
|
||||
<pre>
|
||||
parse_w3c | parse_wnorm_pcdata
|
||||
</pre>
|
||||
or turn the flag off by AND-ing the options value with the NEGation of this flag's constant:
|
||||
<pre>
|
||||
parse_w3c & ~parse_comments
|
||||
</pre>
|
||||
You can access the current options of parser by <b>options()</b> method:
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >options()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >options(</font><b><font color="#0000ff" >unsigned</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >optmsk);</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
(the latter one returns previous options). These options are used when <b>parse_noset</b> flag set is
|
||||
passed to <b>parse()</b> functions (which is the default value of corresponding parameter).
|
||||
</p>
|
||||
|
||||
<a name="Doc_Node">
|
||||
<h3>xml_node class</h3>
|
||||
|
||||
<p>If <b>xml_parser</b> is a heart of constructing a DOM tree from file, <b>xml_node</b> is a heart
|
||||
of processing the tree. This is a simple wrapper, so it's small (4/8 bytes, depending on the size of
|
||||
pointer), you're free to copy it and it does not own anything. I'll continue with a list of methods
|
||||
with their description, with one note in advance. Some functions, that do something according to a
|
||||
string-like parameter, have a pair with a suffix <b>_w</b>. The <b>_w</b> suffix tells, that this
|
||||
function is doing a wildcard matching, instead of simple string comparison. You're free to use wildcards
|
||||
<b>*</b> (that is equal to any sequence of characters (possibly empty)), <b>?</b> (that is equal to
|
||||
any character) and character sets (<b>[Abc]</b> means 'any symbol of A, b and c', <b>[A-Z4]</b> means
|
||||
'any symbol from A to Z, or 4', <b>[!0-9]</b> means 'any symbol, that is not a digit'). So the wildcard
|
||||
<b>?ell_[0-9][0-9]_*</b> will match strings like 'cell_23_xref', 'hell_00_', but will not match the
|
||||
strings like 'ell_23_xref', 'cell_0_x' or 'cell_0a_x'.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<i><font color="#808080" >/// Access iterators for this node's collection of child nodes.</font></i>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >begin()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >end()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<i><font color="#808080" >/// Access iterators for this node's collection of child nodes (same as begin/end).</font></i>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >children_begin()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >children_end()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<i><font color="#808080" >/// Access iterators for this node's collection of attributes.</font></i>
|
||||
<font color="#000000" >attribute_iterator</font> <font color="#000000" >attributes_begin()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >attribute_iterator</font> <font color="#000000" >attributes_end()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<i><font color="#808080" >/// Access iterators for this node's collection of siblings.</font></i>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >siblings_begin()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >iterator</font> <font color="#000000" >siblings_end()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Functions, returning the iterators to walk through children/siblings/attributes. More on that in
|
||||
<a href="#Doc_Iterators">Iterators</a> section.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >operator</font></b> <font color="#000000" >unspecified_bool_type()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>This is a safe bool-like conversion operator. You can check node's validity (<b>if (xml_node)</b>,
|
||||
<b>if (!xml_node)</b>, <b>if (node1 && node2 && !node3 && cond1 && ...)</b> - you get the idea) with
|
||||
it.
|
||||
</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >==(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >!=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" ><(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >>(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" ><=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >>=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Comparison operators</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <font color="#000000" >empty()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p><code>if (node.empty())</code> is equivalent to <code>if (!node)</code></p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node_type</font> <font color="#000000" >type()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >value()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Access node's properties (type, name and value). If there is no name/value, the corresponding functions
|
||||
return <b>""</b> - they <u>never</u> return NULL.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >child(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >child_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get a child node with specified name, or <b>xml_node()</b> (this is an invalid node) if nothing is
|
||||
found</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >attribute(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >attribute_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get an attribute with specified name, or <b>xml_attribute()</b> (this is an invalid attribute) if
|
||||
nothing is found</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >sibling(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >sibling_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get a node's sibling with specified name, or <b>xml_node()</b> if nothing is found.<br>
|
||||
<code>node.sibling(name)</code> is equivalent to <code>node.parent().child(name)</code>.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >next_sibling(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >next_sibling_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >next_sibling()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions get the next sibling, that is, one of the siblings of that node, that is to the
|
||||
right. <code>next_sibling()</code> just returns the right brother of the node (or <b>xml_node()</b>),
|
||||
the two other functions are searching for the sibling with the given name</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >previous_sibling(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >previous_sibling_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >previous_sibling()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions do exactly the same as <code>next_sibling</code> ones, with the exception that they
|
||||
search for the left siblings.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >parent()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get a parent node. The parent node for the root one (the document) is considered to be the document
|
||||
itself.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >child_value()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Look for the first node of type <b>node_pcdata</b> or <b>node_cdata</b> among the
|
||||
children of the current node and return its contents (or <b>""</b> if nothing is found)</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >first_attribute()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >last_attribute()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions get the first and last attributes of the node (or <b>xml_attribute()</b> if the node
|
||||
has no attributes).</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_child()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >last_child()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions get the first and last children of the node (or <b>xml_node()</b> if the node has
|
||||
no children).</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >template</font></b> <font color="#000000" ><</font><b><font color="#0000ff" >typename</font></b> <font color="#000000" >OutputIterator></font> <b><font color="#0000ff" >void</font></b> <font color="#000000" >all_elements_by_name(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <font color="#000000" >OutputIterator</font> <font color="#000000" >it)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >template</font></b> <font color="#000000" ><</font><b><font color="#0000ff" >typename</font></b> <font color="#000000" >OutputIterator></font> <b><font color="#0000ff" >void</font></b> <font color="#000000" >all_elements_by_name_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <font color="#000000" >OutputIterator</font> <font color="#000000" >it)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get all elements with the specified name in the subtree (depth-first search) and return them with
|
||||
the help of output iterator (i.e. std::back_inserter)</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >template</font></b> <font color="#000000" ><</font><b><font color="#0000ff" >typename</font></b> <font color="#000000" >Predicate></font> <font color="#000000" >xml_attribute</font> <font color="#000000" >find_attribute(Predicate</font> <font color="#000000" >pred)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >template</font></b> <font color="#000000" ><</font><b><font color="#0000ff" >typename</font></b> <font color="#000000" >Predicate></font> <font color="#000000" >xml_node</font> <font color="#000000" >find_child(Predicate</font> <font color="#000000" >pred)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >template</font></b> <font color="#000000" ><</font><b><font color="#0000ff" >typename</font></b> <font color="#000000" >Predicate></font> <font color="#000000" >xml_node</font> <font color="#000000" >find_element(Predicate</font> <font color="#000000" >pred)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Find attribute, child or a node in the subtree (find_element - depth-first search) with the help
|
||||
of the given predicate. Predicate should behave like a function which accepts a <b>xml_node</b> or
|
||||
<b>xml_attribute</b> (for find_attribute) parameter and returns <b>bool</b>. The first entity for which
|
||||
the predicate returned true is returned. If predicate returned false for all entities, <b>xml_node()</b>
|
||||
or <b>xml_attribute()</b> is returned.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_value(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_value_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_attribute(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_attribute_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_attribute(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_attribute_w(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_name,</font> <b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >attr_value)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Find the first node (depth-first search), which corresponds to the given criteria (i.e. either has
|
||||
a matching name, or a matching value, or has an attribute with given name/value, or has an attribute
|
||||
and has a matching name). Note that <b>_w</b> versions treat all parameters as wildcards.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_node(xml_node_type</font> <font color="#000000" >type)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Return a first node (depth-first search) with a given type, or <b>xml_node()</b>.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >std::string</font> <font color="#000000" >path(</font><b><font color="#0000ff" >char</font></b> <font color="#000000" >delimiter</font> <font color="#000000" >=</font> <font color="#ff0000" >'/'</font><font color="#000000" >)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get a path of the node (i.e. the string of names of the nodes on the path from the DOM tree root
|
||||
to the node, separated with delimiter (/ by default).</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >first_element_by_path(</font><b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >path,</font> <b><font color="#0000ff" >char</font></b> <font color="#000000" >delimiter</font> <font color="#000000" >=</font> <font color="#ff0000" >'/'</font><font color="#000000" >)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get the first element that has the following path. The path can be absolute (beginning with delimiter) or
|
||||
relative, '..' means 'up-level' (so if we are at the path <b>mesh/fragment/geometry/stream</b>, <b>../..</b>
|
||||
will lead us to <b>mesh/fragment</b>, and <b>/mesh</b> will lead us to <b>mesh</b>).</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <font color="#000000" >traverse(xml_tree_walker&</font> <font color="#000000" >walker)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Traverse the subtree (beginning with current node) with the walker, return the result. See
|
||||
<a href="#Doc_Misc">Miscellaneous</a> section for details.</p>
|
||||
|
||||
<a name="Doc_Attribute">
|
||||
<h3>xml_attribute class</h3>
|
||||
|
||||
<p>Like <b>xml_node</b>, <b>xml_attribute</b> is a simple wrapper of the node's attribute.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >==(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >!=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" ><(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >>(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" ><=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >bool</font></b> <b><font color="#0000ff" >operator</font></b><font color="#000000" >>=(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_attribute&</font> <font color="#000000" >r)</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Comparison operators.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >operator</font></b> <font color="#000000" >unspecified_bool_type()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Safe bool conversion - like in <b>xml_node</b>, use this to check for validity.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <font color="#000000" >empty()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Like with <b>xml_node</b>, <code>if (attr.empty())</code> is equivalent to <code>if (!attr)</code>.
|
||||
</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >next_attribute()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >previous_attribute()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get the next/previous attribute of the node, that owns the current attribute. Return <b>xml_attribute()</b>
|
||||
if no such attribute is found.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >name()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >const</font></b> <b><font color="#0000ff" >char</font></b><font color="#000000" >*</font> <font color="#000000" >value()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get the name and value of the attribute. These methods never return NULL - they return <b>""</b> instead.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >int</font></b> <font color="#000000" >as_int()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >double</font></b> <font color="#000000" >as_double()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
<b><font color="#0000ff" >float</font></b> <font color="#000000" >as_float()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Convert the value of an attribute to the desired type. If the conversion is not successfull, return
|
||||
default value (0 for int, 0.0 for double, 0.0f for float). These functions rely on CRT functions ato*.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <font color="#000000" >as_bool()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Convert the value of an attribute to bool. This method returns true if the first character of the
|
||||
value is '1', 't', 'T', 'y' or 'Y'. Otherwise it returns false.</p>
|
||||
|
||||
<a name="Doc_Iterators">
|
||||
<h3>Iterators</h3>
|
||||
|
||||
<p>Sometimes you have to cycle through the children or the attributes of the node. You can do it either
|
||||
by using <b>next_sibling</b>, <b>previous_sibling</b>, <b>next_attribute</b> and <b>previous_attribute</b>
|
||||
(along with <b>first_child</b>, <b>last_child</b>, <b>first_attribute</b> and <b>last_attribute</b>),
|
||||
or you can use an iterator-like interface. There are two iterator types, <b>xml_node_iterator</b> and
|
||||
<b>xml_attribute_iterator</b>. They are bidirectional constant iterators, which means that you can
|
||||
either increment or decrement them, and use dereferencing and member access operators to get constant
|
||||
access to node/attribute (the constness of iterators may change with the introducing of mutable trees).</p>
|
||||
|
||||
<p>In order to get the iterators, use corresponding functions of <b>xml_node</b>. Note that <b>_end()</b>
|
||||
functions return past-the-end iterator, that is, in order to get the last attribute, you'll have to
|
||||
do something like:
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(node.attributes_begin()</font> <font color="#000000" >!=</font> <font color="#000000" >node.attributes_end())</font> <i><font color="#808080" >// we have at least one attribute</font></i>
|
||||
<font color="#000000" >{</font>
|
||||
<font color="#000000" >xml_attribute</font> <font color="#000000" >last_attrib</font> <font color="#000000" >=</font> <font color="#000000" >*(--node.attributes_end());</font>
|
||||
<font color="#000000" >...</font>
|
||||
<font color="#000000" >}</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
</p>
|
||||
|
||||
<a name="Doc_Misc">
|
||||
<h3>Miscellaneous</h3>
|
||||
|
||||
<p>If you want to traverse a subtree, you can use <b>traverse</b> function. There is a class
|
||||
<b>xml_tree_walker</b>, which has some functions that you can override in order to get custom traversing
|
||||
(the default one just does nothing).
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >bool</font></b> <font color="#000000" >begin(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&);</font>
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >bool</font></b> <font color="#000000" >end(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&);</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions are called when the processing of the node starts/ends. First <b>begin()</b>
|
||||
is called, then all children of the node are processed recursively, then <b>end()</b> is called. If
|
||||
any of these functions returns false, the traversing is stopped and the <b>traverse()</b> function
|
||||
returns false.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >void</font></b> <font color="#000000" >push();</font>
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >void</font></b> <font color="#000000" >pop();</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>These functions are called before and after the processing of node's children. If node has no children,
|
||||
none of these is called. The default behavior is to increment/decrement current node depth.</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >int</font></b> <font color="#000000" >depth()</font> <b><font color="#0000ff" >const</font></b><font color="#000000" >;</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>Get the current depth. You can use this function to do your own indentation, for example.</p>
|
||||
|
||||
<p>Lets get to some minor notes. You can safely write something like:
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<b><font color="#0000ff" >bool</font></b> <font color="#000000" >value</font> <font color="#000000" >=</font> <font color="#000000" >node.child(</font><font color="#ff0000" >"stream"</font><font color="#000000" >).attribute(</font><font color="#ff0000" >"compress"</font><font color="#000000" >).as_bool();</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
If node has a child with the name 'geometry', and this child has an attribute 'compress', than everything
|
||||
is ok. If node has a child with the name 'geometry' with no attribute 'compress', then attribute("compress")
|
||||
will return xml_attribute(), and the corresponding call to as_bool() will return default value (false).
|
||||
If there is no child node 'geometry', the child(...) call will return xml_node(), the subsequent call
|
||||
to attribute(...) will return xml_attribute() (because there are no attributes belonging to invalid
|
||||
node), and as_bool() will again return false, so this call sequence is perfectly safe.</p>
|
||||
|
||||
<a name="Doc_Lifetime">
|
||||
<h3>Lifetime issues and memory management</h3>
|
||||
|
||||
<p>As parsing is done in-situ, the XML data is to persist during the lifetime of <b>xml_parser</b>. If
|
||||
the parsing is called via a function of <b>xml_parser</b>, that accepts <b>char*</b>, you have to ensure
|
||||
yourself, that the string will outlive the <b>xml_parser</b> object.</p>
|
||||
|
||||
<p>The memory for nodes and attributes is allocated in blocks of data (the blocks form a linked list;
|
||||
the default size of the block is 32 kb, though you can change it via changing a <b>memory_block_size</b>
|
||||
constant in <b>pugixml.hpp</b> file. Remember that the first block is allocated on stack (it resides
|
||||
inside <b>xml_parser</b> object), and all subsequent blocks are allocated on heap, so expect a stack overflow
|
||||
when setting too large memory block size), so the <b>xml_parser</b> object (which contains the blocks)
|
||||
should outlive all <b>xml_node</b> and <b>xml_attribute</b> objects (as well as iterators), which belong
|
||||
to the parser's tree. Again, you should ensure it yourself.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Example">
|
||||
<h2>Example</h2>
|
||||
|
||||
<p>Ok, so you are not much of documentation reader, are you? So am I. Let's assume that you're going
|
||||
to parse an xml file... something like this:
|
||||
|
||||
<pre>
|
||||
<span style='color:#004a43; '><?</span><span style='color:#004a43; '>xml</span> <span style='color:#004a43; '>version</span><span style='color:#808030; '>=</span><span style='color:#008c00; '>"1.0"</span> <span style='color:#004a43; '>encoding</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"UTF-8"</span><span style='color:#004a43; '>?></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>mesh</span> <span style='color:#274796; '>name</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>Cathedral</span><span style='color:#0000e6; '>"</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>fragment</span> <span style='color:#274796; '>name</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>Cathedral</span><span style='color:#0000e6; '>"</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>geometry</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>stream</span> <span style='color:#274796; '>usage</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>main</span><span style='color:#0000e6; '>"</span> <span style='color:#274796; '>source</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>StAnna.dmesh</span><span style='color:#0000e6; '>"</span> <span style='color:#274796; '>compress</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>true</span><span style='color:#0000e6; '>"</span> <span style='color:#a65700; '>/></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>stream</span> <span style='color:#274796; '>usage</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>ao</span><span style='color:#0000e6; '>"</span> <span style='color:#274796; '>source</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>StAnna.ao</span><span style='color:#0000e6; '>"</span> <span style='color:#a65700; '>/></span>
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>geometry</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>fragment</span><span style='color:#a65700; '>></span>
|
||||
<span style='color:#a65700; '><</span><span style='color:#5f5035; '>fragment</span> <span style='color:#274796; '>name</span><span style='color:#808030; '>=</span><span style='color:#0000e6; '>"</span><span style='color:#0000e6; '>Cathedral</span><span style='color:#0000e6; '>"</span><span style='color:#a65700; '>></span>
|
||||
...
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>fragment</span><span style='color:#a65700; '>></span>
|
||||
...
|
||||
<span style='color:#a65700; '></</span><span style='color:#5f5035; '>mesh</span><span style='color:#a65700; '>></span>
|
||||
</pre>
|
||||
|
||||
<p><mesh> is a root node, it has 0 or more <fragment>s, each of them has a <geometry>
|
||||
node, and there are <stream> nodes with the shown attributes. We'd like to parse the file and...
|
||||
well, and do something with it's contents. There are several methods of doing that; I'll show 2 of them
|
||||
(the remaining one is using iterators).</p>
|
||||
|
||||
<p>Here we exploit the knowledge of the strict hierarchy of our XML document and read the nodes from
|
||||
DOM tree accordingly. When we have an <b>xml_node</b> object, we can get the desired information from
|
||||
it (name, value, attributes list, nearby nodes in a tree - siblings, parent and children).</p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><fstream></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><vector></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><algorithm></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><iterator></font>
|
||||
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" >"pugixml.hpp"</font>
|
||||
|
||||
<b><font color="#0000ff" >using</font></b> <b><font color="#0000ff" >namespace</font></b> <font color="#000000" >pugi;</font>
|
||||
|
||||
<b><font color="#0000ff" >int</font></b> <font color="#000000" >main()</font>
|
||||
<font color="#000000" >{</font>
|
||||
<font color="#000000" >std::ifstream</font> <font color="#000000" >in(</font><font color="#ff0000" >"mesh.xml"</font><font color="#000000" >);</font>
|
||||
<font color="#000000" >in.unsetf(std::ios::skipws);</font>
|
||||
|
||||
<font color="#000000" >std::vector<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >></font> <font color="#000000" >buf;</font>
|
||||
<font color="#000000" >std::copy(std::istream_iterator<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >>(in),</font> <font color="#000000" >std::istream_iterator<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >>(),</font> <font color="#000000" >std::back_inserter(buf));</font>
|
||||
<font color="#000000" >buf.push_back(</font><b><font color="#40b440" >0</font></b><font color="#000000" >);</font> <i><font color="#808080" >// zero-terminate</font></i>
|
||||
|
||||
<font color="#000000" >xml_parser</font> <font color="#000000" >parser(&buf[</font><b><font color="#40b440" >0</font></b><font color="#000000" >],</font> <font color="#000000" >pugi::parse_w3c);</font>
|
||||
|
||||
<font color="#000000" >xml_node</font> <font color="#000000" >doc</font> <font color="#000000" >=</font> <font color="#000000" >parser.document();</font>
|
||||
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(xml_node</font> <font color="#000000" >mesh</font> <font color="#000000" >=</font> <font color="#000000" >doc.first_element(</font><font color="#ff0000" >"mesh"</font><font color="#000000" >))</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store mesh.attribute("name").value()</font></i>
|
||||
|
||||
<b><font color="#0000ff" >for</font></b> <font color="#000000" >(xml_node</font> <font color="#000000" >fragment</font> <font color="#000000" >=</font> <font color="#000000" >mesh.first_element(</font><font color="#ff0000" >"fragment"</font><font color="#000000" >);</font> <font color="#000000" >fragment;</font> <font color="#000000" >fragment</font> <font color="#000000" >=</font> <font color="#000000" >fragment.next_sibling())</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store fragment.attribute("name").value()</font></i>
|
||||
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(xml_node</font> <font color="#000000" >geometry</font> <font color="#000000" >=</font> <font color="#000000" >fragment.first_element(</font><font color="#ff0000" >"geometry"</font><font color="#000000" >))</font>
|
||||
<b><font color="#0000ff" >for</font></b> <font color="#000000" >(xml_node</font> <font color="#000000" >stream</font> <font color="#000000" >=</font> <font color="#000000" >geometry.first_element(</font><font color="#ff0000" >"stream"</font><font color="#000000" >);</font> <font color="#000000" >stream;</font> <font color="#000000" >stream</font> <font color="#000000" >=</font> <font color="#000000" >stream.next_sibling())</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store stream.attribute("usage").value()</font></i>
|
||||
<i><font color="#808080" >// store stream.attribute("source").value()</font></i>
|
||||
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(stream.attribute(</font><font color="#ff0000" >"compress"</font><font color="#000000" >))</font>
|
||||
<i><font color="#808080" >// store stream.attribute("compress").as_bool()</font></i>
|
||||
|
||||
<font color="#000000" >}</font>
|
||||
<font color="#000000" >}</font>
|
||||
<font color="#000000" >}</font>
|
||||
<font color="#000000" >}</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<p>We can also write a class that will traverse the DOM tree and store the information from nodes based
|
||||
on their names, depths, attributes, etc. This way is well known by the users of SAX parsers. To do that,
|
||||
we have to write an implementation of <b>xml_tree_walker</b> interface </p>
|
||||
|
||||
<table width = "100%" bgcolor="#e6e6e6"><tr><td><pre><font color="white">
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><fstream></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><vector></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><algorithm></font>
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" ><iterator></font>
|
||||
|
||||
<font color="#008000" >#include</font> <font color="#ff0000" >"pugixml.hpp"</font>
|
||||
|
||||
<b><font color="#0000ff" >using</font></b> <b><font color="#0000ff" >namespace</font></b> <font color="#000000" >pugi;</font>
|
||||
|
||||
<b><font color="#0000ff" >struct</font></b> <font color="#000000" >mesh_parser:</font> <b><font color="#0000ff" >public</font></b> <font color="#000000" >xml_tree_walker</font>
|
||||
<font color="#000000" >{</font>
|
||||
<b><font color="#0000ff" >virtual</font></b> <b><font color="#0000ff" >bool</font></b> <font color="#000000" >begin(</font><b><font color="#0000ff" >const</font></b> <font color="#000000" >xml_node&</font> <font color="#000000" >node)</font>
|
||||
<font color="#000000" >{</font>
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(strcmp(node.name(),</font> <font color="#ff0000" >"mesh"</font><font color="#000000" >)</font> <font color="#000000" >==</font> <b><font color="#40b440" >0</font></b><font color="#000000" >)</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store node.attribute("name").value()</font></i>
|
||||
<font color="#000000" >}</font>
|
||||
<b><font color="#0000ff" >else</font></b> <b><font color="#0000ff" >if</font></b> <font color="#000000" >(strcmp(node.name(),</font> <font color="#ff0000" >"fragment"</font><font color="#000000" >)</font> <font color="#000000" >==</font> <b><font color="#40b440" >0</font></b><font color="#000000" >)</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store node.attribute("name").value()</font></i>
|
||||
<font color="#000000" >}</font>
|
||||
<b><font color="#0000ff" >else</font></b> <b><font color="#0000ff" >if</font></b> <font color="#000000" >(strcmp(node.name(),</font> <font color="#ff0000" >"geometry"</font><font color="#000000" >)</font> <font color="#000000" >==</font> <b><font color="#40b440" >0</font></b><font color="#000000" >)</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// ...</font></i>
|
||||
<font color="#000000" >}</font>
|
||||
<b><font color="#0000ff" >else</font></b> <b><font color="#0000ff" >if</font></b> <font color="#000000" >(strcmp(node.name(),</font> <font color="#ff0000" >"stream"</font><font color="#000000" >)</font> <font color="#000000" >==</font> <b><font color="#40b440" >0</font></b><font color="#000000" >)</font>
|
||||
<font color="#000000" >{</font>
|
||||
<i><font color="#808080" >// store node.attribute("usage").value()</font></i>
|
||||
<i><font color="#808080" >// store node.attribute("source").value()</font></i>
|
||||
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(node.attribute(</font><font color="#ff0000" >"compress"</font><font color="#000000" >))</font>
|
||||
<i><font color="#808080" >// store stream.attribute("compress").as_bool()</font></i>
|
||||
<font color="#000000" >}</font>
|
||||
<b><font color="#0000ff" >else</font></b> <b><font color="#0000ff" >return</font></b> <b><font color="#0000ff" >false</font></b><font color="#000000" >;</font>
|
||||
|
||||
<b><font color="#0000ff" >return</font></b> <b><font color="#0000ff" >true</font></b><font color="#000000" >;</font>
|
||||
<font color="#000000" >}</font>
|
||||
<font color="#000000" >};</font>
|
||||
|
||||
<b><font color="#0000ff" >int</font></b> <font color="#000000" >main()</font>
|
||||
<font color="#000000" >{</font>
|
||||
<font color="#000000" >std::ifstream</font> <font color="#000000" >in(</font><font color="#ff0000" >"mesh.xml"</font><font color="#000000" >);</font>
|
||||
<font color="#000000" >in.unsetf(std::ios::skipws);</font>
|
||||
|
||||
<font color="#000000" >std::vector<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >></font> <font color="#000000" >buf;</font>
|
||||
<font color="#000000" >std::copy(std::istream_iterator<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >>(in),</font> <font color="#000000" >std::istream_iterator<</font><b><font color="#0000ff" >char</font></b><font color="#000000" >>(),</font> <font color="#000000" >std::back_inserter(buf));</font>
|
||||
<font color="#000000" >buf.push_back(</font><b><font color="#40b440" >0</font></b><font color="#000000" >);</font> <i><font color="#808080" >// zero-terminate</font></i>
|
||||
|
||||
<font color="#000000" >xml_parser</font> <font color="#000000" >parser(&buf[</font><b><font color="#40b440" >0</font></b><font color="#000000" >],</font> <font color="#000000" >pugi::parse_w3c);</font>
|
||||
|
||||
<font color="#000000" >mesh_parser</font> <font color="#000000" >mp;</font>
|
||||
|
||||
<b><font color="#0000ff" >if</font></b> <font color="#000000" >(!parser.document().traverse(mp))</font>
|
||||
<i><font color="#808080" >// generate an error</font></i>
|
||||
<font color="#000000" >}</font>
|
||||
</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#666666">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Parsing">
|
||||
<h2>Parsing process</h2>
|
||||
|
||||
<p>So, let's talk a bit about parsing process, and about the reason for providing XML data as a contiguous
|
||||
writeable block of memory. Parsing is done in-situ. This means, that the strings, representing the
|
||||
parts of DOM tree (node names, attribute names and values, CDATA content, etc.) are not separately
|
||||
allocated on heap, but instead are parts of the original data. This is the keypoint to parsing speed,
|
||||
because it helps achieve the minimal amount of memory allocations (more on that below) and minimal
|
||||
amount of copying data.</p>
|
||||
|
||||
<p>In-situ parsing can be done in two ways, with zero-segmenting the string (that is, set the past-the-end
|
||||
character for the part of XML string to 0, see <a href="http://www.codeproject.com/soap/pugxml/pugxml_steps.gif">
|
||||
this image</a> for further details), and storing pointer + size of the string instead of pointer to
|
||||
the beginning of ASCIIZ string.</p>
|
||||
|
||||
<p>Originally, <i>pugxml</i> had only the first way, but then authors added the second method, 'non-segmenting'
|
||||
or non-destructive parsing. The advantages of this method are: you no longer need non-constant storage;
|
||||
you can even read data from memory-mapped files directly. Well, there are disadvantages.
|
||||
For one thing, you can not do any of the transformations in-situ. The transformations that are required
|
||||
by XML standard are:
|
||||
<ul>
|
||||
<li>End of line handling (replacing 0x0d 0x0a with 0x0a and any standalone 0x0d with 0x0a) (for the whole
|
||||
document)</li>
|
||||
<li>White space normalization for attribute values (converting space-like characters to spaces (0x20),
|
||||
sometimes trimming leading/trailing spaces and converting sequences of spaces to a single space</li>
|
||||
<li>Character reference expansion (&lt; and alike, <#0a; and alike, <40; and alike)</li>
|
||||
<li>Entity reference expansion (&entityname;)</li>
|
||||
</ul>
|
||||
|
||||
None of these can be done in-situ. <i>pugxml</i> did neither character nor entity reference expansion,
|
||||
and allocated new memory when normalizing white spaces when in non-destructive mode. I chose complete
|
||||
in-situ parsing (the good thing about it is that any transformation, except entity reference, can be
|
||||
done in-situ because it does not increase the amount of characters - even converting a character
|
||||
reference to UTF-8). There is no entity reference expansion because of this and because I do not want
|
||||
to parse DOCTYPE and, moreover, use DOCTYPE in following parsing (performing selective whitespace
|
||||
normalization in attributes and CDATA sections and so on).</p>
|
||||
|
||||
<p>In order to be able to modify the tree (change attribute/node names & values) with in-situ parsing,
|
||||
one needs to implement two ways of storing data (both in-situ and not). The DOM tree is now mutable,
|
||||
but it will change in the future releases (without introducing speed/memory overhead, except on clean-
|
||||
up stage).</p>
|
||||
|
||||
<p>The parsing process itself is more or less straightforward, when you see it - but the impression
|
||||
is fake, because the explicit jumps are made (i.e. we know, that if we come to a closing brace (>),
|
||||
we should expect CDATA after it (or a new tag), so let's just jump to the corresponding code), and,
|
||||
well, there can be bugs (see <a href="#Bugs">Bugs</a> section).</p>
|
||||
|
||||
<p>And, to make things worse, memory allocation (which is done only for node and attribute structures)
|
||||
is done in pools. The pools are single-linked lists with predefined block size (32 kb by default), and
|
||||
well, it increases speed a lot (allocations are slow, and the memory gets fragmented when allocating
|
||||
a bunch of 16-byte (attribute) or 40-byte (node) structures)</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Compliance">
|
||||
<h2>W3C compliance</h2>
|
||||
|
||||
<p><i>pugixml</i> is not a compliant XML parser. The main reason for that is that it does not reject
|
||||
most malformed XML files. The more or less complete list of incompatibilities follows (I will be talking
|
||||
of ones when using <b>parse_w3c</b> mode):
|
||||
|
||||
<ul>
|
||||
<li>The parser is completely DOCTYPE-ignorant, that is, it does not even skip all possible DOCTYPEs
|
||||
correctly, let alone use them for parsing
|
||||
<li>It accepts multiple attributes with the same name in one node
|
||||
<li>It is charset-ignorant
|
||||
<li>It accepts invalid names of tags
|
||||
<li>It accepts invalid attribute values (those with < in them) and does not reject invalid entity
|
||||
references or character references (in fact, it does not do DOCTYPE parsing, so it does not perform
|
||||
entity reference expansion)
|
||||
<li>It does not reject comments with -- inside
|
||||
<li>It does not reject PI with the names of 'xml' and alike; in fact, it parses prolog as a PI, which
|
||||
is not conformant
|
||||
<li>All characters from #x1 to #x20 are considered to be whitespaces
|
||||
<li>And some other things that I forgot to mention
|
||||
</ul>
|
||||
|
||||
In short, it accepts most malformed XML files and does not do anything that is related to DOCTYPE.
|
||||
This is because the main goal was developing fast, easy-to-use and error ignorant (so you can always
|
||||
get something even from a malformed document) parser, there are some good validating and conformant
|
||||
parsers already.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="FAQ">
|
||||
<h2>FAQ</h2>
|
||||
|
||||
<p>I'm always open for questions; feel free to write them to <a href="mailto:zeux@mathcentre.com">zeux@mathcentre.com</a>.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Bugs">
|
||||
<h2>Bugs</h2>
|
||||
|
||||
<p>I'm always open for bug reports; feel free to write them to <a href="mailto:zeux@mathcentre.com">zeux@mathcentre.com</a>.
|
||||
Please provide as much information as possible - version of <i>pugixml</i>, compiling and OS environment
|
||||
(compiler and it's version, STL version, OS version, etc.), the description of the situation in which
|
||||
the bug arises, the code and data files that show the bug, etc. - the more, the better. Though, please,
|
||||
do not send executable files.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Future_work">
|
||||
<h2>Future work</h2>
|
||||
|
||||
<p>Here are some improvements that will be done in future versions (they are sorted by priority, the
|
||||
upper ones will get there sooner).</p>
|
||||
|
||||
<ul>
|
||||
<li>Support for altering the tree (both changing nodes'/attributes' names and values and adding/deleting
|
||||
attributes/nodes) and writing the tree to stream
|
||||
<li>Support for UTF-16 files (parsing BOM to get file's type and converting UTF-16 file to UTF-8 buffer
|
||||
if necessary)
|
||||
<li>Improved API (I'm going to look at SelectNode from MS XML and perhaps there will be some other
|
||||
changes)
|
||||
<li>Externally provided entity reference table (or perhaps even taken from DOCTYPE?)
|
||||
<li>More intelligent parsing of DOCTYPE (it does not always skip DOCTYPE for now)
|
||||
<li>XML 1.1 changes (changed EOL handling, normalization issues,
|
||||
<li>XPath support
|
||||
<li>Name your own?
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Changelog">
|
||||
<h2>Changelog</h2>
|
||||
|
||||
<dl>
|
||||
<dt>15.07.2006 - v0.1
|
||||
<dd>First private release for testing purposes
|
||||
</dt>
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="Acknowledgements">
|
||||
<h2>Acknowledgements</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="mailto:kristen@tima.net">Kristen Wegner</a> for <i>pugxml</i> parser
|
||||
<li><a href="mailto:readonly@getsoft.com">Neville Franks</a> for contributions to <i>pugxml</i> parser
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="License">
|
||||
<h2>License</h2>
|
||||
|
||||
<p>The <i>pugixml</i> parser is released into the public domain (though this may change).</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 15 July, 2006</p>
|
||||
<p><i>© Copyright <a href="mailto:zeux@mathcentre.com">Zeux</a> 2006. All Rights Reserved.</i></p>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/tree.png
Normal file
BIN
docs/tree.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
1868
src/pugixml.cpp
Normal file
1868
src/pugixml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
619
src/pugixml.hpp
Normal file
619
src/pugixml.hpp
Normal file
@ -0,0 +1,619 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Pug Improved XML Parser - Version 0.1
|
||||
// --------------------------------------------------------
|
||||
// Copyright (C) 2006, by Zeux (zeux@mathcentre.com)
|
||||
// This work is based on the pugxml parser, which is:
|
||||
// Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
// Released into the Public Domain. Use at your own risk.
|
||||
// See pugxml.xml for further information, history, etc.
|
||||
// Contributions by Neville Franks (readonly@getsoft.com).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef HEADER_PUGIXML_HPP
|
||||
#define HEADER_PUGIXML_HPP
|
||||
|
||||
/// The PugiXML Parser namespace.
|
||||
namespace pugi
|
||||
{
|
||||
/// Tree node classification.
|
||||
/// See 'xml_node_struct::type'
|
||||
enum xml_node_type
|
||||
{
|
||||
node_null, ///< An undifferentiated entity.
|
||||
node_document, ///< A document tree's absolute root.
|
||||
node_element, ///< E.g. '<...>'
|
||||
node_pcdata, ///< E.g. '<...>'
|
||||
node_cdata, ///< E.g. '<![CDATA[...]]>'
|
||||
node_comment, ///< E.g. '<!--...-->'
|
||||
node_pi ///< E.g. '<?...?>'
|
||||
};
|
||||
|
||||
/// Parser Options
|
||||
const size_t memory_block_size = 32768; ///< Memory block size, 32 kb
|
||||
|
||||
const unsigned int parse_minimal = 0x00000000; ///< Unset the following flags.
|
||||
const unsigned int parse_pi = 0x00000001; ///< Parse '<?...?>'
|
||||
const unsigned int parse_comments = 0x00000002; ///< Parse '<!--...-->'
|
||||
const unsigned int parse_cdata = 0x00000004; ///< Parse '<![CDATA[...]]>'
|
||||
const unsigned int parse_ws_pcdata = 0x00000008; ///< Skip PCDATA that consists only of whitespaces
|
||||
const unsigned int parse_ext_pcdata = 0x00000010; ///< Skip PCDATA that is outside all tags (i.e. root)
|
||||
const unsigned int parse_trim_pcdata = 0x00000020; ///< Trim '>...<'
|
||||
const unsigned int parse_trim_attribute = 0x00000040; ///< Trim 'foo="..."'.
|
||||
const unsigned int parse_escapes_pcdata = 0x00000080; ///< Parse <, >, &, ", ', &#.. sequences
|
||||
const unsigned int parse_escapes_attribute = 0x00000100; ///< Parse <, >, &, ", ', &#.. sequences
|
||||
const unsigned int parse_wnorm_pcdata = 0x00000200; ///< Normalize spaces in pcdata
|
||||
const unsigned int parse_wnorm_attribute = 0x00000400; ///< Normalize spaces in attributes
|
||||
const unsigned int parse_wconv_attribute = 0x00000800; ///< Convert space-like characters to spaces in attributes (only if wnorm is not set)
|
||||
const unsigned int parse_eol_cdata = 0x00001000; ///< Perform EOL handling in CDATA sections
|
||||
const unsigned int parse_check_end_tags = 0x00002000; ///< Check start and end tag names and return error if names mismatch
|
||||
const unsigned int parse_match_end_tags = 0x00004000; ///< Try to find corresponding start tag for an end tag
|
||||
const unsigned int parse_default = 0x0000FFFF & ~parse_ws_pcdata; ///< Set all flags, except parse_ws_pcdata
|
||||
const unsigned int parse_noset = 0x80000000; ///< Parse with flags in xml_parser
|
||||
|
||||
const unsigned int parse_w3c = parse_pi | parse_comments | parse_cdata |
|
||||
parse_escapes_pcdata | parse_escapes_attribute |
|
||||
parse_wconv_attribute | parse_check_end_tags |
|
||||
parse_ws_pcdata | parse_eol_cdata;
|
||||
|
||||
/// Forward declarations
|
||||
struct xml_attribute_struct;
|
||||
struct xml_node_struct;
|
||||
|
||||
class xml_node_iterator;
|
||||
class xml_attribute_iterator;
|
||||
|
||||
class xml_tree_walker;
|
||||
|
||||
/// Provides a light-weight wrapper for manipulating xml_attribute_struct structures.
|
||||
/// Note: xml_attribute does not create any memory for the attribute it wraps;
|
||||
/// it only wraps a pointer to an existing xml_attribute_struct.
|
||||
class xml_attribute
|
||||
{
|
||||
friend class xml_attribute_iterator;
|
||||
friend class xml_node;
|
||||
|
||||
private:
|
||||
const xml_attribute_struct* _attr; ///< The internal attribute pointer.
|
||||
|
||||
/// Safe bool type
|
||||
typedef const xml_attribute_struct* xml_attribute::*unspecified_bool_type;
|
||||
|
||||
/// Initializing ctor
|
||||
explicit xml_attribute(const xml_attribute_struct* attr);
|
||||
|
||||
public:
|
||||
/// Default ctor
|
||||
xml_attribute();
|
||||
|
||||
public:
|
||||
/// Comparison operators
|
||||
bool operator==(const xml_attribute& r) const;
|
||||
bool operator!=(const xml_attribute& r) const;
|
||||
bool operator<(const xml_attribute& r) const;
|
||||
bool operator>(const xml_attribute& r) const;
|
||||
bool operator<=(const xml_attribute& r) const;
|
||||
bool operator>=(const xml_attribute& r) const;
|
||||
|
||||
/// Safe bool conversion
|
||||
operator unspecified_bool_type() const;
|
||||
|
||||
/// Get next attribute if any, else xml_attribute()
|
||||
xml_attribute next_attribute() const;
|
||||
|
||||
/// Get previous attribute if any, else xml_attribute()
|
||||
xml_attribute previous_attribute() const;
|
||||
|
||||
/// Cast attribute value as int. If not found, return 0.
|
||||
/// \return Attribute value as int, or 0.
|
||||
int as_int() const;
|
||||
|
||||
/// Cast attribute value as double. If not found, return 0.0.
|
||||
/// \return Attribute value as double, or 0.0.
|
||||
double as_double() const;
|
||||
|
||||
/// Cast attribute value as float. If not found, return 0.0.
|
||||
/// \return Attribute value as float, or 0.0.
|
||||
float as_float() const;
|
||||
|
||||
/// Cast attribute value as bool. If not found, return false.
|
||||
/// \return Attribute value as bool, or false.
|
||||
bool as_bool() const;
|
||||
|
||||
public:
|
||||
/// True if internal pointer is valid
|
||||
bool empty() const;
|
||||
|
||||
public:
|
||||
/// Access the attribute name.
|
||||
const char* name() const;
|
||||
|
||||
/// Access the attribute value.
|
||||
const char* value() const;
|
||||
};
|
||||
|
||||
/// Provides a light-weight wrapper for manipulating xml_node_struct structures.
|
||||
class xml_node
|
||||
{
|
||||
friend class xml_node_iterator;
|
||||
friend class xml_parser;
|
||||
|
||||
private:
|
||||
const xml_node_struct* _root; ///< Pointer to node root.
|
||||
|
||||
/// Safe bool type
|
||||
typedef const xml_node_struct* xml_node::*unspecified_bool_type;
|
||||
|
||||
private:
|
||||
/// Node is tree root.
|
||||
bool type_document() const;
|
||||
|
||||
public:
|
||||
/// Default constructor.
|
||||
/// Node root points to a dummy 'xml_node_struct' structure. Test for this
|
||||
/// with 'empty'.
|
||||
xml_node();
|
||||
|
||||
/// Construct, wrapping the given 'xml_node_struct' pointer.
|
||||
explicit xml_node(const xml_node_struct* p);
|
||||
|
||||
public:
|
||||
/// Base iterator type (for child nodes). Same as 'child_iterator'.
|
||||
typedef xml_node_iterator iterator;
|
||||
|
||||
/// Attribute iterator type.
|
||||
typedef xml_attribute_iterator attribute_iterator;
|
||||
|
||||
/// Access the begin iterator for this node's collection of child nodes.
|
||||
/// Same as 'children_begin'.
|
||||
iterator begin() const;
|
||||
|
||||
/// Access the end iterator for this node's collection of child nodes.
|
||||
/// Same as 'children_end'.
|
||||
iterator end() const;
|
||||
|
||||
/// Access the begin iterator for this node's collection of child nodes.
|
||||
/// Same as 'begin'.
|
||||
iterator children_begin() const;
|
||||
|
||||
/// Access the end iterator for this node's collection of child nodes.
|
||||
/// Same as 'end'.
|
||||
iterator children_end() const;
|
||||
|
||||
/// Access the begin iterator for this node's collection of attributes.
|
||||
attribute_iterator attributes_begin() const;
|
||||
|
||||
/// Access the end iterator for this node's collection of attributes.
|
||||
attribute_iterator attributes_end() const;
|
||||
|
||||
/// Access the begin iterator for this node's collection of siblings.
|
||||
iterator siblings_begin() const;
|
||||
|
||||
/// Access the end iterator for this node's collection of siblings.
|
||||
iterator siblings_end() const;
|
||||
|
||||
public:
|
||||
/// Safe bool conversion
|
||||
operator unspecified_bool_type() const;
|
||||
|
||||
/// Comparison operators
|
||||
bool operator==(const xml_node& r) const;
|
||||
bool operator!=(const xml_node& r) const;
|
||||
bool operator<(const xml_node& r) const;
|
||||
bool operator>(const xml_node& r) const;
|
||||
bool operator<=(const xml_node& r) const;
|
||||
bool operator>=(const xml_node& r) const;
|
||||
|
||||
public:
|
||||
/// Node pointer is null, or type is node_null. Same as type_null.
|
||||
bool empty() const;
|
||||
|
||||
public:
|
||||
/// Access node entity type.
|
||||
xml_node_type type() const;
|
||||
|
||||
/// Access pointer to node name if any, else empty string.
|
||||
const char* name() const;
|
||||
|
||||
/// Access pointer to data if any, else empty string.
|
||||
const char* value() const;
|
||||
|
||||
/// Access child node at name as xml_node or xml_node(NULL) if bad name.
|
||||
xml_node child(const char* name) const;
|
||||
|
||||
/// Access child node at name as xml_node or xml_node(NULL) if bad name.
|
||||
/// Enable wildcard matching.
|
||||
xml_node child_w(const char* name) const;
|
||||
|
||||
/// Access the attribute having 'name'.
|
||||
xml_attribute attribute(const char* name) const;
|
||||
|
||||
/// Access the attribute having 'name'.
|
||||
/// Enable wildcard matching.
|
||||
xml_attribute attribute_w(const char* name) const;
|
||||
|
||||
/// Access sibling node at name as xml_node or xml_node(NULL) if bad name.
|
||||
xml_node sibling(const char* name) const;
|
||||
|
||||
/// Access sibling node at name as xml_node or xml_node(NULL) if bad name.
|
||||
/// Enable wildcard matching.
|
||||
xml_node sibling_w(const char* name) const;
|
||||
|
||||
/// Access current node's next sibling by position and name.
|
||||
xml_node next_sibling(const char* name) const;
|
||||
|
||||
/// Access current node's next sibling by position and name.
|
||||
/// Enable wildcard matching.
|
||||
xml_node next_sibling_w(const char* name) const;
|
||||
|
||||
/// Access current node's next sibling by position.
|
||||
xml_node next_sibling() const;
|
||||
|
||||
/// Access current node's previous sibling by position and name.
|
||||
xml_node previous_sibling(const char* name) const;
|
||||
|
||||
/// Access current node's previous sibling by position and name.
|
||||
/// Enable wildcard matching.
|
||||
xml_node previous_sibling_w(const char* name) const;
|
||||
|
||||
/// Access current node's previous sibling by position.
|
||||
xml_node previous_sibling() const;
|
||||
|
||||
/// Access node's parent if any, else xml_node(NULL)
|
||||
xml_node parent() const;
|
||||
|
||||
/// Return PCDATA/CDATA that is child of current node. If none, return empty string.
|
||||
const char* child_value() const;
|
||||
|
||||
public:
|
||||
/// Access node's first attribute if any, else xml_attribute()
|
||||
xml_attribute first_attribute() const;
|
||||
|
||||
/// Access node's last attribute if any, else xml_attribute()
|
||||
xml_attribute last_attribute() const;
|
||||
|
||||
/// Find all elements having the given name.
|
||||
template <typename OutputIterator> void all_elements_by_name(const char* name, OutputIterator it) const;
|
||||
|
||||
/// Find all elements having the given name.
|
||||
/// Enable wildcard matching.
|
||||
template <typename OutputIterator> void all_elements_by_name_w(const char* name, OutputIterator it) const;
|
||||
|
||||
/// Access node's first child if any, else xml_node()
|
||||
xml_node first_child() const;
|
||||
|
||||
/// Access node's last child if any, else xml_node()
|
||||
xml_node last_child() const;
|
||||
|
||||
/// Find attribute using the predicate
|
||||
/// Predicate should take xml_attribute and return bool.
|
||||
template <typename Predicate> xml_attribute find_attribute(Predicate pred) const;
|
||||
|
||||
/// Find child using the predicate
|
||||
/// Predicate should take xml_node and return bool.
|
||||
template <typename Predicate> xml_node find_child(Predicate pred) const;
|
||||
|
||||
/// Recursively-implemented depth-first find element using the predicate
|
||||
/// Predicate should take xml_node and return bool.
|
||||
template <typename Predicate> xml_node find_element(Predicate pred) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element.
|
||||
/// Use for shallow drill-downs.
|
||||
xml_node first_element(const char* name) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element.
|
||||
/// Use for shallow drill-downs.
|
||||
/// Enable wildcard matching.
|
||||
xml_node first_element_w(const char* name) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element
|
||||
/// also having matching PCDATA.
|
||||
xml_node first_element_by_value(const char* name, const char* value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element
|
||||
/// also having matching PCDATA.
|
||||
/// Enable wildcard matching.
|
||||
xml_node first_element_by_value_w(const char* name, const char* value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element
|
||||
/// also having matching attribute.
|
||||
xml_node first_element_by_attribute(const char* name, const char* attr_name, const char* attr_value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching element
|
||||
/// also having matching attribute.
|
||||
/// Enable wildcard matching.
|
||||
xml_node first_element_by_attribute_w(const char* name, const char* attr_name, const char* attr_value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first element
|
||||
/// having matching attribute.
|
||||
xml_node first_element_by_attribute(const char* attr_name, const char* attr_value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first element
|
||||
/// having matching attribute.
|
||||
/// Enable wildcard matching.
|
||||
xml_node first_element_by_attribute_w(const char* attr_name, const char* attr_value) const;
|
||||
|
||||
/// Recursively-implemented depth-first find the first matching entity.
|
||||
/// Use for shallow drill-downs.
|
||||
xml_node first_node(xml_node_type type) const;
|
||||
|
||||
/// Compile the absolute node path from root as a text string.
|
||||
/// \param delimiter - Delimiter character to insert between element names.
|
||||
/// \return path string (e.g. with '/' as delimiter, '/document/.../this'.
|
||||
std::string path(char delimiter = '/') const;
|
||||
|
||||
/// Search for a node by path.
|
||||
/// \param path - Path string; e.g. './foo/bar' (relative to node), '/foo/bar' (relative
|
||||
/// to root), '../foo/bar' (pop relative position).
|
||||
/// \param delimiter - Delimiter character to use in tokenizing path.
|
||||
/// \return Matching node, or xml_node() if not found.
|
||||
xml_node first_element_by_path(const char* path, char delimiter = '/') const;
|
||||
|
||||
/// Recursively traverse the tree.
|
||||
bool traverse(xml_tree_walker& walker) const;
|
||||
};
|
||||
|
||||
/// Child node iterator.
|
||||
class xml_node_iterator: public std::iterator<std::bidirectional_iterator_tag, const xml_node>
|
||||
{
|
||||
friend class xml_node;
|
||||
|
||||
private:
|
||||
xml_node _prev;
|
||||
xml_node _wrap;
|
||||
|
||||
/// Initializing ctor
|
||||
explicit xml_node_iterator(const xml_node_struct* ref);
|
||||
public:
|
||||
/// Default ctor
|
||||
xml_node_iterator();
|
||||
|
||||
/// Initializing ctor
|
||||
xml_node_iterator(const xml_node& node);
|
||||
|
||||
/// Initializing ctor (for past-the-end)
|
||||
xml_node_iterator(const xml_node_struct* ref, const xml_node_struct* prev);
|
||||
|
||||
bool operator==(const xml_node_iterator& rhs) const;
|
||||
bool operator!=(const xml_node_iterator& rhs) const;
|
||||
|
||||
const xml_node& operator*() const;
|
||||
const xml_node* operator->() const;
|
||||
|
||||
const xml_node_iterator& operator++();
|
||||
xml_node_iterator operator++(int);
|
||||
|
||||
const xml_node_iterator& operator--();
|
||||
xml_node_iterator operator--(int);
|
||||
};
|
||||
|
||||
/// Attribute iterator.
|
||||
class xml_attribute_iterator: public std::iterator<std::bidirectional_iterator_tag, const xml_attribute>
|
||||
{
|
||||
friend class xml_node;
|
||||
|
||||
private:
|
||||
xml_attribute _prev;
|
||||
xml_attribute _wrap;
|
||||
|
||||
/// Initializing ctor
|
||||
explicit xml_attribute_iterator(const xml_attribute_struct* ref);
|
||||
public:
|
||||
/// Default ctor
|
||||
xml_attribute_iterator();
|
||||
|
||||
/// Initializing ctor
|
||||
xml_attribute_iterator(const xml_attribute& attr);
|
||||
|
||||
/// Initializing ctor (for past-the-end)
|
||||
xml_attribute_iterator(const xml_attribute_struct* ref, const xml_attribute_struct* prev);
|
||||
|
||||
bool operator==(const xml_attribute_iterator& rhs) const;
|
||||
bool operator!=(const xml_attribute_iterator& rhs) const;
|
||||
|
||||
const xml_attribute& operator*() const;
|
||||
const xml_attribute* operator->() const;
|
||||
|
||||
const xml_attribute_iterator& operator++();
|
||||
xml_attribute_iterator operator++(int);
|
||||
|
||||
const xml_attribute_iterator& operator--();
|
||||
xml_attribute_iterator operator--(int);
|
||||
};
|
||||
|
||||
/// Abstract tree walker class for xml_node::traverse().
|
||||
class xml_tree_walker
|
||||
{
|
||||
private:
|
||||
int _deep; ///< Current node depth.
|
||||
public:
|
||||
/// Default ctor
|
||||
xml_tree_walker();
|
||||
|
||||
/// Virtual dtor
|
||||
virtual ~xml_tree_walker();
|
||||
|
||||
public:
|
||||
/// Increment node depth.
|
||||
virtual void push();
|
||||
|
||||
/// Decrement node depth
|
||||
virtual void pop();
|
||||
|
||||
/// Access node depth
|
||||
virtual int depth() const;
|
||||
|
||||
public:
|
||||
/// Callback when traverse on a node begins.
|
||||
/// \return returning false will abort the traversal.
|
||||
virtual bool begin(const xml_node&);
|
||||
|
||||
/// Callback when traverse on a node ends.
|
||||
/// \return Returning false will abort the traversal.
|
||||
virtual bool end(const xml_node&);
|
||||
};
|
||||
|
||||
/// Memory block (internal)
|
||||
struct xml_memory_block
|
||||
{
|
||||
xml_memory_block();
|
||||
|
||||
xml_memory_block* next;
|
||||
size_t size;
|
||||
|
||||
char data[memory_block_size];
|
||||
};
|
||||
|
||||
/// Provides a high-level interface to the XML parser.
|
||||
class xml_parser
|
||||
{
|
||||
private:
|
||||
std::vector<char> _buffer; ///< character buffer
|
||||
|
||||
xml_memory_block _memory; ///< Memory block
|
||||
|
||||
xml_node_struct* _xmldoc; ///< Pointer to current XML document tree root.
|
||||
unsigned int _optmsk; ///< Parser options.
|
||||
|
||||
xml_parser(const xml_parser&);
|
||||
const xml_parser& operator=(const xml_parser&);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \param optmsk - Options mask.
|
||||
xml_parser(unsigned int optmsk = parse_default);
|
||||
|
||||
/// Parse constructor.
|
||||
/// \param xmlstr - readwrite string with xml data
|
||||
/// \param optmsk - Options mask.
|
||||
/// \see parse
|
||||
xml_parser(char* xmlstr, unsigned int optmsk = parse_default);
|
||||
|
||||
/// Parse constructor.
|
||||
/// \param stream - stream with xml data
|
||||
/// \param optmsk - Options mask.
|
||||
/// \see parse
|
||||
xml_parser(std::istream& stream, unsigned int optmsk = parse_default);
|
||||
|
||||
/// Dtor
|
||||
~xml_parser();
|
||||
|
||||
public:
|
||||
/// Cast as xml_node (same as document).
|
||||
operator xml_node() const;
|
||||
|
||||
/// Returns the root wrapped by an xml_node.
|
||||
xml_node document() const;
|
||||
|
||||
public:
|
||||
/// Get parser options mask.
|
||||
unsigned int options() const;
|
||||
|
||||
/// Set parser options mask.
|
||||
unsigned int options(unsigned int optmsk);
|
||||
|
||||
public:
|
||||
/// Parse the given XML stream
|
||||
/// \param stream - stream with xml data
|
||||
/// \param optmsk - Options mask.
|
||||
void parse(std::istream& stream, unsigned int optmsk = parse_noset);
|
||||
|
||||
/// Parse the given XML string in-situ.
|
||||
/// \param xmlstr - readwrite string with xml data
|
||||
/// \param optmsk - Options mask.
|
||||
/// \return last position or NULL
|
||||
/// \rem input string is zero-segmented
|
||||
char* parse(char* xmlstr, unsigned int optmsk = parse_noset);
|
||||
};
|
||||
|
||||
/// Utility functions for xml
|
||||
|
||||
/// Convert utf16 to utf8
|
||||
std::string utf8(const wchar_t* str);
|
||||
|
||||
/// Convert utf8 to utf16
|
||||
std::wstring utf16(const char* str);
|
||||
}
|
||||
|
||||
/// Inline implementation
|
||||
|
||||
namespace pugi
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
int strcmpwild(const char*, const char*);
|
||||
}
|
||||
|
||||
template <typename OutputIterator> void xml_node::all_elements_by_name(const char* name, OutputIterator it) const
|
||||
{
|
||||
if (empty()) return;
|
||||
|
||||
for (xml_node node = first_child(); node; node = node.next_sibling())
|
||||
{
|
||||
if (!strcmp(name, node.name()))
|
||||
{
|
||||
*it = node;
|
||||
++it;
|
||||
}
|
||||
|
||||
if (node.first_child()) node.all_elements_by_name(name, it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIterator> void xml_node::all_elements_by_name_w(const char* name, OutputIterator it) const
|
||||
{
|
||||
if (empty()) return;
|
||||
|
||||
for (xml_node node = first_child(); node; node = node.next_sibling())
|
||||
{
|
||||
if (!impl::strcmpwild(name, node.name()))
|
||||
{
|
||||
*it = node;
|
||||
++it;
|
||||
}
|
||||
|
||||
if (node.first_child()) node.all_elements_by_name_w(name, it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Predicate> inline xml_attribute xml_node::find_attribute(Predicate pred) const
|
||||
{
|
||||
if (!empty())
|
||||
for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())
|
||||
if (pred(attrib))
|
||||
return attrib;
|
||||
|
||||
return xml_attribute();
|
||||
}
|
||||
|
||||
template <typename Predicate> inline xml_node xml_node::find_child(Predicate pred) const
|
||||
{
|
||||
if (!empty())
|
||||
for (xml_node node = first_child(); node; node = node.next_sibling())
|
||||
if (pred(node))
|
||||
return node;
|
||||
|
||||
return xml_node();
|
||||
}
|
||||
|
||||
template <typename Predicate> inline xml_node xml_node::find_element(Predicate pred) const
|
||||
{
|
||||
if (!empty())
|
||||
for (xml_node node = first_child(); node; node = node.next_sibling())
|
||||
{
|
||||
if (pred(node))
|
||||
return node;
|
||||
|
||||
if (node.first_child())
|
||||
{
|
||||
xml_node found = node.find_element(pred);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
|
||||
return xml_node();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user