2 * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
3 * are covered by the GNU Lesser General Public License, which should be
4 * included with libxml++ as the file COPYING.
8 #include <libxml/debugXML.h>
9 #include <libxml/xpath.h>
10 #include <libxml/xpathInternals.h>
12 #define XML_VERSION "1.0"
14 static XMLNode *readnode(xmlNodePtr);
15 static void writenode(xmlDocPtr, XMLNode *, xmlNodePtr, int);
16 static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string xpath);
25 XMLTree::XMLTree(const string &fn)
33 XMLTree::XMLTree(const XMLTree * from)
35 _filename = from->filename();
36 _root = new XMLNode(*from->root());
37 _compression = from->compression();
48 XMLTree::set_compression(int c)
71 xmlKeepBlanksDefault(0);
73 doc = xmlParseFile(_filename.c_str());
78 _root = readnode(xmlDocGetRootElement(doc));
85 XMLTree::read_buffer(const string & buffer)
96 doc = xmlParseMemory((char *) buffer.c_str(), buffer.length());
101 _root = readnode(xmlDocGetRootElement(doc));
109 XMLTree::write(void) const
112 XMLNodeList children;
115 xmlKeepBlanksDefault(0);
116 doc = xmlNewDoc((xmlChar *) XML_VERSION);
117 xmlSetDocCompressMode(doc, _compression);
118 writenode(doc, _root, doc->children, 1);
119 result = xmlSaveFormatFileEnc(_filename.c_str(), doc, "UTF-8", 1);
130 XMLTree::debug(FILE* out) const
133 XMLNodeList children;
135 xmlKeepBlanksDefault(0);
136 doc = xmlNewDoc((xmlChar *) XML_VERSION);
137 xmlSetDocCompressMode(doc, _compression);
138 writenode(doc, _root, doc->children, 1);
139 xmlDebugDumpDocument (out, doc);
144 XMLTree::write_buffer(void) const
146 static string retval;
150 XMLNodeList children;
152 xmlKeepBlanksDefault(0);
153 doc = xmlNewDoc((xmlChar *) XML_VERSION);
154 xmlSetDocCompressMode(doc, _compression);
155 writenode(doc, _root, doc->children, 1);
156 xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len);
166 XMLNode::XMLNode(const string & n)
167 : _name(n), _is_content(false), _content(string())
171 XMLNode::XMLNode(const string & n, const string & c)
172 :_name(n), _is_content(true), _content(c)
176 XMLNode::XMLNode(const XMLNode& from)
178 XMLPropertyList props;
179 XMLPropertyIterator curprop;
181 XMLNodeIterator curnode;
184 set_content(from.content());
186 props = from.properties();
187 for (curprop = props.begin(); curprop != props.end(); ++curprop) {
188 add_property((*curprop)->name().c_str(), (*curprop)->value());
191 nodes = from.children();
192 for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) {
193 add_child_copy(**curnode);
199 XMLNodeIterator curchild;
200 XMLPropertyIterator curprop;
202 for (curchild = _children.begin(); curchild != _children.end(); ++curchild) {
206 for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) {
212 XMLNode::set_content(const string & c)
226 XMLNode::child (const char *name) const
228 /* returns first child matching name */
230 XMLNodeConstIterator cur;
236 for (cur = _children.begin(); cur != _children.end(); ++cur) {
237 if ((*cur)->name() == name) {
246 XMLNode::children(const string& n) const
248 /* returns all children matching name */
250 static XMLNodeList retval;
251 XMLNodeConstIterator cur;
257 retval.erase(retval.begin(), retval.end());
259 for (cur = _children.begin(); cur != _children.end(); ++cur) {
260 if ((*cur)->name() == n) {
261 retval.insert(retval.end(), *cur);
269 XMLNode::add_child(const char * n)
271 return add_child_copy(XMLNode (n));
275 XMLNode::add_child_nocopy (XMLNode& n)
277 _children.insert(_children.end(), &n);
281 XMLNode::add_child_copy(const XMLNode& n)
283 XMLNode *copy = new XMLNode (n);
284 _children.insert(_children.end(), copy);
288 boost::shared_ptr<XMLSharedNodeList>
289 XMLNode::find(const string xpath) const
291 xmlDocPtr doc = xmlNewDoc((xmlChar *) XML_VERSION);
292 writenode(doc, (XMLNode *) this, doc->children, 1);
293 xmlXPathContext* ctxt = xmlXPathNewContext(doc);
295 boost::shared_ptr<XMLSharedNodeList> result =
296 boost::shared_ptr<XMLSharedNodeList>(find_impl(ctxt, xpath));
298 xmlXPathFreeContext(ctxt);
305 XMLNode::attribute_value()
307 XMLNodeList children = this->children();
308 assert(!_is_content);
309 assert(children.size() == 1);
310 XMLNode* child = *(children.begin());
311 assert(child->is_content());
312 return child->content();
316 XMLNode::add_content(const string & c)
318 return add_child_copy(XMLNode (string(), c));
322 XMLNode::property(const char * n)
325 map<string,XMLProperty*>::iterator iter;
327 if ((iter = _propmap.find(ns)) != _propmap.end()) {
335 XMLNode::property(const string & ns)
337 map<string,XMLProperty*>::iterator iter;
339 if ((iter = _propmap.find(ns)) != _propmap.end()) {
347 XMLNode::add_property(const char * n, const string & v)
350 if(_propmap.find(ns) != _propmap.end()){
354 XMLProperty *tmp = new XMLProperty(ns, v);
360 _propmap[tmp->name()] = tmp;
361 _proplist.insert(_proplist.end(), tmp);
367 XMLNode::add_property(const char * n, const char * v)
370 return add_property(n, vs);
374 XMLNode::remove_property(const string & n)
376 if (_propmap.find(n) != _propmap.end()) {
377 _proplist.remove(_propmap[n]);
383 XMLNode::remove_nodes(const string & n)
385 XMLNodeIterator i = _children.begin();
388 while (i != _children.end()) {
391 if ((*i)->name() == n) {
399 XMLNode::remove_nodes_and_delete(const string & n)
401 XMLNodeIterator i = _children.begin();
404 while (i != _children.end()) {
407 if ((*i)->name() == n) {
416 XMLNode::remove_nodes_and_delete(const string& propname, const string& val)
418 XMLNodeIterator i = _children.begin();
422 while (i != _children.end()) {
426 prop = (*i)->property(propname);
427 if(prop && prop->value() == val) {
436 XMLProperty::XMLProperty(const string &n, const string &v)
442 XMLProperty::~XMLProperty()
447 readnode(xmlNodePtr node)
449 string name, content;
455 name = (char *) node->name;
458 tmp = new XMLNode(name);
460 for (attr = node->properties; attr; attr = attr->next) {
462 if (attr->children) {
463 content = (char *) attr->children->content;
465 tmp->add_property((char *) attr->name, content);
469 tmp->set_content((char *) node->content);
471 tmp->set_content(string());
474 for (child = node->children; child; child = child->next) {
475 tmp->add_child_nocopy (*readnode(child));
482 writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = 0)
484 XMLPropertyList props;
485 XMLPropertyIterator curprop;
486 XMLNodeList children;
487 XMLNodeIterator curchild;
491 node = doc->children = xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0);
493 node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
496 if (n->is_content()) {
497 node->type = XML_TEXT_NODE;
498 xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length());
501 props = n->properties();
502 for (curprop = props.begin(); curprop != props.end(); ++curprop) {
503 xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str());
506 children = n->children();
507 for (curchild = children.begin(); curchild != children.end(); ++curchild) {
508 writenode(doc, *curchild, node);
512 static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string xpath)
514 xmlXPathObject* result = xmlXPathEval((const xmlChar*)xpath.c_str(), ctxt);
518 xmlXPathFreeContext(ctxt);
519 xmlFreeDoc(ctxt->doc);
521 throw XMLException("Invalid XPath: " + xpath);
524 if(result->type != XPATH_NODESET)
526 xmlXPathFreeObject(result);
527 xmlXPathFreeContext(ctxt);
528 xmlFreeDoc(ctxt->doc);
530 throw XMLException("Only nodeset result types are supported.");
533 xmlNodeSet* nodeset = result->nodesetval;
534 XMLSharedNodeList* nodes = new XMLSharedNodeList();
537 for (int i = 0; i < nodeset->nodeNr; ++i) {
538 XMLNode* node = readnode(nodeset->nodeTab[i]);
539 nodes->push_back(boost::shared_ptr<XMLNode>(node));
547 xmlXPathFreeObject(result);