diff options
Diffstat (limited to 'sca-cpp/trunk/modules/xml')
-rw-r--r-- | sca-cpp/trunk/modules/xml/Makefile.am | 29 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/xml/test.xml | 2 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/xml/xml-test.cpp | 373 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/xml/xml-test.hpp | 33 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/xml/xml.hpp | 418 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/xml/xsd-test.cpp | 107 |
6 files changed, 962 insertions, 0 deletions
diff --git a/sca-cpp/trunk/modules/xml/Makefile.am b/sca-cpp/trunk/modules/xml/Makefile.am new file mode 100644 index 0000000000..e99218a736 --- /dev/null +++ b/sca-cpp/trunk/modules/xml/Makefile.am @@ -0,0 +1,29 @@ +# 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. + +incl_HEADERS = *.hpp +incldir = $(prefix)/include/modules/xml + +xml_test_SOURCES = xml-test.cpp +xml_test_LDFLAGS = -lxml2 + +xsd_test_SOURCES = xsd-test.cpp +xsd_test_LDFLAGS = -lxml2 + +noinst_PROGRAMS = xml-test xsd-test +TESTS = xml-test + diff --git a/sca-cpp/trunk/modules/xml/test.xml b/sca-cpp/trunk/modules/xml/test.xml new file mode 100644 index 0000000000..501d9ac477 --- /dev/null +++ b/sca-cpp/trunk/modules/xml/test.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feed><title>Search Results</title><id>search</id><entry><title>An empty app template</title><id>new</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty test app</title><id>test</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Check my public social data</title><id>me360</id><author>admin@example.com</author><updated>Apr 28, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme</title><id>nearme</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme2</title><id>nearme2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Our photos of an event</title><id>ourphotos</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>My online store</title><id>shoppingcart</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Slice</title><id>slice</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test animation components</title><id>testanimation</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test database components</title><id>testdb</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test event components</title><id>testevents</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test logic components</title><id>testlogic</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test search components</title><id>testsearch</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test social components</title><id>testsocial</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test text processing components</title><id>testtext</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test URL components</title><id>testurl</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test values and lists</title><id>testvalues</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test widgets</title><id>testwidgets</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test more widgets</title><id>testwidgets2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTML generator components</title><id>testwidgets3</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>jsdtest</title><id>jsdtest</id><author>jsdelfino</author><updated>Jul 27, 2012</updated><content><stats><description>Test app</description></stats></content></entry><entry><title>SMS send service</title><id>twsms</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>boao</title><id>boao</id><author>jsdelfino</author><updated>2012-10-12T12:06:59+00:00</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty test app</title><id>test</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty app template</title><id>new</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme</title><id>nearme</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme2</title><id>nearme2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Our photos of an event</title><id>ourphotos</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>My online store</title><id>shoppingcart</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Slice</title><id>slice</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test animation components</title><id>testanimation</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test database components</title><id>testdb</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test event components</title><id>testevents</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test social components</title><id>testsocial</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test logic components</title><id>testlogic</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test search components</title><id>testsearch</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test text processing components</title><id>testtext</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test URL components</title><id>testurl</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test values and lists</title><id>testvalues</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test widgets</title><id>testwidgets</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test more widgets</title><id>testwidgets2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTML generator components</title><id>testwidgets3</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>test9</title><id>test9</id><author>jsdelfino</author><updated>2012-09-25T06:17:18+00:00</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>SMS send service</title><id>twsms</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Check my public social data</title><id>me360</id><author>admin@example.com</author><updated>Apr 28, 2012</updated><content><stats><description>Sample app</description></stats></content></entry></feed> diff --git a/sca-cpp/trunk/modules/xml/xml-test.cpp b/sca-cpp/trunk/modules/xml/xml-test.cpp new file mode 100644 index 0000000000..dd2be2f9c2 --- /dev/null +++ b/sca-cpp/trunk/modules/xml/xml-test.cpp @@ -0,0 +1,373 @@ +/* + * 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 XML handling functions. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "list.hpp" +#include "value.hpp" +#include "element.hpp" +#include "perf.hpp" +#include "xml.hpp" +#include "xml-test.hpp" + +namespace tuscany { +namespace xml { + +const string currencyXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<composite xmlns=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" targetNamespace=\"http://services\" name=\"currency\">" + "<component name=\"CurrencyConverterWebService\">" + "<implementation.java class=\"services.CurrencyConverterImpl\"/>" + "<service name=\"CurrencyConverter\">" + "<binding.ws/>" + "</service>" + "</component>" + "<component name=\"CurrencyConverterWebService2\">" + "<implementation.java class=\"services.CurrencyConverterImpl2\"/>" + "<service name=\"CurrencyConverter2\">" + "<binding.atom/>" + "</service>" + "<property name=\"currency\">US</property>" + "</component>" +"</composite>\n"; + +const string customerXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<customer>" + "<name>jdoe</name>" + "<address>" + "<city>san francisco</city>" + "<state>ca</state>" + "</address>" + "<account>" + "<id>1234</id>" + "<balance>1000</balance>" + "</account>" + "<account>" + "<id>6789</id>" + "<balance>2000</balance>" + "</account>" + "<account>" + "<id>4567</id>" + "<balance>3000</balance>" + "</account>" +"</customer>\n"; + +const string abcXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<a>" + "<m>abc</m>" + "<m>def</m>" + "<m>xyz</m>" + "<m>tuv</m>" +"</a>\n"; + +const string xyzXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<a>" + "<m>" + "<id>123</id>" + "<name>abc</name>" + "</m>" + "<m>" + "<id>234</id>" + "<name>def</name>" + "</m>" + "<m>" + "<id>345</id>" + "<name>xyz</name>" + "</m>" + "<m>" + "<id>456</id>" + "<name>tuv</name>" + "</m>" +"</a>\n"; + +const string boolXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<x>true</x>\n"; + +const string numberXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<x>123.4</x>\n"; + +const bool isName(const value& token) { + return isTaggedList(token, attribute) && attributeName(token) == "name"; +} + +const bool testReadXML() { + { + istringstream is(customerXML); + const list<value> c = content(readElements(streamList(is))); + } + { + istringstream is(currencyXML); + const list<value> c = content(readElements(streamList(is))); + + const value composite = car(c); + assert(isTaggedList(composite, element)); + assert(elementName(composite) == "composite"); + assert(attributeValue(car(filter<value>(isName, elementChildren(composite)))) == string("currency")); + } + { + istringstream is(boolXML); + const list<value> c = content(readElements(streamList(is))); + assert(caddr<value>(car(c)) == value(true)); + } + { + istringstream is(numberXML); + const list<value> c = content(readElements(streamList(is))); + assert(caddr<value>(car(c)) == value(123.4)); + } + return true; +} + +ostream* xmlWriter(const string& s, ostream* os) { + (*os) << s; + return os; +} + +const bool testWriteXML() { + { + istringstream is(customerXML); + const list<value> c = content(readElements(streamList(is))); + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, c); + assert(str(os) == customerXML); + } + { + istringstream is(currencyXML); + const list<value> c = content(readElements(streamList(is))); + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, c); + assert(str(os) == currencyXML); + } + return true; +} + +const bool testElements() { + { + const list<value> ad = mklist<value>(mklist<value>("city", string("san francisco")), mklist<value>("state", string("ca"))); + const list<value> ac1 = mklist<value>(mklist<value>("id", string("1234")), mklist<value>("balance", 1000)); + const list<value> ac2 = mklist<value>(mklist<value>("id", string("6789")), mklist<value>("balance", 2000)); + const list<value> ac3 = mklist<value>(mklist<value>("id", string("4567")), mklist<value>("balance", 3000)); + { + const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), mklist<value>("account", mklist<value>(ac1, ac2, ac3)))); + const list<value> e = valuesToElements(c); + const list<value> v = elementsToValues(e); + assert(v == c); + + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + { + const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", string("jdoe")), cons<value>("address", ad), cons<value>("account", ac1), cons<value>("account", ac2), cons<value>("account", ac3))); + const list<value> e = valuesToElements(c); + const list<value> v = elementsToValues(e); + + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + } + { + istringstream is(abcXML); + const list<value> c = content(readElements(streamList(is))); + const list<value> v = elementsToValues(c); + const list<value> e = valuesToElements(v); + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, e); + assert(str(os) == abcXML); + } + { + istringstream is(xyzXML); + const list<value> c = content(readElements(streamList(is))); + const list<value> v = elementsToValues(c); + const list<value> e = valuesToElements(v); + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, e); + assert(str(os) == xyzXML); + } + { + istringstream is(customerXML); + const list<value> c = content(readElements(streamList(is))); + const list<value> v = elementsToValues(c); + const list<value> e = valuesToElements(v); + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, e); + assert(str(os) == customerXML); + } + return true; +} + +const bool testValues() { + { + const list<value> l = mklist<value>(nilListValue + "ns1:echoString" + (nilListValue + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (nilListValue + "text" + string("Hello World!"))); + const list<value> e = valuesToElements(l); + const failable<list<string> > lx = writeElements(e); + ostringstream os; + write(content(lx), os); + istringstream is(str(os)); + const list<value> x = content(readElements(streamList(is))); + const list<value> v = elementsToValues(x); + assert(v == l); + } + return true; +} + +const bool testReadWrite() { + const gc_scoped_pool pool; + + istringstream is(customerXML); + const list<string> il = streamList(is); + const list<value> r = elementsToValues(content(readElements(il))); + + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, valuesToElements(r)); + //assert(str(os) == customerXML); + return true; +} + +const bool testReadWritePerf() { + const gc_scoped_pool pool; + + const blambda rwl = blambda(testReadWrite); + cout << "XML read + write test " << time(rwl, 5, 200) << " ms" << endl; + + return true; +} + +const bool testReadWriteBigDoc() { + const gc_scoped_pool pool; + + istringstream is(testBigDoc); + const list<string> il = streamList(is); + const list<value> r = elementsToValues(content(readElements(il))); + + ostringstream os; + writeElements<ostream*>(xmlWriter, &os, valuesToElements(r)); + //assert(str(os) == testBigDoc); + return true; +} + +const bool testReadWriteBigDocPerf() { + const gc_scoped_pool pool; + + const blambda rwl = blambda(testReadWriteBigDoc); + cout << "XML big doc read + write test " << time(rwl, 5, 200) << " ms" << endl; + + return true; +} + +const string customersXML = +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +"<customers>" + "<customer>" + "<name>jane doe</name>" + "<address>" + "<city>san francisco</city>" + "<state>ca</state>" + "</address>" + "<account>" + "<id>1234</id>" + "<balance>1000</balance>" + "</account>" + "<account>" + "<id>6789</id>" + "<balance>4000</balance>" + "</account>" + "</customer>" + "<customer>" + "<name>john doe</name>" + "<address>" + "<city>new york</city>" + "<state>ny</state>" + "</address>" + "<account>" + "<id>5678</id>" + "<balance>2000</balance>" + "</account>" + "<account>" + "<id>4321</id>" + "<balance>1000</balance>" + "</account>" + "</customer>" +"</customers>\n"; + +const bool testQuery() { + { + const gc_scoped_pool pool; + + // Read XML doc containing customers + istringstream is(customersXML); + const list<value> c = content(readElements(streamList(is))); + //cout << c << endl; + + // Map list of customers to a list of (customer name, customer balance) pairs + const list<value> nb = map<value, value>([](value e) -> const value { + + // Map list of accounts to a list of balances + list<value> bals = map<value, value>([](value e) -> const value { + return (double)elementValue(elementChild("balance", e)); + }, elementChildren("account", e)); + + // Reduce list of balances to compute customer balance + value total = reduce<value, value>([](value accum, value v) -> const value { + return (double)accum + (double)v; + }, value(0), bals); + + // Return (customer name, customer balance) pair + return mklist<value>(elementValue(elementChild("name", e)), total); + + }, elementChildren("customer", elementChild("customers", c))); + + // The resulting list of (customer name, customer balance) pairs + //cout << nb << endl; + assert(nb == mklist<value>(mklist<value>("jane doe", 5000), mklist<value>("john doe", 3000))); + } + return true; +} + +} +} + +int main() { + const tuscany::gc_scoped_pool p; + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::xml::testReadXML(); + tuscany::xml::testWriteXML(); + tuscany::xml::testElements(); + tuscany::xml::testValues(); + tuscany::xml::testReadWritePerf(); + tuscany::xml::testReadWriteBigDocPerf(); + tuscany::xml::testQuery(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/modules/xml/xml-test.hpp b/sca-cpp/trunk/modules/xml/xml-test.hpp new file mode 100644 index 0000000000..470ba40880 --- /dev/null +++ b/sca-cpp/trunk/modules/xml/xml-test.hpp @@ -0,0 +1,33 @@ +/* + * 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 XML doc. + */ + +namespace tuscany { +namespace xml { + +const string testBigDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed><title>Search Results</title><id>search</id><entry><title>An empty app template</title><id>new</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty test app</title><id>test</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Check my public social data</title><id>me360</id><author>admin@example.com</author><updated>Apr 28, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme</title><id>nearme</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme2</title><id>nearme2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Our photos of an event</title><id>ourphotos</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>My online store</title><id>shoppingcart</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Slice</title><id>slice</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test animation components</title><id>testanimation</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test database components</title><id>testdb</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test event components</title><id>testevents</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test logic components</title><id>testlogic</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test search components</title><id>testsearch</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test social components</title><id>testsocial</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test text processing components</title><id>testtext</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test URL components</title><id>testurl</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test values and lists</title><id>testvalues</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test widgets</title><id>testwidgets</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test more widgets</title><id>testwidgets2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTML generator components</title><id>testwidgets3</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>jsdtest</title><id>jsdtest</id><author>jsdelfino</author><updated>Jul 27, 2012</updated><content><stats><description>Test app</description></stats></content></entry><entry><title>SMS send service</title><id>twsms</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>boao</title><id>boao</id><author>jsdelfino</author><updated>2012-10-12T12:06:59+00:00</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty test app</title><id>test</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>An empty app template</title><id>new</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme</title><id>nearme</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>nearme2</title><id>nearme2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Our photos of an event</title><id>ourphotos</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>My online store</title><id>shoppingcart</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Slice</title><id>slice</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test animation components</title><id>testanimation</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test database components</title><id>testdb</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test event components</title><id>testevents</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test social components</title><id>testsocial</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test logic components</title><id>testlogic</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test search components</title><id>testsearch</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTTP components</title><id>testhttp</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test text processing components</title><id>testtext</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test URL components</title><id>testurl</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test values and lists</title><id>testvalues</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test widgets</title><id>testwidgets</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test more widgets</title><id>testwidgets2</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Test HTML generator components</title><id>testwidgets3</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>test9</title><id>test9</id><author>jsdelfino</author><updated>2012-09-25T06:17:18+00:00</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>SMS send service</title><id>twsms</id><author>admin@example.com</author><updated>Jan 01, 2012</updated><content><stats><description>Sample app</description></stats></content></entry><entry><title>Check my public social data</title><id>me360</id><author>admin@example.com</author><updated>Apr 28, 2012</updated><content><stats><description>Sample app</description></stats></content></entry></feed>\n"; + +} +} + diff --git a/sca-cpp/trunk/modules/xml/xml.hpp b/sca-cpp/trunk/modules/xml/xml.hpp new file mode 100644 index 0000000000..0a04d5f90a --- /dev/null +++ b/sca-cpp/trunk/modules/xml/xml.hpp @@ -0,0 +1,418 @@ +/* + * 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_xml_hpp +#define tuscany_xml_hpp + +/** + * XML read/write functions. + */ + +#include <libxml/xmlreader.h> +#include <libxml/xmlwriter.h> +#include <libxml/xmlschemas.h> +#include <libxml/globals.h> +#include "string.hpp" +#include "list.hpp" +#include "stream.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace xml { + +/** + * Initializes the libxml2 library. + */ +class XMLParser { +public: + inline XMLParser() { + debug("xml::XMLParser"); + xmlMemSetup(gc_pool_free, gc_pool_malloc, gc_pool_realloc, gc_pool_strdup); + xmlInitParser(); + } + + inline ~XMLParser() { + } +} xmlParser; + +/** + * Encapsulates a libxml2 xmlTextReader and its state. + */ +class XMLReader { +public: + enum TokenType { + None = 0, Element = 1, Attribute = 2, Text = 3, EndElement = 15, Identifier = 100, End = 101 + }; + + inline XMLReader(xmlTextReaderPtr xml) : xml(xml), owner(true), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) { + debug("xml::XMLReader::xml"); + xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1); + xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1); + } + + inline XMLReader(const XMLReader& r) : xml(r.xml), owner(false), tokenType(r.tokenType), isEmptyElement(r.isEmptyElement), hasValue(r.hasValue), hasAttributes(r.hasAttributes) { + debug("xml::XMLReader::copy"); + } + + XMLReader& operator=(const XMLReader& r) = delete; + + inline ~XMLReader() { + if (!owner) + return; + xmlTextReaderClose(xml); + xmlFreeTextReader(xml); + } + + /** + * Read the next XML token and return its type. + */ + inline const int read() { + if (tokenType == End) + return tokenType; + if (tokenType == Element) { + isEmptyElement = xmlTextReaderIsEmptyElement(xml); + hasAttributes = xmlTextReaderHasAttributes(xml); + return tokenType = Identifier; + } + if (tokenType == Identifier && hasAttributes && xmlTextReaderMoveToFirstAttribute(xml) == 1) + return tokenType = Attribute; + if (tokenType == Attribute && xmlTextReaderMoveToNextAttribute(xml) == 1) + return tokenType = Attribute; + if (isEmptyElement && (tokenType == Identifier || tokenType == Attribute)) + return tokenType = EndElement; + if (!xmlTextReaderRead(xml)) + return tokenType = End; + return tokenType = xmlTextReaderNodeType(xml); + } + + inline operator xmlTextReaderPtr() const { + return xml; + } + +private: + const xmlTextReaderPtr xml; + const bool owner; + int tokenType; + bool isEmptyElement; + bool hasValue; + bool hasAttributes; +}; + +/** + * Constants used to tag XML tokens. + */ +const value endElement("<"); +const value startElement(">"); + +/** + * Read a value from a text string, automatically detects a boolean or number value. + */ +const value readTextValue(const char* const val) { + if (!strcmp("true", val)) + return value(true); + if (!strcmp("false", val)) + return value(false); + + char e[2]; + double d; + const int n = sscanf(val, "%lg%1s", &d, e); + if (n == 1) + return value(d); + + return value(string(val)); +} + +/** + * Read an XML identifier. + */ +inline const value readIdentifier(XMLReader& reader) { + const char* const name = (const char*)xmlTextReaderConstName(reader); + return name; +} + +/** + * Read XML text. + */ +inline const value readText(XMLReader& reader) { + const char* const val = (const char*)xmlTextReaderConstValue(reader); + return readTextValue(val); +} + +/** + * Read an XML attribute. + */ +inline const value readAttribute(XMLReader& reader) { + const char* const name = (const char*)xmlTextReaderConstName(reader); + const char* const val = (const char*)xmlTextReaderConstValue(reader); + return mklist<value>(attribute, name, readTextValue(val)); +} + +/** + * Read an XML token. + */ +inline const value readToken(XMLReader& reader) { + const int tokenType = reader.read(); + if (tokenType == XMLReader::None || tokenType == XMLReader::End) + return nilValue; + if (tokenType == XMLReader::Element) + return startElement; + if (tokenType == XMLReader::Identifier) + return readIdentifier(reader); + if (tokenType == XMLReader::Attribute) + return readAttribute(reader); + if (tokenType == XMLReader::Text) + return readText(reader); + if (tokenType == XMLReader::EndElement) + return endElement; + return readToken(reader); +} + +/** + * Read a list of values from XML tokens. + */ +inline const list<value> readList(const list<value>& listSoFar, XMLReader& reader) { + const value token = readToken(reader); + if(isNil(token) || endElement == token) + return reverse(listSoFar); + if(startElement == token) + return readList(cons<value>(readList(mklist(element), reader), listSoFar), reader); + return readList(cons(token, listSoFar), reader); +} + +/** + * Read a list of values from a libxml2 XML reader. + */ +inline const list<value> read(XMLReader& reader) { + const value nextToken = readToken(reader); + if (startElement == nextToken) + return mklist<value>(readList(mklist(element), reader)); + return nilListValue; +} + +/** + * Context passed to the read callback function. + */ +class XMLReadContext { +public: + inline XMLReadContext(const list<string>& ilist) : ilist(ilist) { + } + + gc_mutable_ref<list<string> > ilist; +}; + +/** + * Callback function called by libxml2 to read XML. + */ +inline int readCallback(void *context, char* buffer, int len) { + XMLReadContext& rc = *(XMLReadContext*)context; + if (isNil((const list<string>)rc.ilist)) + return 0; + const list<string> f(fragment(rc.ilist, len)); + const string s(car(f)); + rc.ilist = cdr(f); + memcpy(buffer, c_str(s), length(s)); + return (int)length(s); +} + +/** + * Return true if a list of strings contains an XML document. + */ +inline const bool isXML(const list<string>& ls) { + if (isNil(ls)) + return false; + return substr(car(ls), 0, 5) == "<?xml"; +} + +/** + * Read a list of values from a list of strings representing an XML document. + */ +inline const failable<list<value> > readElements(const list<string>& ilist) { + debug(ilist, "xml::readElements"); + XMLReadContext cx(ilist); + const xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &cx, NULL, NULL, XML_PARSE_NONET | XML_PARSE_NODICT); + if (xml == NULL) + return nilListValue; + XMLReader reader(xml); + return read(reader); +} + +/** + * Default encoding used to write XML documents. + */ +const char* const encoding = "UTF-8"; + + +/** + * Write a list of XML element or attribute tokens. + */ +inline const list<value> expandElementValues(const value& n, const list<value>& l) { + if (isNil(l)) + return l; + return cons<value>(value(cons<value>(element, cons<value>(n, isList(car(l))? (list<value>)car(l) : mklist(car(l))))), expandElementValues(n, cdr(l))); +} + +inline const failable<bool> writeList(const list<value>& l, const xmlTextWriterPtr xml) { + if (isNil(l)) + return true; + + // Write an attribute + const value token(car(l)); + if (isTaggedList(token, attribute)) { + if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)c_str(string(attributeName(token))), (const xmlChar*)c_str(string(attributeValue(token)))) < 0) + return mkfailure<bool>("xmlTextWriterWriteAttribute failed"); + + } else if (isTaggedList(token, element)) { + + // Write an element containing a value + if (elementHasValue(token)) { + const value v = elementValue(token); + if (isList(v)) { + + // Write an element per entry in a list of values + const list<value> e = expandElementValues(elementName(token), v); + writeList(e, xml); + + } else { + + // Write an element with a single value + if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0) + return mkfailure<bool>("xmlTextWriterStartElement failed"); + + // Write its children + const failable<bool> w = writeList(elementChildren(token), xml); + if (!hasContent(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure<bool>("xmlTextWriterEndElement failed"); + } + } + else { + + // Write an element + if (xmlTextWriterStartElement(xml, (const xmlChar*)c_str(string(elementName(token)))) < 0) + return mkfailure<bool>("xmlTextWriterStartElement failed"); + + // Write its children + const failable<bool> w = writeList(elementChildren(token), xml); + if (!hasContent(w)) + return w; + + if (xmlTextWriterEndElement(xml) < 0) + return mkfailure<bool>("xmlTextWriterEndElement failed"); + } + } else { + + // Write XML text + if (xmlTextWriterWriteString(xml, (const xmlChar*)c_str(string(token))) < 0) + return mkfailure<bool>("xmlTextWriterWriteString failed"); + } + + // Go on + return writeList(cdr(l), xml); +} + +/** + * Write a list of values to a libxml2 XML writer. + */ +inline const failable<bool> write(const list<value>& l, const xmlTextWriterPtr xml, bool xmlTag) { + if (xmlTag) { + if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0) + return mkfailure<bool>("xmlTextWriterStartDocument failed"); + } + + const failable<bool> w = writeList(l, xml); + if (!hasContent(w)) + return w; + + if (xmlTag) { + if (xmlTextWriterEndDocument(xml) < 0) + return mkfailure<bool>("xmlTextWriterEndDocument failed"); + } + return true; +} + +/** + * Context passed to the write callback function. + */ +template<typename R> class XMLWriteContext { +public: + inline XMLWriteContext(const lambda<const R(const string&, const R)>& reduce, const R& accum) : reduce(reduce), accum(accum) { + } + + const lambda<const R(const string&, const R)> reduce; + gc_mutable_ref<R> accum; +}; + +/** + * Callback function called by libxml2 to write XML out. + */ +template<typename R> inline int writeCallback(void *context, const char* buffer, int len) { + XMLWriteContext<R>& cx = *(XMLWriteContext<R>*)context; + cx.accum = cx.reduce(string(buffer, len), cx.accum); + return len; +} + +/** + * Convert a list of values to an XML document. + */ +template<typename R> inline const failable<R> writeElements(const lambda<const R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const bool xmlTag) { + XMLWriteContext<R> cx(reduce, initial); + xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback<R>, NULL, &cx, NULL); + if (out == NULL) + return mkfailure<R>("xmlOutputBufferCreateIO failed"); + xmlTextWriterPtr xml = xmlNewTextWriter(out); + if (xml == NULL) + return mkfailure<R>("xmlNewTextWriter failed"); + xmlTextWriterSetIndent(xml, 0); + + const failable<bool> w = write(l, xml, xmlTag); + xmlFreeTextWriter(xml); + if (!hasContent(w)) { + return mkfailure<R>(w); + } + return (R)cx.accum; +} + +template<typename R> inline const failable<R> writeElements(const lambda<const R(const string&, const R)>& reduce, const R& initial, const list<value>& l) { + return writeElements(reduce, initial, l, true); +} + +/** + * Convert a list of values to a list of strings representing an XML document. + */ +inline const failable<list<string> > writeElements(const list<value>& l, const bool xmlTag) { + debug(l, "xml::writeElements"); + const failable<list<string> > ls = writeElements<list<string> >(rcons<string>, list<string>(), l, xmlTag); + if (!hasContent(ls)) + return ls; + return reverse(list<string>(content(ls))); +} + +inline const failable<list<string> > writeElements(const list<value>& l) { + return writeElements(l, true); +} + +} +} +#endif /* tuscany_xml_hpp */ diff --git a/sca-cpp/trunk/modules/xml/xsd-test.cpp b/sca-cpp/trunk/modules/xml/xsd-test.cpp new file mode 100644 index 0000000000..b10ad27379 --- /dev/null +++ b/sca-cpp/trunk/modules/xml/xsd-test.cpp @@ -0,0 +1,107 @@ +/* + * 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 validation of a composite file against an SCDL schema. + */ + +#include "string.hpp" +#include "fstream.hpp" +#include <libxml/xmlreader.h> +#include <libxml/xmlschemas.h> + +namespace tuscany { + +const bool printNode(xmlTextReaderPtr reader) { + const xmlChar* name = xmlTextReaderConstName(reader); + if(name == NULL) + name = (xmlChar *)"<unknown>"; + const xmlChar* const value = xmlTextReaderConstValue(reader); + cerr << xmlTextReaderDepth(reader) << " " << xmlTextReaderNodeType(reader) << " " << name << " " + << xmlTextReaderIsEmptyElement(reader) << " " << xmlTextReaderHasValue(reader); + if(value == NULL) + cerr << endl; + else + cerr << value << endl; + return true; +} + +int xmlRead(void *context, char* buffer, int len) { + return (int)fread(buffer, 1, len, (FILE*)context); +} + +int xmlClose(void *context) { + fclose((FILE*)context); + return 0; +} + +const bool readFile(const char* const xsdfilename, const char* const filename) { + cout << "Loading schema " << xsdfilename << endl; + const xmlDocPtr xsddoc = xmlReadFile(xsdfilename, NULL, XML_PARSE_NONET); + const xmlSchemaParserCtxtPtr xsdctx = xmlSchemaNewDocParserCtxt(xsddoc); + const xmlSchemaPtr xsd = xmlSchemaParse(xsdctx); + const xmlSchemaValidCtxtPtr validctx = xmlSchemaNewValidCtxt(xsd); + + cout << "Reading file " << filename << endl; + FILE* const file = fopen(filename, "r"); + if (file != NULL) { + const xmlTextReaderPtr reader = xmlReaderForIO(xmlRead, xmlClose, file, filename, NULL, XML_PARSE_NONET); + xmlTextReaderSetParserProp(reader, XML_PARSER_DEFAULTATTRS, 1); + xmlTextReaderSetParserProp(reader, XML_PARSER_SUBST_ENTITIES, 1); + + if(reader != NULL) { + xmlTextReaderSchemaValidateCtxt(reader, validctx, 0); + + int rc; + while((rc = xmlTextReaderRead(reader)) == 1) { + printNode(reader); + } + if(xmlTextReaderIsValid(reader) != 1) + cout << "Could not validate document" << endl; + xmlFreeTextReader(reader); + if(rc != 0) + cout << "Could not parse document" << endl; + } else + cout << "Could not create parser" << endl; + } else + cout << "Could not open document" << endl; + + xmlSchemaFreeValidCtxt(validctx); + xmlSchemaFree(xsd); + xmlSchemaFreeParserCtxt(xsdctx); + + return true; +} + +} + +int main(const int argc, const char** const argv) { + tuscany::cout << "Testing..." << tuscany::endl; + if(argc != 3) + return 1; + + tuscany::readFile(argv[1], argv[2]); + + xmlCleanupParser(); + + tuscany::cout << "OK" << tuscany::endl; + return 0; +} |