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 + |