summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2011-01-31 10:18:58 +0000
committerrandomdan <randomdan@localhost>2011-01-31 10:18:58 +0000
commit66032f772aec1583f419419addf9fe241ae02bca (patch)
tree8f7de0d483afe2e5d3ee177c6511beea0a42ab85
parentOnly trim newline from lines that end with newline (diff)
downloadproject2-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.jam3
-rw-r--r--project2/dumpTask.cpp10
-rw-r--r--project2/exceptions.h1
-rw-r--r--project2/iterate.cpp3
-rw-r--r--project2/rowProcessor.cpp3
-rw-r--r--project2/rowView.cpp3
-rw-r--r--project2/xslRows.cpp199
-rw-r--r--project2/xslRows.h57
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
+