more docu
This commit is contained in:
21
AUTHORS
21
AUTHORS
@@ -0,0 +1,21 @@
|
||||
<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>
|
||||
<email>marc@waeckerlin.org</email>
|
||||
<email>marc.waeckerlin@swisssign.com</email>
|
||||
<url>http://dev.swisssign.com/trac/libxml-cxx</url>
|
||||
<url>http://marc.wäckerlin.ch</url>
|
||||
<url>http://marc.waeckerlin.org</url>
|
||||
<url>http://dev.swisssign.com</url>
|
||||
<url>http://swissign.com</url>
|
||||
<url>http://swissign.ch</url>
|
||||
</address>
|
||||
|
22
README
22
README
@@ -0,0 +1,22 @@
|
||||
This is a C++ class for reading and writing XML structures.
|
||||
|
||||
All informaton can be found in the generated doxygen project documentation.
|
||||
|
||||
Rationale: The initial idea was to map C++ data structures to XML
|
||||
files for configuration files that can easily be edited by hand. This
|
||||
library does not need any kind of C++ code parser or special pre
|
||||
compiler. You can specify a schema entirly in native C++. 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.
|
||||
|
||||
(More rationale: See also "related Pages" in the doxygen project documentation)
|
||||
|
||||
Structure of the files:
|
||||
src: The source code of the library
|
||||
doc/html: Doxygen documentation oft the library usage
|
||||
doc/examples: Example code (included in doxygen documentation)
|
||||
test: CppUnit test files - can also be taken as examples
|
||||
|
||||
Project URL: http://dev.swisssign.com
|
||||
|
14
configure.in
14
configure.in
@@ -12,7 +12,7 @@ AM_INIT_AUTOMAKE(x_packagename, x_major.x_minor.x_least, [marc@waeckerlin.org])
|
||||
|
||||
# files to create
|
||||
AC_CONFIG_FILES(makefile
|
||||
src/makefile test/makefile
|
||||
src/makefile test/makefile doc/examples/makefile
|
||||
doc/doxyfile doc/makefile)
|
||||
|
||||
# copy M4 to shell
|
||||
@@ -71,18 +71,6 @@ AC_ARG_ENABLE(dot,
|
||||
test "$enableval" = "yes" && HAVE_DOT="YES" || HAVE_DOT="NO";
|
||||
AM_PATH_CPPUNIT([1.0.0], [have_cppunit="yes"], [have_cppunit="no"])
|
||||
|
||||
# Special Options
|
||||
AC_ARG_ENABLE(win,
|
||||
[AS_HELP_STRING([--enable-win],
|
||||
[on linux, also builds windows version using mingw])],
|
||||
[build_win="$enableval"], [build_win="no"])
|
||||
AM_CONDITIONAL(BUILD_WIN, test "$build_win" = "yes")
|
||||
AC_ARG_ENABLE(32bit-linux,
|
||||
[AS_HELP_STRING([--enable-32bit-linux],
|
||||
[build for 32bit linux instead of plattform specific])],
|
||||
[build_lin32="$enableval"], [build_lin32="no"])
|
||||
AM_CONDITIONAL(BUILD_LIN32, test "$build_lin32" = "yes")
|
||||
|
||||
# export macros
|
||||
SRCDIR=${srcdir}
|
||||
AC_SUBST(SRCDIR)
|
||||
|
@@ -60,7 +60,7 @@ CREATE_SUBDIRS = NO
|
||||
# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
|
||||
# and Ukrainian.
|
||||
|
||||
OUTPUT_LANGUAGE = German
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
@@ -578,7 +578,7 @@ EXCLUDE_SYMBOLS =
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = .
|
||||
EXAMPLE_PATH = @SRCDIR@/..
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
|
62
doc/examples/address.cxx
Normal file
62
doc/examples/address.cxx
Normal file
@@ -0,0 +1,62 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
// g++ -I../src ../src/xml.cxx address.cxx
|
||||
|
||||
#include <xml-cxx/xml.hxx>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
int main(int, char**) try {
|
||||
// Example template in factory instantiation
|
||||
xml::Factory addrTpl(xml::Node("address")
|
||||
<<(xml::Node("name").limits(1, 1)
|
||||
<<xml::String("first").limits(1, 1)
|
||||
<<xml::String("middle") // 0..n -> .limit(0, 0)
|
||||
<<xml::String("last").limits(1, 1))
|
||||
<<(xml::Node("location").max(1)
|
||||
<<xml::String("line").min(1))
|
||||
<<xml::String("email")
|
||||
<<xml::String("url")
|
||||
<<xml::String("country").max(1));
|
||||
// Example XML file to read
|
||||
std::stringstream ss("\
|
||||
<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>\
|
||||
<email>marc@waeckerlin.org</email>\
|
||||
<email>marc.waeckerlin@swisssign.com</email>\
|
||||
<url>http://dev.swisssign.com/trac/libxml-cxx</url>\
|
||||
<url>http://marc.wäckerlin.ch</url>\
|
||||
<url>http://marc.waeckerlin.org</url>\
|
||||
<url>http://dev.swisssign.com</url>\
|
||||
<url>http://swissign.com</url>\
|
||||
<url>http://swissign.ch</url>\
|
||||
</address>");
|
||||
std::auto_ptr<xml::Node> author(addrTpl.read(ss));
|
||||
// write to stdout
|
||||
std::cout<<"Successfully read:"<<std::endl
|
||||
<<"------------------------------"<<std::endl
|
||||
<<*author<<std::endl
|
||||
<<"------------------------------"<<std::endl;
|
||||
// store in project's AUTHORS file
|
||||
std::ofstream ofs("../AUTHORS");
|
||||
ofs<<*author<<std::endl;
|
||||
return 0;
|
||||
} catch (std::exception& e) {
|
||||
std::cerr<<"**** Error: "<<e.what()<<std::endl;
|
||||
}
|
14
doc/examples/makefile.am
Normal file
14
doc/examples/makefile.am
Normal file
@@ -0,0 +1,14 @@
|
||||
## @id $Id$
|
||||
|
||||
## 1 2 3 4 5 6 7 8
|
||||
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
AM_CXXFLAGS += -I ${top_srcdir}/src
|
||||
AM_LDFLAGS = -L${top_builddir}/src
|
||||
|
||||
noinst_PROGRAMS = address
|
||||
|
||||
address_SOURCES = address.cxx
|
||||
address_LDADD = -lxml-cxx
|
||||
|
||||
MAINTAINERCLEANFILES = makefile.in
|
@@ -5,6 +5,8 @@
|
||||
## 1 2 3 4 5 6 7 8
|
||||
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
SUBDIRS = examples
|
||||
|
||||
develdir = ${pkgdatadir}/doc
|
||||
devel_DATA = html/index.html
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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. <p><p><p></p></p></p>)
|
||||
- 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++.
|
||||
|
68
src/xml.cxx
68
src/xml.cxx
@@ -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 <address>
|
||||
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);
|
||||
|
Reference in New Issue
Block a user