more docu

This commit is contained in:
Marc Wäckerlin
2009-04-22 08:25:20 +00:00
parent 650e88e2c3
commit 9548b27052
10 changed files with 243 additions and 36 deletions

View File

@@ -11,9 +11,4 @@ nobase_include_HEADERS = xml-cxx/xml.hxx
libxml_cxx_la_SOURCES = xml.cxx
if BUILD_WIN
else
endif
CLEANFILES =
MAINTAINERCLEANFILES = makefile.in

View File

@@ -15,17 +15,72 @@
#include <map>
#include <memory>
/*! @page limitations Known Limitations
/*! @mainpage
- Templates cannot specify number of sub-elements.
- XML-Comments are only ignored.
@section maintitle C++ XML Class Library
- Specify your XML schema in C++ using common C++ syntax,
such as shift, dereference, etc.
- Verify the schema of XML files while they are read from a stream.
From the README file:
@include README
@page Known Limitations
- XML-Comments are only ignored, not read, not stored.
- Mixed tags and text is not supported. Tags may either contain
other tags only (type xml::Node) or text only (type
xml::String).
xml::String). -> This is intended behaviour!
- Unlimited recursion is not possible
(e.g. &ltp&gt;&ltp&gt;&ltp&gt;&lt/p&gt;&lt/p&gt;&lt/p&gt;)
- No check yet for optional and mandatory attributes in xml::Factory
- Exceptions should be optional, best effort otherwise (option "strict") */
- Exceptions should be optional, best effort otherwise (option "strict")
@page rationale Rationale - Limitations of other libraries
The initial idea was to map C++ data structures to XML files
(e.g. for configuration files) that can easily be edited by
hand. This library does not need any kind of C++ code parser or
proprietary pre compiler. You can specify a schema entirly in
native C++. Access to the XML structures is through typical C++
operators which rresults in a simple and intuitive syntax. The
schema is verified when XML is read and exceptions are thrown when
the XML to be pares is invalid. Exceptions specify exactly the
location and reason of the problem, so that the editor of the XML
file can easily find and correct the problem. Due to the
verification, it is not necessary to check every access: Only
optional attributes and tags must be tested for their existence,
before they can be accessed.
There are a lot of different approaches for using XML in C++, all
of them have their specific limitations. This library should be
better.
The design is based on my experiance with gsoap
(http://gsoap.sf.net), boost serialization (http://boost.org) and
Qt XML (http://qtsoftware.com).
@section Qt XML, a typical DOM approach
One is the XML part of the Qt library. These classes can read XML
into a DOM tree, but then the user has to check for every detail.
This looks like:
@code
QDomDocument doc;
if (!doc.setContent(_http.readAll())); // error
QDomNodeList releases(doc.elementsByTagName("release"));
for(int i(0); i<releases.size(); ++i)
if (releases.at(i).attributes().contains("type") &&
releases.at(i).attributes().namedItem("type").nodeValue()==_name) {
_software = releases.at(i).firstChildElement("software");
_firmware = releases.at(i).firstChildElement("firmware");
if (_software.isNull() || _firmware.isNull() ||
releases.at(i).firstChildElement("notes").isNull()); // error
...
@endcode
@example doc/examples/address.cxx */
//! Represents classes for handling C++ access to XML files with strict schema.
/*! The schema ist not presented through xsd, but it can be declared in C++.

View File

@@ -244,7 +244,7 @@ namespace xml {
//! Copy node, reset parent.
/*! The parent is reset, the node does not belong to the same parent
as the source of the copy.
@see xml::Node::clone for more information on the parenting. */
@see xml::Node::clone() for more information on the parenting. */
Node::Node(const Node& o) throw():
_attributes(o._attributes), _name(o.name()), _parent(0),
_min(o._min), _max(o._max) {
@@ -255,7 +255,7 @@ namespace xml {
//! Assign new node, keep parent.
/*! The parent remains unchanged, the node does not belong to the
same parent as the source of the copy.
@see xml::Node::clone for more information on the parenting. */
@see xml::Node::clone() for more information on the parenting. */
Node& Node::operator=(const Node& o) throw() {
_attributes=o._attributes;
_name = o.name();
@@ -270,7 +270,18 @@ namespace xml {
}
//! Clones But clears the parent.
/*! You get a new instance of the node, but detached from the
parent. It is then ready to be inserted below a new parent. */
parent. It is then ready to be inserted below a new parent.
If you clone (or copy) a node, the parent is not copied. This is
because otherwise the new now would need to be appended to the
parent's child list. That's most probably not
intended. Therefore, in a normal copy construction the parent is
set to @c 0 (no parent). Then the new node can be appended to a
parent if needed. In a copy assignment, the parent remains
uncanged and the other data is copied.
The user of this library doesn't have to and is not able to care
about the parenting. */
std::auto_ptr<Node> Node::clone() const throw() {
std::auto_ptr<Node> res(new Node(*this));
res->_parent = 0;
@@ -544,13 +555,6 @@ namespace xml {
return 0;
}
//! Clone a node, but assign a new parent.
/*! If you clone (or copy) a node, the parent is not copied. This is
because otherwise the new now would need to be appended to the
parent's child list. That's most probably not
intended. Therefore, in a normal copy operation (copy-construct
or copy-assign) the parent is set to @c 0 (no parent). Then the
new node can be appended to a parent if needed. In this method,
the new parent can be given in the same step. */
std::auto_ptr<Node> Node::clone(Node* p) const throw() {
std::auto_ptr<Node> c(clone());
c->_parent = p;
@@ -643,9 +647,11 @@ namespace xml {
_text = ss.str();
return *this;
}
//! Returns the contents as number.
unsigned long UnsignedInteger::number() const throw() {
return number(*this);
}
//! Returns the contents as number.
unsigned long UnsignedInteger::number(const Node& node) throw() {
unsigned long i(0);
std::stringstream ss(node.text());
@@ -654,6 +660,48 @@ namespace xml {
}
//----------------------------------------------------------------------------
//! To instanciate a factory, a template must be given.
/*! The template is a node that specifies the schema of the data
that can be loaded from streams through a xml::Factory
instance.
The root element has automatically set the limits 1..1
(<code>xml::Node::limits(1, 1)</code>, see xml::Node::limits),
which means that the root element must exist exactly once. If
you pass another limit, your limit is overwritten.
E.g. to load an address, that contains a tag &lt;address&gt;
with at least a name and optional an address in it's body, you
may write:
@code
xml::Factory addrTpl(xml::Node("address")
(<<xml::Node("name").limit(1, 1)
(<<xml::String("first").limit(1, 1)
<<xml::String("middle") // 0..n -> .limit(0, 0)
<<xml::String("last").limit(1, 1))
<<(xml::Node("location").max(1)
<<xml::String("line").min(1))
<<xml::String("country").max(1)));
@endcode
According to this example, a valid XML file could be:
@verbatim
<address>
<name>
<first>Marc</first>
<middle>Roman</middle>
<last>Wäckerlin</last>
</name>
<location>
<line>SwissSign AG</line>
<line>Pfingstweidstrasse 60b</line>
<line>8005 Zürich</line>
</location>
<country>Schweiz</country>
</address>
@endverbatim */
Factory::Factory(const Node& t) throw():
_template(xml::Node("<xml::start>")<<t), _line(0) {
_template[0].min(1);