summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
+