Per altre informazioni scrivi a fabriziocaldarelli@negusweb.it
XPath con libxml++ su Linux
Da Programmazione Software.
Descrizione
In ambiente Linux, si può parserizzare un file xml tramite le libxml di Gnome (http://www.xmlsoft.org) oppure tramite libxml++ (http://libxmlplusplus.sourceforge.net/). Queste ultime richiedono un pò meno sforzo implementativo ma qualche chiamata a librerie esterne in più. Qui di seguito il codice di una classe che incapsula le libxml++ ed un codice di prova:
include/Xml/CXml.h
/** CXml.h** Created on: 12-mar-2009* Author: negus*//*** Include DIRS* ----------------------------------I/usr/include/libxml++-2.6-I/usr/lib/libxml++-2.6/include-I/usr/include/libxml2-I/usr/include/glibmm-2.4-I/usr/lib/glibmm-2.4/include-I/usr/include/sigc++-2.0-I/usr/lib/sigc++-2.0/include-I/usr/include/glib-2.0-I/usr/lib/glib-2.0/include* ---------------------------------*//*** Against LIBS* ----------------------------------lxml++-2.6-lxml2-lglibmm-2.4-lgobject-2.0-lsigc-2.0-lglib-2.0* ---------------------------------*/#ifndef CXML_H_#define CXML_H_#include <libxml++ libxml++.h="">#include <iostream>#include <string>using namespace std;
class CXml {
public: // Constructors / Destructors
CXml(const string& iPathFileXml);
virtual ~CXml();
public:
xmlpp::Node* getRootNode();
private:
int _ParseXml(const string& iPathFileXml,xmlpp::Node **oRootNode);
private:
string pathFileXml;xmlpp::Node *rootNode; // deleted from parser destructor
xmlpp::DomParser *parser;
};
#endif /* CXML_H_ */
include/Xml/CXml.cpp
/** CXml.cpp** Created on: 12-mar-2009* Author: negus*/#include "Xml/CXml.h"CXml::CXml(const string& iPathFileXml) {
this->pathFileXml = iPathFileXml;
this->_ParseXml(iPathFileXml,&this->rootNode);
}CXml::~CXml() {
delete parser;
}int CXml::_ParseXml(const string& iPathFileXml,xmlpp::Node** oRootNode)
{*oRootNode = NULL;
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLEDtry{#endif //LIBXMLCPP_EXCEPTIONS_ENABLEDparser = new xmlpp::DomParser(iPathFileXml);
if(parser)
{const xmlpp::Node* root = parser->get_document()->get_root_node(); //deleted by DomParser.
*oRootNode = (xmlpp::Node*)root;
}#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED}catch(const std::exception& ex)
{std::cout << "Exception caught: " << ex.what() << std::endl;
}#endif //LIBXMLCPP_EXCEPTIONS_ENABLEDreturn 0;
}xmlpp::Node* CXml::getRootNode() { return this->rootNode; }
E ora un pezzo di codice per fare delle prove: main.cpp
/** main.cpp** Created on: 12-mar-2009* Author: negus*/#include "Xml/CXml.h"void xpath_test(const xmlpp::Node* node, const Glib::ustring& xpath);
void print_indentation(unsigned int indentation);
void print_node(const xmlpp::Node* node, unsigned int indentation);
int main()
{CXml *xml = new CXml("/home/negus/prova.xml");
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLEDtry{#endif //LIBXMLCPP_EXCEPTIONS_ENABLEDxmlpp::Node* root = xml->getRootNode();
if(root)
{// Find all sections, no matter where:xpath_test(root, "//livello1");
// Find the title node (if there is one)://xpath_test(root, "title");std::cout << std::endl;
// And finally test whether intra-document links are well-formed.// To be well-formed, the 'linkend' attribute must refer to// an element in terms of its 'id'.//// Find out whether there are linkend attributes that don't have// corresponding 'id'sstd::cout << "searching for unresolved internal references "
<< "(see docbook manual):" << std::endl;
//xpath_test(root, "//xref/@linkend");}#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED}catch(const std::exception& ex)
{std::cout << "Exception caught: " << ex.what() << std::endl;
}#endif //LIBXMLCPP_EXCEPTIONS_ENABLEDdelete xml;
return 0;
}void xpath_test(const xmlpp::Node* node, const Glib::ustring& xpath)
{std::cout << std::endl; //Separate tests by an empty line.
std::cout << "searching with xpath '" << xpath << "' in root node: " << std::endl;
xmlpp::NodeSet set = node->find(xpath);
//std::cout << set.size() << " nodes have been found:" << std::endl;//Print the structural paths:for(xmlpp::NodeSet::iterator i = set.begin(); i != set.end(); ++i)
{//std::cout << " " << (*i)->get_path() << std::endl;//print_node(*i,0);}}void print_indentation(unsigned int indentation)
{for(unsigned int i = 0; i < indentation; ++i)
std::cout << " ";
}void print_node(const xmlpp::Node* node, unsigned int indentation)
{std::cout << std::endl; //Separate nodes by an empty line.
const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::contentnode*="">(node);
const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::textnode*="">(node);
const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::commentnode*="">(node);
if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
return;
Glib::ustring nodename = node->get_name();
if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
{print_indentation(indentation);
std::cout << "Node name = " << node->get_name() << std::endl;
std::cout << "Node name = " << nodename << std::endl;
}else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is.
{print_indentation(indentation);
std::cout << "Text Node" << std::endl;
}//Treat the various node types differently:if(nodeText)
{print_indentation(indentation);
std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl;
}else if(nodeComment)
{print_indentation(indentation);
std::cout << "comment = " << nodeComment->get_content() << std::endl;
}else if(nodeContent)
{print_indentation(indentation);
std::cout << "content = " << nodeContent->get_content() << std::endl;
}else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::element*="">(node))
{//A normal Element node://line() works only for ElementNodes.print_indentation(indentation);
std::cout << " line = " << node->get_line() << std::endl;
//Print attributes:const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes();
for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
{const xmlpp::Attribute* attribute = *iter;
print_indentation(indentation);
std::cout << " Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl;
}const xmlpp::Attribute* attribute = nodeElement->get_attribute("title");
if(attribute)
{std::cout << "title found: =" << attribute->get_value() << std::endl;
}}if(!nodeContent)
{//Recurse through child nodes:xmlpp::Node::NodeList list = node->get_children();
for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
{print_node(*iter, indentation + 2); //recursive
}}}

