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, bool validate)
30 read_internal(validate);
33 XMLTree::XMLTree(const XMLTree * from)
35 _filename = from->filename();
36 _root = new XMLNode(*from->root());
37 _compression = from->compression();
46 XMLTree::set_compression(int c)
60 XMLTree::read_internal(bool validate)
62 //shouldnt be used anywhere ATM, remove if so!
68 xmlParserCtxtPtr ctxt; /* the parser context */
69 xmlDocPtr doc; /* the resulting document tree */
71 xmlKeepBlanksDefault(0);
72 /* parse the file, activating the DTD validation option */
74 /* create a parser context */
75 ctxt = xmlNewParserCtxt();
79 doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_DTDVALID);
81 doc = xmlParseFile(_filename.c_str());
84 /* check if parsing suceeded */
87 xmlFreeParserCtxt(ctxt);
91 /* check if validation suceeded */
92 if (validate && ctxt->valid == 0) {
93 xmlFreeParserCtxt(ctxt);
96 throw XMLException("Failed to validate document " + _filename);
100 _root = readnode(xmlDocGetRootElement(doc));
102 /* free up the parser context */
104 xmlFreeParserCtxt(ctxt);
113 XMLTree::read_buffer(const string & buffer)
122 doc = xmlParseMemory((char *) buffer.c_str(), buffer.length());
127 _root = readnode(xmlDocGetRootElement(doc));
135 XMLTree::write(void) const
138 XMLNodeList children;
141 xmlKeepBlanksDefault(0);
142 doc = xmlNewDoc((xmlChar *) XML_VERSION);
143 xmlSetDocCompressMode(doc, _compression);
144 writenode(doc, _root, doc->children, 1);
145 result = xmlSaveFormatFileEnc(_filename.c_str(), doc, "UTF-8", 1);
156 XMLTree::debug(FILE* out) const
159 XMLNodeList children;
161 xmlKeepBlanksDefault(0);
162 doc = xmlNewDoc((xmlChar *) XML_VERSION);
163 xmlSetDocCompressMode(doc, _compression);
164 writenode(doc, _root, doc->children, 1);
165 xmlDebugDumpDocument (out, doc);
170 XMLTree::write_buffer(void) const
172 static string retval;
176 XMLNodeList children;
178 xmlKeepBlanksDefault(0);
179 doc = xmlNewDoc((xmlChar *) XML_VERSION);
180 xmlSetDocCompressMode(doc, _compression);
181 writenode(doc, _root, doc->children, 1);
182 xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len);
192 XMLNode::XMLNode(const string & n)
193 : _name(n), _is_content(false), _content(string())
197 XMLNode::XMLNode(const string & n, const string & c)
198 :_name(n), _is_content(true), _content(c)
202 XMLNode::XMLNode(const XMLNode& from)
204 XMLPropertyList props;
205 XMLPropertyIterator curprop;
207 XMLNodeIterator curnode;
210 set_content(from.content());
212 props = from.properties();
213 for (curprop = props.begin(); curprop != props.end(); ++curprop) {
214 add_property((*curprop)->name().c_str(), (*curprop)->value());
217 nodes = from.children();
218 for (curnode = nodes.begin(); curnode != nodes.end(); ++curnode) {
219 add_child_copy(**curnode);
225 XMLNodeIterator curchild;
226 XMLPropertyIterator curprop;
228 for (curchild = _children.begin(); curchild != _children.end(); ++curchild) {
232 for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) {
238 XMLNode::set_content(const string & c)
252 XMLNode::child (const char *name) const
254 /* returns first child matching name */
256 XMLNodeConstIterator cur;
262 for (cur = _children.begin(); cur != _children.end(); ++cur) {
263 if ((*cur)->name() == name) {
272 XMLNode::children(const string& n) const
274 /* returns all children matching name */
276 XMLNodeConstIterator cur;
282 _selected_children.clear();
284 for (cur = _children.begin(); cur != _children.end(); ++cur) {
285 if ((*cur)->name() == n) {
286 _selected_children.insert(_selected_children.end(), *cur);
290 return _selected_children;
294 XMLNode::add_child(const char * n)
296 return add_child_copy(XMLNode (n));
300 XMLNode::add_child_nocopy (XMLNode& n)
302 _children.insert(_children.end(), &n);
306 XMLNode::add_child_copy(const XMLNode& n)
308 XMLNode *copy = new XMLNode (n);
309 _children.insert(_children.end(), copy);
313 boost::shared_ptr<XMLSharedNodeList>
314 XMLNode::find(const string xpath) const
316 xmlDocPtr doc = xmlNewDoc((xmlChar *) XML_VERSION);
317 writenode(doc, (XMLNode *) this, doc->children, 1);
318 xmlXPathContext* ctxt = xmlXPathNewContext(doc);
320 boost::shared_ptr<XMLSharedNodeList> result =
321 boost::shared_ptr<XMLSharedNodeList>(find_impl(ctxt, xpath));
323 xmlXPathFreeContext(ctxt);
330 XMLNode::attribute_value()
332 XMLNodeList children = this->children();
333 assert(!_is_content);
334 assert(children.size() == 1);
335 XMLNode* child = *(children.begin());
336 assert(child->is_content());
337 return child->content();
341 XMLNode::add_content(const string & c)
343 return add_child_copy(XMLNode (string(), c));
347 XMLNode::property(const char * n)
350 map<string,XMLProperty*>::iterator iter;
352 if ((iter = _propmap.find(ns)) != _propmap.end()) {
360 XMLNode::property(const string & ns)
362 map<string,XMLProperty*>::iterator iter;
364 if ((iter = _propmap.find(ns)) != _propmap.end()) {
372 XMLNode::add_property(const char * n, const string & v)
375 if(_propmap.find(ns) != _propmap.end()){
379 XMLProperty *tmp = new XMLProperty(ns, v);
385 _propmap[tmp->name()] = tmp;
386 _proplist.insert(_proplist.end(), tmp);
392 XMLNode::add_property(const char * n, const char * v)
395 return add_property(n, vs);
399 XMLNode::add_property(const char *name, const long value)
401 static char str[1024];
402 snprintf(str, 1024, "%ld", value);
403 return add_property(name, str);
407 XMLNode::remove_property(const string & n)
409 if (_propmap.find(n) != _propmap.end()) {
410 _proplist.remove(_propmap[n]);
416 XMLNode::remove_nodes(const string & n)
418 XMLNodeIterator i = _children.begin();
421 while (i != _children.end()) {
424 if ((*i)->name() == n) {
432 XMLNode::remove_nodes_and_delete(const string & n)
434 XMLNodeIterator i = _children.begin();
437 while (i != _children.end()) {
440 if ((*i)->name() == n) {
449 XMLNode::remove_nodes_and_delete(const string& propname, const string& val)
451 XMLNodeIterator i = _children.begin();
455 while (i != _children.end()) {
459 prop = (*i)->property(propname);
460 if(prop && prop->value() == val) {
469 XMLProperty::XMLProperty(const string &n, const string &v)
473 // Normalize property name (replace '_' with '-' as old session are inconsistent)
474 for (size_t i = 0; i < _name.length(); ++i) {
475 if (_name[i] == '_') {
481 XMLProperty::~XMLProperty()
486 readnode(xmlNodePtr node)
488 string name, content;
494 name = (char *) node->name;
497 tmp = new XMLNode(name);
499 for (attr = node->properties; attr; attr = attr->next) {
501 if (attr->children) {
502 content = (char *) attr->children->content;
504 tmp->add_property((char *) attr->name, content);
508 tmp->set_content((char *) node->content);
510 tmp->set_content(string());
513 for (child = node->children; child; child = child->next) {
514 tmp->add_child_nocopy (*readnode(child));
521 writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root = 0)
523 XMLPropertyList props;
524 XMLPropertyIterator curprop;
525 XMLNodeList children;
526 XMLNodeIterator curchild;
530 node = doc->children = xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0);
532 node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
535 if (n->is_content()) {
536 node->type = XML_TEXT_NODE;
537 xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length());
540 props = n->properties();
541 for (curprop = props.begin(); curprop != props.end(); ++curprop) {
542 xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str());
545 children = n->children();
546 for (curchild = children.begin(); curchild != children.end(); ++curchild) {
547 writenode(doc, *curchild, node);
551 static XMLSharedNodeList* find_impl(xmlXPathContext* ctxt, const string xpath)
553 xmlXPathObject* result = xmlXPathEval((const xmlChar*)xpath.c_str(), ctxt);
557 xmlXPathFreeContext(ctxt);
558 xmlFreeDoc(ctxt->doc);
560 throw XMLException("Invalid XPath: " + xpath);
563 if(result->type != XPATH_NODESET)
565 xmlXPathFreeObject(result);
566 xmlXPathFreeContext(ctxt);
567 xmlFreeDoc(ctxt->doc);
569 throw XMLException("Only nodeset result types are supported.");
572 xmlNodeSet* nodeset = result->nodesetval;
573 XMLSharedNodeList* nodes = new XMLSharedNodeList();
576 for (int i = 0; i < nodeset->nodeNr; ++i) {
577 XMLNode* node = readnode(nodeset->nodeTab[i]);
578 nodes->push_back(boost::shared_ptr<XMLNode>(node));
586 xmlXPathFreeObject(result);