summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/rss
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-05-31 02:29:45 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-05-31 02:29:45 +0000
commit7808f187b68261a58de9e348a722b6d0e32dcbe9 (patch)
treea1b97c546f15448e46565bc40ff7e20ff5525092 /sca-cpp/trunk/modules/rss
parent90b55b93704adb3e1fac59d58c2d644d37537bc9 (diff)
Add support for RSS feeds and minor fixes to ATOM support.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@949652 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/modules/rss')
-rw-r--r--sca-cpp/trunk/modules/rss/Makefile.am22
-rw-r--r--sca-cpp/trunk/modules/rss/rss-test.cpp214
-rw-r--r--sca-cpp/trunk/modules/rss/rss.hpp201
3 files changed, 437 insertions, 0 deletions
diff --git a/sca-cpp/trunk/modules/rss/Makefile.am b/sca-cpp/trunk/modules/rss/Makefile.am
new file mode 100644
index 0000000000..5254eacb25
--- /dev/null
+++ b/sca-cpp/trunk/modules/rss/Makefile.am
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+rss_test_SOURCES = rss-test.cpp
+rss_test_LDFLAGS = -lxml2
+
+noinst_PROGRAMS = rss-test
+TESTS = rss-test
diff --git a/sca-cpp/trunk/modules/rss/rss-test.cpp b/sca-cpp/trunk/modules/rss/rss-test.cpp
new file mode 100644
index 0000000000..3168e1f474
--- /dev/null
+++ b/sca-cpp/trunk/modules/rss/rss-test.cpp
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test RSS data conversion functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "rss.hpp"
+
+namespace tuscany {
+namespace rss {
+
+ostream* writer(const string& s, ostream* os) {
+ (*os) << s;
+ return os;
+}
+
+string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>"
+ "<fruit>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</fruit>"
+ "</description>"
+ "</item>\n");
+
+string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>Apple</description>"
+ "</item>\n");
+
+string incompleteEntry("<item>"
+ "<title>fruit</title><description>"
+ "<fruit xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</fruit>"
+ "</description>"
+ "</item>");
+
+string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<item>"
+ "<title>fruit</title>"
+ "<link></link>"
+ "<description>"
+ "<fruit xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</fruit>"
+ "</description>"
+ "</item>\n");
+
+bool testEntry() {
+ {
+ const list<value> i = list<value>() + element + value("fruit")
+ + value(list<value>() + element + value("name") + value(string("Apple")))
+ + value(list<value>() + element + value("price") + value(string("$2.99")));
+ const list<value> a = mklist<value>(string("fruit"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = mklist<value>(string("fruit"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), "Apple");
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(itemEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(itemTextEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == itemTextEntry);
+ }
+ {
+ const list<value> a = content(readRSSEntry(mklist(incompleteEntry)));
+ ostringstream os;
+ writeRSSEntry<ostream*>(writer, &os, a);
+ assert(str(os) == completedEntry);
+ }
+ return true;
+}
+
+string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rss version=\"2.0\">"
+ "<channel>"
+ "<title>Feed</title>"
+ "<link>1234</link>"
+ "<description>Feed</description>"
+ "</channel>"
+ "</rss>\n");
+
+string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rss version=\"2.0\">"
+ "<channel>"
+ "<title>Feed</title>"
+ "<link>1234</link>"
+ "<description>Feed</description>"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</link>"
+ "<description>"
+ "<fruit>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</fruit>"
+ "</description>"
+ "</item>"
+ "<item>"
+ "<title>fruit</title>"
+ "<link>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</link>"
+ "<description>"
+ "<fruit>"
+ "<name>Orange</name><price>$3.55</price>"
+ "</fruit>"
+ "</description>"
+ "</item>"
+ "</channel>"
+ "</rss>\n");
+
+bool testFeed() {
+ {
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, mklist<value>("Feed", "1234"));
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> a = content(readRSSFeed(mklist(emptyFeed)));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == emptyFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + (list<value>() + element + "fruit"
+ + (list<value>() + element + "name" + "Apple")
+ + (list<value>() + element + "price" + "$2.99")))
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + (list<value>() + element + "fruit"
+ + (list<value>() + element + "name" + "Orange")
+ + (list<value>() + element + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ + valueToElement(list<value>() + "fruit"
+ + (list<value>() + "name" + "Apple")
+ + (list<value>() + "price" + "$2.99")))
+ + (list<value>() + "fruit" + "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ + valueToElement(list<value>() + "fruit"
+ + (list<value>() + "name" + "Orange")
+ + (list<value>() + "price" + "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ {
+ const list<value> a = content(readRSSFeed(mklist(itemFeed)));
+ ostringstream os;
+ writeRSSFeed<ostream*>(writer, &os, a);
+ assert(str(os) == itemFeed);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::rss::testEntry();
+ tuscany::rss::testFeed();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/rss/rss.hpp b/sca-cpp/trunk/modules/rss/rss.hpp
new file mode 100644
index 0000000000..506d1f4a6d
--- /dev/null
+++ b/sca-cpp/trunk/modules/rss/rss.hpp
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_rss_hpp
+#define tuscany_rss_hpp
+
+/**
+ * RSS data conversion functions.
+ */
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+namespace rss {
+
+/**
+ * Convert a list of elements to a list of values representing an RSS entry.
+ */
+const list<value> entryElementsToValues(const list<value>& e) {
+ const list<value> lt = filter<value>(selector(mklist<value>(element, "title")), e);
+ const value t = isNil(lt)? value(emptyString) : elementValue(car(lt));
+ const list<value> li = filter<value>(selector(mklist<value>(element, "link")), e);
+ const value i = isNil(li)? value(emptyString) : elementValue(car(li));
+ const list<value> ld = filter<value>(selector(mklist<value>(element, "description")), e);
+ return mklist<value>(t, i, elementValue(car(ld)));
+}
+
+/**
+ * Convert a list of elements to a list of values representing RSS entries.
+ */
+const list<value> entriesElementsToValues(const list<value>& e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)));
+}
+
+/**
+ * Return true if a list of strings contains an RSS feed.
+ */
+const bool isRSSFeed(const list<string>& ls) {
+ if (!isXML(ls))
+ return false;
+ return contains(car(ls), "<rss");
+}
+
+/**
+ * Convert a list of strings to a list of values representing an RSS entry.
+ */
+const failable<list<value> > readRSSEntry(const list<string>& ilist) {
+ const list<value> e = readXML(ilist);
+ if (isNil(e))
+ return mkfailure<list<value> >("Empty entry");
+ return entryElementsToValues(car(e));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to a value.
+ */
+const value entryValue(const list<value>& e) {
+ const list<value> v = elementsToValues(mklist<value>(caddr(e)));
+ return cons(car(e), mklist<value>(cadr(e), isList(car(v))? (value)cdr<value>(car(v)) : car(v)));
+}
+
+/**
+ * Convert a list of strings to a list of values representing an RSS feed.
+ */
+const failable<list<value> > readRSSFeed(const list<string>& ilist) {
+ const list<value> f = readXML(ilist);
+ if (isNil(f))
+ return mkfailure<list<value> >("Empty feed");
+ const list<value> c = filter<value>(selector(mklist<value>(element, "channel")), car(f));
+ const list<value> t = filter<value>(selector(mklist<value>(element, "title")), car(c));
+ const list<value> i = filter<value>(selector(mklist<value>(element, "link")), car(c));
+ const list<value> e = filter<value>(selector(mklist<value>(element, "item")), car(c));
+ if (isNil(e))
+ return mklist<value>(elementValue(car(t)), elementValue(car(i)));
+ return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)));
+}
+
+/**
+ * Convert an RSS feed containing elements to an RSS feed containing values.
+ */
+const list<value> feedValuesLoop(const list<value> e) {
+ if (isNil(e))
+ return e;
+ return cons<value>(entryValue(car(e)), feedValuesLoop(cdr(e)));
+}
+
+const list<value> feedValues(const list<value>& e) {
+ return cons(car<value>(e), cons<value>(cadr<value>(e), feedValuesLoop(cddr<value>(e))));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to a list of elements.
+ * The first two values in the list are the entry title and id.
+ */
+const list<value> entryElement(const list<value>& l) {
+ return list<value>()
+ + element + "item"
+ + (list<value>() + element + "title" + car(l))
+ + (list<value>() + element + "link" + cadr(l))
+ + (list<value>() + element + "description" + caddr(l));
+}
+
+/**
+ * Convert a list of values representing RSS entries to a list of elements.
+ */
+const list<value> entriesElements(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(entryElement(car(l)), entriesElements(cdr(l)));
+}
+
+/**
+ * Convert a list of values representing an RSS entry to an RSS entry.
+ * The first two values in the list are the entry id and title.
+ */
+template<typename R> const failable<R> writeRSSEntry(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML<R>(reduce, initial, mklist<value>(entryElement(l)));
+}
+
+const failable<list<string> > writeRSSEntry(const list<value>& l) {
+ const failable<list<string> > ls = writeRSSEntry<list<string> >(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert a list of values representing an RSS feed to an RSS feed.
+ * The first two values in the list are the feed id and title.
+ */
+template<typename R> const failable<R> writeRSSFeed(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l) {
+ const list<value> c = list<value>()
+ + (list<value>() + element + "title" + car(l))
+ + (list<value>() + element + "link" + cadr(l))
+ + (list<value>() + element + "description" + car(l));
+ const list<value> ce = isNil(cddr(l))? c : append(c, entriesElements(cddr(l)));
+ const list<value> fe = list<value>()
+ + element + "rss" + (list<value>() + attribute + "version" + "2.0")
+ + append(list<value>() + element + "channel", ce);
+ return writeXML<R>(reduce, initial, mklist<value>(fe));
+}
+
+/**
+ * Convert a list of values representing an RSS feed to a list of strings.
+ * The first two values in the list are the feed id and title.
+ */
+const failable<list<string> > writeRSSFeed(const list<value>& l) {
+ const failable<list<string> > ls = writeRSSFeed<list<string>>(rcons<string>, list<string>(), l);
+ if (!hasContent(ls))
+ return ls;
+ return reverse(list<string>(content(ls)));
+}
+
+/**
+ * Convert an RSS entry containing a value to an RSS entry containing an item element.
+ */
+const list<value> entryValuesToElements(const list<value> val) {
+ return cons(car(val), cons(cadr(val), valuesToElements(mklist<value>(cons<value>("item", (list<value>)caddr(val))))));
+}
+
+/**
+ * Convert an RSS feed containing values to an RSS feed containing elements.
+ */
+const list<value> feedValuesToElementsLoop(const list<value> val) {
+ if (isNil(val))
+ return val;
+ return cons<value>(entryValuesToElements(car(val)), feedValuesToElementsLoop(cdr(val)));
+}
+
+const list<value> feedValuesToElements(const list<value>& val) {
+ return cons(car<value>(val), cons<value>(cadr<value>(val), feedValuesToElementsLoop(cddr<value>(val))));
+}
+
+}
+}
+
+#endif /* tuscany_rss_hpp */