[Xmlstorage-commits] SF.net SVN: xmlstorage: [82] trunk/c++
Brought to you by:
martinfuchs
From: <mar...@us...> - 2008-02-04 09:34:00
|
Revision: 82 http://xmlstorage.svn.sourceforge.net/xmlstorage/?rev=82&view=rev Author: martinfuchs Date: 2008-02-04 01:34:00 -0800 (Mon, 04 Feb 2008) Log Message: ----------- XMLStorage Version 1.3: - introduction of XPathElement and XPath - use XPathElement to search for child nodes - count() to count child nodes using simple XPath expressions - filter() to filter XML tree structures using simple XPath expressions Modified Paths: -------------- trunk/c++/xmlstorage.cpp trunk/c++/xmlstorage.dsw trunk/c++/xmlstorage.h Added Paths: ----------- trunk/c++/example-xpath.cpp Added: trunk/c++/example-xpath.cpp =================================================================== --- trunk/c++/example-xpath.cpp (rev 0) +++ trunk/c++/example-xpath.cpp 2008-02-04 09:34:00 UTC (rev 82) @@ -0,0 +1,91 @@ + + // + // XML storage classes + // + // example-xpath.cpp + // + // Copyright (c) 2008 Martin Fuchs <mar...@gm...> + // + + +/* + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <xmlstorage.h> +using namespace XMLStorage; + +#include <iostream> +using namespace std; + + +void test_write() +{ + XMLWriter out("example-xpath.xml"); + + out.create("Test"); + out.create("Child"); + out.set_content("Wert1"); + out.back(); + + out.create("Child"); + out["id"] = XMLInt(1234); + out.set_content("Wert2"); + out.back(); + + out.create("Child"); + out.set_content("Wert3"); + out.back(); + out.back(); +} + + +void test_read() +{ + XMLDoc doc; + + // Einlesen des XML-Files + doc.read_file("example-xpath.xml"); + + XMLPos pos(&doc); + + cout << "matching 'Test/Child': " << pos.count("Test/Child") << endl; + cout << "matching 'Test/Child[@id=1234]': " << pos.count("Test/Child[@id=1234]") << endl; + + XMLDoc target; + pos.filter("Test/Child[@id=1234]", target); + target.write(cout); +} + + +int main() +{ + test_write(); + test_read(); + + return 0; +} Property changes on: trunk/c++/example-xpath.cpp ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: trunk/c++/xmlstorage.cpp =================================================================== --- trunk/c++/xmlstorage.cpp 2008-02-04 09:31:26 UTC (rev 81) +++ trunk/c++/xmlstorage.cpp 2008-02-04 09:34:00 UTC (rev 82) @@ -1,6 +1,6 @@ // - // XML storage C++ classes version 1.2 + // XML storage C++ classes version 1.3 // // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs <mar...@gm...> // @@ -104,19 +104,13 @@ } - /// move XPath like to position in XML tree -bool XMLPos::go(const char* path) + /// move to the position defined by xpath in XML tree +bool XMLPos::go(const XPath& xpath) { - XMLNode* node = _cur; + XMLNode* node = xpath._absolute? _root: _cur; - // Is this an absolute path? - if (*path == '/') { - node = _root; - ++path; - } + node = node->find_relative(xpath); - node = node->find_relative(path); - if (node) { go_to(node); return true; @@ -124,19 +118,13 @@ return false; } - /// move XPath like to position in XML tree -bool const_XMLPos::go(const char* path) + /// move to the position defined by xpath in XML tree +bool const_XMLPos::go(const XPath& xpath) { - const XMLNode* node = _cur; + const XMLNode* node = xpath._absolute? _root: _cur; - // Is this an absolute path? - if (*path == '/') { - node = _root; - ++path; - } + node = node->find_relative(xpath); - node = node->find_relative(path); - if (node) { go_to(node); return true; @@ -145,41 +133,8 @@ } -const XMLNode* XMLNode::find_relative(const char* path) const +const char* XPathElement::parse(const char* path) { - const XMLNode* node = this; - - // parse relative path - while(*path) { - node = const_cast<XMLNode*>(node)->get_child_relative(path, false); // get_child_relative() ist const for create==false - - if (!node) - return NULL; - - if (*path == '/') - ++path; - } - - return node; -} - -XMLNode* XMLNode::create_relative(const char* path) -{ - XMLNode* node = this; - - // parse relative path - while(*path) { - node = node->get_child_relative(path, true); - - if (*path == '/') - ++path; - } - - return node; -} - -XMLNode* XMLNode::get_child_relative(const char*& path, bool create) -{ const char* slash = strchr(path, '/'); if (slash == path) return NULL; @@ -191,8 +146,7 @@ // look for [n] and [@attr_name="attr_value"] expressions in path components const char* bracket = strchr(comp.c_str(), '['); l = bracket? bracket-comp.c_str(): comp.length(); - std::string child_name(comp.c_str(), l); - std::string attr_name, attr_value; + _child_name.assign(comp.c_str(), l); int n = 0; if (bracket) { @@ -202,7 +156,7 @@ n = atoi(p); // read index number if (n) - n = n - 1; // convert into zero based index + _child_idx = n - 1; // convert into zero based index const char* at = strchr(p, '@'); @@ -212,33 +166,201 @@ // read attribute name and value if (equal) { - attr_name = unescape(p, equal-p); - attr_value = unescape(equal+1); + _attr_name = unescape(p, equal-p); + _attr_value = unescape(equal+1); } } } - XMLNode* child; + return path; +} - if (attr_name.empty()) - // search n.th child node with specified name - child = find(child_name, n); +XMLNode* XPathElement::find(XMLNode* node) const +{ + int n = 0; + + for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it) + if (matches(**it, n)) + return *it; + + return NULL; +} + +const XMLNode* XPathElement::const_find(const XMLNode* node) const +{ + int n = 0; + + for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it) + if (matches(**it, n)) + return *it; + + return NULL; +} + +bool XPathElement::matches(const XMLNode& node, int& n) const +{ + if (node != _child_name) + if (_child_name != "*") // use asterisk as wildcard + return false; + + if (!_attr_name.empty()) + if (node.get(_attr_name) != _attr_value) + return false; + + if (_child_idx == -1) + return true; + else if (n++ == _child_idx) + return true; else - // search n.th child node with specified name and matching attribute value - child = find(child_name, attr_name, attr_value, n); + return false; +} - if (!child && create) { - child = new XMLNode(child_name); - add_child(child); - if (!attr_name.empty()) - (*this)[attr_name] = attr_value; +XPath::XPath(const char* path) +{ + // Is this an absolute path? + if (*path == '/') { + _absolute = true; + ++path; + } else + _absolute = false; + + // parse path + while(*path) { + XPathElement elem; + + path = elem.parse(path); + + if (!path) + break; + + if (*path == '/') + ++path; + + push_back(elem); } +} - return child; + +const XMLNode* XMLNode::find_relative(const XPath& xpath) const +{ + const XMLNode* node = this; + + for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) { + node = it->const_find(node); + + if (!node) + return NULL; + } + + return node; } +XMLNode* XMLNode::find_relative(const XPath& xpath) +{ + XMLNode* node = this; + for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) { + node = it->find(node); + + if (!node) + return NULL; + } + + return node; +} + +XMLNode* XMLNode::create_relative(const XPath& xpath) +{ + XMLNode* node = this; + + for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) { + XMLNode* child = it->find(this); + + if (!child) { + child = new XMLNode(it->_child_name); + add_child(child); + + if (!it->_attr_name.empty()) + (*this)[it->_attr_name] = it->_attr_value; + } + } + + return node; +} + + /// count the nodes matching the given relative XPath expression +int XMLNode::count(XPath::const_iterator from, const XPath::const_iterator& to) const +{ + const XPathElement& elem = *from++; + int cnt = 0; + int n = 0; + + for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + if (elem.matches(**it, n)) + if (from != to) + // iterate deeper + cnt += (*it)->count(from, to); + else + // increment match counter + ++cnt; + + return cnt; +} + + /// copy matching tree nodes using the given XPath filter expression +bool XMLNode::filter(const XPath& xpath, XMLNode& target) const +{ + XMLNode* ret = filter(xpath.begin(), xpath.end()); + + if (ret) { + // move returned nodes to target node + target._children.move(ret->_children); + target._attributes = ret->_attributes; + + delete ret; + + return true; + } else + return false; +} + + /// create a new node tree using the given XPath filter expression +XMLNode* XMLNode::filter(XPath::const_iterator from, const XPath::const_iterator& to) const +{ + XMLNode* copy = NULL; + + const XPathElement& elem = *from++; + int cnt = 0; + int n = 0; + + for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) + if (elem.matches(**it, n)) { + if (!copy) + copy = new XMLNode(*this, XMLNode::COPY_NOCHILDREN); + + if (from != to) { + XMLNode* ret = (*it)->filter(from, to); + + if (ret) { + copy->add_child(ret); + ++cnt; + } + } else { + copy->add_child(new XMLNode(**it, XMLNode::COPY_NOCHILDREN)); + ++cnt; + } + } + + if (cnt > 0) { + return copy; + } else { + delete copy; + return NULL; + } +} + + /// encode XML string literals std::string EncodeXMLString(const XS_String& str, bool cdata) { Modified: trunk/c++/xmlstorage.dsw =================================================================== --- trunk/c++/xmlstorage.dsw 2008-02-04 09:31:26 UTC (rev 81) +++ trunk/c++/xmlstorage.dsw 2008-02-04 09:34:00 UTC (rev 82) @@ -72,6 +72,18 @@ ############################################################################### +Project: "example_xpath"=".\example-xpath.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "writertest"=.\writertest.dsp - Package Owner=<4> Package=<5> Modified: trunk/c++/xmlstorage.h =================================================================== --- trunk/c++/xmlstorage.h 2008-02-04 09:31:26 UTC (rev 81) +++ trunk/c++/xmlstorage.h 2008-02-04 09:34:00 UTC (rev 82) @@ -1,6 +1,6 @@ // - // XML storage C++ classes version 1.2 + // XML storage C++ classes version 1.3 // // Copyright (c) 2004, 2005, 2006, 2007, 2008 Martin Fuchs <mar...@gm...> // @@ -781,6 +781,43 @@ }; +struct XMLNode; + +struct XPathElement +{ + XPathElement() : _child_idx(-1) {} + + XPathElement(const XS_String& child_name, int child_idx=-1) + : _child_name(child_name), _child_idx(child_idx) {} + + XPathElement(const XS_String& child_name, int child_idx, const XS_String& attr_name, const XS_String& attr_value) + : _child_name(child_name), _child_idx(child_idx), + _attr_name(attr_name), _attr_value(attr_value) + { + } + + XS_String _child_name; + int _child_idx; + + XS_String _attr_name; + XS_String _attr_value; + + const char* parse(const char* path); + + XMLNode* find(XMLNode* node) const; + const XMLNode* const_find(const XMLNode* node) const; + + bool matches(const XMLNode& node, int& n) const; +}; + +struct XPath : std::list<XPathElement> +{ + XPath(const char* path); + + bool _absolute; +}; + + /// in memory representation of an XML node struct XMLNode : public XS_String { @@ -839,11 +876,41 @@ /// internal children node list struct Children : public std::list<XMLNode*> { - void assign(const Children& other) + typedef std::list<XMLNode*> super; + + Children() { + } + + Children(Children& other) + { + for(Children::const_iterator it=other.begin(); it!=other.end(); ++it) + push_back(*it); + } + + void assign(Children& other) + { clear(); + move(other); + } + void move(Children& other) + { for(Children::const_iterator it=other.begin(); it!=other.end(); ++it) + push_back(*it); + + other.reset(); + } + + Children& operator=(Children& other) + { + assign(other); + return *this; + } + + void copy(const Children& other) + { + for(Children::const_iterator it=other.begin(); it!=other.end(); ++it) push_back(new XMLNode(**it)); } @@ -868,12 +935,19 @@ return false; } + + private: + void reset() + { + super::clear(); + } }; // access to protected class members for XMLPos and XMLReader friend struct XMLPos; friend struct const_XMLPos; friend struct XMLReaderBase; + friend struct XPathElement; XMLNode(const XS_String& name) : XS_String(name) @@ -901,6 +975,22 @@ _children.push_back(new XMLNode(**it)); } + enum COPY_FLAGS {COPY_NOCHILDREN}; + + XMLNode(const XMLNode& other, COPY_FLAGS copy_no_children) + : XS_String(other), + _attributes(other._attributes), + _leading(other._leading), + _content(other._content), + _end_leading(other._end_leading), + _trailing(other._trailing) +#ifdef XMLNODE_LOCATION + , _location(other._location) +#endif + { +// assert(copy_no_children==COPY_NOCHILDREN); + } + virtual ~XMLNode() { while(!_children.empty()) { @@ -924,7 +1014,8 @@ XMLNode& operator=(const XMLNode& other) { - _children.assign(other._children); + _children.clear(); + _children.copy(other._children); _attributes = other._attributes; @@ -982,9 +1073,9 @@ } /// convenient value access in children node - XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const + XS_String subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) const { - const XMLNode* node = find(name, n); + const XMLNode* node = XPathElement(child_name, n).const_find(this); if (node) return node->get(attr_name); @@ -993,12 +1084,12 @@ } /// convenient storage of distinct values in children node - XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0) + XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) { - XMLNode* node = find(name, n); + XMLNode* node = XPathElement(child_name, n).find(this); if (!node) { - node = new XMLNode(name); + node = new XMLNode(child_name); add_child(node); } @@ -1007,9 +1098,9 @@ #if defined(UNICODE) && !defined(XS_STRING_UTF8) /// convenient value access in children node - XS_String subvalue(const char* name, const char* attr_name, int n=0) const + XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const { - const XMLNode* node = find(name, n); + const XMLNode* node = XPathElement(child_name, n).find(this); if (node) return node->get(attr_name); @@ -1020,10 +1111,10 @@ /// convenient storage of distinct values in children node XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0) { - XMLNode* node = find(name, n); + XMLNode* node = XPathElement(child_name, n).find(this); if (!node) { - node = new XMLNode(name); + node = new XMLNode(child_name); add_child(node); } @@ -1095,6 +1186,18 @@ return out.good(); } + /// count the nodes matching the given relative XPath expression + int count(const XPath& xpath) const + { + return count(xpath.begin(), xpath.end()); + } + + /// count the nodes matching the given relative XPath expression + int count(XPath::const_iterator from, const XPath::const_iterator& to) const; + + /// copy matching tree nodes using the given XPath filter expression + bool filter(const XPath& xpath, XMLNode& target) const; + protected: Children _children; AttributeMap _attributes; @@ -1116,72 +1219,22 @@ return NULL; } - XMLNode* find(const XS_String& name, int n=0) const - { - for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) - if (**it == name) - if (!n--) - return *it; - - return NULL; - } - - XMLNode* find(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value, int n=0) const - { - for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { - const XMLNode& node = **it; - - if (node==name && node.get(attr_name)==attr_value) - if (!n--) - return *it; - } - - return NULL; - } - -#if defined(UNICODE) && !defined(XS_STRING_UTF8) - XMLNode* find(const char* name, int n=0) const - { - for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) - if (**it == name) - if (!n--) - return *it; - - return NULL; - } - - template<typename T, typename U> - XMLNode* find(const char* name, const T& attr_name, const U& attr_value, int n=0) const - { - for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { - const XMLNode& node = **it; - - if (node==name && node.get(attr_name)==attr_value) - if (!n--) - return *it; - } - - return NULL; - } -#endif - /// XPath find function (const) - const XMLNode* find_relative(const char* path) const; + const XMLNode* find_relative(const XPath& xpath) const; /// XPath find function - XMLNode* find_relative(const char* path) - {return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));} + XMLNode* find_relative(const XPath& xpath); /// relative XPath create function - XMLNode* create_relative(const char* path); + XMLNode* create_relative(const XPath& xpath); + /// create a new node tree using the given XPath filter expression + XMLNode* filter(XPath::const_iterator from, const XPath::const_iterator& to) const; + void write_worker(std::ostream& out) const; void plain_write_worker(std::ostream& out) const; void pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; void smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; - -protected: - XMLNode* get_child_relative(const char*& path, bool create); // mutable for create==true }; @@ -1489,9 +1542,9 @@ } /// search for child and go down - bool go_down(const XS_String& name, int n=0) + bool go_down(const XS_String& child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + XMLNode* node = XPathElement(child_name, n).find(_cur); if (node) { go_to(node); @@ -1500,13 +1553,13 @@ return false; } - /// move XPath like to position in XML tree - bool go(const char* path); + /// move to the position defined by xpath in XML tree + bool go(const XPath& xpath); /// create child nodes using XPath notation and move to the deepest child - bool create_relative(const char* path) + bool create_relative(const XPath& xpath) { - XMLNode* node = _cur->create_relative(path); + XMLNode* node = _cur->create_relative(xpath); if (!node) return false; // invalid path specified @@ -1521,35 +1574,47 @@ } /// create node if not already existing and move to it - void smart_create(const XS_String& name) + void smart_create(const XS_String& child_name) { - XMLNode* node = _cur->find(name); + XMLNode* node = XPathElement(child_name).find(_cur); if (node) go_to(node); else - add_down(new XMLNode(name)); + add_down(new XMLNode(child_name)); } /// search matching child node identified by key name and an attribute value - void smart_create(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) + void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value) { - XMLNode* node = _cur->find(name, attr_name, attr_value); + XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur); if (node) go_to(node); else { - node = new XMLNode(name); + node = new XMLNode(child_name); add_down(node); (*node)[attr_name] = attr_value; } } + /// count the nodes matching the given relative XPath expression + int count(const XPath& xpath) const + { + return _cur->count(xpath); + } + + /// create a new node tree using the given XPath filter expression + int filter(const XPath& xpath, XMLNode& target) const + { + return _cur->filter(xpath, target); + } + #if defined(UNICODE) && !defined(XS_STRING_UTF8) /// search for child and go down - bool go_down(const char* name, int n=0) + bool go_down(const char* child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + XMLNode* node = XPathElement(child_name, n).find(_cur); if (node) { go_to(node); @@ -1559,32 +1624,32 @@ } /// create node and move to it - void create(const char* name) + void create(const char* child_name) { - add_down(new XMLNode(name)); + add_down(new XMLNode(child_name)); } /// create node if not already existing and move to it - void smart_create(const char* name) + void smart_create(const char* child_name) { - XMLNode* node = _cur->find(name); + XMLNode* node = _cur->find(child_name); if (node) go_to(node); else - add_down(new XMLNode(name)); + add_down(new XMLNode(child_name)); } /// search matching child node identified by key name and an attribute value template<typename T, typename U> - void smart_create(const char* name, const T& attr_name, const U& attr_value) + void smart_create(const char* child_name, const T& attr_name, const U& attr_value) { - XMLNode* node = _cur->find(name, attr_name, attr_value); + XMLNode* node = _cur->find(child_name, attr_name, attr_value); if (node) go_to(node); else { - XMLNode* node = new XMLNode(name); + XMLNode* node = new XMLNode(child_name); add_down(node); (*node)[attr_name] = attr_value; } @@ -1696,9 +1761,9 @@ } /// search for child and go down - bool go_down(const XS_String& name, int n=0) + bool go_down(const XS_String& child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + const XMLNode* node = XPathElement(child_name, n).const_find(_cur); if (node) { go_to(node); @@ -1707,14 +1772,14 @@ return false; } - /// move XPath like to position in XML tree - bool go(const char* path); + /// move to the position defined by xpath in XML tree + bool go(const XPath& xpath); #if defined(UNICODE) && !defined(XS_STRING_UTF8) /// search for child and go down - bool go_down(const char* name, int n=0) + bool go_down(const char* child_name, int n=0) { - XMLNode* node = _cur->find(name, n); + XMLNode* node = XPathElement(child_name, n).const_find(_cur); if (node) { go_to(node); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |