diff options
| -rw-r--r-- | project2/Jamfile.jam | 3 | ||||
| -rw-r--r-- | project2/dumpTask.cpp | 10 | ||||
| -rw-r--r-- | project2/exceptions.h | 1 | ||||
| -rw-r--r-- | project2/iterate.cpp | 3 | ||||
| -rw-r--r-- | project2/rowProcessor.cpp | 3 | ||||
| -rw-r--r-- | project2/rowView.cpp | 3 | ||||
| -rw-r--r-- | project2/xslRows.cpp | 199 | ||||
| -rw-r--r-- | project2/xslRows.h | 57 | 
8 files changed, 269 insertions, 10 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index cdffad9..0bec35a 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -40,10 +40,11 @@ lib p2common :  	;  lib p2xml : -	xmlRows.cpp +	xmlRows.cpp xslRows.cpp  	:  	<library>../libmisc//misc  	<library>libxmlpp +	<library>libxslt  	;  lib p2processes : diff --git a/project2/dumpTask.cpp b/project2/dumpTask.cpp index 0d485f8..caf3c86 100644 --- a/project2/dumpTask.cpp +++ b/project2/dumpTask.cpp @@ -24,17 +24,15 @@ DumpTask::loadComplete(const CommonObjects *)  void  DumpTask::execute() const  { -	const RowSet::RowValuesStack::value_type & r = RowSet::Stack().back(); +	const RowSet::RowValuesStack::value_type & r = *++RowSet::Stack().rbegin();  	unsigned int cols = r->columnCount();  	for (unsigned int c = 0; c < cols; c += 1) {  		if (c > 0) {  			fprintf(stderr, ", ");  		} -		try { -			fprintf(stderr, "%s = '%s'", r->getColumnName(c).c_str(), r->getCurrentValue(c).c_str()); -		} -		catch (const RowSet::FieldDoesNotExist &) { -			fprintf(stderr, "%s = null", r->getColumnName(c).c_str()); +		fprintf(stderr, "%s = ", r->getColumnName(c).c_str()); +		if (!r->isNull(c)) { +			fprintf(stderr, "'%s'", r->getCurrentValue(c).c_str());  		}  	}  	fprintf(stderr, "\n"); diff --git a/project2/exceptions.h b/project2/exceptions.h index 84c8c19..d156636 100644 --- a/project2/exceptions.h +++ b/project2/exceptions.h @@ -11,6 +11,7 @@ class NotSupported : public std::runtime_error {  };  class FileNotReadable : public std::exception { };  class FileNotWritable : public std::exception { }; +class FilterNotFound : public std::exception { };  #endif diff --git a/project2/iterate.cpp b/project2/iterate.cpp index 9e5c7f7..f4c8d81 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -35,6 +35,9 @@ Iterate::rowReady() const  void  Iterate::execute() const  { +	if (!filter.empty()) { +		source->setFilter(filter); +	}  	RowSet::beginRow(source.get());  	try {  		source->execute(this); diff --git a/project2/rowProcessor.cpp b/project2/rowProcessor.cpp index 26275a9..71d2548 100644 --- a/project2/rowProcessor.cpp +++ b/project2/rowProcessor.cpp @@ -16,8 +16,5 @@ void  RowProcessor::loadComplete(const CommonObjects * co)  {  	source = co->getSource(recordSource); -	if (!filter.empty()) { -		source->setFilter(filter); -	}  } diff --git a/project2/rowView.cpp b/project2/rowView.cpp index e0cca9c..10fece5 100644 --- a/project2/rowView.cpp +++ b/project2/rowView.cpp @@ -59,6 +59,9 @@ RowView::rowReady() const  void  RowView::execute(const Presenter * p) const  { +	if (!filter.empty()) { +		source->setFilter(filter); +	}  	presenter = p;  	presenter->pushSub(rootName);  	RowSet::beginRow(source.get()); diff --git a/project2/xslRows.cpp b/project2/xslRows.cpp new file mode 100644 index 0000000..696edb9 --- /dev/null +++ b/project2/xslRows.cpp @@ -0,0 +1,199 @@ +#include "xslRows.h" +#include "rowProcessor.h" +#include "xml.h" +#include "exceptions.h" +#include "xmlObjectLoader.h" +#include <boost/lexical_cast.hpp> +#include <libxml/HTMLparser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include "../libmisc/curlsup.h" + +ElementLoaderImpl<XslRows> xslrowLoader("xslrows"); + +class XmlParseError : public std::exception { }; +class XpathInitError : public std::exception { }; +class XpathEvalError : public std::exception { }; +class ResourceDownloadError : public std::exception { }; + +XslRows::XslRows(const xmlpp::Element * p) : +	SourceObject(p), +	RowSet(p), +	url(p->get_attribute_value("url")), +	html(p->get_attribute_value("html") == "true"), +	warnings(p->get_attribute_value("warnings") != "false") +{ +	BOOST_FOREACH(const xmlpp::Node * node, p->find("filterview")) { +		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node); +		if (elem) { +			FilterViewPtr fv = new FilterView(elem); +			fvs[fv->name] = fv; +		} +	} +	BOOST_FOREACH(const xmlpp::Node * node, p->find("namespace")) { +		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node); +		if (elem) { +			namespaces[elem->get_attribute_value("prefix")] = elem->get_attribute_value("url"); +		} +	} +} + +XslRows::~XslRows() +{ +} + +void +XslRows::loadComplete(const CommonObjects *) +{ +} + +void +XslRows::setFilter(const Glib::ustring & f) +{ +	FilterViews::const_iterator i = fvs.find(f); +	if (i == fvs.end()) { +		throw FilterNotFound(); +	} +	fv = i->second; +} + +size_t +XslRows::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream) +{ +	std::string * buf = static_cast<std::string *>(stream); +	buf->append(ptr, size * nmemb); +	return size * nmemb; +} + +xmlDocPtr +XslRows::getDocument(const Glib::ustring & url) const +{ +	Documents::const_iterator i = documents.find(url); +	if (i == documents.end()) { +		CurlHandle::Ptr c = new CurlHandle(); +		c->setopt(CURLOPT_URL, url.c_str()); +		c->setopt(CURLOPT_FOLLOWLOCATION, 1); +		c->setopt(CURLOPT_ENCODING, "deflate, gzip"); +		c->setopt(CURLOPT_USERAGENT, "project2/0.3"); +		std::string buf; +		c->setopt(CURLOPT_WRITEDATA, &buf); +		c->setopt(CURLOPT_WRITEFUNCTION, &handleDataHelper); +		if (c->perform()) { +			throw ResourceDownloadError(); +		} + +		int flags = 0; +		flags |= warnings ? 0 : XML_PARSE_NOWARNING | XML_PARSE_NOERROR; +		xmlDocPtr doc = html ? +			htmlReadMemory(buf.c_str(), buf.length(), url.c_str(), NULL, flags) : +			xmlReadMemory(buf.c_str(), buf.length(), url.c_str(), NULL, flags); +		if (!doc) { +			throw XmlParseError(); +		} +		documents.insert(Documents::value_type(url, Documents::value_type::second_type(doc, xmlFreeDoc))); +		return doc; +	} +	else { +		return i->second.get(); +	} +} + +void +XslRows::execute(const RowProcessor * rp) const +{ +	xmlDocPtr doc = getDocument(url()); +	xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); +	if (!xpathCtx) { +		throw XpathInitError(); +	} +	BOOST_FOREACH(const Namespaces::value_type & ns, namespaces) { +		xmlXPathRegisterNs(xpathCtx, BAD_CAST ns.first.c_str(), BAD_CAST ns.second.c_str()); +	} +	xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(BAD_CAST fv->root().c_str(), xpathCtx); +	if (!xpathObj || !xpathObj->nodesetval) { +		xmlXPathFreeContext(xpathCtx); +		throw XpathEvalError(); +	} +	rowNum = 1; +	for (int row = 0; row < xpathObj->nodesetval->nodeNr; row += 1) { +		xmlNodePtr rowRoot = xpathObj->nodesetval->nodeTab[row]; +		xpathCtx->node = rowRoot; +		values.clear(); +		BOOST_FOREACH(const FilterView::XPaths::value_type & xp, fv->xpaths) { +			xmlXPathObjectPtr xpathObjI = xmlXPathEvalExpression(BAD_CAST xp.second().c_str(), xpathCtx); +			if (!xpathObjI) { +				xmlXPathFreeObject(xpathObj); +				xmlXPathFreeContext(xpathCtx); +				throw XpathEvalError(); +			} +			if (xpathObjI->floatval) { +				values[xp.first] = boost::shared_ptr<const Glib::ustring>(new Glib::ustring(boost::lexical_cast<Glib::ustring>(xpathObjI->floatval))); +			} +			else if (xpathObjI->stringval) { +				values[xp.first] = boost::shared_ptr<const Glib::ustring>(new Glib::ustring((const char *)xpathObjI->stringval)); +			} +			else if (xpathObjI->nodesetval && xpathObjI->nodesetval->nodeNr == 1) { +				if (xpathObjI->nodesetval->nodeTab[0]->children && xpathObjI->nodesetval->nodeTab[0]->children->content) { +					xmlChar * val = xpathObjI->nodesetval->nodeTab[0]->children->content; +					values[xp.first] = boost::shared_ptr<const Glib::ustring>(new Glib::ustring((const char *)val)); +				} +			} +			xmlXPathFreeObject(xpathObjI); +		} +		rp->rowReady(); +		rowNum += 1; +	} +	xmlXPathFreeObject(xpathObj); +	xmlXPathFreeContext(xpathCtx); +} + +XslRows::FilterView::FilterView(const xmlpp::Element * p) : +	name(p->get_attribute_value("name")), +	root(p->get_attribute_value("root")) +{ +	BOOST_FOREACH(const xmlpp::Node * node, p->find("field")) { +		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node); +		if (elem) { +			xpaths.insert(XPaths::value_type(elem->get_attribute_value("name"), elem->get_attribute_value("xpath"))); +		} +	} +} + +const Glib::ustring & +XslRows::getCurrentValue(const Glib::ustring & id) const +{ +	return *values.find(id)->second; +} + +const Glib::ustring & +XslRows::getCurrentValue(unsigned int col) const +{ +	return getCurrentValue(getColumnName(col)); +} + +bool +XslRows::isNull(unsigned int col) const +{ +	return isNull(getColumnName(col)); +} + +bool +XslRows::isNull(const Glib::ustring & col) const +{ +	return (values.find(col) == values.end()); +} + +unsigned int +XslRows::columnCount() const +{ +	return fv->xpaths.size(); +} + +const Glib::ustring & +XslRows::getColumnName(unsigned int col) const +{ +	FilterView::XPaths::const_iterator i = fv->xpaths.begin(); +	while (col--) i++; +	return i->first; +} + diff --git a/project2/xslRows.h b/project2/xslRows.h new file mode 100644 index 0000000..0cc92c7 --- /dev/null +++ b/project2/xslRows.h @@ -0,0 +1,57 @@ +#ifndef XSLROWS_H +#define XSLROWS_H + +#include <libxml++/nodes/element.h> +#include <libxml/tree.h> +#include <boost/intrusive_ptr.hpp> +#include <map> +#include "rowSet.h" + +class XslRows : public RowSet { +	public: + +		XslRows(const xmlpp::Element * p); +		~XslRows(); + +		void execute(const RowProcessor *) const; +		virtual void loadComplete(const CommonObjects *); +		virtual void setFilter(const Glib::ustring &); +		unsigned int columnCount() const; +		const Glib::ustring & getColumnName(unsigned int col) const; +		const Glib::ustring & getCurrentValue(const Glib::ustring & id) const; +		const Glib::ustring & getCurrentValue(unsigned int col) const; +		bool isNull(unsigned int col) const; +		bool isNull(const Glib::ustring & id) const; + +		const Variable url; +		const bool html; +		const bool warnings; + +	private: +		class FilterView : public virtual IntrusivePtrBase { +			public: +				typedef std::map<const Glib::ustring, Variable> XPaths; + +				FilterView(const xmlpp::Element * p); + +				const Glib::ustring name; +				const Variable root; +				XPaths xpaths; +		}; +		typedef boost::intrusive_ptr<FilterView> FilterViewPtr; +		typedef std::map<const Glib::ustring, FilterViewPtr> FilterViews; +		FilterViews fvs; +		FilterViewPtr fv; + +		typedef std::map<const Glib::ustring, Glib::ustring> Namespaces; +		mutable Namespaces namespaces; +		typedef std::map<const Glib::ustring, boost::shared_ptr<const Glib::ustring> > Values; +		mutable Values values; +		typedef std::map<const Glib::ustring, boost::shared_ptr<xmlDoc> > Documents; +		mutable Documents documents; +		static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream); +		xmlDocPtr getDocument(const Glib::ustring & url) const; +}; + +#endif +  | 
