diff options
author | randomdan <randomdan@localhost> | 2011-01-31 10:18:58 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2011-01-31 10:18:58 +0000 |
commit | 66032f772aec1583f419419addf9fe241ae02bca (patch) | |
tree | 8f7de0d483afe2e5d3ee177c6511beea0a42ab85 | |
parent | Only trim newline from lines that end with newline (diff) | |
download | project2-66032f772aec1583f419419addf9fe241ae02bca.tar.bz2 project2-66032f772aec1583f419419addf9fe241ae02bca.tar.xz project2-66032f772aec1583f419419addf9fe241ae02bca.zip |
Call curl global cleanup when finished
Don't bind filters on load complete, there might be multiple different users
Add XSL rows
Fix several problems with dump (bin me, console app should support views)
-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 + |