Add phpspecgen and easyrdf
authorMo McRoberts <mo.mcroberts@bbc.co.uk>
Mon, 09 Sep 2013 21:02:53 +0100
changeset 19 9bb7b2b9b9da
parent 18 e1fa0fe40911
child 20 7eb74bbe9931
Add phpspecgen and easyrdf
easyrdf/CHANGELOG.md
easyrdf/LICENSE.md
easyrdf/Makefile
easyrdf/README.md
easyrdf/composer.json
easyrdf/config/phpcs_ruleset.xml
easyrdf/config/phpunit.xml
easyrdf/config/sami.php
easyrdf/doap.php
easyrdf/docs/01-getting-started.md
easyrdf/docs/02-property-paths.md
easyrdf/examples/artistinfo.php
easyrdf/examples/basic.php
easyrdf/examples/basic_sparql.php
easyrdf/examples/converter.php
easyrdf/examples/dump.php
easyrdf/examples/foafinfo.php
easyrdf/examples/foafmaker.php
easyrdf/examples/graph_direct.php
easyrdf/examples/graphstore.php
easyrdf/examples/graphviz.php
easyrdf/examples/html_tag_helpers.php
easyrdf/examples/httpget.php
easyrdf/examples/parse_rss.php
easyrdf/examples/serialise.php
easyrdf/examples/sparql_queryform.php
easyrdf/examples/uk_postcode.php
easyrdf/examples/villages.php
easyrdf/examples/zend_framework.php
easyrdf/lib/EasyRdf.php
easyrdf/lib/EasyRdf/Collection.php
easyrdf/lib/EasyRdf/Container.php
easyrdf/lib/EasyRdf/Exception.php
easyrdf/lib/EasyRdf/Format.php
easyrdf/lib/EasyRdf/Graph.php
easyrdf/lib/EasyRdf/GraphStore.php
easyrdf/lib/EasyRdf/Http.php
easyrdf/lib/EasyRdf/Http/Client.php
easyrdf/lib/EasyRdf/Http/Response.php
easyrdf/lib/EasyRdf/Literal.php
easyrdf/lib/EasyRdf/Literal/Boolean.php
easyrdf/lib/EasyRdf/Literal/Date.php
easyrdf/lib/EasyRdf/Literal/DateTime.php
easyrdf/lib/EasyRdf/Literal/Decimal.php
easyrdf/lib/EasyRdf/Literal/HTML.php
easyrdf/lib/EasyRdf/Literal/HexBinary.php
easyrdf/lib/EasyRdf/Literal/Integer.php
easyrdf/lib/EasyRdf/Literal/XML.php
easyrdf/lib/EasyRdf/Namespace.php
easyrdf/lib/EasyRdf/ParsedUri.php
easyrdf/lib/EasyRdf/Parser.php
easyrdf/lib/EasyRdf/Parser/Arc.php
easyrdf/lib/EasyRdf/Parser/Exception.php
easyrdf/lib/EasyRdf/Parser/Json.php
easyrdf/lib/EasyRdf/Parser/Ntriples.php
easyrdf/lib/EasyRdf/Parser/Rapper.php
easyrdf/lib/EasyRdf/Parser/RdfPhp.php
easyrdf/lib/EasyRdf/Parser/RdfXml.php
easyrdf/lib/EasyRdf/Parser/Rdfa.php
easyrdf/lib/EasyRdf/Parser/Redland.php
easyrdf/lib/EasyRdf/Parser/Turtle.php
easyrdf/lib/EasyRdf/Resource.php
easyrdf/lib/EasyRdf/Serialiser.php
easyrdf/lib/EasyRdf/Serialiser/Arc.php
easyrdf/lib/EasyRdf/Serialiser/GraphViz.php
easyrdf/lib/EasyRdf/Serialiser/Json.php
easyrdf/lib/EasyRdf/Serialiser/JsonLd.php
easyrdf/lib/EasyRdf/Serialiser/Ntriples.php
easyrdf/lib/EasyRdf/Serialiser/Rapper.php
easyrdf/lib/EasyRdf/Serialiser/RdfPhp.php
easyrdf/lib/EasyRdf/Serialiser/RdfXml.php
easyrdf/lib/EasyRdf/Serialiser/Turtle.php
easyrdf/lib/EasyRdf/Sparql/Client.php
easyrdf/lib/EasyRdf/Sparql/Result.php
easyrdf/lib/EasyRdf/TypeMapper.php
easyrdf/lib/EasyRdf/Utils.php
easyrdf/scripts/copyright_updater.php
easyrdf/test/EasyRdf/CollectionTest.php
easyrdf/test/EasyRdf/ContainerTest.php
easyrdf/test/EasyRdf/ExceptionTest.php
easyrdf/test/EasyRdf/FormatTest.php
easyrdf/test/EasyRdf/GraphStoreTest.php
easyrdf/test/EasyRdf/GraphTest.php
easyrdf/test/EasyRdf/Http/ClientTest.php
easyrdf/test/EasyRdf/Http/MockClient.php
easyrdf/test/EasyRdf/Http/MockClientTest.php
easyrdf/test/EasyRdf/Http/ResponseTest.php
easyrdf/test/EasyRdf/HttpTest.php
easyrdf/test/EasyRdf/Literal/BooleanTest.php
easyrdf/test/EasyRdf/Literal/DateTest.php
easyrdf/test/EasyRdf/Literal/DateTimeTest.php
easyrdf/test/EasyRdf/Literal/DecimalTest.php
easyrdf/test/EasyRdf/Literal/HTMLTest.php
easyrdf/test/EasyRdf/Literal/HexBinaryTest.php
easyrdf/test/EasyRdf/Literal/IntegerTest.php
easyrdf/test/EasyRdf/Literal/XMLTest.php
easyrdf/test/EasyRdf/LiteralTest.php
easyrdf/test/EasyRdf/NamespaceTest.php
easyrdf/test/EasyRdf/ParsedUriTest.php
easyrdf/test/EasyRdf/Parser/ArcTest.php
easyrdf/test/EasyRdf/Parser/ExceptionTest.php
easyrdf/test/EasyRdf/Parser/JsonTest.php
easyrdf/test/EasyRdf/Parser/NtriplesTest.php
easyrdf/test/EasyRdf/Parser/RapperTest.php
easyrdf/test/EasyRdf/Parser/RdfPhpTest.php
easyrdf/test/EasyRdf/Parser/RdfXmlTest.php
easyrdf/test/EasyRdf/Parser/RdfaTest.php
easyrdf/test/EasyRdf/Parser/RedlandTest.php
easyrdf/test/EasyRdf/Parser/TurtleTest.php
easyrdf/test/EasyRdf/ParserTest.php
easyrdf/test/EasyRdf/ResourceTest.php
easyrdf/test/EasyRdf/Serialiser/ArcTest.php
easyrdf/test/EasyRdf/Serialiser/GraphVizTest.php
easyrdf/test/EasyRdf/Serialiser/JsonLdTest.php
easyrdf/test/EasyRdf/Serialiser/JsonTest.php
easyrdf/test/EasyRdf/Serialiser/NtriplesArray.php
easyrdf/test/EasyRdf/Serialiser/NtriplesTest.php
easyrdf/test/EasyRdf/Serialiser/RapperTest.php
easyrdf/test/EasyRdf/Serialiser/RdfPhpTest.php
easyrdf/test/EasyRdf/Serialiser/RdfXmlTest.php
easyrdf/test/EasyRdf/Serialiser/TurtleTest.php
easyrdf/test/EasyRdf/SerialiserTest.php
easyrdf/test/EasyRdf/Sparql/ClientTest.php
easyrdf/test/EasyRdf/Sparql/ResultTest.php
easyrdf/test/EasyRdf/TestCase.php
easyrdf/test/EasyRdf/TypeMapperTest.php
easyrdf/test/EasyRdf/UtilsTest.php
easyrdf/test/FusekiTest.php
easyrdf/test/ParserPerformance.php
easyrdf/test/TestHelper.php
easyrdf/test/cli_example_wrapper.php
easyrdf/test/examples/ArtistinfoTest.php
easyrdf/test/examples/BasicSparqlTest.php
easyrdf/test/examples/BasicTest.php
easyrdf/test/examples/ConverterTest.php
easyrdf/test/examples/DumpTest.php
easyrdf/test/examples/FoafinfoTest.php
easyrdf/test/examples/FoafmakerTest.php
easyrdf/test/examples/GraphdirectTest.php
easyrdf/test/examples/HttpgetTest.php
easyrdf/test/examples/ParseRssTest.php
easyrdf/test/examples/SerialiseTest.php
easyrdf/test/examples/SparqlqueryformTest.php
easyrdf/test/examples/UkpostcodeTest.php
easyrdf/test/examples/VillagesTest.php
easyrdf/test/fixtures/empty.rdf
easyrdf/test/fixtures/foaf.bad-json
easyrdf/test/fixtures/foaf.html
easyrdf/test/fixtures/foaf.json
easyrdf/test/fixtures/foaf.json-triples
easyrdf/test/fixtures/foaf.nt
easyrdf/test/fixtures/foaf.rdf
easyrdf/test/fixtures/foaf.ttl
easyrdf/test/fixtures/http_response_200
easyrdf/test/fixtures/http_response_200_chunked
easyrdf/test/fixtures/http_response_302
easyrdf/test/fixtures/http_response_404
easyrdf/test/fixtures/http_response_500
easyrdf/test/fixtures/not_sparql_result.xml
easyrdf/test/fixtures/rdf-collection.rdf
easyrdf/test/fixtures/rdf-seq.rdf
easyrdf/test/fixtures/rdfa/0001.nt
easyrdf/test/fixtures/rdfa/0001.xhtml
easyrdf/test/fixtures/rdfa/0006.nt
easyrdf/test/fixtures/rdfa/0006.xhtml
easyrdf/test/fixtures/rdfa/0007.nt
easyrdf/test/fixtures/rdfa/0007.xhtml
easyrdf/test/fixtures/rdfa/0008.nt
easyrdf/test/fixtures/rdfa/0008.xhtml
easyrdf/test/fixtures/rdfa/0009.nt
easyrdf/test/fixtures/rdfa/0009.xhtml
easyrdf/test/fixtures/rdfa/0010.nt
easyrdf/test/fixtures/rdfa/0010.xhtml
easyrdf/test/fixtures/rdfa/0012.nt
easyrdf/test/fixtures/rdfa/0012.xhtml
easyrdf/test/fixtures/rdfa/0013.nt
easyrdf/test/fixtures/rdfa/0013.xhtml
easyrdf/test/fixtures/rdfa/0014.nt
easyrdf/test/fixtures/rdfa/0014.xhtml
easyrdf/test/fixtures/rdfa/0015.nt
easyrdf/test/fixtures/rdfa/0015.xhtml
easyrdf/test/fixtures/rdfa/0017.nt
easyrdf/test/fixtures/rdfa/0017.xhtml
easyrdf/test/fixtures/rdfa/0018.nt
easyrdf/test/fixtures/rdfa/0018.xhtml
easyrdf/test/fixtures/rdfa/0019.nt
easyrdf/test/fixtures/rdfa/0019.xhtml
easyrdf/test/fixtures/rdfa/0020.nt
easyrdf/test/fixtures/rdfa/0020.xhtml
easyrdf/test/fixtures/rdfa/0021.nt
easyrdf/test/fixtures/rdfa/0021.xhtml
easyrdf/test/fixtures/rdfa/0023.nt
easyrdf/test/fixtures/rdfa/0023.xhtml
easyrdf/test/fixtures/rdfa/0025.nt
easyrdf/test/fixtures/rdfa/0025.xhtml
easyrdf/test/fixtures/rdfa/0026.nt
easyrdf/test/fixtures/rdfa/0026.xhtml
easyrdf/test/fixtures/rdfa/0027.nt
easyrdf/test/fixtures/rdfa/0027.xhtml
easyrdf/test/fixtures/rdfa/0029.nt
easyrdf/test/fixtures/rdfa/0029.xhtml
easyrdf/test/fixtures/rdfa/0030.nt
easyrdf/test/fixtures/rdfa/0030.xhtml
easyrdf/test/fixtures/rdfa/0031.nt
easyrdf/test/fixtures/rdfa/0031.xhtml
easyrdf/test/fixtures/rdfa/0032.nt
easyrdf/test/fixtures/rdfa/0032.xhtml
easyrdf/test/fixtures/rdfa/0033.nt
easyrdf/test/fixtures/rdfa/0033.xhtml
easyrdf/test/fixtures/rdfa/0034.nt
easyrdf/test/fixtures/rdfa/0034.xhtml
easyrdf/test/fixtures/rdfa/0035.nt
easyrdf/test/fixtures/rdfa/0035.xhtml
easyrdf/test/fixtures/rdfa/0036.nt
easyrdf/test/fixtures/rdfa/0036.xhtml
easyrdf/test/fixtures/rdfa/0037.nt
easyrdf/test/fixtures/rdfa/0037.xhtml
easyrdf/test/fixtures/rdfa/0038.nt
easyrdf/test/fixtures/rdfa/0038.xhtml
easyrdf/test/fixtures/rdfa/0039.nt
easyrdf/test/fixtures/rdfa/0039.xhtml
easyrdf/test/fixtures/rdfa/0041.nt
easyrdf/test/fixtures/rdfa/0041.xhtml
easyrdf/test/fixtures/rdfa/0048.nt
easyrdf/test/fixtures/rdfa/0048.xhtml
easyrdf/test/fixtures/rdfa/0049.nt
easyrdf/test/fixtures/rdfa/0049.xhtml
easyrdf/test/fixtures/rdfa/0050.nt
easyrdf/test/fixtures/rdfa/0050.xhtml
easyrdf/test/fixtures/rdfa/0051.nt
easyrdf/test/fixtures/rdfa/0051.xhtml
easyrdf/test/fixtures/rdfa/0052.nt
easyrdf/test/fixtures/rdfa/0052.xhtml
easyrdf/test/fixtures/rdfa/0053.nt
easyrdf/test/fixtures/rdfa/0053.xhtml
easyrdf/test/fixtures/rdfa/0054.nt
easyrdf/test/fixtures/rdfa/0054.xhtml
easyrdf/test/fixtures/rdfa/0055.nt
easyrdf/test/fixtures/rdfa/0055.xhtml
easyrdf/test/fixtures/rdfa/0056.nt
easyrdf/test/fixtures/rdfa/0056.xhtml
easyrdf/test/fixtures/rdfa/0057.nt
easyrdf/test/fixtures/rdfa/0057.xhtml
easyrdf/test/fixtures/rdfa/0059.nt
easyrdf/test/fixtures/rdfa/0059.xhtml
easyrdf/test/fixtures/rdfa/0060.nt
easyrdf/test/fixtures/rdfa/0060.xhtml
easyrdf/test/fixtures/rdfa/0063.nt
easyrdf/test/fixtures/rdfa/0063.xhtml
easyrdf/test/fixtures/rdfa/0064.nt
easyrdf/test/fixtures/rdfa/0064.xhtml
easyrdf/test/fixtures/rdfa/0065.nt
easyrdf/test/fixtures/rdfa/0065.xhtml
easyrdf/test/fixtures/rdfa/0066.nt
easyrdf/test/fixtures/rdfa/0066.xhtml
easyrdf/test/fixtures/rdfa/0067.nt
easyrdf/test/fixtures/rdfa/0067.xhtml
easyrdf/test/fixtures/rdfa/0068.nt
easyrdf/test/fixtures/rdfa/0068.xhtml
easyrdf/test/fixtures/rdfa/0069.nt
easyrdf/test/fixtures/rdfa/0069.xhtml
easyrdf/test/fixtures/rdfa/0070.nt
easyrdf/test/fixtures/rdfa/0070.xhtml
easyrdf/test/fixtures/rdfa/0071.nt
easyrdf/test/fixtures/rdfa/0071.xhtml
easyrdf/test/fixtures/rdfa/0072.nt
easyrdf/test/fixtures/rdfa/0072.xhtml
easyrdf/test/fixtures/rdfa/0073.nt
easyrdf/test/fixtures/rdfa/0073.xhtml
easyrdf/test/fixtures/rdfa/0074.nt
easyrdf/test/fixtures/rdfa/0074.xhtml
easyrdf/test/fixtures/rdfa/0075.nt
easyrdf/test/fixtures/rdfa/0075.xhtml
easyrdf/test/fixtures/rdfa/0079.nt
easyrdf/test/fixtures/rdfa/0079.xhtml
easyrdf/test/fixtures/rdfa/0080.nt
easyrdf/test/fixtures/rdfa/0080.xhtml
easyrdf/test/fixtures/rdfa/0083.nt
easyrdf/test/fixtures/rdfa/0083.xhtml
easyrdf/test/fixtures/rdfa/0084.nt
easyrdf/test/fixtures/rdfa/0084.xhtml
easyrdf/test/fixtures/rdfa/0085.nt
easyrdf/test/fixtures/rdfa/0085.xhtml
easyrdf/test/fixtures/rdfa/0087.nt
easyrdf/test/fixtures/rdfa/0087.xhtml
easyrdf/test/fixtures/rdfa/0088.nt
easyrdf/test/fixtures/rdfa/0088.xhtml
easyrdf/test/fixtures/rdfa/0089.nt
easyrdf/test/fixtures/rdfa/0089.xhtml
easyrdf/test/fixtures/rdfa/0091.nt
easyrdf/test/fixtures/rdfa/0091.xhtml
easyrdf/test/fixtures/rdfa/0093.nt
easyrdf/test/fixtures/rdfa/0093.xhtml
easyrdf/test/fixtures/rdfa/0099.nt
easyrdf/test/fixtures/rdfa/0099.xhtml
easyrdf/test/fixtures/rdfa/0104.nt
easyrdf/test/fixtures/rdfa/0104.xhtml
easyrdf/test/fixtures/rdfa/0106.nt
easyrdf/test/fixtures/rdfa/0106.xhtml
easyrdf/test/fixtures/rdfa/0107.nt
easyrdf/test/fixtures/rdfa/0107.xhtml
easyrdf/test/fixtures/rdfa/0110.nt
easyrdf/test/fixtures/rdfa/0110.xhtml
easyrdf/test/fixtures/rdfa/0111.nt
easyrdf/test/fixtures/rdfa/0111.xhtml
easyrdf/test/fixtures/rdfa/0112.nt
easyrdf/test/fixtures/rdfa/0112.xhtml
easyrdf/test/fixtures/rdfa/0114.nt
easyrdf/test/fixtures/rdfa/0114.xhtml
easyrdf/test/fixtures/rdfa/0115.nt
easyrdf/test/fixtures/rdfa/0115.xhtml
easyrdf/test/fixtures/rdfa/0117.nt
easyrdf/test/fixtures/rdfa/0117.xhtml
easyrdf/test/fixtures/rdfa/0118.nt
easyrdf/test/fixtures/rdfa/0118.xhtml
easyrdf/test/fixtures/rdfa/0119.nt
easyrdf/test/fixtures/rdfa/0119.xhtml
easyrdf/test/fixtures/rdfa/0120.nt
easyrdf/test/fixtures/rdfa/0120.xhtml
easyrdf/test/fixtures/rdfa/0121.nt
easyrdf/test/fixtures/rdfa/0121.xhtml
easyrdf/test/fixtures/rdfa/0122.nt
easyrdf/test/fixtures/rdfa/0122.xhtml
easyrdf/test/fixtures/rdfa/0126.nt
easyrdf/test/fixtures/rdfa/0126.xhtml
easyrdf/test/fixtures/rdfa/0131.nt
easyrdf/test/fixtures/rdfa/0131.xhtml
easyrdf/test/fixtures/rdfa/0134.nt
easyrdf/test/fixtures/rdfa/0134.xhtml
easyrdf/test/fixtures/rdfa/0140.nt
easyrdf/test/fixtures/rdfa/0140.xhtml
easyrdf/test/fixtures/rdfa/0147.nt
easyrdf/test/fixtures/rdfa/0147.xhtml
easyrdf/test/fixtures/rdfa/0174.nt
easyrdf/test/fixtures/rdfa/0174.xhtml
easyrdf/test/fixtures/rdfa/0175.nt
easyrdf/test/fixtures/rdfa/0175.xhtml
easyrdf/test/fixtures/rdfa/0176.nt
easyrdf/test/fixtures/rdfa/0176.xhtml
easyrdf/test/fixtures/rdfa/0177.nt
easyrdf/test/fixtures/rdfa/0177.xhtml
easyrdf/test/fixtures/rdfa/0178.nt
easyrdf/test/fixtures/rdfa/0178.xhtml
easyrdf/test/fixtures/rdfa/0179.nt
easyrdf/test/fixtures/rdfa/0179.xhtml
easyrdf/test/fixtures/rdfa/0180.nt
easyrdf/test/fixtures/rdfa/0180.xhtml
easyrdf/test/fixtures/rdfa/0181.nt
easyrdf/test/fixtures/rdfa/0181.xhtml
easyrdf/test/fixtures/rdfa/0182.nt
easyrdf/test/fixtures/rdfa/0182.xhtml
easyrdf/test/fixtures/rdfa/0183.nt
easyrdf/test/fixtures/rdfa/0183.xhtml
easyrdf/test/fixtures/rdfa/0186.nt
easyrdf/test/fixtures/rdfa/0186.xhtml
easyrdf/test/fixtures/rdfa/0187.nt
easyrdf/test/fixtures/rdfa/0187.xhtml
easyrdf/test/fixtures/rdfa/0188.nt
easyrdf/test/fixtures/rdfa/0188.xhtml
easyrdf/test/fixtures/rdfa/0189.nt
easyrdf/test/fixtures/rdfa/0189.xhtml
easyrdf/test/fixtures/rdfa/0190.nt
easyrdf/test/fixtures/rdfa/0190.xhtml
easyrdf/test/fixtures/rdfa/0196.nt
easyrdf/test/fixtures/rdfa/0196.xhtml
easyrdf/test/fixtures/rdfa/0197.nt
easyrdf/test/fixtures/rdfa/0197.xhtml
easyrdf/test/fixtures/rdfa/0198.nt
easyrdf/test/fixtures/rdfa/0198.xhtml
easyrdf/test/fixtures/rdfa/0206.nt
easyrdf/test/fixtures/rdfa/0206.xhtml
easyrdf/test/fixtures/rdfa/0207.nt
easyrdf/test/fixtures/rdfa/0207.xhtml
easyrdf/test/fixtures/rdfa/0213.nt
easyrdf/test/fixtures/rdfa/0213.xhtml
easyrdf/test/fixtures/rdfa/0214.nt
easyrdf/test/fixtures/rdfa/0214.xhtml
easyrdf/test/fixtures/rdfa/0216.nt
easyrdf/test/fixtures/rdfa/0216.xhtml
easyrdf/test/fixtures/rdfa/0217.nt
easyrdf/test/fixtures/rdfa/0217.xhtml
easyrdf/test/fixtures/rdfa/0218.nt
easyrdf/test/fixtures/rdfa/0218.xhtml
easyrdf/test/fixtures/rdfa/0219.nt
easyrdf/test/fixtures/rdfa/0219.xhtml
easyrdf/test/fixtures/rdfa/0220.nt
easyrdf/test/fixtures/rdfa/0220.xhtml
easyrdf/test/fixtures/rdfa/0221.nt
easyrdf/test/fixtures/rdfa/0221.xhtml
easyrdf/test/fixtures/rdfa/0222.nt
easyrdf/test/fixtures/rdfa/0222.xhtml
easyrdf/test/fixtures/rdfa/0223.nt
easyrdf/test/fixtures/rdfa/0223.xhtml
easyrdf/test/fixtures/rdfa/0224.nt
easyrdf/test/fixtures/rdfa/0224.xhtml
easyrdf/test/fixtures/rdfa/0225.nt
easyrdf/test/fixtures/rdfa/0225.xhtml
easyrdf/test/fixtures/rdfa/0226.nt
easyrdf/test/fixtures/rdfa/0226.xhtml
easyrdf/test/fixtures/rdfa/0227.nt
easyrdf/test/fixtures/rdfa/0227.xhtml
easyrdf/test/fixtures/rdfa/0228.nt
easyrdf/test/fixtures/rdfa/0228.xhtml
easyrdf/test/fixtures/rdfa/0229.nt
easyrdf/test/fixtures/rdfa/0229.xhtml
easyrdf/test/fixtures/rdfa/0230.nt
easyrdf/test/fixtures/rdfa/0230.xhtml
easyrdf/test/fixtures/rdfa/0231.nt
easyrdf/test/fixtures/rdfa/0231.xhtml
easyrdf/test/fixtures/rdfa/0232.nt
easyrdf/test/fixtures/rdfa/0232.xhtml
easyrdf/test/fixtures/rdfa/0233.nt
easyrdf/test/fixtures/rdfa/0233.xhtml
easyrdf/test/fixtures/rdfa/0234.nt
easyrdf/test/fixtures/rdfa/0234.xhtml
easyrdf/test/fixtures/rdfa/0246.nt
easyrdf/test/fixtures/rdfa/0246.xhtml
easyrdf/test/fixtures/rdfa/0247.nt
easyrdf/test/fixtures/rdfa/0247.xhtml
easyrdf/test/fixtures/rdfa/0248.nt
easyrdf/test/fixtures/rdfa/0248.xhtml
easyrdf/test/fixtures/rdfa/0249.nt
easyrdf/test/fixtures/rdfa/0249.xhtml
easyrdf/test/fixtures/rdfa/0250.nt
easyrdf/test/fixtures/rdfa/0250.xhtml
easyrdf/test/fixtures/rdfa/0251.nt
easyrdf/test/fixtures/rdfa/0251.xhtml
easyrdf/test/fixtures/rdfa/0252.nt
easyrdf/test/fixtures/rdfa/0252.xhtml
easyrdf/test/fixtures/rdfa/0253.nt
easyrdf/test/fixtures/rdfa/0253.xhtml
easyrdf/test/fixtures/rdfa/0254.nt
easyrdf/test/fixtures/rdfa/0254.xhtml
easyrdf/test/fixtures/rdfa/0255.nt
easyrdf/test/fixtures/rdfa/0255.xhtml
easyrdf/test/fixtures/rdfa/0256.nt
easyrdf/test/fixtures/rdfa/0256.xhtml
easyrdf/test/fixtures/rdfa/0257.nt
easyrdf/test/fixtures/rdfa/0257.xhtml
easyrdf/test/fixtures/rdfa/0258.nt
easyrdf/test/fixtures/rdfa/0258.xhtml
easyrdf/test/fixtures/rdfa/0259.nt
easyrdf/test/fixtures/rdfa/0259.xhtml
easyrdf/test/fixtures/rdfa/0261.nt
easyrdf/test/fixtures/rdfa/0261.xhtml
easyrdf/test/fixtures/rdfa/0262.nt
easyrdf/test/fixtures/rdfa/0262.xhtml
easyrdf/test/fixtures/rdfa/0263.nt
easyrdf/test/fixtures/rdfa/0263.xhtml
easyrdf/test/fixtures/rdfa/0264.nt
easyrdf/test/fixtures/rdfa/0264.xhtml
easyrdf/test/fixtures/rdfa/0265.nt
easyrdf/test/fixtures/rdfa/0265.xhtml
easyrdf/test/fixtures/rdfa/0266.nt
easyrdf/test/fixtures/rdfa/0266.xhtml
easyrdf/test/fixtures/rdfa/0267.nt
easyrdf/test/fixtures/rdfa/0267.xhtml
easyrdf/test/fixtures/rdfa/0268.nt
easyrdf/test/fixtures/rdfa/0268.xhtml
easyrdf/test/fixtures/rdfa/0269.nt
easyrdf/test/fixtures/rdfa/0269.xhtml
easyrdf/test/fixtures/rdfa/0271.nt
easyrdf/test/fixtures/rdfa/0271.xhtml
easyrdf/test/fixtures/rdfa/0272.nt
easyrdf/test/fixtures/rdfa/0272.xhtml
easyrdf/test/fixtures/rdfa/0273.nt
easyrdf/test/fixtures/rdfa/0273.xhtml
easyrdf/test/fixtures/rdfa/0274.nt
easyrdf/test/fixtures/rdfa/0274.xhtml
easyrdf/test/fixtures/rdfa/0275.nt
easyrdf/test/fixtures/rdfa/0275.xhtml
easyrdf/test/fixtures/rdfa/0276.nt
easyrdf/test/fixtures/rdfa/0276.xhtml
easyrdf/test/fixtures/rdfa/0277.nt
easyrdf/test/fixtures/rdfa/0277.xhtml
easyrdf/test/fixtures/rdfa/0278.nt
easyrdf/test/fixtures/rdfa/0278.xhtml
easyrdf/test/fixtures/rdfa/0279.nt
easyrdf/test/fixtures/rdfa/0279.xhtml
easyrdf/test/fixtures/rdfa/0280.nt
easyrdf/test/fixtures/rdfa/0280.xhtml
easyrdf/test/fixtures/rdfa/0281.nt
easyrdf/test/fixtures/rdfa/0281.xhtml
easyrdf/test/fixtures/rdfa/0282.nt
easyrdf/test/fixtures/rdfa/0282.xhtml
easyrdf/test/fixtures/rdfa/0283.nt
easyrdf/test/fixtures/rdfa/0283.xhtml
easyrdf/test/fixtures/rdfa/0284.nt
easyrdf/test/fixtures/rdfa/0284.xhtml
easyrdf/test/fixtures/rdfa/0285.nt
easyrdf/test/fixtures/rdfa/0285.xhtml
easyrdf/test/fixtures/rdfa/0286.nt
easyrdf/test/fixtures/rdfa/0286.xhtml
easyrdf/test/fixtures/rdfa/0287.nt
easyrdf/test/fixtures/rdfa/0287.xhtml
easyrdf/test/fixtures/rdfa/0289.nt
easyrdf/test/fixtures/rdfa/0289.xhtml
easyrdf/test/fixtures/rdfa/0290.nt
easyrdf/test/fixtures/rdfa/0290.xhtml
easyrdf/test/fixtures/rdfa/0291.nt
easyrdf/test/fixtures/rdfa/0291.xhtml
easyrdf/test/fixtures/rdfa/0292.nt
easyrdf/test/fixtures/rdfa/0292.xhtml
easyrdf/test/fixtures/rdfa/0293.nt
easyrdf/test/fixtures/rdfa/0293.xhtml
easyrdf/test/fixtures/rdfa/0295.nt
easyrdf/test/fixtures/rdfa/0295.xhtml
easyrdf/test/fixtures/rdfa/0296.nt
easyrdf/test/fixtures/rdfa/0296.xhtml
easyrdf/test/fixtures/rdfa/0297.nt
easyrdf/test/fixtures/rdfa/0297.xhtml
easyrdf/test/fixtures/rdfa/0298.nt
easyrdf/test/fixtures/rdfa/0298.xhtml
easyrdf/test/fixtures/rdfa/0299.nt
easyrdf/test/fixtures/rdfa/0299.xhtml
easyrdf/test/fixtures/rdfa/0300.nt
easyrdf/test/fixtures/rdfa/0300.xhtml
easyrdf/test/fixtures/rdfa/0301.nt
easyrdf/test/fixtures/rdfa/0301.xhtml
easyrdf/test/fixtures/rdfa/0302.nt
easyrdf/test/fixtures/rdfa/0302.xhtml
easyrdf/test/fixtures/rdfa/0303.nt
easyrdf/test/fixtures/rdfa/0303.xhtml
easyrdf/test/fixtures/rdfa/0311.nt
easyrdf/test/fixtures/rdfa/0311.xhtml
easyrdf/test/fixtures/rdfa/0312.nt
easyrdf/test/fixtures/rdfa/0312.xhtml
easyrdf/test/fixtures/rdfa/0315.nt
easyrdf/test/fixtures/rdfa/0315.xhtml
easyrdf/test/fixtures/rdfa/0316.nt
easyrdf/test/fixtures/rdfa/0316.xhtml
easyrdf/test/fixtures/rdfa/0317.nt
easyrdf/test/fixtures/rdfa/0317.xhtml
easyrdf/test/fixtures/rdfa/update.php
easyrdf/test/fixtures/sparql_ask_false.json
easyrdf/test/fixtures/sparql_ask_false.xml
easyrdf/test/fixtures/sparql_ask_true.json
easyrdf/test/fixtures/sparql_ask_true.xml
easyrdf/test/fixtures/sparql_invalid.json
easyrdf/test/fixtures/sparql_invalid.xml
easyrdf/test/fixtures/sparql_invalid_term.json
easyrdf/test/fixtures/sparql_select_all.json
easyrdf/test/fixtures/sparql_select_all.xml
easyrdf/test/fixtures/sparql_select_all_types.xml
easyrdf/test/fixtures/sparql_select_all_ws.xml
easyrdf/test/fixtures/sparql_select_count.json
easyrdf/test/fixtures/sparql_select_count_zero.json
easyrdf/test/fixtures/sparql_select_empty.json
easyrdf/test/fixtures/sparql_select_empty.xml
easyrdf/test/fixtures/sparql_select_lang.json
easyrdf/test/fixtures/sparql_select_lang.xml
easyrdf/test/fixtures/sparql_select_named_graphs.json
easyrdf/test/fixtures/sparql_select_unbound.xml
easyrdf/test/fixtures/sparql_typed_literal.json
easyrdf/test/fixtures/sparql_typed_literal.xml
easyrdf/test/fixtures/turtle/README.txt
easyrdf/test/fixtures/turtle/bad-00.ttl
easyrdf/test/fixtures/turtle/bad-01.ttl
easyrdf/test/fixtures/turtle/bad-02.ttl
easyrdf/test/fixtures/turtle/bad-03.ttl
easyrdf/test/fixtures/turtle/bad-04.ttl
easyrdf/test/fixtures/turtle/bad-05.ttl
easyrdf/test/fixtures/turtle/bad-06.ttl
easyrdf/test/fixtures/turtle/bad-07.ttl
easyrdf/test/fixtures/turtle/bad-08.ttl
easyrdf/test/fixtures/turtle/bad-09.ttl
easyrdf/test/fixtures/turtle/bad-10.ttl
easyrdf/test/fixtures/turtle/bad-11.ttl
easyrdf/test/fixtures/turtle/bad-12.ttl
easyrdf/test/fixtures/turtle/bad-13.ttl
easyrdf/test/fixtures/turtle/bad-14.ttl
easyrdf/test/fixtures/turtle/base1.out
easyrdf/test/fixtures/turtle/base1.ttl
easyrdf/test/fixtures/turtle/quotes1.out
easyrdf/test/fixtures/turtle/quotes1.ttl
easyrdf/test/fixtures/turtle/rdf-schema.out
easyrdf/test/fixtures/turtle/rdf-schema.ttl
easyrdf/test/fixtures/turtle/test-00.out
easyrdf/test/fixtures/turtle/test-00.ttl
easyrdf/test/fixtures/turtle/test-01.out
easyrdf/test/fixtures/turtle/test-01.ttl
easyrdf/test/fixtures/turtle/test-02.out
easyrdf/test/fixtures/turtle/test-02.ttl
easyrdf/test/fixtures/turtle/test-03.out
easyrdf/test/fixtures/turtle/test-03.ttl
easyrdf/test/fixtures/turtle/test-04.out
easyrdf/test/fixtures/turtle/test-04.ttl
easyrdf/test/fixtures/turtle/test-05.out
easyrdf/test/fixtures/turtle/test-05.ttl
easyrdf/test/fixtures/turtle/test-06.out
easyrdf/test/fixtures/turtle/test-06.ttl
easyrdf/test/fixtures/turtle/test-07.out
easyrdf/test/fixtures/turtle/test-07.ttl
easyrdf/test/fixtures/turtle/test-08.out
easyrdf/test/fixtures/turtle/test-08.ttl
easyrdf/test/fixtures/turtle/test-09.out
easyrdf/test/fixtures/turtle/test-09.ttl
easyrdf/test/fixtures/turtle/test-10.out
easyrdf/test/fixtures/turtle/test-10.ttl
easyrdf/test/fixtures/turtle/test-11.out
easyrdf/test/fixtures/turtle/test-11.ttl
easyrdf/test/fixtures/turtle/test-12.out
easyrdf/test/fixtures/turtle/test-12.ttl
easyrdf/test/fixtures/turtle/test-13.out
easyrdf/test/fixtures/turtle/test-13.ttl
easyrdf/test/fixtures/turtle/test-17.out
easyrdf/test/fixtures/turtle/test-17.ttl
easyrdf/test/fixtures/turtle/test-18.out
easyrdf/test/fixtures/turtle/test-18.ttl
easyrdf/test/fixtures/turtle/test-19.out
easyrdf/test/fixtures/turtle/test-19.ttl
easyrdf/test/fixtures/turtle/test-20.out
easyrdf/test/fixtures/turtle/test-20.ttl
easyrdf/test/fixtures/turtle/test-21.out
easyrdf/test/fixtures/turtle/test-21.ttl
easyrdf/test/fixtures/turtle/test-22.out
easyrdf/test/fixtures/turtle/test-22.ttl
easyrdf/test/fixtures/turtle/test-23.out
easyrdf/test/fixtures/turtle/test-23.ttl
easyrdf/test/fixtures/turtle/test-24.out
easyrdf/test/fixtures/turtle/test-24.ttl
easyrdf/test/fixtures/turtle/test-25.out
easyrdf/test/fixtures/turtle/test-25.ttl
easyrdf/test/fixtures/turtle/test-26.out
easyrdf/test/fixtures/turtle/test-26.ttl
easyrdf/test/fixtures/turtle/test-27.out
easyrdf/test/fixtures/turtle/test-27.ttl
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-01.out
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-01.ttl
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-02.out
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-02.ttl
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-03.out
easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-03.ttl
easyrdf/test/fixtures/webid.ttl
easyrdf/test/fixtures/xml_literal.rdf
easyrdf/test/testcases/rdfxml-testcases.php
phpspecgen/README.md
phpspecgen/composer.json
phpspecgen/phpspecgen.php
phpspecgen/style.css
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/CHANGELOG.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,256 @@
+EasyRdf 0.8.0
+=============
+
+API changes
+-----------
+* is_a() has been renamed to isA()
+* isBnode() has been renamed to isBNode()
+* getNodeId() has been renamed to getBNodeId()
+
+Major new features
+------------------
+* Now PSR-2 compliant
+* Added RDFa parser
+
+Enhancements
+------------
+
+Bug Fixes
+---------
+
+
+
+EasyRdf 0.7.2
+=============
+
+Enhancements
+------------
+* Removed automatic registration of ARC2 and librdf parsers and serialisers
+** You must now specifically choose the parser or serialiser
+* Refactored `EasyRdf_Literal` with datatypes so that it preserves exact value
+* Changed Turtle serialiser to not escape Unicode characters unnecessarily
+* Fix for escaping literals objects in Turtle serialiser
+* Added a new static function `newAndLoad()` to `EasyRdf_Graph`
+* Added setters for each of the components of the URI to the class `EasyRdf_ParsedUri`
+* Added option to the converter example, to allow raw output, without any HTML
+
+Bug Fixes
+---------
+* Fixed broken Redland parser (thanks to Jon Phipps)
+* Fix for serialising two bnodes that reference each other in Turtle
+* Added support for parsing literals with single quotes in Turtle
+* Removed require for EasyRdf/Exception.php
+* Fix for serialising `EasyRdf_Literal_DateTime` to Turtle
+* Fix for serialising Turtle literals with a shorthand syntax
+* Several typo fixes and minor corrections
+
+
+EasyRdf 0.7.1
+=============
+
+Enhancements
+------------
+* Changed minimum version of PHPUnit to 3.5.15
+* Added RDFa namespace
+* Added Open Graph Protocol namespace
+* Made improvements to formatting of the Turtle serialiser
+* Added new splitUri() function to EasyRdf_Namespace
+* Made improvements to format guessing
+
+Bug Fixes
+---------
+* Fix for RDF/XML parser not returning the number of triples
+* Added re-mapping of b-nodes to N-Triples and Redland parsers
+
+
+EasyRdf 0.7.0
+=============
+
+API Changes
+-----------
+* You must now wrap full property URIs in angle brackets
+
+Major new features
+------------------
+* Added a new pure-PHP Turtle parser
+* Added basic property-path support for traversing graphs
+* Added support for serialising to the GraphViz dot format (and generating images)
+* Added a new class `EasyRdf_ParsedUri` - a RFC3986 compliant URI parser
+
+Enhancements
+------------
+* The load() function in `EasyRdf_Graph` no-longer takes a $data argument
+* The parse() and load() methods, now return the number of triples parsed
+* Added count() method to `EasyRdf_Resource` and `EasyRdf_Graph`
+* Added localName() method to `EasyRdf_Resource`
+* Added htmlLink() method to `EasyRdf_Resource`
+* Added methods deleteResource() and deleteLiteral() to `EasyRdf_Graph`
+* Added support for guessing the file format based on the file extension
+* Performance improvements to built-in serialisers
+
+Environment changes
+-------------------
+* Added PHP Composer description to the project
+* Now properly PSR-0 autoloader compatible
+* New minimum version of PHP is 5.2.8
+* Changed test suite to require PHPUnit 3.6
+* Changed from Phing to GNU Make based build system
+* Added automated testing of the examples
+
+Bug Fixes
+---------
+* Fix for loading https:// URLs
+* Fix for storing the value 0 in a `EasyRdf_Graph`
+* Fix for HTTP servers that return relative URIs in the Location header
+* Fix for Literals with languages in the SPARQL Query Results XML Format
+* Fix for SPARQL servers that put extra whitespace into the XML result
+* Fix for the httpget.php example in PHP 5.4+
+
+
+EasyRdf 0.6.3
+=============
+* Added $graph->parseFile() method.
+* Added support for SSL (https) to the built-in HTTP client
+* Fixes for HTTP responses with a charset parameter in the Content Type.
+* Improved error handling and empty documents in JSON and rapper parsers.
+* Added connivence class for xsd:hexBinary literals:
+  - `EasyRdf_Literal_HexBinary`
+* Made EasyRdf more tolerant of 'badly serialised bnodes'
+* Fix for SPARQL servers that return charset in the MIME Type.
+* Fix for using xml:lang in SPARQL 1.1 Query Results JSON Format
+* Changed datetime ISO formatting to use 'Z' instead of +0000 for UTC dateTimes
+* Added the namespace for 'The Cert Ontology' to EasyRdf.
+
+
+EasyRdf 0.6.2
+=============
+* Bug fix for missing triples in the RDF/XML serialiser.
+* Added countTriples() method to `EasyRdf_Graph`.
+* Re-factored the mechanism for mapping RDF datatypes to PHP classes.
+* Added subclasses of `EasyRdf_Literal` for various XSD datatypes:
+  - `EasyRdf_Literal_Boolean`
+  - `EasyRdf_Literal_Date`
+  - `EasyRdf_Literal_DateTime`
+  - `EasyRdf_Literal_Decimal`
+  - `EasyRdf_Literal_Integer`
+* Made the Redland based parser write triples directly to `EasyRdf_Graph`
+* Added support for datatypes and languages in the `EasyRdf_Parser_Ntriples` parser.
+* Fix for parsing XML Literals in RDF/XML
+
+
+EasyRdf 0.6.1
+=============
+* Updated API documentation for new classes and methods added in 0.6.0
+* Added a description to the top of the source code for each example.
+* Changed the generated bnode identifier names from eidXXX to genidXXX.
+* Implemented inlining of resources in the RDF/XML serialiser.
+* Added new reversePropertyUris() method to `EasyRdf_Graph` and `EasyRdf_Resource`.
+* Added addType() and setType() to `EasyRdf_Resource`.
+* Added a textarea to the converter example.
+* Added support for parsing the json-triples format.
+* Renamed `EasyRdf_SparqlClient` to `EasyRdf_Sparql_Client`
+* Renamed `EasyRdf_SparqlResult` to `EasyRdf_Sparql_Result`
+* Fix for $graph->isEmpty() failing after adding and deleting some triples
+* Added new `EasyRdf_DatatypeMapper` class that allows you to map RDF datatypes to PHP classes.
+* Renamed guessDatatype() to getDatatypeForValue() in `EasyRdf_Literal`.
+* Added getResource() and allResources() to `EasyRdf_Graph` and `EasyRdf_Resource`
+* Implemented value casting in literals based on the datatype.
+
+
+EasyRdf 0.6.0
+=============
+* Major re-factor of the way data is stored internally in `EasyRdf_Graph`.
+* Parsing and serialising is now much faster and will enable further optimisations.
+* API is mostly backwards-compatible apart from:
+  - Changed inverse property operator from - to ^ to match Sparql 1.1 property paths.
+  - New `EasyRdf_Graphs` will not automatically be loaded on creation
+    You must now call $graph->load();
+  - Setting the default HTTP client is now part of a new `EasyRdf_Http` class
+  - It is no-longer possible to add multiple properties at once using an associative array.
+* Added methods to `EasyRdf_Graph` for direct manipulation of triples.
+* Added new `EasyRdf_GraphStore` - class for fetching, saving and deleting graphs to a Graph Store over HTTP.
+* Added new `EasyRdf_SparqlClient` and `EasyRdf_SparqlResult` - class for querying a SPARQL endpoint over HTTP.
+* Added q values for each Mime-Type associated with an `EasyRdf_Format`.
+* New example demonstrating integration with the Zend Framework.
+* New `EasyRdf_HTTP_MockClient` class makes testing easier.
+
+
+EasyRdf 0.5.2
+=============
+* Added a built-in RDF/XML parser
+* Made the RDF/XML serialiser use the rdf:type to open tags
+* Added support for comments in the N-Triples parser
+* Added new resolveUriReference() function to `EasyRdf_Utils`
+* Added the application/rdf+json and text/rdf+n3 mime types
+
+
+EasyRdf 0.5.1
+=============
+* Bug fixes for PHP 5.2
+
+
+EasyRdf 0.5.0
+=============
+* Added support for inverse properties.
+* Updated RDF/XML and Turtle serialisers to create new namespaces if possible.
+* Added new is_a($type) method to `EasyRdf_Resource`.
+* Added support for passing an array of properties to the get() method.
+* Added primaryTopic() method to `EasyRdf_Resource`.
+* The function label() in `EasyRdf_Resource` will no longer attempted to shorten the URI,
+  if there is no label available.
+* Resource types are now stored as resources, instead of shortened URIs.
+* Added support for deleting a specific value for property to `EasyRdf_Resource`.
+* Properties and datatypes are now stored as full URIs and not
+  converted to qnames during import.
+* Change the TypeMapper to store full URIs internally.
+* Added bibo and geo to the set of default namespaces.
+* Improved bnode links in dump format
+* Fix for converting non-string `EasyRdf_Literal` to string.
+* Created an example that resolves UK postcodes using uk-postcodes.com.
+
+
+EasyRdf 0.4.0
+=============
+* Moved source code to Github
+* Added an `EasyRdf_Literal` class
+* Added proper support for Datatypes and Languages
+* Added built-in RDF/XML serialiser
+* Added built-in Turtle serialiser
+* Added a new `EasyRdf_Format` class to deal with mime types etc.
+* finished a major refactoring of the Parser/Serialiser registration
+* removed all parsing related code from `EasyRdf_Graph`
+* Added a basic serialisation example
+* Added additional common namespaces
+* Test fixes
+
+
+EasyRdf 0.3.0
+=============
+* Generated Wiki pages from phpdoc
+* Filtering of literals by language
+* Moved parsers into `EasyRdf_Parser_XXX` namespace
+* Added support for serialisation
+* Wrote RDF generation example (foafmaker.php)
+* Added built-in ntriples parser/generator
+* Added built-in RDF/PHP serialiser
+* Added built-in RDF/JSON serialiser
+* Added SKOS and RSS to the set of default namespaces.
+
+
+EasyRdf 0.2.0
+=============
+* Added support for Redland PHP bindings
+* Added support for n-triples document type.
+* Improved blank node handing and added newBNode() method to `EasyRdf_Graph`.
+* Add option to `EasyRdf_RapperParser` to choose location of rapper command
+* Added Rails style HTML tag helpers to examples to make them simpler
+
+
+EasyRdf 0.1.0
+=============
+* First public release
+* Support for ARC2 and Rapper
+* Built-in HTTP Client
+* API Documentation
+* PHP Unit tests for every class.
+* Several usage examples
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/LICENSE.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,23 @@
+LICENSE
+=======
+
+Copyright (c) 2009-2011 Nicholas J Humfrey.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * The name of the author 'Nicholas J Humfrey" may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/Makefile	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,152 @@
+PACKAGE = easyrdf
+VERSION = $(shell php -r "print json_decode(file_get_contents('composer.json'))->version;")
+distdir = $(PACKAGE)-$(VERSION)
+PHP = $(shell which php)
+COMPOSER_FLAGS=--no-ansi --no-interaction
+PHPUNIT = vendor/bin/phpunit 
+PHPUNIT_FLAGS = -c config/phpunit.xml
+PHPCS = vendor/bin/phpcs
+PHPCS_FLAGS = --standard=./config/phpcs_ruleset.xml --encoding=utf8 --extensions=php
+SAMI = vendor/bin/sami.php
+
+# Composer doesn't work with bsdtar - try and use GNU tar
+TAR = $(shell which gtar || which gnutar || which tar)
+
+# Disable copying extended attributes and resource forks on Mac OS X
+export COPYFILE_DISABLE=true
+
+EXAMPLE_FILES = examples/*.php
+SOURCE_FILES = lib/EasyRdf.php \
+               lib/EasyRdf/*.php \
+               lib/EasyRdf/*/*.php
+TEST_FILES = test/*/*Test.php \
+             test/*/*/*Test.php
+TEST_SUPPORT = Makefile test/cli_example_wrapper.php \
+               test/TestHelper.php \
+               test/EasyRdf/TestCase.php \
+               test/EasyRdf/Http/MockClient.php \
+               test/EasyRdf/Serialiser/NtriplesArray.php \
+               test/fixtures/*
+DOC_FILES = docs/*.md \
+            docs/api
+INFO_FILES = composer.json \
+             doap.rdf \
+             README.md \
+             LICENSE.md \
+             CHANGELOG.md
+
+DISTFILES = $(EXAMPLE_FILES) $(SOURCE_FILES) $(TEST_FILES) \
+            $(TEST_SUPPORT) $(INFO_FILES) $(DOC_FILES)
+
+
+.DEFAULT: help
+all: help
+
+# TARGET:test                Run all the PHPUnit tests
+.PHONY: test
+test: $(PHPUNIT)
+	mkdir -p reports
+	$(PHP) $(PHPUNIT) $(PHPUNIT_FLAGS)
+
+# TARGET:test-examples       Run PHPUnit tests for each of the examples
+.PHONY: test-examples
+test-examples: $(PHPUNIT)
+	mkdir -p reports
+	$(PHP) $(PHPUNIT) $(PHPUNIT_FLAGS) --testsuite "EasyRdf Examples"
+
+# TARGET:test-lib            Run PHPUnit tests for the library
+.PHONY: test-lib
+test-lib: $(PHPUNIT)
+	mkdir -p reports
+	$(PHP) $(PHPUNIT) $(PHPUNIT_FLAGS) --testsuite "EasyRdf Library"
+
+# TARGET:coverage            Run library tests and generate coverage report
+.PHONY: coverage
+coverage: $(PHPUNIT)
+	mkdir -p reports/coverage
+	$(PHP) $(PHPUNIT) $(PHPUNIT_FLAGS) --coverage-html ./reports/coverage --testsuite "EasyRdf Library"
+
+# TARGET:apidocs             Generate HTML API documentation
+.PHONY: apidocs
+apidocs: $(SAMI)
+	$(PHP) $(SAMI) update config/sami.php -n -v --force
+
+docs/api: apidocs
+
+doap.rdf: doap.php composer.json vendor/autoload.php
+	$(PHP) doap.php > doap.rdf
+
+# TARGET:cs                  Check the code style of the PHP source code
+.PHONY: cs
+cs: $(PHPCS)
+	$(PHPCS) $(PHPCS_FLAGS) lib test
+
+# TARGET:lint                Perform basic PHP syntax check on all files
+.PHONY: lint
+lint: $(EXAMPLE_FILES) $(SOURCE_FILES) $(TEST_FILES)
+	@for file in $^; do  \
+	  $(PHP) -l $$file || exit -1; \
+	done
+
+# TARGET:dist                Build archives for distribution
+.PHONY: dist
+dist: $(distdir).tar.gz
+	rm -Rf $(distdir)
+	@echo "Done."
+
+%.tar.gz: %
+	$(TAR) zcf $@ $^
+
+$(distdir): $(DISTFILES)
+	$(gatherfiles)
+
+define gatherfiles
+	@for file in $^; do  \
+		dir=$@/`dirname "$$file"`; \
+		test -d "$$dir" || mkdir -p "$$dir" || exit -1; \
+		cp -Rfp "$$file" "$@/$$file" || exit -1; \
+	done
+endef
+
+# TARGET:clean               Delete any temporary and generated files
+.PHONY: clean
+clean:
+	find . -name '.DS_Store' -type f -delete
+	-rm -Rf $(distdir) reports vendor
+	-rm -Rf docs/api samicache
+	-rm -f composer.phar composer.lock
+	-rm -f doap.rdf
+
+# TARGET:check-fixme         Scan for files containing the words TODO or FIXME
+.PHONY: check-fixme
+check-fixme:
+	@git grep -n -E 'FIXME|TODO' || echo "No FIXME or TODO lines found."
+
+# TARGET:help                You're looking at it!
+.PHONY: help
+help:
+	# Usage:
+	#   make <target> [OPTION=value]
+	#
+	# Targets:
+	@egrep "^# TARGET:" [Mm]akefile | sed 's/^# TARGET:/#   /'
+	#
+	# Options:
+	#   PHP                 Path to php
+
+
+
+# Composer rules
+composer.phar:
+	curl -s -z composer.phar -o composer.phar http://getcomposer.org/composer.phar
+
+composer-install: composer.phar
+	$(PHP) composer.phar $(COMPOSER_FLAGS) install --dev
+
+composer-update: clean composer.phar
+	$(PHP) composer.phar $(COMPOSER_FLAGS) update --dev
+
+vendor/autoload.php: composer-install
+vendor/bin/phpunit: composer-install
+vendor/bin/phpcs: composer-install
+vendor/bin/sami.php: composer-install
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/README.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,111 @@
+EasyRdf
+=======
+EasyRdf is a PHP library designed to make it easy to consume and produce [RDF].
+It was designed for use in mixed teams of experienced and inexperienced RDF
+developers. It is written in Object Oriented PHP and has been tested
+extensively using PHPUnit.
+
+After parsing EasyRdf builds up a graph of PHP objects that can then be walked
+around to get the data to be placed on the page. Dump methods are available to
+inspect what data is available during development.
+
+Data is typically loaded into a [EasyRdf_Graph] object from source RDF
+documents, loaded from the web via HTTP. The [EasyRdf_GraphStore] class
+simplifies loading and saving data to a SPARQL 1.1 Graph Store.
+
+SPARQL queries can be made over HTTP to a Triplestore using the
+[EasyRdf_Sparql_Client] class. SELECT and ASK queries will return an
+[EasyRdf_Sparql_Result] object and CONSTRUCT and DESCRIBE queries will return
+an [EasyRdf_Graph] object.
+
+### Example ###
+
+    $foaf = new EasyRdf_Graph("http://njh.me/foaf.rdf");
+    $foaf->load();
+    $me = $foaf->primaryTopic();
+    echo "My name is: ".$me->get('foaf:name')."\n";
+
+
+Downloads
+---------
+
+The latest _stable_ version of EasyRdf can be [downloaded from the EasyRdf website].
+
+
+Links
+-----
+
+* [EasyRdf Homepage](http://www.easyrdf.org/)
+* [API documentation](http://www.easyrdf.org/docs/api)
+* [Change Log](http://github.com/njh/easyrdf/blob/master/CHANGELOG.md)
+* Source Code: <http://github.com/njh/easyrdf>
+* Issue Tracker: <http://github.com/njh/easyrdf/issues>
+
+
+Requirements
+------------
+
+* PHP 5.2.8 or higher
+
+
+Features
+--------
+
+* API documentation written in phpdoc
+* Extensive unit tests written using phpunit
+  * Automated testing against PHP 5.2, 5.3 and 5.4
+* Built-in parsers and serialisers: RDF/JSON, N-Triples, RDF/XML, Turtle
+* Optional parsing support for: [ARC2], [Redland Bindings], [rapper]
+* Optional support for [Zend_Http_Client]
+* No required external dependancies upon other libraries (PEAR, Zend, etc...)
+* Complies with Zend Framework coding style.
+* Type mapper - resources of type foaf:Person can be mapped into PHP object of class Foaf_Person
+* Support for visualisation of graphs using [GraphViz]
+* Comes with a number of examples
+
+
+More Examples
+-------------
+
+* [artistinfo.php](https://github.com/njh/easyrdf/blob/master/examples/artistinfo.php#slider) - Example of mapping an RDF class type to a PHP Class
+* [basic.php](https://github.com/njh/easyrdf/blob/master/examples/basic.php#slider) - Basic "Hello World" type example
+* [basic_sparql.php](https://github.com/njh/easyrdf/blob/master/examples/basic_sparql.php#slider) - Example of making a SPARQL SELECT query
+* [converter.php](https://github.com/njh/easyrdf/blob/master/examples/converter.php#slider) - Convert RDF from one format to another
+* [dump.php](https://github.com/njh/easyrdf/blob/master/examples/dump.php#slider) - Display the contents of a graph
+* [foafinfo.php](https://github.com/njh/easyrdf/blob/master/examples/foafinfo.php#slider) - Display the basic information in a FOAF document
+* [foafmaker.php](https://github.com/njh/easyrdf/blob/master/examples/foafmaker.php#slider) - Construct a FOAF document with a choice of serialisations
+* [graph_direct.php](https://github.com/njh/easyrdf/blob/master/examples/graph_direct.php#slider) - Example of using EasyRdf_Graph directly without EasyRdf_Resource
+* [graphstore.php](https://github.com/njh/easyrdf/blob/master/examples/graphstore.php#slider) - Store and retrieve data from a SPARQL 1.1 Graph Store
+* [graphviz.php](https://github.com/njh/easyrdf/blob/master/examples/graphviz.php#slider) - GraphViz rendering example
+* [html_tag_helpers.php](https://github.com/njh/easyrdf/blob/master/examples/html_tag_helpers.php#slider) - Rails Style html tag helpers to make the EasyRdf examples simplier
+* [httpget.php](https://github.com/njh/easyrdf/blob/master/examples/httpget.php#slider) - No RDF, just test EasyRdf_Http_Client
+* [serialise.php](https://github.com/njh/easyrdf/blob/master/examples/serialise.php#slider) - Basic serialisation example
+* [sparql_queryform.php](https://github.com/njh/easyrdf/blob/master/examples/sparql_queryform.php#slider) - Form to submit SPARQL queries and display the result
+* [uk_postcode.php](https://github.com/njh/easyrdf/blob/master/examples/uk_postcode.php#slider) - Example of resolving UK postcodes using uk-postcodes.com
+* [villages.php](https://github.com/njh/easyrdf/blob/master/examples/villages.php#slider) - Fetch and information about villages in Fife from dbpedialite.org
+* [zend_framework.php](https://github.com/njh/easyrdf/blob/master/examples/zend_framework.php#slider) - Example of using Zend_Http_Client and Zend_Loader_Autoloader with EasyRdf
+
+
+Licensing
+---------
+
+The EasyRdf library and tests are licensed under the [BSD-3-Clause] license.
+The examples are in the public domain, for more information see [UNLICENSE].
+
+
+
+[EasyRdf_Graph]:http://www.easyrdf.org/docs/api/EasyRdf_Graph.html
+[EasyRdf_GraphStore]:http://www.easyrdf.org/docs/api/EasyRdf_GraphStore.html
+[EasyRdf_Sparql_Client]:http://www.easyrdf.org/docs/api/EasyRdf_Sparql_Client.html
+[EasyRdf_Sparql_Result]:http://www.easyrdf.org/docs/api/EasyRdf_Sparql_Result.html
+
+[ARC2]:http://github.com/semsol/arc2/
+[BSD-3-Clause]:http://www.opensource.org/licenses/BSD-3-Clause
+[downloaded from the EasyRdf website]:http://www.easyrdf.org/downloads
+[GraphViz]:http://www.graphviz.org/
+[rapper]:http://librdf.org/raptor/rapper.html
+[RDF]:http://en.wikipedia.org/wiki/Resource_Description_Framework
+[Redland Bindings]:http://librdf.org/bindings/
+[SPARQL 1.1 query language]:http://www.w3.org/TR/sparql11-query/
+[UNLICENSE]:http://unlicense.org/
+[Zend_Http_Client]:http://framework.zend.com/manual/en/zend.http.client.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/composer.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,40 @@
+{
+    "name": "easyrdf/easyrdf",
+    "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.",
+    "version": "0.8.0-beta.2",
+    "type": "library",
+    "keywords": ["RDF", "Semantic Web", "Linked Data", "Turtle", "RDFa", "SPARQL"],
+    "homepage": "http://www.easyrdf.org/",
+    "license": "BSD-3-Clause",
+    "authors": [
+        {
+            "name": "Nicholas Humfrey",
+            "email": "njh@aelius.com",
+            "homepage": "http://www.aelius.com/njh/",
+            "role": "Developer"
+        }
+    ],
+    "support": {
+        "forum": "http://groups.google.com/group/easyrdf/",
+        "issues": "http://github.com/njh/easyrdf/issues",
+        "irc": "irc://chat.freenode.net/easyrdf"
+    },
+    "require": {
+        "php": ">=5.2.8"
+    },
+    "suggest": {
+        "ml/json-ld": "dev-master"
+    },
+    "require-dev": {
+        "phpunit/PHPUnit": ">=3.5.15",
+        "squizlabs/php_codesniffer": ">=1.4.3",
+        "sami/sami": "dev-master",
+        "ml/json-ld": "dev-master"
+    },
+    "replace": {
+        "njh/easyrdf": "self.version"
+    },
+    "autoload": {
+        "psr-0": { "EasyRdf_": "lib/" }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/config/phpcs_ruleset.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<ruleset name="EasyRdf">
+ <description>Extensions to the PSR-2 coding standard.</description>
+
+ <!-- Include the PSR-2 standard -->
+ <rule ref="PSR2">
+    <!--
+      These two sniffs doesn't detect PHP 5.2 namespaces / class names correctly
+      See: https://pear.php.net/bugs/bug.php?id=19774
+    -->
+    <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
+    <exclude name="Squiz.Classes.ValidClassName"/>
+
+    <!-- FIXME: We currently use side-effects to register classes -->
+    <exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
+ </rule>
+
+</ruleset>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/config/phpunit.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit
+    backupGlobals="false"
+    backupStaticAttributes="false"
+    colors="false"
+    convertErrorsToExceptions="true"
+    convertNoticesToExceptions="true"
+    convertWarningsToExceptions="true"
+    processIsolation="false"
+    stopOnFailure="false"
+    strict="true"
+    syntaxCheck="false"
+    verbose="false">
+
+    <php>
+      <!--
+        Fix for coverage report causing Seg Fault
+        (see https://bugs.php.net/bug.php?id=53976)
+      -->
+      <ini name="zend.enable_gc" value="0" />
+    </php>
+
+    <testsuites>
+      <testsuite name="EasyRdf Library">
+        <directory suffix="Test.php">../test/EasyRdf/</directory>
+      </testsuite>
+      <testsuite name="EasyRdf Examples">
+        <directory suffix="Test.php">../test/examples/</directory>
+      </testsuite>
+    </testsuites>
+
+    <!-- Files to be included in the coverage report -->
+    <filter>
+      <whitelist addUncoveredFilesFromWhitelist="true">
+        <directory suffix=".php">../lib/EasyRdf/</directory>
+      </whitelist>
+    </filter>
+
+    <logging>
+        <log type="text" target="php://stdout" />
+        <log type="junit" target="../reports/test-results.xml" />
+    </logging>
+</phpunit>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/config/sami.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+
+use Sami\Sami;
+use Symfony\Component\Finder\Finder;
+
+$root = realpath(__DIR__ . "/..");
+$iterator = Finder::create()
+    ->files()
+    ->name('*.php')
+    ->exclude('arc')
+    ->in($root.'/lib')
+;
+
+return new Sami($iterator, array(
+    'title'               => 'EasyRdf API Documentation',
+    'theme'               => 'enhanced',
+    'build_dir'           => "$root/docs/api",
+    'cache_dir'           => "$root/samicache",
+    'include_parent_data' => true,
+    'simulate_namespaces' => true,
+    'default_opened_level' => 1,
+));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/doap.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,45 @@
+<?php
+    require_once "vendor/autoload.php";
+
+    // Load some properties from the composer file
+    $composer = json_decode(file_get_contents(__DIR__."/composer.json"));
+
+    // Start building up a RDF graph
+    $doap = new EasyRdf_Graph($composer->homepage.'doap.rdf');
+    $easyrdf = $doap->resource('#easyrdf', 'doap:Project', 'foaf:Project');
+    $easyrdf->addLiteral('doap:name',  'EasyRDF');
+    $easyrdf->addLiteral('doap:shortname', 'easyrdf');
+    $easyrdf->addLiteral('doap:revision', $composer->version);
+    $easyrdf->addLiteral('doap:shortdesc', $composer->description, 'en');
+    $easyrdf->addResource('doap:homepage', $composer->homepage);
+
+    $easyrdf->addLiteral('doap:programming-language', 'PHP');
+    $easyrdf->addLiteral(
+        'doap:description', 'EasyRdf is a PHP library designed to make it easy to consume and produce RDF. '.
+        'It was designed for use in mixed teams of experienced and inexperienced RDF developers. '.
+        'It is written in Object Oriented PHP and has been tested extensively using PHPUnit.', 'en'
+    );
+    $easyrdf->addResource('doap:license', 'http://usefulinc.com/doap/licenses/bsd');
+    $easyrdf->addResource('doap:download-page', 'http://github.com/njh/easyrdf/downloads');
+    $easyrdf->addResource('doap:download-page', 'http://github.com/njh/easyrdf/downloads');
+    $easyrdf->addResource('doap:bug-database', 'http://github.com/njh/easyrdf/issues');
+    $easyrdf->addResource('doap:mailing-list', 'http://groups.google.com/group/easyrdf');
+
+    $easyrdf->addResource('doap:category', 'http://dbpedia.org/resource/Resource_Description_Framework');
+    $easyrdf->addResource('doap:category', 'http://dbpedia.org/resource/PHP');
+    $easyrdf->addResource('doap:category', 'http://dbpedialite.org/things/24131#id');
+    $easyrdf->addResource('doap:category', 'http://dbpedialite.org/things/53847#id');
+
+    $repository = $doap->newBNode('doap:GitRepository');
+    $repository->addResource('doap:browse', 'http://github.com/njh/easyrdf');
+    $repository->addResource('doap:location', 'git://github.com/njh/easyrdf.git');
+    $easyrdf->addResource('doap:repository', $repository);
+
+    $njh = $doap->resource('http://njh.me/', 'foaf:Person');
+    $njh->addLiteral('foaf:name', 'Nicholas J Humfrey');
+    $njh->addResource('foaf:homepage', 'http://www.aelius.com/njh/');
+    $easyrdf->add('doap:maintainer', $njh);
+    $easyrdf->add('doap:developer', $njh);
+    $easyrdf->add('foaf:maker', $njh);
+
+    print $doap->serialise('rdfxml');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/docs/01-getting-started.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,47 @@
+Getting Started
+===============
+
+The preferred method of downloading and installing EasyRdf, is to use
+[Composer], a dependency manager that tracks all dependencies of your project.
+
+
+First, install composer in your project:
+
+    curl -s https://getcomposer.org/installer | php
+
+
+Create a composer.json file in your project root:
+
+    {
+        "require": {
+            "easyrdf/easyrdf": "*"
+        }
+    }
+
+
+Install EasyRdf (and any other dependencies) using:
+
+    php composer.phar install
+
+
+Then to start using EasyRdf in your project, add this to the top of your file:
+
+    <?php
+    require 'vendor/autoload.php';
+
+This will load composer's autoloader and make the EasyRdf classes available to your 
+programme.
+
+
+A full basic example looks like this:
+
+    <?php
+    require 'vendor/autoload.php';
+
+    $foaf = new EasyRdf_Graph("http://njh.me/foaf.rdf");
+    $foaf->load();
+    $me = $foaf->primaryTopic();
+    echo "My name is: ".$me->get('foaf:name')."\n";
+
+
+[Composer]:http://getcomposer.org/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/docs/02-property-paths.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,26 @@
+Property Paths
+==============
+
+EasyRdf supports querying the data in a graph using basic property paths.
+This is a small subset of the property paths described in [SPARQL 1.1 query language].
+
+
+You may use the caret character (^) to get an inverse property, for example:
+
+    $person = $homepage->get('^foaf:homepage');
+
+You can use the pipe character (|) to get alternate properties, for example:
+
+    $title = $document->get('dc:title|dc11:title');
+
+You can use a forward slash (/) to follow a property sequence, for example to get
+the names of all my friends:
+
+    $names = $me->all('foaf:knows/foaf:name');
+
+Finally, in order to use a full property URI, enclose it in angle brackets:
+
+    $name = $me->get('<http://xmlns.com/foaf/0.1/name>');
+
+
+[SPARQL 1.1 query language]:http://www.w3.org/TR/sparql11-query/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/artistinfo.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,91 @@
+<?php
+    /**
+     * Mapping an RDF class type to a PHP Class
+     *
+     * This example fetches and displays artist information from the
+     * BBC Music website. The artist object is an instance of the
+     * Model_MusicArtist class, so it is possible to call custom PHP
+     * methods on the object.
+     *
+     * It also demonstrates setting new namespaces.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+
+    class Model_MusicArtist extends EasyRdf_Resource
+    {
+        function birthEvent()
+        {
+            foreach ($this->all('bio:event') as $event) {
+                if (in_array('bio:Birth', $event->types())) {
+                    return $event;
+                }
+            }
+            return null;
+        }
+
+        function age()
+        {
+            $birth = $this->birthEvent();
+            if ($birth) {
+                $year = substr($birth->get('bio:date'), 0, 4);
+                if ($year) {
+                    return date('Y') - $year;
+                }
+            }
+            return 'unknown';
+        }
+    }
+
+    ## Add namespaces
+    EasyRdf_Namespace::set('mo', 'http://purl.org/ontology/mo/');
+    EasyRdf_Namespace::set('bio', 'http://purl.org/vocab/bio/0.1/');
+    EasyRdf_TypeMapper::set('mo:MusicArtist', 'Model_MusicArtist');
+?>
+<html>
+<head><title>EasyRdf Artist Info Example</title></head>
+<body>
+<h1>EasyRdf Artist Info Example</h1>
+
+<?= form_tag() ?>
+<?= text_field_tag('uri', 'http://www.bbc.co.uk/music/artists/70248960-cb53-4ea4-943a-edb18f7d336f.rdf', array('size'=>50)) ?>
+<?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+        $graph = EasyRdf_Graph::newAndLoad($_REQUEST['uri']);
+        $artist = $graph->primaryTopic();
+    }
+
+    if (isset($artist)) {
+?>
+
+<dl>
+    <dt>Artist Name:</dt><dd><?= $artist->get('foaf:name') ?></dd>
+    <dt>Type:</dt><dd><?= join(', ', $artist->types()) ?></dd>
+    <dt>Homepage:</dt><dd><?= link_to($artist->get('foaf:homepage')) ?></dd>
+    <dt>Wikipedia page:</dt><dd><?= link_to($artist->get('mo:wikipedia')) ?></dd>
+    <?php
+        if ($artist->isA('mo:SoloMusicArtist')) {
+            echo "  <dt>Age:</dt>";
+            echo "  <dd>".$artist->age()."</dd>\n";
+        }
+    ?>
+</dl>
+<?php
+    }
+
+    if (isset($graph)) {
+        echo $graph->dump();
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/basic.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,34 @@
+<?php
+    /**
+     * Basic "Hello World" type example
+     *
+     * A new EasyRdf_Graph object is created and then the contents
+     * of my FOAF profile is loaded from the web. An EasyRdf_Resource for
+     * the primary topic of the document (me, Nicholas Humfrey) is returned
+     * and then used to display my name.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+?>
+<html>
+<head>
+  <title>Basic FOAF example</title>
+</head>
+<body>
+
+<?php
+  $foaf = EasyRdf_Graph::newAndLoad('http://njh.me/foaf.rdf');
+  $me = $foaf->primaryTopic();
+?>
+
+<p>
+  My name is: <?= $me->get('foaf:name') ?>
+</p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/basic_sparql.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,57 @@
+<?php
+    /**
+     * Making a SPARQL SELECT query
+     *
+     * This example creates a new SPARQL client, pointing at the
+     * dbpedia.org endpoint. It then makes a SELECT query that
+     * returns all of the countries in DBpedia along with an
+     * english label.
+     *
+     * Note how the namespace prefix declarations are automatically
+     * added to the query.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    // Setup some additional prefixes for DBpedia
+    EasyRdf_Namespace::set('category', 'http://dbpedia.org/resource/Category:');
+    EasyRdf_Namespace::set('dbpedia', 'http://dbpedia.org/resource/');
+    EasyRdf_Namespace::set('dbo', 'http://dbpedia.org/ontology/');
+    EasyRdf_Namespace::set('dbp', 'http://dbpedia.org/property/');
+
+    $sparql = new EasyRdf_Sparql_Client('http://dbpedia.org/sparql');
+?>
+<html>
+<head>
+  <title>EasyRdf Basic Sparql Example</title>
+  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<h1>EasyRdf Basic Sparql Example</h1>
+
+<h2>List of countries</h2>
+<ul>
+<?php
+    $result = $sparql->query(
+        'SELECT * WHERE {'.
+        '  ?country rdf:type dbo:Country .'.
+        '  ?country rdfs:label ?label .'.
+        '  ?country dc:subject category:Member_states_of_the_United_Nations .'.
+        '  FILTER ( lang(?label) = "en" )'.
+        '} ORDER BY ?label'
+    );
+    foreach ($result as $row) {
+        echo "<li>".link_to($row->label, $row->country)."</li>\n";
+    }
+?>
+</ul>
+<p>Total number of countries: <?= $result->numRows() ?></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/converter.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,97 @@
+<?php
+    /**
+     * Convert RDF from one format to another
+     *
+     * The source RDF data can either be fetched from the web
+     * or typed into the Input box.
+     *
+     * The first thing that this script does is make a list the names of the
+     * supported input and output formats. These options are then
+     * displayed on the HTML form.
+     *
+     * The input data is loaded or parsed into an EasyRdf_Graph.
+     * That graph is than outputted again in the desired output format.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    $input_format_options = array('Guess' => 'guess');
+    $output_format_options = array();
+    foreach (EasyRdf_Format::getFormats() as $format) {
+        if ($format->getSerialiserClass()) {
+            $output_format_options[$format->getLabel()] = $format->getName();
+        }
+        if ($format->getParserClass()) {
+            $input_format_options[$format->getLabel()] = $format->getName();
+        }
+    }
+
+    // Stupid PHP :(
+    if (get_magic_quotes_gpc() and isset($_REQUEST['data'])) {
+        $_REQUEST['data'] = stripslashes($_REQUEST['data']);
+    }
+
+    // Default to Guess input and Turtle output
+    if (!isset($_REQUEST['output_format'])) {
+        $_REQUEST['output_format'] = 'turtle';
+    }
+    if (!isset($_REQUEST['input_format'])) {
+        $_REQUEST['input_format'] = 'guess';
+    }
+
+    // Display the form, if raw option isn't set
+    if (!isset($_REQUEST['raw'])) {
+        print "<html>\n";
+        print "<head><title>EasyRdf Converter</title></head>\n";
+        print "<body>\n";
+        print "<h1>EasyRdf Converter</h1>\n";
+
+        print "<div style='margin: 10px'>\n";
+        print form_tag();
+        print label_tag('data', 'Input Data: ').'<br />'.text_area_tag('data', '', array('cols'=>80, 'rows'=>10)) . "<br />\n";
+        print label_tag('uri', 'or Uri: ').text_field_tag('uri', 'http://www.dajobe.org/foaf.rdf', array('size'=>80)) . "<br />\n";
+        print label_tag('input_format', 'Input Format: ').select_tag('input_format', $input_format_options) . "<br />\n";
+        print label_tag('output_format', 'Output Format: ').select_tag('output_format', $output_format_options) . "<br />\n";
+        print label_tag('raw', 'Raw Output: ').check_box_tag('raw') . "<br />\n";
+        print reset_tag() . submit_tag();
+        print form_end_tag();
+        print "</div>\n";
+    }
+
+    if (isset($_REQUEST['uri']) or isset($_REQUEST['data'])) {
+        // Parse the input
+        $graph = new EasyRdf_Graph($_REQUEST['uri']);
+        if (empty($_REQUEST['data'])) {
+            $graph->load($_REQUEST['uri'], $_REQUEST['input_format']);
+        } else {
+            $graph->parse($_REQUEST['data'], $_REQUEST['input_format'], $_REQUEST['uri']);
+        }
+
+        // Lookup the output format
+        $format = EasyRdf_Format::getFormat($_REQUEST['output_format']);
+
+        // Serialise to the new output format
+        $output = $graph->serialise($format);
+        if (!is_scalar($output)) {
+            $output = var_export($output, true);
+        }
+
+        // Send the output back to the client
+        if (isset($_REQUEST['raw'])) {
+            header('Content-Type: '.$format->getDefaultMimeType());
+            print $output;
+        } else {
+            print '<pre>'.htmlspecialchars($output).'</pre>';
+        }
+    }
+
+    if (!isset($_REQUEST['raw'])) {
+        print "</body>\n";
+        print "</html>\n";
+    }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/dump.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,60 @@
+<?php
+    /**
+     * Display the contents of a graph
+     *
+     * Data from the chosen URI is loaded into an EasyRdf_Graph object.
+     * Then the graph is dumped and printed to the page using the
+     * $graph->dump() method.
+     *
+     * The call to preg_replace() replaces links in the page with
+     * links back to this dump script.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+?>
+<html>
+<head><title>EasyRdf Graph Dumper</title></head>
+<body>
+<h1>EasyRdf Graph Dumper</h1>
+
+<div style="margin: 10px">
+  <?= form_tag() ?>
+  URI: <?= text_field_tag('uri', 'http://mmt.me.uk/foaf.rdf', array('size'=>80)) ?><br />
+  Format: <?= label_tag('format_html', 'HTML').' '.radio_button_tag('format', 'html', true) ?>
+          <?= label_tag('format_text', 'Text').' '.radio_button_tag('format', 'text') ?><br />
+
+  <?= submit_tag() ?>
+  <?= form_end_tag() ?>
+</div>
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+        $graph = EasyRdf_Graph::newAndLoad($_REQUEST['uri']);
+        if ($graph) {
+            if (isset($_REQUEST['format']) && $_REQUEST['format'] == 'text') {
+                print "<pre>".$graph->dump('text')."</pre>";
+            } else {
+                $dump = $graph->dump('html');
+                print preg_replace_callback("/ href='([^#][^']*)'/", 'makeLinkLocal', $dump);
+            }
+        } else {
+            print "<p>Failed to create graph.</p>";
+        }
+    }
+
+    # Callback function to re-write links in the dump to point back to this script
+    function makeLinkLocal($matches)
+    {
+        $href = $matches[1];
+        return " href='?uri=".urlencode($href)."#$href'";
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/foafinfo.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,88 @@
+<?php
+    /**
+     * Display the basic information in a FOAF document
+     *
+     * The example starts by loading the requested FOAF document
+     * from the web. It then tries to work out if the URI given
+     * was for the person or the document about the person.
+     *
+     * If a person is found, then the person's name, homepage
+     * and description are shown, along with a list of the
+     * person's friends.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+?>
+<html>
+<head><title>EasyRdf FOAF Info Example</title></head>
+<body>
+<h1>EasyRdf FOAF Info Example</h1>
+
+<?= form_tag() ?>
+<?= text_field_tag('uri', 'http://njh.me/foaf.rdf', array('size'=>50)) ?>
+<?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+        $graph = EasyRdf_Graph::newAndLoad($_REQUEST['uri']);
+        if ($graph->type() == 'foaf:PersonalProfileDocument') {
+            $person = $graph->primaryTopic();
+        } elseif ($graph->type() == 'foaf:Person') {
+            $person = $graph->resource();
+        }
+    }
+
+    if (isset($person)) {
+?>
+
+<dl>
+  <dt>Name:</dt><dd><?= $person->get('foaf:name') ?></dd>
+  <dt>Homepage:</dt><dd><?= link_to($person->get('foaf:homepage')) ?></dd>
+</dl>
+
+<?php
+        echo "<h2>Known Persons</h2>\n";
+        echo "<ul>\n";
+        foreach ($person->all('foaf:knows') as $friend) {
+            $label = $friend->label();
+            if (!$label) {
+                $label = $friend->getUri();
+            }
+
+            if ($friend->isBNode()) {
+                echo "<li>$label</li>";
+            } else {
+                echo "<li>".link_to_self($label, 'uri='.urlencode($friend))."</li>";
+            }
+        }
+        echo "</ul>\n";
+
+        echo "<h2>Interests</h2>\n";
+        echo "<ul>\n";
+        foreach ($person->all('foaf:interest') as $interest) {
+            $label = $interest->label();
+            if ($label) {
+                if ($interest->isBNode()) {
+                    echo "<li>$label</li>";
+                } else {
+                    echo "<li>".$interest->htmlLink($label)."</li>";
+                }
+            }
+        }
+        echo "</ul>\n";
+    }
+
+    if (isset($graph)) {
+        echo "<br />";
+        echo $graph->dump();
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/foafmaker.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,115 @@
+<?php
+    /**
+     * Construct a FOAF document with a choice of serialisations
+     *
+     * This example is similar in concept to Leigh Dodds' FOAF-a-Matic.
+     * The fields in the HTML form are inserted into an empty
+     * EasyRdf_Graph and then serialised to the chosen format.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    if (isset($_REQUEST['enable_arc']) && $_REQUEST['enable_arc']) {
+        require_once "EasyRdf/Serialiser/Arc.php";
+        EasyRdf_Format::registerSerialiser('ntriples', 'EasyRdf_Serialiser_Arc');
+        EasyRdf_Format::registerSerialiser('posh', 'EasyRdf_Serialiser_Arc');
+        EasyRdf_Format::registerSerialiser('rdfxml', 'EasyRdf_Serialiser_Arc');
+        EasyRdf_Format::registerSerialiser('turtle', 'EasyRdf_Serialiser_Arc');
+    }
+
+    if (isset($_REQUEST['enable_rapper']) && $_REQUEST['enable_rapper']) {
+        require_once "EasyRdf/Serialiser/Rapper.php";
+        EasyRdf_Format::registerSerialiser('dot', 'EasyRdf_Serialiser_Rapper');
+        EasyRdf_Format::registerSerialiser('rdfxml', 'EasyRdf_Serialiser_Rapper');
+        EasyRdf_Format::registerSerialiser('turtle', 'EasyRdf_Serialiser_Rapper');
+    }
+
+    $format_options = array();
+    foreach (EasyRdf_Format::getFormats() as $format) {
+        if ($format->getSerialiserClass()) {
+            $format_options[$format->getLabel()] = $format->getName();
+        }
+    }
+?>
+<html>
+<head><title>EasyRdf FOAF Maker Example</title></head>
+<body>
+<h1>EasyRdf FOAF Maker Example</h1>
+
+<?= form_tag(null, array('method' => 'POST')) ?>
+
+<h2>Your Identifier</h2>
+<?= labeled_text_field_tag('uri', 'http://www.example.com/joe#me', array('size'=>40)) ?><br />
+
+<h2>Your details</h2>
+<?= labeled_text_field_tag('title', 'Mr', array('size'=>8)) ?><br />
+<?= labeled_text_field_tag('given_name', 'Joseph') ?><br />
+<?= labeled_text_field_tag('family_name', 'Bloggs') ?><br />
+<?= labeled_text_field_tag('nickname', 'Joe') ?><br />
+<?= labeled_text_field_tag('email', 'joe@example.com') ?><br />
+<?= labeled_text_field_tag('homepage', 'http://www.example.com/', array('size'=>40)) ?><br />
+
+<h2>People you know</h2>
+<?= labeled_text_field_tag('person_1', 'http://www.example.com/dave#me', array('size'=>40)) ?><br />
+<?= labeled_text_field_tag('person_2', '', array('size'=>40)) ?><br />
+<?= labeled_text_field_tag('person_3', '', array('size'=>40)) ?><br />
+<?= labeled_text_field_tag('person_4', '', array('size'=>40)) ?><br />
+
+<h2>Output</h2>
+Enable Arc 2? <?= check_box_tag('enable_arc') ?><br />
+Enable Rapper? <?= check_box_tag('enable_rapper') ?><br />
+<?= label_tag('format').select_tag('format', $format_options, 'rdfxml') ?><br />
+
+<?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+
+        $graph = new EasyRdf_Graph();
+
+        # 1st Technique
+        $me = $graph->resource($_REQUEST['uri'], 'foaf:Person');
+        $me->set('foaf:name', $_REQUEST['title'].' '.$_REQUEST['given_name'].' '.$_REQUEST['family_name']);
+        if ($_REQUEST['email']) {
+            $email = $graph->resource("mailto:".$_REQUEST['email']);
+            $me->add('foaf:mbox', $email);
+        }
+        if ($_REQUEST['homepage']) {
+            $homepage = $graph->resource($_REQUEST['homepage']);
+            $me->add('foaf:homepage', $homepage);
+        }
+
+        # 2nd Technique
+        $graph->addLiteral($_REQUEST['uri'], 'foaf:title', $_REQUEST['title']);
+        $graph->addLiteral($_REQUEST['uri'], 'foaf:givenname', $_REQUEST['given_name']);
+        $graph->addLiteral($_REQUEST['uri'], 'foaf:family_name', $_REQUEST['family_name']);
+        $graph->addLiteral($_REQUEST['uri'], 'foaf:nick', $_REQUEST['nickname']);
+
+        # Add friends
+        for($i=1; $i<=4; $i++) {
+            if ($_REQUEST["person_$i"]) {
+                $person = $graph->resource($_REQUEST["person_$i"]);
+                $graph->add($me, 'foaf:knows', $person);
+            }
+        }
+
+        # Finally output the graph
+        $data = $graph->serialise($_REQUEST['format']);
+        if (!is_scalar($data)) {
+            $data = var_export($data, true);
+        }
+        print "<pre>".htmlspecialchars($data)."</pre>";
+    }
+
+?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/graph_direct.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,49 @@
+<?php
+    /**
+     * Using EasyRdf_Graph directly without EasyRdf_Resource
+     *
+     * Triple data is inserted and retrieved directly from a graph object,
+     * where it is stored internally as an associative array.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+?>
+<html>
+<head>
+  <title>Example of using EasyRdf_Graph directly</title>
+</head>
+<body>
+
+<?php
+  $graph = new EasyRdf_Graph();
+  $graph->addResource("http://example.com/joe", "rdf:type", "foaf:Person");
+  $graph->addLiteral("http://example.com/joe", "foaf:name", "Joe Bloggs");
+  $graph->addLiteral("http://example.com/joe", "foaf:name", "Joseph Bloggs");
+  $graph->add("http://example.com/joe", "rdfs:label", "Joe");
+
+  $graph->setType("http://njh.me/", "foaf:Person");
+  $graph->add("http://njh.me/", "rdfs:label", "Nick");
+  $graph->addLiteral("http://njh.me/", "foaf:name", "Nicholas Humfrey");
+  $graph->addResource("http://njh.me/", "foaf:homepage", "http://www.aelius.com/njh/");
+?>
+
+<p>
+  <b>Name:</b> <?= $graph->get("http://example.com/joe", "foaf:name") ?> <br />
+  <b>Names:</b> <?= $graph->join("http://example.com/joe", "foaf:name") ?> <br />
+
+  <b>Label:</b> <?= $graph->label("http://njh.me/") ?> <br />
+  <b>Properties:</b> <?= join(', ', $graph->properties("http://example.com/joe")) ?> <br />
+  <b>PropertyUris:</b> <?= join(', ', $graph->propertyUris("http://example.com/joe")) ?> <br />
+  <b>People:</b> <?= join(', ', $graph->allOfType('foaf:Person')) ?> <br />
+  <b>Unknown:</b> <?= $graph->get("http://example.com/joe", "unknown:property") ?> <br />
+</p>
+
+<?= $graph->dump() ?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/graphstore.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,42 @@
+<?php
+    /**
+     * Store and retrieve data from a SPARQL 1.1 Graph Store
+     *
+     * This example adds a triple containing the current time into
+     * a local graph store. It then fetches the whole graph out
+     * and displays the contents.
+     *
+     * Note that you will need a graph store, for example RedStore,
+     * running on your local machine in order to test this example.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+?>
+<html>
+<head>
+  <title>GraphStore example</title>
+</head>
+<body>
+
+<?php
+  // Use a local SPARQL 1.1 Graph Store (eg RedStore)
+  $gs = new EasyRdf_GraphStore('http://localhost:8080/data/');
+
+  // Add the current time in a graph
+  $graph1 = new EasyRdf_Graph();
+  $graph1->add('http://example.com/test', 'rdfs:label', 'Test');
+  $graph1->add('http://example.com/test', 'dc:date', time());
+  $gs->insert($graph1, 'time.rdf');
+
+  // Get the graph back out of the graph store and display it
+  $graph2 = $gs->get('time.rdf');
+  print $graph2->dump();
+?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/graphviz.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,86 @@
+<?php
+    /**
+     * GraphViz rendering example
+     *
+     * This example demonstrates converting an EasyRdf_Graph into the
+     * GraphViz graph file language. Using the 'Use Labels' option, you
+     * can have resource URIs replaced with text based labels and using
+     * 'Only Labelled' option, only the resources and properties with
+     * a label will be displayed.
+     *
+     * Rending a graph to an image will only work if you have the
+     * GraphViz 'dot' command installed.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2012-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    $formats = array(
+      'PNG' => 'png',
+      'GIF' => 'gif',
+      'SVG' => 'svg'
+    );
+
+    $format = EasyRdf_Format::getFormat(
+        isset($_REQUEST['format']) ? $_REQUEST['format'] : 'png'
+    );
+
+    // Construct a graph of three people
+    $graph = new EasyRdf_Graph();
+    $graph->set('foaf:knows', 'rdfs:label', 'knows');
+    $bob = $graph->resource('http://www.example.com/bob', 'foaf:Person');
+    $alice = $graph->resource('http://www.example.com/alice', 'foaf:Person');
+    $carol = $graph->resource('http://www.example.com/carol', 'foaf:Person');
+    $bob->set('foaf:name', 'Bob');
+    $alice->set('foaf:name', 'Alice');
+    $carol->set('foaf:name', 'Carol');
+    $bob->add('foaf:knows', $alice);
+    $bob->add('foaf:knows', $carol);
+    $alice->add('foaf:knows', $bob);
+    $alice->add('foaf:knows', $carol);
+
+    // Create a GraphViz serialiser
+    $gv = new EasyRdf_Serialiser_GraphViz();
+    $gv->setUseLabels(isset($_REQUEST['ul']));
+    $gv->setOnlyLabelled(isset($_REQUEST['ol']));
+
+    // If this is a request for the image, just render it and exit
+    if (isset($_REQUEST['image'])) {
+        header("Content-Type: ".$format->getDefaultMimeType());
+        echo $gv->renderImage($graph, $format);
+        exit;
+    }
+?>
+<html>
+<head><title>EasyRdf GraphViz Example</title></head>
+<body>
+<h1>EasyRdf GraphViz Example</h1>
+
+<form action='' method='get'>
+<?php
+    echo label_tag('format').' '.select_tag('format', $formats).tag('br');
+    echo label_tag('ul', 'Use labels:').' '.check_box_tag('ul').tag('br');
+    echo label_tag('ol', 'Only labelled:').' '.check_box_tag('ol').tag('br');
+    echo submit_tag();
+?>
+</form>
+
+<div>
+    <img src='?image&<?=$_SERVER["QUERY_STRING"]?>' />
+</div>
+
+<pre style="margin: 0.5em; padding:0.5em; background-color:#eee; border:dashed 1px grey;">
+<?php
+    print htmlspecialchars(
+        $gv->serialise($graph, 'dot')
+    );
+?>
+</pre>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/html_tag_helpers.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,218 @@
+<?php
+
+/**
+ * Rails Style html tag helpers
+ *
+ * These are used by the other examples to make the code
+ * more concise and simpler to read.
+ *
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://unlicense.org/
+ */
+
+/* Examples:
+
+echo content_tag('p','Paragraph Tag', array('class'=>'foo'));
+
+echo tag('br');
+echo link_to('Hyperlink', 'http://www.example.com/?a=1&b=2');
+echo tag('br');
+
+echo form_tag();
+
+  echo label_tag('first_name').text_field_tag('first_name', 'Joe').tag('br');
+  echo label_tag('password').password_field_tag().tag('br');
+
+  echo label_tag('radio1_value1', 'Radio 1').radio_button_tag('radio1', 'value1').tag('br');
+  echo label_tag('radio1_value2', 'Radio 2').radio_button_tag('radio1', 'value2', true).tag('br');
+  echo label_tag('radio1_value3', 'Radio 3').radio_button_tag('radio1', 'value3').tag('br');
+
+  echo label_tag('check1', 'Check 1').check_box_tag('check1', 'value1').tag('br');
+  echo label_tag('check2', 'Check 2').check_box_tag('check2', 'value2', true).tag('br');
+  echo label_tag('check3', 'Check 3').check_box_tag('check3', 'value3').tag('br');
+
+  $options = array('Label 1' => 'value1', 'Label 2' => 'value2', 'Label 3' => 'value3');
+  echo label_tag('select1', 'Select Something:');
+  echo select_tag('select1', $options, 'value2').tag('br');
+
+  echo label_tag('textarea1', 'Type Something:');
+  echo text_area_tag('textarea1', "Hello World!").tag('br');
+
+  echo submit_tag();
+
+echo form_end_tag();
+
+*/
+
+
+function tag_options($options)
+{
+    $html = "";
+    foreach ($options as $key => $value) {
+        if ($key and $value) {
+            $html .= " ".htmlspecialchars($key)."=\"".
+                         htmlspecialchars($value)."\"";
+        }
+    }
+    return $html;
+}
+
+function tag($name, $options = array(), $open = false)
+{
+    return "<$name".tag_options($options).($open ? ">" : " />");
+}
+
+function content_tag($name, $content = null, $options = array())
+{
+    return "<$name".tag_options($options).">".
+           htmlspecialchars($content)."</$name>";
+}
+
+function link_to($text, $uri = null, $options = array())
+{
+    if ($uri == null) $uri = $text;
+    $options = array_merge(array('href' => $uri), $options);
+    return content_tag('a', $text, $options);
+}
+
+function link_to_self($text, $query_string, $options = array())
+{
+    return link_to($text, $_SERVER['PHP_SELF'].'?'.$query_string, $options);
+}
+
+function image_tag($src, $options = array())
+{
+    $options = array_merge(array('src' => $src), $options);
+    return tag('img', $options);
+}
+
+function input_tag($type, $name, $value = null, $options = array())
+{
+    $options = array_merge(
+        array(
+            'type' => $type,
+            'name' => $name,
+            'id' => $name,
+            'value' => $value
+        ),
+        $options
+    );
+    return tag('input', $options);
+}
+
+function text_field_tag($name, $default = null, $options = array())
+{
+    $value = isset($_REQUEST[$name]) ? $_REQUEST[$name] : $default;
+    return input_tag('text', $name, $value, $options);
+}
+
+function text_area_tag($name, $default = null, $options = array())
+{
+    $content = isset($_REQUEST[$name]) ? $_REQUEST[$name] : $default;
+    $options = array_merge(
+        array(
+            'name' => $name,
+            'id' => $name,
+            'cols' => 60,
+            'rows' => 5
+        ),
+        $options
+    );
+    return content_tag('textarea', $content, $options);
+}
+
+function hidden_field_tag($name, $default = null, $options = array())
+{
+    $value = isset($_REQUEST[$name]) ? $_REQUEST[$name] : $default;
+    return input_tag('hidden', $name, $value, $options);
+}
+
+function password_field_tag($name = 'password', $default = null, $options = array())
+{
+    $value = isset($_REQUEST[$name]) ? $_REQUEST[$name] : $default;
+    return input_tag('password', $name, $value, $options);
+}
+
+function radio_button_tag($name, $value, $default = false, $options = array())
+{
+    if ((isset($_REQUEST[$name]) and $_REQUEST[$name] == $value) or
+        (!isset($_REQUEST[$name]) and $default))
+    {
+        $options = array_merge(array('checked' => 'checked'), $options);
+    }
+    $options = array_merge(array('id' => $name.'_'.$value), $options);
+    return input_tag('radio', $name, $value, $options);
+}
+
+function check_box_tag($name, $value = '1', $default = false, $options = array())
+{
+    if ((isset($_REQUEST[$name]) and $_REQUEST[$name] == $value) or
+        (!isset($_REQUEST['submit']) and $default))
+    {
+        $options = array_merge(array('checked' => 'checked'),$options);
+    }
+    return input_tag('checkbox', $name, $value, $options);
+}
+
+function submit_tag($name = '', $value = 'Submit', $options = array())
+{
+    return input_tag('submit', $name, $value, $options);
+}
+
+function reset_tag($name = '', $value = 'Reset', $options = array())
+{
+    return input_tag('reset', $name, $value, $options);
+}
+
+function label_tag($name, $text = null, $options = array())
+{
+    if ($text == null) {
+        $text = ucwords(str_replace('_', ' ', $name)).': ';
+    }
+    $options = array_merge(
+        array('for' => $name, 'id' => "label_for_$name"),
+        $options
+    );
+    return content_tag('label', $text, $options);
+}
+
+function labeled_text_field_tag($name, $default = null, $options = array())
+{
+    return label_tag($name).text_field_tag($name, $default, $options);
+}
+
+function select_tag($name, $options, $default = null, $html_options = array())
+{
+    $opts = '';
+    foreach ($options as $key => $value) {
+        $arr = array('value' => $value);
+        if ((isset($_REQUEST[$name]) and $_REQUEST[$name] == $value) or
+            (!isset($_REQUEST[$name]) and $default == $value))
+        {
+            $arr = array_merge(array('selected' => 'selected'),$arr);
+        }
+        $opts .= content_tag('option', $key, $arr);
+    }
+    $html_options = array_merge(
+        array('name' => $name, 'id' => $name),
+        $html_options
+    );
+    return "<select".tag_options($html_options).">$opts</select>";
+}
+
+function form_tag($uri = null, $options = array())
+{
+    if ($uri == null) {
+        $uri = $_SERVER['PHP_SELF'];
+    }
+    $options = array_merge(
+        array('method' => 'get', 'action' => $uri),
+        $options
+    );
+    return tag('form', $options, true);
+}
+
+function form_end_tag()
+{
+    return "</form>";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/httpget.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,84 @@
+<?php
+    /**
+     * No RDF, just test EasyRdf_Http_Client
+     *
+     * This example does nothing but test EasyRdf's build in HTTP client.
+     * It demonstrates setting Accept headers and displays the response
+     * headers and body.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    $accept_options = array(
+      'text/html' => 'text/html',
+      'application/rdf+xml' => 'application/rdf+xml',
+      'application/xhtml+xml' => 'application/xhtml+xml',
+      'application/json' => 'application/json',
+      'text/turtle' => 'text/turtle',
+    );
+?>
+<html>
+<head>
+  <title>Test EasyRdf_HTTP_Client Get</title>
+  <style type="text/css">
+    .body
+    {
+      width: 800px;
+      font-family: monospace;
+      font-size: 0.8em;
+    }
+  </style>
+</head>
+<body>
+<h1>Test EasyRdf_HTTP_Client Get</h1>
+<?= form_tag() ?>
+<?= text_field_tag('uri', 'http://tomheath.com/id/me', array('size'=>50)) ?><br />
+<?= label_tag('accept', 'Accept Header: ').select_tag('accept',$accept_options) ?>
+<?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+        $client = new EasyRdf_Http_Client($_REQUEST['uri']);
+        $client->setHeaders('Accept',$_REQUEST['accept']);
+        $response = $client->request();
+
+?>
+
+    <p class="status">
+    <b>Status</b>: <?= $response->getStatus() ?><br />
+    <b>Message</b>: <?= $response->getMessage() ?><br />
+    <b>Version</b>: HTTP/<?= $response->getVersion() ?><br />
+    </p>
+
+    <p class="headers">
+    <?php
+        foreach ($response->getHeaders() as $name => $value) {
+            echo "<b>$name</b>: $value<br />\n";
+        }
+    ?>
+    </p>
+
+    <p class="body">
+      <?php
+        if (defined('ENT_SUBSTITUTE')) {
+            // This is needed for PHP 5.4+
+            print nl2br(htmlentities($response->getBody(), ENT_SUBSTITUTE | ENT_QUOTES));
+        } else {
+            print nl2br(htmlentities($response->getBody()));
+        }
+      ?>
+    </p>
+
+<?php
+    }
+?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/parse_rss.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,56 @@
+<?php
+    /**
+     * Parse an RSS 1.0 feed and display titles
+     *
+     * The example demonstrates fetching an RSS 1.0 feed from the
+     * web and then parsing as RDF/XML. The channel is found by getting
+     * the first object of type rss:channel (a file should only contain
+     * a single RSS channel).
+     *
+     * In RSS 1.0, the list of items in the feed are listed by relating
+     * the rss:channel to the rss:items using an rdf:Seq. In EasyRdf
+     * this maps into an EasyRdf_Container object, which can be
+     * iterated over using a foreach() loop.
+     *
+     * Note that this example only works with RSS 1.0 and no
+     * other version (0.90, 1.1 and 2.0) as they are not RDF.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+?>
+<html>
+<head>
+  <title>EasyRdf RSS 1.0 Parsing example</title>
+	<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<h1>EasyRdf RSS 1.0 Parsing example</h1>
+
+<?= form_tag() ?>
+<?= text_field_tag('uri', 'http://planetrdf.com/index.rdf', array('size'=>50)) ?>
+<?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+<?php
+    if (isset($_REQUEST['uri'])) {
+        $graph = EasyRdf_Graph::newAndLoad($_REQUEST['uri'], 'rdfxml');
+        $channel = $graph->get('rss:channel', '^rdf:type');
+
+        print "<p>Channel: ".link_to($channel->label(), $channel->get('rss:link'))."</p>\n";
+        print "<p>Description: ".$channel->get('rss:description')."</p>\n";
+
+        print "<ol>\n";
+        foreach($channel->get('rss:items') as $item) {
+            print "<li>".link_to($item->get('rss:title'), $item)."</li>\n";
+        }
+        print "</ol>\n";
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/serialise.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+    /**
+     * Basic serialisation example
+     *
+     * This example create a simple FOAF graph in memory and then
+     * serialises it to the page in the format of choice.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+
+    $graph = new EasyRdf_Graph();
+    $me = $graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+    $me->set('foaf:name', 'Joseph Bloggs');
+    $me->set('foaf:title', 'Mr');
+    $me->set('foaf:nick', 'Joe');
+    $me->add('foaf:homepage', $graph->resource('http://example.com/joe/'));
+
+    // I made these up; they are not officially part of FOAF
+    $me->set('foaf:dateOfBirth', new EasyRdf_Literal_Date('1980-09-08'));
+    $me->set('foaf:height', 1.82);
+
+    $project = $graph->newBnode('foaf:Project');
+    $project->set('foaf:name', "Joe's current project");
+    $me->set('foaf:currentProject', $project);
+
+    if (isset($_REQUEST['format'])) {
+        $format = preg_replace("/[^\w\-]+/", '', strtolower($_REQUEST['format']));
+    } else {
+        $format = 'ntriples';
+    }
+?>
+<html>
+<head><title>EasyRdf Serialiser Example</title></head>
+<body>
+<h1>EasyRdf Serialiser Example</h1>
+
+<ul>
+<?php
+    foreach (EasyRdf_Format::getFormats() as $f) {
+        if ($f->getSerialiserClass()) {
+            if ($f->getName() == $format) {
+                print "<li><b>".$f->getLabel()."</b></li>\n";
+            } else {
+                print "<li><a href='?format=$f'>";
+                print $f->getLabel()."</a></li>\n";
+            }
+        }
+    }
+?>
+</ul>
+
+<pre style="margin: 0.5em; padding:0.5em; background-color:#eee; border:dashed 1px grey;">
+<?php
+    $data = $graph->serialise($format);
+    if (!is_scalar($data)) {
+        $data = var_export($data, true);
+    }
+    print htmlspecialchars($data);
+?>
+</pre>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/sparql_queryform.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,79 @@
+<?php
+    /**
+     * Form to submit and display SPARQL queries
+     *
+     * This example presents a form that you can enter the URI
+     * of a a SPARQL endpoint and a SPARQL query into. The
+     * results are displayed using a call to dump() on what will be
+     * either a EasyRdf_Sparql_Result or EasyRdf_Graph object.
+     *
+     * A list of registered namespaces is displayed above the query
+     * box - any of these namespaces can be used in the query and PREFIX
+     * statements will automatically be added to the start of the query
+     * string.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    // Stupid PHP :(
+    if (get_magic_quotes_gpc() and isset($_REQUEST['query'])) {
+        $_REQUEST['query'] = stripslashes($_REQUEST['query']);
+    }
+?>
+<html>
+<head>
+  <title>EasyRdf SPARQL Query Form</title>
+  <style type="text/css">
+    .error {
+      width: 35em;
+      border: 2px red solid;
+      padding: 1em;
+      margin: 0.5em;
+      background-color: #E6E6E6;
+    }
+  </style>
+</head>
+<body>
+<h1>EasyRdf SPARQL Query Form</h1>
+
+<div style="margin: 0.5em">
+  <?php
+    print form_tag();
+    print label_tag('endpoint');
+    print text_field_tag('endpoint', "http://dbpedia.org/sparql", array('size'=>80)).'<br />';
+    print "<code>";
+    foreach(EasyRdf_Namespace::namespaces() as $prefix => $uri) {
+        print "PREFIX $prefix: &lt;".htmlspecialchars($uri)."&gt;<br />\n";
+    }
+    print "</code>";
+    print text_area_tag('query', "SELECT * WHERE {\n  ?s ?p ?o\n}\nLIMIT 10", array('rows' => 10, 'cols' => 80)).'<br />';
+    print check_box_tag('text') . label_tag('text', 'Plain text results').'<br />';
+    print reset_tag() . submit_tag();
+    print form_end_tag();
+  ?>
+</div>
+
+<?php
+  if (isset($_REQUEST['endpoint']) and isset($_REQUEST['query'])) {
+      $sparql = new EasyRdf_Sparql_Client($_REQUEST['endpoint']);
+      try {
+          $results = $sparql->query($_REQUEST['query']);
+          if (isset($_REQUEST['text'])) {
+              print "<pre>".htmlspecialchars($results->dump('text'))."</pre>";
+          } else {
+              print $results->dump('html');
+          }
+      } catch (Exception $e) {
+          print "<div class='error'>".$e->getMessage()."</div>\n";
+      }
+  }
+?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/uk_postcode.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,74 @@
+<?php
+    /**
+     * Resolving UK postcodes using uk-postcodes.com
+     *
+     * Another basic example that demonstrates registering namespaces,
+     * loading RDF data from the web and then directly displaying
+     * literals from the graph on the page.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    EasyRdf_Namespace::set('postcode', 'http://data.ordnancesurvey.co.uk/ontology/postcode/');
+    EasyRdf_Namespace::set('sr', 'http://data.ordnancesurvey.co.uk/ontology/spatialrelations/');
+    EasyRdf_Namespace::set('eg', 'http://statistics.data.gov.uk/def/electoral-geography/');
+    EasyRdf_Namespace::set('ag', 'http://statistics.data.gov.uk/def/administrative-geography/');
+    EasyRdf_Namespace::set('osag', 'http://data.ordnancesurvey.co.uk/ontology/admingeo/');
+?>
+<html>
+<head>
+  <title>EasyRdf UK Postcode Resolver</title>
+  <style type="text/css" media="all">
+    #map
+    {
+        border: 1px gray solid;
+        float: right;
+        margin: 0 0 20px 20px;
+    }
+    th { text-align: right }
+    td { padding: 5px; }
+  </style>
+</head>
+<body>
+<h1>EasyRdf UK Postcode Resolver</h1>
+
+<?= form_tag() ?>
+  <?= text_field_tag('postcode', 'W1A 1AA', array('size'=>10)) ?>
+  <?= submit_tag() ?>
+<?= form_end_tag() ?>
+
+<?php
+    if (isset($_REQUEST['postcode'])) {
+        $postcode = str_replace(' ', '', strtoupper($_REQUEST['postcode']));
+        $docuri = "http://www.uk-postcodes.com/postcode/$postcode.rdf";
+        $graph = EasyRdf_Graph::newAndLoad($docuri);
+
+
+        // Get the first resource of type PostcodeUnit
+        $res = $graph->get('postcode:PostcodeUnit', '^rdf:type');
+        if ($res) {
+            $ll = $res->get('geo:lat').','.$res->get('geo:long');
+            print "<iframe id='map' width='500' height='250' frameborder='0' scrolling='no' src='http://maps.google.com/maps?f=q&amp;ll=$ll&amp;output=embed'></iframe>";
+            print "<table id='facts'>\n";
+            print "<tr><th>Easting:</th><td>" . $res->get('sr:easting') . "</td></tr>\n";
+            print "<tr><th>Northing:</th><td>" . $res->get('sr:northing') . "</td></tr>\n";
+            print "<tr><th>Longitude:</th><td>" . $res->get('geo:long') . "</td></tr>\n";
+            print "<tr><th>Latitude:</th><td>" . $res->get('geo:lat') . "</td></tr>\n";
+            print "<tr><th>Local Authority:</th><td>" . $res->get('ag:localAuthority')->label() . "</td></tr>\n";
+            print "<tr><th>Electoral Ward:</th><td>" . $res->get('eg:ward')->label() . "</td></tr>\n";
+            print "</table>\n";
+
+            print "<div style='clear: both'></div>\n";
+        }
+
+        print $graph->dump();
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/villages.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,67 @@
+<?php
+    /**
+     * Consuming Linked Data from dbpedialite.org
+     *
+     * This example demonstrates fetching information about villages in Fife
+     * from dbpedialite.org.
+     *
+     * First it fetches a list of villages that are members of the
+     * Wikipedia category 'Villages in Fife' and displays them as a list.
+     *
+     * If you click on an village, then it displays a page about that village
+     * with a title, synopsis and Google Map.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+    require_once "EasyRdf.php";
+    require_once "html_tag_helpers.php";
+
+    $CATEGORY_ID = 4309010;
+?>
+<html>
+<head><title>EasyRdf Village Info Example</title></head>
+<body>
+<h1>EasyRdf Village Info Example</h1>
+
+<?php
+    if (isset($_REQUEST['id'])) {
+        $graph = EasyRdf_Graph::newAndLoad("http://dbpedialite.org/things/".$_REQUEST['id']);
+
+        $village = $graph->primaryTopic();
+        print content_tag('h2',$village->label());
+
+        if ($village->get('foaf:depiction')) {
+            print image_tag(
+                $village->get('foaf:depiction'),
+                array('style'=>'max-width:400px;max-height:250px;')
+            );
+        }
+
+        print content_tag('p',$village->get('rdfs:comment'));
+
+        if ($village->get('geo:long')) {
+            $ll = $village->get('geo:lat').','.$village->get('geo:long');
+            print "<iframe width='425' height='350' frameborder='0' scrolling='no' marginheight='0' marginwidth='0' src='http://maps.google.com/maps?f=q&amp;ll=$ll&amp;output=embed'></iframe>";
+        }
+
+        echo "<br /><br />";
+        echo $graph->dump();
+    } else {
+        $graph = EasyRdf_Graph::newAndLoad("http://dbpedialite.org/categories/".$CATEGORY_ID);
+        $category = $graph->primaryTopic();
+
+        print "<ul>\n";
+        foreach ($category->all('^rdf:type') as $resource) {
+            if (preg_match("|http://dbpedialite.org/things/(\d+)#id|", $resource, $matches)) {
+                print '<li>'.link_to_self($resource->label(), "id=".$matches[1])."</li>\n";
+            }
+        }
+        print "</ul>\n";
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/examples/zend_framework.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,61 @@
+<?php
+    /**
+     * Using EasyRdf with the Zend Framework
+     *
+     * This example demonstrates using Zend_Http_Client and
+     * Zend_Loader_Autoloader with EasyRdf.
+     *
+     * It creates a simple graph in memory, saves it to a local graphstore
+     * and then fetches the data back using a SPARQL SELECT query.
+     * Zend's curl HTTP client adaptor is used to perform the HTTP requests.
+     *
+     * @package    EasyRdf
+     * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+     * @license    http://unlicense.org/
+     */
+
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../lib/');
+
+    // require the Zend Autoloader
+    require_once 'Zend/Loader/Autoloader.php';
+    $autoloader = Zend_Loader_Autoloader::getInstance();
+    $autoloader->setFallbackAutoloader(true);
+
+    // use the CURL based HTTP client adaptor
+    $client = new Zend_Http_Client(
+        null,
+        array(
+            'adapter' => 'Zend_Http_Client_Adapter_Curl',
+            'keepalive' => true,
+            'useragent' => "EasyRdf/zendtest"
+        )
+    );
+    EasyRdf_Http::setDefaultHttpClient($client);
+?>
+
+<html>
+<head>
+  <title>Zend Framework Example</title>
+</head>
+<body>
+<h1>Zend Framework Example</h1>
+
+<?php
+    # Load some sample data into a graph
+    $graph = new EasyRdf_Graph('http://example.com/joe');
+    $joe = $graph->resource('http://example.com/joe#me', 'foaf:Person');
+    $joe->add('foaf:name', 'Joe Bloggs');
+    $joe->addResource('foaf:homepage', 'http://example.com/joe/');
+
+    # Store it in a local graphstore
+    $store = new EasyRdf_GraphStore('http://localhost:8080/data/');
+    $store->replace($graph);
+
+    # Now make a query to the graphstore
+    $sparql = new EasyRdf_Sparql_Client('http://localhost:8080/sparql/');
+    $result = $sparql->query('SELECT * WHERE {<http://example.com/joe#me> ?p ?o}');
+    echo $result->dump();
+?>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * Use this file to load the core of EasyRdf, if you don't have an autoloader.
+ *
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2011-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * @see EasyRdf_Exception
+ */
+require_once "EasyRdf/Exception.php";
+
+/**
+ * @see EasyRdf_Format
+ */
+require_once "EasyRdf/Format.php";
+
+/**
+ * @see EasyRdf_Graph
+ */
+require_once "EasyRdf/Graph.php";
+
+/**
+ * @see EasyRdf_GraphStore
+ */
+require_once "EasyRdf/GraphStore.php";
+
+/**
+ * @see EasyRdf_Http
+ */
+require_once "EasyRdf/Http.php";
+
+/**
+ * @see EasyRdf_Http_Client
+ */
+require_once "EasyRdf/Http/Client.php";
+
+/**
+ * @see EasyRdf_Http_Response
+ */
+require_once "EasyRdf/Http/Response.php";
+
+/**
+ * @see EasyRdf_Namespace
+ */
+require_once "EasyRdf/Namespace.php";
+
+/**
+ * @see EasyRdf_Literal
+ */
+require_once "EasyRdf/Literal.php";
+
+/**
+ * @see EasyRdf_Literal_Boolean
+ */
+require_once "EasyRdf/Literal/Boolean.php";
+
+/**
+ * @see EasyRdf_Literal_Date
+ */
+require_once "EasyRdf/Literal/Date.php";
+
+/**
+ * @see EasyRdf_Literal_DateTime
+ */
+require_once "EasyRdf/Literal/DateTime.php";
+
+/**
+ * @see EasyRdf_Literal_Decimal
+ */
+require_once "EasyRdf/Literal/Decimal.php";
+
+/**
+ * @see EasyRdf_Literal_HexBinary
+ */
+require_once "EasyRdf/Literal/HexBinary.php";
+
+/**
+ * @see EasyRdf_Literal_HTML
+ */
+require_once "EasyRdf/Literal/HTML.php";
+
+/**
+ * @see EasyRdf_Literal_Integer
+ */
+require_once "EasyRdf/Literal/Integer.php";
+
+/**
+ * @see EasyRdf_Literal_XML
+ */
+require_once "EasyRdf/Literal/XML.php";
+
+/**
+ * @see EasyRdf_ParsedUri
+ */
+require_once "EasyRdf/ParsedUri.php";
+
+/**
+ * @see EasyRdf_Parser
+ */
+require_once "EasyRdf/Parser.php";
+
+/**
+ * @see EasyRdf_Parser_Exception
+ */
+require_once "EasyRdf/Parser/Exception.php";
+
+/**
+ * @see EasyRdf_Parser_RdfPhp
+ */
+require_once "EasyRdf/Parser/RdfPhp.php";
+
+/**
+ * @see EasyRdf_Parser_Ntriples
+ */
+require_once "EasyRdf/Parser/Ntriples.php";
+
+/**
+ * @see EasyRdf_Parser_Json
+ */
+require_once "EasyRdf/Parser/Json.php";
+
+/**
+ * @see EasyRdf_Parser_Rdfa
+ */
+require_once "EasyRdf/Parser/Rdfa.php";
+
+/**
+ * @see EasyRdf_Parser_RdfXml
+ */
+require_once "EasyRdf/Parser/RdfXml.php";
+
+/**
+ * @see EasyRdf_Parser_Turtle
+ */
+require_once "EasyRdf/Parser/Turtle.php";
+
+/**
+ * @see EasyRdf_Resource
+ */
+require_once "EasyRdf/Resource.php";
+
+/**
+ * @see EasyRdf_Collection
+ */
+require_once "EasyRdf/Collection.php";
+
+/**
+ * @see EasyRdf_Container
+ */
+require_once "EasyRdf/Container.php";
+
+/**
+ * @see EasyRdf_Serialiser
+ */
+require_once "EasyRdf/Serialiser.php";
+
+/**
+ * @see EasyRdf_Serialiser_GraphViz
+ */
+require_once "EasyRdf/Serialiser/GraphViz.php";
+
+/**
+ * @see EasyRdf_Serialiser_RdfPhp
+ */
+require_once "EasyRdf/Serialiser/RdfPhp.php";
+
+/**
+ * @see EasyRdf_Serialiser_Ntriples
+ */
+require_once "EasyRdf/Serialiser/Ntriples.php";
+
+/**
+ * @see EasyRdf_Serialiser_Json
+ */
+require_once "EasyRdf/Serialiser/Json.php";
+
+/**
+ * @see EasyRdf_Serialiser_RdfXml
+ */
+require_once "EasyRdf/Serialiser/RdfXml.php";
+
+/**
+ * @see EasyRdf_Serialiser_Turtle
+ */
+require_once "EasyRdf/Serialiser/Turtle.php";
+
+/**
+ * @see EasyRdf_Sparql_Client
+ */
+require_once "EasyRdf/Sparql/Client.php";
+
+/**
+ * @see EasyRdf_Sparql_Result
+ */
+require_once "EasyRdf/Sparql/Result.php";
+
+/**
+ * @see EasyRdf_TypeMapper
+ */
+require_once "EasyRdf/TypeMapper.php";
+
+/**
+ * @see EasyRdf_Utils
+ */
+require_once "EasyRdf/Utils.php";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Collection.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,333 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Sub-class of EasyRdf_Resource that represents an RDF collection (rdf:List)
+ *
+ * This class can be used to iterate through a collection of items.
+ *
+ * Note that items are numbered from 1 (not 0) for consistency with RDF Containers.
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#date
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Collection extends EasyRdf_Resource implements ArrayAccess, Countable, SeekableIterator
+{
+    private $position;
+    private $current;
+
+    /** Create a new collection - do not use this directly
+     *
+     * @ignore
+     */
+    public function __construct($uri, $graph)
+    {
+        $this->position = 1;
+        $this->current = null;
+        parent::__construct($uri, $graph);
+    }
+
+    /** Seek to a specific position in the container
+     *
+     * The first item is postion 1
+     *
+     * @param  integer  $position     The position in the container to seek to
+     * @throws OutOfBoundsException
+     */
+    public function seek($position)
+    {
+        if (is_int($position) and $position > 0) {
+            list($node, $actual) = $this->getCollectionNode($position);
+            if ($actual === $position) {
+                $this->position = $actual;
+                $this->current = $node;
+            } else {
+                throw new OutOfBoundsException(
+                    "Unable to seek to position $position in the collection"
+                );
+            }
+        } else {
+            throw new InvalidArgumentException(
+                "Collection position must be a positive integer"
+            );
+        }
+    }
+
+    /** Rewind the iterator back to the start of the collection
+     *
+     */
+    public function rewind()
+    {
+        $this->position = 1;
+        $this->current = null;
+    }
+
+    /** Return the current item in the collection
+     *
+     * @return mixed The current item
+     */
+    public function current()
+    {
+        if ($this->position === 1) {
+            return $this->get('rdf:first');
+        } elseif ($this->current) {
+            return $this->current->get('rdf:first');
+        }
+    }
+
+    /** Return the key / current position in the collection
+     *
+     * Note: the first item is number 1
+     *
+     * @return int The current position
+     */
+    public function key()
+    {
+        return $this->position;
+    }
+
+    /** Move forward to next item in the collection
+     *
+     */
+    public function next()
+    {
+        if ($this->position === 1) {
+            $this->current = $this->get('rdf:rest');
+        } elseif ($this->current) {
+            $this->current = $this->current->get('rdf:rest');
+        }
+        $this->position++;
+    }
+
+    /** Checks if current position is valid
+     *
+     * @return bool True if the current position is valid
+     */
+    public function valid()
+    {
+        if ($this->position === 1 and $this->hasProperty('rdf:first')) {
+            return true;
+        } elseif ($this->current !== null and $this->current->hasProperty('rdf:first')) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /** Get a node for a particular offset into the collection
+     *
+     * This function may not return the item you requested, if
+     * it does not exist. Please check the $postion parameter
+     * returned.
+     *
+     * If the offset is null, then the last node in the
+     * collection (before rdf:nil) will be returned.
+     *
+     * @param  integer $offset          The offset into the collection (or null)
+     * @return array   $node, $postion  The node object and postion of the node
+     */
+    public function getCollectionNode($offset)
+    {
+        $position = 1;
+        $node = $this;
+        $nil = $this->graph->resource('rdf:nil');
+        while (($rest = $node->get('rdf:rest')) and $rest !== $nil and (is_null($offset) or ($position < $offset))) {
+            $node = $rest;
+            $position++;
+        }
+        return array($node, $position);
+    }
+
+    /** Counts the number of items in the collection
+     *
+     * Note that this is an slow method - it is more efficient to use
+     * the iterator interface, if you can.
+     *
+     * @return integer The number of items in the collection
+     */
+    public function count()
+    {
+        // Find the end of the collection
+        list($node, $position) = $this->getCollectionNode(null);
+        if (!$node->hasProperty('rdf:first')) {
+            return 0;
+        } else {
+            return $position;
+        }
+    }
+
+    /** Append an item to the end of the collection
+     *
+     * @param  mixed $value      The value to append
+     * @return integer           The number of values appended (1 or 0)
+     */
+    public function append($value)
+    {
+        // Find the end of the collection
+        list($node, $position) = $this->getCollectionNode(null);
+        $rest = $node->get('rdf:rest');
+
+        if ($node === $this and is_null($rest)) {
+            $node->set('rdf:first', $value);
+            $node->addResource('rdf:rest', 'rdf:nil');
+        } else {
+            $new = $this->graph->newBnode();
+            $node->set('rdf:rest', $new);
+            $new->add('rdf:first', $value);
+            $new->addResource('rdf:rest', 'rdf:nil');
+        }
+
+        return 1;
+    }
+
+    /** Array Access: check if a position exists in collection using array syntax
+     *
+     * Example: isset($list[2])
+     */
+    public function offsetExists($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            list($node, $position) = $this->getCollectionNode($offset);
+            return ($node and $position === $offset and $node->hasProperty('rdf:first'));
+        } else {
+            throw new InvalidArgumentException(
+                "Collection offset must be a positive integer"
+            );
+        }
+    }
+
+    /** Array Access: get an item at a specified position in collection using array syntax
+     *
+     * Example: $item = $list[2];
+     */
+    public function offsetGet($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            list($node, $position) = $this->getCollectionNode($offset);
+            if ($node and $position === $offset) {
+                return $node->get('rdf:first');
+            }
+        } else {
+            throw new InvalidArgumentException(
+                "Collection offset must be a positive integer"
+            );
+        }
+    }
+
+    /**
+     * Array Access: set an item at a positon in collection using array syntax
+     *
+     * Example: $list[2] = $item;
+     */
+    public function offsetSet($offset, $value)
+    {
+        if (is_null($offset)) {
+            // No offset - append to end of collection
+            $this->append($value);
+        } elseif (is_int($offset) and $offset > 0) {
+            list($node, $position) = $this->getCollectionNode($offset);
+
+            // Create nodes, if they are missing
+            while ($position < $offset) {
+                $new = $this->graph->newBnode();
+                $node->set('rdf:rest', $new);
+                $new->addResource('rdf:rest', 'rdf:nil');
+                $node = $new;
+                $position++;
+            }
+
+            // Terminate the list
+            if (!$node->hasProperty('rdf:rest')) {
+                $node->addResource('rdf:rest', 'rdf:nil');
+            }
+
+            return $node->set('rdf:first', $value);
+        } else {
+            throw new InvalidArgumentException(
+                "Collection offset must be a positive integer"
+            );
+        }
+    }
+
+    /**
+     * Array Access: delete an item at a specific postion using array syntax
+     *
+     * Example: unset($seq[2]);
+     */
+    public function offsetUnset($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            list($node, $position) = $this->getCollectionNode($offset);
+        } else {
+            throw new InvalidArgumentException(
+                "Collection offset must be a positive integer"
+            );
+        }
+
+        // Does the item exist?
+        if ($node and $position === $offset) {
+            $nil = $this->graph->resource('rdf:nil');
+            if ($position === 1) {
+                $rest = $node->get('rdf:rest');
+                if ($rest and $rest !== $nil) {
+                    // Move second value, so we can keep the head of list
+                    $node->set('rdf:first', $rest->get('rdf:first'));
+                    $node->set('rdf:rest', $rest->get('rdf:rest'));
+                    $rest->delete('rdf:first');
+                    $rest->delete('rdf:rest');
+                } else {
+                    // Just remove the value
+                    $node->delete('rdf:first');
+                    $node->delete('rdf:rest');
+                }
+            } else {
+                // Remove the value and re-link the list
+                $node->delete('rdf:first');
+                $rest = $node->get('rdf:rest');
+                $previous = $node->get('^rdf:rest');
+                if (is_null($rest)) {
+                    $rest = $nil;
+                }
+                if ($previous) {
+                    $previous->set('rdf:rest', $rest);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Container.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,230 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Sub-class of EasyRdf_Resource that represents an RDF container
+ * (rdf:Alt, rdf:Bag and rdf:Seq)
+ *
+ * This class can be used to iterate through a list of items.
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#date
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Container extends EasyRdf_Resource implements ArrayAccess, Countable, SeekableIterator
+{
+    private $position;
+
+    /** Create a new container - do not use this directly
+     *
+     * @ignore
+     */
+    public function __construct($uri, $graph)
+    {
+        $this->position = 1;
+        parent::__construct($uri, $graph);
+    }
+
+    /** Seek to a specific position in the container
+     *
+     * The first item is postion 1
+     *
+     * @param  integer  $position     The position in the container to seek to
+     * @throws OutOfBoundsException
+     */
+    public function seek($position)
+    {
+        if (is_int($position) and $position > 0) {
+            if ($this->hasProperty('rdf:_'.$position)) {
+                $this->position = $position;
+            } else {
+                throw new OutOfBoundsException(
+                    "Unable to seek to position $position in the container"
+                );
+            }
+        } else {
+            throw new InvalidArgumentException(
+                "Container position must be a positive integer"
+            );
+        }
+    }
+
+    /** Rewind the iterator back to the start of the container (item 1)
+     *
+     */
+    public function rewind()
+    {
+        $this->position = 1;
+    }
+
+    /** Return the current item in the container
+     *
+     * @return mixed The current item
+     */
+    public function current()
+    {
+        return $this->get('rdf:_'.$this->position);
+    }
+
+    /** Return the key / current position in the container
+     *
+     * @return int The current position
+     */
+    public function key()
+    {
+        return $this->position;
+    }
+
+    /** Move forward to next item in the container
+     *
+     */
+    public function next()
+    {
+        $this->position++;
+    }
+
+    /** Checks if current position is valid
+     *
+     * @return bool True if the current position is valid
+     */
+    public function valid()
+    {
+        return $this->hasProperty('rdf:_'.$this->position);
+    }
+
+    /** Counts the number of items in the container
+     *
+     * Note that this is an slow method - it is more efficient to use
+     * the iterator interface, if you can.
+     *
+     * @return integer The number of items in the container
+     */
+    public function count()
+    {
+        $pos = 1;
+        while ($this->hasProperty('rdf:_'.$pos)) {
+            $pos++;
+        }
+        return $pos - 1;
+    }
+
+    /** Append an item to the end of the container
+     *
+     * @param  mixed $value      The value to append
+     * @return integer           The number of values appended (1 or 0)
+     */
+    public function append($value)
+    {
+        // Find the end of the list
+        $pos = 1;
+        while ($this->hasProperty('rdf:_'.$pos)) {
+            $pos++;
+        }
+
+        // Add the item
+        return $this->add('rdf:_'.$pos, $value);
+    }
+
+    /** Array Access: check if a position exists in container using array syntax
+     *
+     * Example: isset($seq[2])
+     */
+    public function offsetExists($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            return $this->hasProperty('rdf:_'.$offset);
+        } else {
+            throw new InvalidArgumentException(
+                "Container position must be a positive integer"
+            );
+        }
+    }
+
+    /** Array Access: get an item at a specified position in container using array syntax
+     *
+     * Example: $item = $seq[2];
+     */
+    public function offsetGet($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            return $this->get('rdf:_'.$offset);
+        } else {
+            throw new InvalidArgumentException(
+                "Container position must be a positive integer"
+            );
+        }
+    }
+
+    /**
+     * Array Access: set an item at a positon in container using array syntax
+     *
+     * Example: $seq[2] = $item;
+     *
+     * Warning: creating gaps in the sequence will result in unexpected behavior
+     */
+    public function offsetSet($offset, $value)
+    {
+        if (is_int($offset) and $offset > 0) {
+            return $this->set('rdf:_'.$offset, $value);
+        } elseif (is_null($offset)) {
+            return $this->append($value);
+        } else {
+            throw new InvalidArgumentException(
+                "Container position must be a positive integer"
+            );
+        }
+    }
+
+    /**
+     * Array Access: delete an item at a specific postion using array syntax
+     *
+     * Example: unset($seq[2]);
+     *
+     * Warning: creating gaps in the sequence will result in unexpected behavior
+     */
+    public function offsetUnset($offset)
+    {
+        if (is_int($offset) and $offset > 0) {
+            return $this->delete('rdf:_'.$offset);
+        } else {
+            throw new InvalidArgumentException(
+                "Container position must be a positive integer"
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Exception.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * EasyRdf Exception class
+ *
+ * All exceptions thrown by EasyRdf are an instance of this class.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Exception extends Exception
+{
+    // Comment to make PHP CodeSniffer happy
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Format.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,687 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class the represents an RDF file format.
+ *
+ * For each format, the name, label, URIs and associated MIME Types are
+ * stored. A single parser and serialiser can also be registered to each
+ * format.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Format
+{
+    private static $formats = array();
+
+    private $name = array();
+    private $label = null;
+    private $uri = null;
+    private $mimeTypes = array();
+    private $extensions = array();
+    private $parserClass = null;
+    private $serialiserClass = null;
+
+    /** Get a list of format names
+     *
+     * @return array          An array of formats name
+     */
+    public static function getNames()
+    {
+        return array_keys(self::$formats);
+    }
+
+    /** Get a list of all the registered formats
+     *
+     * @return array          An array of format objects
+     */
+    public static function getFormats()
+    {
+        return self::$formats;
+    }
+
+    /** Generates an HTTP Accept header string
+     *
+     * The string will contain all of the MIME Types that we
+     * are able to parse.
+     *
+     * It is also possible to specify additional MIME types
+     * in the form array('text/plain' => 0.5) where 0.5 is the
+     * q value for that type. The types are sorted by q value
+     * before constructing the string.
+     *
+     * @param array $extraTypes    extra MIME types to add
+     * @return string              list of supported MIME types
+     */
+    public static function getHttpAcceptHeader($extraTypes = array())
+    {
+        $accept = $extraTypes;
+        foreach (self::$formats as $format) {
+            if ($format->parserClass and count($format->mimeTypes) > 0) {
+                $accept = array_merge($accept, $format->mimeTypes);
+            }
+        }
+        arsort($accept, SORT_NUMERIC);
+
+        $acceptStr='';
+        foreach ($accept as $type => $q) {
+            if ($acceptStr) {
+                $acceptStr .= ',';
+            }
+            if ($q == 1.0) {
+                $acceptStr .= $type;
+            } else {
+                $acceptStr .= sprintf("%s;q=%1.1f", $type, $q);
+            }
+        }
+        return $acceptStr;
+    }
+
+    /** Check if a named graph exists
+     *
+     * @param string $name    the name of the format
+     * @return boolean        true if the format exists
+     */
+    public static function formatExists($name)
+    {
+        return array_key_exists($name, self::$formats);
+    }
+
+    /** Get a EasyRdf_Format from a name, uri or mime type
+     *
+     * @param string $query   a query string to search for
+     * @return object         the first EasyRdf_Format that matches the query
+     * @throws EasyRdf_Exception  if no format is found
+     */
+    public static function getFormat($query)
+    {
+        if (!is_string($query) or $query == null or $query == '') {
+            throw new InvalidArgumentException(
+                "\$query should be a string and cannot be null or empty"
+            );
+        }
+
+        foreach (self::$formats as $format) {
+            if ($query == $format->name or
+                $query == $format->uri or
+                array_key_exists($query, $format->mimeTypes) or
+                in_array($query, $format->extensions)) {
+                return $format;
+            }
+        }
+
+        # No match
+        throw new EasyRdf_Exception(
+            "Format is not recognised: $query"
+        );
+    }
+
+    /** Register a new format
+     *
+     * @param  string  $name       The name of the format (e.g. ntriples)
+     * @param  string  $label      The label for the format (e.g. N-Triples)
+     * @param  string  $uri        The URI for the format
+     * @param  string  $mimeTypes  One or more mime types for the format
+     * @param  string  $extensions One or more extensions (file suffix)
+     * @return object              The new EasyRdf_Format object
+     */
+    public static function register(
+        $name,
+        $label = null,
+        $uri = null,
+        $mimeTypes = array(),
+        $extensions = array()
+    ) {
+        if (!is_string($name) or $name == null or $name == '') {
+            throw new InvalidArgumentException(
+                "\$name should be a string and cannot be null or empty"
+            );
+        }
+
+        if (!array_key_exists($name, self::$formats)) {
+            self::$formats[$name] = new EasyRdf_Format($name);
+        }
+
+        self::$formats[$name]->setLabel($label);
+        self::$formats[$name]->setUri($uri);
+        self::$formats[$name]->setMimeTypes($mimeTypes);
+        self::$formats[$name]->setExtensions($extensions);
+        return self::$formats[$name];
+    }
+
+    /** Remove a format from the registry
+     *
+     * @param  string  $name      The name of the format (e.g. ntriples)
+     */
+    public static function unregister($name)
+    {
+        unset(self::$formats[$name]);
+    }
+
+    /** Class method to register a parser class to a format name
+     *
+     * @param  string  $name   The name of the format (e.g. ntriples)
+     * @param  string  $class  The name of the class (e.g. EasyRdf_Parser_Ntriples)
+     */
+    public static function registerParser($name, $class)
+    {
+        if (!self::formatExists($name)) {
+            self::register($name);
+        }
+        self::getFormat($name)->setParserClass($class);
+    }
+
+    /** Class method to register a serialiser class to a format name
+     *
+     * @param  string  $name   The name of the format (e.g. ntriples)
+     * @param  string  $class  The name of the class (e.g. EasyRdf_Serialiser_Ntriples)
+     */
+    public static function registerSerialiser($name, $class)
+    {
+        if (!self::formatExists($name)) {
+            self::register($name);
+        }
+        self::getFormat($name)->setSerialiserClass($class);
+    }
+
+    /** Attempt to guess the document format from some content.
+     *
+     * If $filename is given, then the suffix is first used to guess the format.
+     *
+     * If the document format is not recognised, null is returned.
+     *
+     * @param  string $data     The document data
+     * @param  string $filename Optional filename
+     * @return object EasyRdf_Format The format object
+     */
+    public static function guessFormat($data, $filename = null)
+    {
+        if (is_array($data)) {
+            # Data has already been parsed into RDF/PHP
+            return self::getFormat('php');
+        }
+
+        // First try and identify by the filename
+        if ($filename and preg_match("/\.(\w+)$/", $filename, $matches)) {
+            foreach (self::$formats as $format) {
+                if (in_array($matches[1], $format->extensions)) {
+                    return $format;
+                }
+            }
+        }
+
+        // Then try and guess by the first 1024 bytes of content
+        $short = substr($data, 0, 1024);
+        if (preg_match("/^\s*\{/", $short)) {
+            return self::getFormat('json');
+        } elseif (preg_match("/<rdf:/i", $short)) {
+            return self::getFormat('rdfxml');
+        } elseif (preg_match("/@prefix\s|@base\s/", $short)) {
+            return self::getFormat('turtle');
+        } elseif (preg_match("/^\s*<.+> <.+>/m", $short)) {
+            return self::getFormat('ntriples');
+        } elseif (preg_match("|http://www.w3.org/2005/sparql-results|", $short)) {
+            return self::getFormat('sparql-xml');
+        } elseif (preg_match("/\WRDFa\W/i", $short)) {
+            return self::getFormat('rdfa');
+        } elseif (preg_match("/<!DOCTYPE html|<html/i", $short)) {
+            # We don't support any other microformats embedded in HTML
+            return self::getFormat('rdfa');
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * This constructor is for internal use only.
+     * To create a new format, use the register method.
+     *
+     * @param  string  $name    The name of the format
+     * @see    EasyRdf_Format::register()
+     * @ignore
+     */
+    public function __construct($name)
+    {
+        $this->name = $name;
+        $this->label = $name;  # Only a default
+    }
+
+    /** Get the name of a format object
+     *
+     * @return string The name of the format (e.g. rdfxml)
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /** Get the label for a format object
+     *
+     * @return string The format label (e.g. RDF/XML)
+     */
+    public function getLabel()
+    {
+        return $this->label;
+    }
+
+    /** Set the label for a format object
+     *
+     * @param  string $label  The new label for the format
+     */
+    public function setLabel($label)
+    {
+        if ($label) {
+            if (!is_string($label)) {
+                throw new InvalidArgumentException(
+                    "\$label should be a string"
+                );
+            }
+            return $this->label = $label;
+        } else {
+            return $this->label = null;
+        }
+    }
+
+    /** Get the URI for a format object
+     *
+     * @return string The format URI
+     */
+    public function getUri()
+    {
+        return $this->uri;
+    }
+
+    /** Set the URI for a format object
+     *
+     * @param string $uri  The new URI for the format
+     */
+    public function setUri($uri)
+    {
+        if ($uri) {
+            if (!is_string($uri)) {
+                throw new InvalidArgumentException(
+                    "\$uri should be a string"
+                );
+            }
+            return $this->uri = $uri;
+        } else {
+            return $this->uri = null;
+        }
+    }
+
+    /** Get the default registered mime type for a format object
+     *
+     * @return string The default mime type as a string.
+     */
+    public function getDefaultMimeType()
+    {
+        $types = array_keys($this->mimeTypes);
+        if (isset($types[0])) {
+            return $types[0];
+        }
+    }
+
+    /** Get all the registered mime types for a format object
+     *
+     * @return array One or more MIME types in an array with
+     *               the mime type as the key and q value as the value
+     */
+    public function getMimeTypes()
+    {
+        return $this->mimeTypes;
+    }
+
+    /** Set the MIME Types for a format object
+     *
+     * @param array $mimeTypes  One or more mime types
+     */
+    public function setMimeTypes($mimeTypes)
+    {
+        if ($mimeTypes) {
+            if (!is_array($mimeTypes)) {
+                $mimeTypes = array($mimeTypes);
+            }
+            $this->mimeTypes = $mimeTypes;
+        } else {
+            $this->mimeTypes = array();
+        }
+    }
+
+    /** Get the default registered file extension (filename suffix) for a format object
+     *
+     * @return string The default extension as a string.
+     */
+    public function getDefaultExtension()
+    {
+        if (isset($this->extensions[0])) {
+            return $this->extensions[0];
+        }
+    }
+
+    /** Get all the registered file extensions (filename suffix) for a format object
+     *
+     * @return array One or more extensions as an array
+     */
+    public function getExtensions()
+    {
+        return $this->extensions;
+    }
+
+    /** Set the file format extensions (filename suffix) for a format object
+     *
+     * @param mixed $extensions  One or more file extensions
+     */
+    public function setExtensions($extensions)
+    {
+        if ($extensions) {
+            if (!is_array($extensions)) {
+                $extensions = array($extensions);
+            }
+            $this->extensions = $extensions;
+        } else {
+            $this->extensions = array();
+        }
+    }
+
+    /** Set the parser to use for a format
+     *
+     * @param string $class  The name of the class
+     */
+    public function setParserClass($class)
+    {
+        if ($class) {
+            if (!is_string($class)) {
+                throw new InvalidArgumentException(
+                    "\$class should be a string"
+                );
+            }
+            $this->parserClass = $class;
+        } else {
+            $this->parserClass = null;
+        }
+    }
+
+    /** Get the name of the class to use to parse the format
+     *
+     * @return string The name of the class
+     */
+    public function getParserClass()
+    {
+        return $this->parserClass;
+    }
+
+    /** Create a new parser to parse this format
+     *
+     * @return object The new parser object
+     */
+    public function newParser()
+    {
+        $parserClass = $this->parserClass;
+        if (!$parserClass) {
+            throw new EasyRdf_Exception(
+                "No parser class available for format: ".$this->getName()
+            );
+        }
+        return (new $parserClass());
+    }
+
+    /** Set the serialiser to use for a format
+     *
+     * @param string $class  The name of the class
+     */
+    public function setSerialiserClass($class)
+    {
+        if ($class) {
+            if (!is_string($class)) {
+                throw new InvalidArgumentException(
+                    "\$class should be a string"
+                );
+            }
+            $this->serialiserClass = $class;
+        } else {
+            $this->serialiserClass = null;
+        }
+    }
+
+    /** Get the name of the class to use to serialise the format
+     *
+     * @return string The name of the class
+     */
+    public function getSerialiserClass()
+    {
+        return $this->serialiserClass;
+    }
+
+    /** Create a new serialiser to parse this format
+     *
+     * @return object The new serialiser object
+     */
+    public function newSerialiser()
+    {
+        $serialiserClass = $this->serialiserClass;
+        if (!$serialiserClass) {
+            throw new EasyRdf_Exception(
+                "No serialiser class available for format: ".$this->getName()
+            );
+        }
+        return (new $serialiserClass());
+    }
+
+    /** Magic method to return the name of the format when casted to string
+     *
+     * @return string The name of the format
+     */
+    public function __toString()
+    {
+        return $this->name;
+    }
+}
+
+
+/*
+   Register default set of supported formats
+   NOTE: they are ordered by preference
+*/
+
+EasyRdf_Format::register(
+    'php',
+    'RDF/PHP',
+    'http://n2.talis.com/wiki/RDF_PHP_Specification',
+    array(
+        'application/x-httpd-php-source' => 1.0
+    ),
+    array('phps')
+);
+
+EasyRdf_Format::register(
+    'json',
+    'RDF/JSON Resource-Centric',
+    'http://n2.talis.com/wiki/RDF_JSON_Specification',
+    array(
+        'application/json' => 1.0,
+        'text/json' => 0.9,
+        'application/rdf+json' => 0.9
+    ),
+    array('json')
+);
+
+EasyRdf_Format::register(
+    'ntriples',
+    'N-Triples',
+    'http://www.w3.org/TR/n-triples/',
+    array(
+        'application/n-triples' => 1.0,
+        'text/plain' => 0.9,
+        'text/ntriples' => 0.9,
+        'application/ntriples' => 0.9,
+        'application/x-ntriples' => 0.9
+    ),
+    array('nt')
+);
+
+EasyRdf_Format::register(
+    'turtle',
+    'Turtle Terse RDF Triple Language',
+    'http://www.dajobe.org/2004/01/turtle',
+    array(
+        'text/turtle' => 0.8,
+        'application/turtle' => 0.7,
+        'application/x-turtle' => 0.7
+    ),
+    array('ttl')
+);
+
+EasyRdf_Format::register(
+    'rdfxml',
+    'RDF/XML',
+    'http://www.w3.org/TR/rdf-syntax-grammar',
+    array(
+        'application/rdf+xml' => 0.8
+    ),
+    array('rdf', 'xrdf')
+);
+
+EasyRdf_Format::register(
+    'dot',
+    'Graphviz',
+    'http://www.graphviz.org/doc/info/lang.html',
+    array(
+        'text/vnd.graphviz' => 0.8
+    ),
+    array('gv', 'dot')
+);
+
+EasyRdf_Format::register(
+    'json-triples',
+    'RDF/JSON Triples'
+);
+
+EasyRdf_Format::register(
+    'n3',
+    'Notation3',
+    'http://www.w3.org/2000/10/swap/grammar/n3#',
+    array(
+        'text/n3' => 0.5,
+        'text/rdf+n3' => 0.5
+    ),
+    array('n3')
+);
+
+EasyRdf_Format::register(
+    'rdfa',
+    'RDFa',
+    'http://www.w3.org/TR/rdfa-core/',
+    array(
+        'text/html' => 0.4,
+        'application/xhtml+xml' => 0.4
+    ),
+    array('html')
+);
+
+EasyRdf_Format::register(
+    'sparql-xml',
+    'SPARQL XML Query Results',
+    'http://www.w3.org/TR/rdf-sparql-XMLres/',
+    array(
+        'application/sparql-results+xml' => 1.0
+    )
+);
+
+EasyRdf_Format::register(
+    'sparql-json',
+    'SPARQL JSON Query Results',
+    'http://www.w3.org/TR/rdf-sparql-json-res/',
+    array(
+        'application/sparql-results+json' => 1.0
+    )
+);
+
+EasyRdf_Format::register(
+    'png',
+    'Portable Network Graphics (PNG)',
+    'http://www.w3.org/TR/PNG/',
+    array(
+        'image/png' => 0.3
+    ),
+    array('png')
+);
+
+EasyRdf_Format::register(
+    'gif',
+    'Graphics Interchange Format (GIF)',
+    'http://www.w3.org/Graphics/GIF/spec-gif89a.txt',
+    array(
+        'image/gif' => 0.2
+    ),
+    array('gif')
+);
+
+EasyRdf_Format::register(
+    'svg',
+    'Scalable Vector Graphics (SVG)',
+    'http://www.w3.org/TR/SVG/',
+    array(
+        'image/svg+xml' => 0.3
+    ),
+    array('svg')
+);
+
+
+/*
+   Register default set of parsers and serialisers
+*/
+
+EasyRdf_Format::registerParser('json', 'EasyRdf_Parser_Json');
+EasyRdf_Format::registerParser('ntriples', 'EasyRdf_Parser_Ntriples');
+EasyRdf_Format::registerParser('php', 'EasyRdf_Parser_RdfPhp');
+EasyRdf_Format::registerParser('rdfxml', 'EasyRdf_Parser_RdfXml');
+EasyRdf_Format::registerParser('turtle', 'EasyRdf_Parser_Turtle');
+EasyRdf_Format::registerParser('rdfa', 'EasyRdf_Parser_Rdfa');
+
+EasyRdf_Format::registerSerialiser('json', 'EasyRdf_Serialiser_Json');
+EasyRdf_Format::registerSerialiser('n3', 'EasyRdf_Serialiser_Turtle');
+EasyRdf_Format::registerSerialiser('ntriples', 'EasyRdf_Serialiser_Ntriples');
+EasyRdf_Format::registerSerialiser('php', 'EasyRdf_Serialiser_RdfPhp');
+EasyRdf_Format::registerSerialiser('rdfxml', 'EasyRdf_Serialiser_RdfXml');
+EasyRdf_Format::registerSerialiser('turtle', 'EasyRdf_Serialiser_Turtle');
+
+EasyRdf_Format::registerSerialiser('dot', 'EasyRdf_Serialiser_GraphViz');
+EasyRdf_Format::registerSerialiser('gif', 'EasyRdf_Serialiser_GraphViz');
+EasyRdf_Format::registerSerialiser('png', 'EasyRdf_Serialiser_GraphViz');
+EasyRdf_Format::registerSerialiser('svg', 'EasyRdf_Serialiser_GraphViz');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Graph.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1648 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Container for collection of EasyRdf_Resources.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Graph
+{
+    /** The URI of the graph */
+    private $uri = null;
+    private $parsedUri = null;
+
+    /** Array of resources contained in the graph */
+    private $resources = array();
+
+    private $index = array();
+    private $revIndex = array();
+
+    /** Counter for the number of bnodes */
+    private $bNodeCount = 0;
+
+    /** Array of URLs that have been loaded into the graph */
+    private $loaded = array();
+
+    private $maxRedirects = 10;
+
+
+    /**
+     * Constructor
+     *
+     * If no URI is given then an unnamed graph is created.
+     *
+     * The $data parameter is optional and will be parsed into
+     * the graph if given.
+     *
+     * The data format is optional and should be specified if it
+     * can't be guessed by EasyRdf.
+     *
+     * @param  string  $uri     The URI of the graph
+     * @param  string  $data    Data for the graph
+     * @param  string  $format  The document type of the data (e.g. rdfxml)
+     * @return object EasyRdf_Graph
+     */
+    public function __construct($uri = null, $data = null, $format = null)
+    {
+        $this->checkResourceParam($uri, true);
+
+        if ($uri) {
+            $this->uri = $uri;
+            $this->parsedUri = new EasyRdf_ParsedUri($uri);
+            if ($data) {
+                $this->parse($data, $format, $this->uri);
+            }
+        }
+    }
+
+    /**
+     * Create a new graph and load RDF data from a URI into it
+     *
+     * This static function is shorthand for:
+     *     $graph = new EasyRdf_Graph($uri);
+     *     $graph->load($uri, $format);
+     *
+     * The document type is optional but should be specified if it
+     * can't be guessed or got from the HTTP headers.
+     *
+     * @param  string  $uri     The URI of the data to load
+     * @param  string  $format  Optional format of the data (eg. rdfxml)
+     * @return object EasyRdf_Graph    The new the graph object
+     */
+    public static function newAndLoad($uri, $format = null)
+    {
+        $graph = new self($uri);
+        $graph->load($uri, $format);
+        return $graph;
+    }
+
+    /** Get or create a resource stored in a graph
+     *
+     * If the resource did not previously exist, then a new resource will
+     * be created. If you provide an RDF type and that type is registered
+     * with the EasyRdf_TypeMapper, then the resource will be an instance
+     * of the class registered.
+     *
+     * If URI is null, then the URI of the graph is used.
+     *
+     * @param  string  $uri    The URI of the resource
+     * @param  mixed   $types  RDF type of a new resource (e.g. foaf:Person)
+     * @return object EasyRdf_Resource
+     */
+    public function resource($uri = null, $types = array())
+    {
+        $this->checkResourceParam($uri, true);
+        if (!$uri) {
+            throw new InvalidArgumentException(
+                '$uri is null and EasyRdf_Graph object has no URI either.'
+            );
+        }
+
+        // Resolve relative URIs
+        if ($this->parsedUri) {
+            $uri = $this->parsedUri->resolve($uri)->toString();
+        }
+
+        // Add the types
+        $this->addType($uri, $types);
+
+        // Create resource object if it doesn't already exist
+        if (!isset($this->resources[$uri])) {
+            $resClass = $this->classForResource($uri);
+            $this->resources[$uri] = new $resClass($uri, $this);
+        }
+
+        return $this->resources[$uri];
+    }
+
+    /** Work out the class to instantiate a resource as
+     *  @ignore
+     */
+    protected function classForResource($uri)
+    {
+        $rdfType = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
+        if (isset($this->index[$uri][$rdfType])) {
+            foreach ($this->index[$uri][$rdfType] as $type) {
+                if ($type['type'] == 'uri' or $type['type'] == 'bnode') {
+                    $class = EasyRdf_TypeMapper::get($type['value']);
+                    if ($class != null) {
+                        return $class;
+                    }
+                }
+            }
+        }
+
+        // Parsers don't typically add a rdf:type to rdf:List, so we have to
+        // do a bit of 'inference' here using properties.
+        if ($uri == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' or
+            isset($this->index[$uri]['http://www.w3.org/1999/02/22-rdf-syntax-ns#first']) or
+            isset($this->index[$uri]['http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'])
+        ) {
+            return 'EasyRdf_Collection';
+        }
+        return 'EasyRdf_Resource';
+    }
+
+    /**
+     * Create a new blank node in the graph and return it.
+     *
+     * If you provide an RDF type and that type is registered
+     * with the EasyRdf_TypeMapper, then the resource will be an instance
+     * of the class registered.
+     *
+     * @param  mixed  $types  RDF type of a new blank node (e.g. foaf:Person)
+     * @return object EasyRdf_Resource The new blank node
+     */
+    public function newBNode($types = array())
+    {
+        return $this->resource($this->newBNodeId(), $types);
+    }
+
+    /**
+     * Create a new unique blank node identifier and return it.
+     *
+     * @return string The new blank node identifier (e.g. _:genid1)
+     */
+    public function newBNodeId()
+    {
+        return "_:genid".(++$this->bNodeCount);
+    }
+
+    /**
+     * Parse some RDF data into the graph object.
+     *
+     * @param  string  $data    Data to parse for the graph
+     * @param  string  $format  Optional format of the data
+     * @param  string  $uri     The URI of the data to load
+     * @return integer          The number of triples added to the graph
+     */
+    public function parse($data, $format = null, $uri = null)
+    {
+        $this->checkResourceParam($uri, true);
+
+        if (empty($format) or $format == 'guess') {
+            // Guess the format if it is Unknown
+            $format = EasyRdf_Format::guessFormat($data, $uri);
+        } else {
+            $format = EasyRdf_Format::getFormat($format);
+        }
+
+        if (!$format) {
+            throw new EasyRdf_Exception(
+                "Unable to parse data of an unknown format."
+            );
+        }
+
+        $parser = $format->newParser();
+        return $parser->parse($this, $data, $format, $uri);
+    }
+
+    /**
+     * Parse a file containing RDF data into the graph object.
+     *
+     * @param  string  $filename The path of the file to load
+     * @param  string  $format   Optional format of the file
+     * @param  string  $uri      The URI of the file to load
+     * @return integer           The number of triples added to the graph
+     */
+    public function parseFile($filename, $format = null, $uri = null)
+    {
+        if ($uri === null) {
+            $uri = "file://$filename";
+        }
+
+        return $this->parse(
+            file_get_contents($filename),
+            $format,
+            $uri
+        );
+    }
+
+    /**
+     * Load RDF data into the graph from a URI.
+     *
+     * If no URI is given, then the URI of the graph will be used.
+     *
+     * The document type is optional but should be specified if it
+     * can't be guessed or got from the HTTP headers.
+     *
+     * @param  string  $uri     The URI of the data to load
+     * @param  string  $format  Optional format of the data (eg. rdfxml)
+     * @return integer          The number of triples added to the graph
+     */
+    public function load($uri = null, $format = null)
+    {
+        $this->checkResourceParam($uri, true);
+
+        if (!$uri) {
+            throw new EasyRdf_Exception(
+                "No URI given to load() and the graph does not have a URI."
+            );
+        }
+
+        // Setup the HTTP client
+        $client = EasyRdf_Http::getDefaultHttpClient();
+        $client->resetParameters(true);
+        $client->setConfig(array('maxredirects' => 0));
+        $client->setMethod('GET');
+        $client->setHeaders('Accept', EasyRdf_Format::getHttpAcceptHeader());
+
+        $requestUrl = $uri;
+        $response = null;
+        $redirectCounter = 0;
+        do {
+            // Have we already loaded it into the graph?
+            $requestUrl = EasyRdf_Utils::removeFragmentFromUri($requestUrl);
+            if (in_array($requestUrl, $this->loaded)) {
+                return 0;
+            }
+
+            // Make the HTTP request
+            $client->setHeaders('host', null);
+            $client->setUri($requestUrl);
+            $response = $client->request();
+
+            // Add the URL to the list of URLs loaded
+            $this->loaded[] = $requestUrl;
+
+            if ($response->isRedirect() and $location = $response->getHeader('location')) {
+                // Avoid problems with buggy servers that add whitespace
+                $location = trim($location);
+
+                // Some servers return relative URLs in the location header
+                // resolve it in relation to previous request
+                $baseUri = new EasyRdf_ParsedUri($requestUrl);
+                $requestUrl = $baseUri->resolve($location)->toString();
+                $requestUrl = EasyRdf_Utils::removeFragmentFromUri($requestUrl);
+
+                // If it is a 303 then drop the parameters
+                if ($response->getStatus() == 303) {
+                    $client->resetParameters();
+                }
+
+                ++$redirectCounter;
+            } elseif ($response->isSuccessful()) {
+                // If we didn't get any location, stop redirecting
+                break;
+            } else {
+                throw new EasyRdf_Exception(
+                    "HTTP request for $requestUrl failed: ".$response->getMessage()
+                );
+            }
+        } while ($redirectCounter < $this->maxRedirects);
+
+        if (!$format or $format == 'guess') {
+            list($format, $params) = EasyRdf_Utils::parseMimeType(
+                $response->getHeader('Content-Type')
+            );
+        }
+
+        // Parse the data
+        return $this->parse($response->getBody(), $format, $uri);
+    }
+
+    /** Get an associative array of all the resources stored in the graph.
+     *  The keys of the array is the URI of the EasyRdf_Resource.
+     *
+     * @return array Array of EasyRdf_Resource
+     */
+    public function resources()
+    {
+        foreach ($this->index as $subject => $properties) {
+            if (!isset($this->resources[$subject])) {
+                $this->resource($subject);
+            }
+        }
+
+        foreach ($this->revIndex as $object => $properties) {
+            if (!isset($this->resources[$object])) {
+                $this->resource($object);
+            }
+        }
+
+        return $this->resources;
+    }
+
+    /** Get an arry of resources matching a certain property and optional value.
+     *
+     * For example this routine could be used as a way of getting
+     * everyone who has name:
+     * $people = $graph->resourcesMatching('foaf:name')
+     *
+     * Or everyone who is male:
+     * $people = $graph->resourcesMatching('foaf:gender', 'male');
+     *
+     * Or all homepages:
+     * $people = $graph->resourcesMatching('^foaf:homepage');
+     *
+     * @param  string  $property   The property to check.
+     * @param  mixed   $value      Optional, the value of the propery to check for.
+     * @return array   Array of EasyRdf_Resource
+     */
+    public function resourcesMatching($property, $value = null)
+    {
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        // Use the reverse index if it is an inverse property
+        if ($inverse) {
+            $index = &$this->revIndex;
+        } else {
+            $index = &$this->index;
+        }
+
+        $matched = array();
+        foreach ($index as $subject => $props) {
+            if (isset($index[$subject][$property])) {
+                if (isset($value)) {
+                    foreach ($this->index[$subject][$property] as $v) {
+                        if ($v['type'] == $value['type'] and
+                            $v['value'] == $value['value']) {
+                            $matched[] = $this->resource($subject);
+                            break;
+                        }
+                    }
+                } else {
+                    $matched[] = $this->resource($subject);
+                }
+            }
+        }
+        return $matched;
+    }
+
+    /** Get the URI of the graph
+     *
+     * @return string The URI of the graph
+     */
+    public function getUri()
+    {
+        return $this->uri;
+    }
+
+    /** Check that a URI/resource parameter is valid, and convert it to a string
+     *  @ignore
+     */
+    protected function checkResourceParam(&$resource, $allowNull = false)
+    {
+        if ($allowNull == true) {
+            if ($resource === null) {
+                if ($this->uri) {
+                    $resource = $this->uri;
+                } else {
+                    return;
+                }
+            }
+        } elseif ($resource === null) {
+            throw new InvalidArgumentException(
+                "\$resource cannot be null"
+            );
+        }
+
+        if (is_object($resource) and $resource instanceof EasyRdf_Resource) {
+            $resource = $resource->getUri();
+        } elseif (is_object($resource) and $resource instanceof EasyRdf_ParsedUri) {
+            $resource = strval($resource);
+        } elseif (is_string($resource)) {
+            if ($resource == '') {
+                throw new InvalidArgumentException(
+                    "\$resource cannot be an empty string"
+                );
+            } elseif (preg_match("|^<(.+)>$|", $resource, $matches)) {
+                $resource = $matches[1];
+            } else {
+                $resource = EasyRdf_Namespace::expand($resource);
+            }
+        } else {
+            throw new InvalidArgumentException(
+                "\$resource should be a string or an EasyRdf_Resource"
+            );
+        }
+    }
+
+    /** Check that a single URI/property parameter (not a property path)
+     *  is valid, and expand it if required
+     *  @ignore
+     */
+    protected function checkSinglePropertyParam(&$property, &$inverse)
+    {
+        if (is_object($property) and $property instanceof EasyRdf_Resource) {
+            $property = $property->getUri();
+        } elseif (is_object($property) and $property instanceof EasyRdf_ParsedUri) {
+            $property = strval($property);
+        } elseif (is_string($property)) {
+            if ($property == '') {
+                throw new InvalidArgumentException(
+                    "\$property cannot be an empty string"
+                );
+            } elseif (substr($property, 0, 1) == '^') {
+                $inverse = true;
+                $property = EasyRdf_Namespace::expand(substr($property, 1));
+            } elseif (substr($property, 0, 2) == '_:') {
+                throw new InvalidArgumentException(
+                    "\$property cannot be a blank node"
+                );
+            } else {
+                $inverse = false;
+                $property = EasyRdf_Namespace::expand($property);
+            }
+        }
+
+        if ($property === null or !is_string($property)) {
+            throw new InvalidArgumentException(
+                "\$property should be a string or EasyRdf_Resource and cannot be null"
+            );
+        }
+    }
+
+    /** Check that a value parameter is valid, and convert it to an associative array if needed
+     *  @ignore
+     */
+    protected function checkValueParam(&$value)
+    {
+        if (isset($value)) {
+            if (is_object($value)) {
+                if (!method_exists($value, 'toRdfPhp')) {
+                    // Convert to a literal object
+                    $value = EasyRdf_Literal::create($value);
+                }
+                $value = $value->toRdfPhp();
+            } elseif (is_array($value)) {
+                if (!isset($value['type'])) {
+                    throw new InvalidArgumentException(
+                        "\$value is missing a 'type' key"
+                    );
+                }
+
+                if (!isset($value['value'])) {
+                    throw new InvalidArgumentException(
+                        "\$value is missing a 'value' key"
+                    );
+                }
+
+                // Fix ordering and remove unknown keys
+                $value = array(
+                    'type' => strval($value['type']),
+                    'value' => strval($value['value']),
+                    'lang' => isset($value['lang']) ? strval($value['lang']) : null,
+                    'datatype' => isset($value['datatype']) ? strval($value['datatype']) : null
+                );
+            } else {
+                $value = array(
+                    'type' => 'literal',
+                    'value' => strval($value),
+                    'datatype' => EasyRdf_Literal::getDatatypeForValue($value)
+                );
+            }
+            if (!in_array($value['type'], array('uri', 'bnode', 'literal'), true)) {
+                throw new InvalidArgumentException(
+                    "\$value does not have a valid type (".$value['type'].")"
+                );
+            }
+            if (empty($value['datatype'])) {
+                unset($value['datatype']);
+            }
+            if (empty($value['lang'])) {
+                unset($value['lang']);
+            }
+            if (isset($value['lang']) and isset($value['datatype'])) {
+                throw new InvalidArgumentException(
+                    "\$value cannot have both and language and a datatype"
+                );
+            }
+        }
+    }
+
+    /** Get a single value for a property of a resource
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * If $property is an array, then the first item in the array that matches
+     * a property that exists is returned.
+     *
+     * This method will return null if the property does not exist.
+     *
+     * @param  string    $resource       The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string    $propertyPath   A valid property path
+     * @param  string    $type           The type of value to filter by (e.g. literal or resource)
+     * @param  string    $lang           The language to filter by (e.g. en)
+     * @return mixed                     A value associated with the property
+     */
+    public function get($resource, $propertyPath, $type = null, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+
+        if (is_object($propertyPath) and $propertyPath instanceof EasyRdf_Resource) {
+            return $this->getSingleProperty($resource, $propertyPath->getUri(), $type, $lang);
+        } elseif (is_string($propertyPath) and preg_match('|^(\^?)<(.+)>|', $propertyPath, $matches)) {
+            return $this->getSingleProperty($resource, "$matches[1]$matches[2]", $type, $lang);
+        } elseif ($propertyPath === null or !is_string($propertyPath)) {
+            throw new InvalidArgumentException(
+                "\$propertyPath should be a string or EasyRdf_Resource and cannot be null"
+            );
+        } elseif ($propertyPath === '') {
+            throw new InvalidArgumentException(
+                "\$propertyPath cannot be an empty string"
+            );
+        }
+
+        // Loop through each component in the path
+        foreach (explode('/', $propertyPath) as $part) {
+            // Stop if we come to a literal
+            if ($resource instanceof EasyRdf_Literal) {
+                return null;
+            }
+
+            // Try each of the alternative paths
+            foreach (explode('|', $part) as $p) {
+                $res = $this->getSingleProperty($resource, $p, $type, $lang);
+                if ($res) {
+                    break;
+                }
+            }
+
+            // Stop if nothing was found
+            $resource = $res;
+            if (!$resource) {
+                break;
+            }
+        }
+
+        return $resource;
+    }
+
+    /** Get a single value for a property of a resource
+     *
+     * @param  string    $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string    $property The name of the property (e.g. foaf:name)
+     * @param  string    $type     The type of value to filter by (e.g. literal or resource)
+     * @param  string    $lang     The language to filter by (e.g. en)
+     * @return mixed               A value associated with the property
+     *
+     * @ignore
+     */
+    protected function getSingleProperty($resource, $property, $type = null, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+
+        // Get an array of values for the property
+        $values = $this->propertyValuesArray($resource, $property, $inverse);
+        if (!isset($values)) {
+            return null;
+        }
+
+        // Filter the results
+        $result = null;
+        if ($type) {
+            foreach ($values as $value) {
+                if ($type == 'literal' and $value['type'] == 'literal') {
+                    if ($lang == null or (isset($value['lang']) and $value['lang'] == $lang)) {
+                        $result = $value;
+                        break;
+                    }
+                } elseif ($type == 'resource') {
+                    if ($value['type'] == 'uri' or $value['type'] == 'bnode') {
+                        $result = $value;
+                        break;
+                    }
+                }
+            }
+        } else {
+            $result = $values[0];
+        }
+
+        // Convert the internal data structure into a PHP object
+        return $this->arrayToObject($result);
+    }
+
+    /** Get a single literal value for a property of a resource
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * This method will return null if there is not literal value for the
+     * property.
+     *
+     * @param  string       $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string|array $property The name of the property (e.g. foaf:name)
+     * @param  string       $lang     The language to filter by (e.g. en)
+     * @return object EasyRdf_Literal Literal value associated with the property
+     */
+    public function getLiteral($resource, $property, $lang = null)
+    {
+        return $this->get($resource, $property, 'literal', $lang);
+    }
+
+    /** Get a single resource value for a property of a resource
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * This method will return null if there is not resource for the
+     * property.
+     *
+     * @param  string       $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string|array $property The name of the property (e.g. foaf:name)
+     * @return object EasyRdf_Resource Resource associated with the property
+     */
+    public function getResource($resource, $property)
+    {
+        return $this->get($resource, $property, 'resource');
+    }
+
+    /** Return all the values for a particular property of a resource
+     *  @ignore
+     */
+    protected function propertyValuesArray($resource, $property, $inverse = false)
+    {
+        // Is an inverse property being requested?
+        if ($inverse) {
+            if (isset($this->revIndex[$resource])) {
+                $properties = &$this->revIndex[$resource];
+            }
+        } else {
+            if (isset($this->index[$resource])) {
+                $properties = &$this->index[$resource];
+            }
+        }
+
+        if (isset($properties[$property])) {
+            return $properties[$property];
+        } else {
+            return null;
+        }
+    }
+
+    /** Get an EasyRdf_Resource or EasyRdf_Literal object from an associative array.
+     *  @ignore
+     */
+    protected function arrayToObject($data)
+    {
+        if ($data) {
+            if ($data['type'] == 'uri' or $data['type'] == 'bnode') {
+                return $this->resource($data['value']);
+            } else {
+                return EasyRdf_Literal::create($data);
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /** Get all values for a property path
+     *
+     * This method will return an empty array if the property does not exist.
+     *
+     * @param  string  $resource      The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string  $propertyPath  A valid property path
+     * @param  string  $type          The type of value to filter by (e.g. literal)
+     * @param  string  $lang          The language to filter by (e.g. en)
+     * @return array                  An array of values associated with the property
+     */
+    public function all($resource, $propertyPath, $type = null, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+
+        if (is_object($propertyPath) and $propertyPath instanceof EasyRdf_Resource) {
+            return $this->allForSingleProperty($resource, $propertyPath->getUri(), $type, $lang);
+        } elseif (is_string($propertyPath) and preg_match('|^(\^?)<(.+)>|', $propertyPath, $matches)) {
+            return $this->allForSingleProperty($resource, "$matches[1]$matches[2]", $type, $lang);
+        } elseif ($propertyPath === null or !is_string($propertyPath)) {
+            throw new InvalidArgumentException(
+                "\$propertyPath should be a string or EasyRdf_Resource and cannot be null"
+            );
+        } elseif ($propertyPath === '') {
+            throw new InvalidArgumentException(
+                "\$propertyPath cannot be an empty string"
+            );
+        }
+
+        $objects = array($resource);
+
+        // Loop through each component in the path
+        foreach (explode('/', $propertyPath) as $part) {
+
+            $results = array();
+            foreach (explode('|', $part) as $p) {
+                foreach ($objects as $o) {
+                    // Ignore literals found earlier in path
+                    if ($o instanceof EasyRdf_Literal) {
+                        continue;
+                    }
+
+                    $results = array_merge(
+                        $results,
+                        $this->allForSingleProperty($o, $p, $type, $lang)
+                    );
+                }
+            }
+
+            // Stop if we don't have anything
+            if (empty($objects)) {
+                break;
+            }
+
+            // Use the results as the input to the next iteration
+            $objects = $results;
+        }
+
+        return $results;
+    }
+
+    /** Get all values for a single property of a resource
+     *
+     * @param  string  $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $type     The type of value to filter by (e.g. literal)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return array             An array of values associated with the property
+     *
+     * @ignore
+     */
+    protected function allForSingleProperty($resource, $property, $type = null, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+
+        // Get an array of values for the property
+        $values = $this->propertyValuesArray($resource, $property, $inverse);
+        if (!isset($values)) {
+            return array();
+        }
+
+        $objects = array();
+        if ($type) {
+            foreach ($values as $value) {
+                if ($type == 'literal' and $value['type'] == 'literal') {
+                    if ($lang == null or (isset($value['lang']) and $value['lang'] == $lang)) {
+                        $objects[] = $this->arrayToObject($value);
+                    }
+                } elseif ($type == 'resource') {
+                    if ($value['type'] == 'uri' or $value['type'] == 'bnode') {
+                        $objects[] = $this->arrayToObject($value);
+                    }
+                }
+            }
+        } else {
+            foreach ($values as $value) {
+                $objects[] = $this->arrayToObject($value);
+            }
+        }
+        return $objects;
+    }
+
+    /** Get all literal values for a property of a resource
+     *
+     * This method will return an empty array if the resource does not
+     * has any literal values for that property.
+     *
+     * @param  string  $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return array             An array of values associated with the property
+     */
+    public function allLiterals($resource, $property, $lang = null)
+    {
+        return $this->all($resource, $property, 'literal', $lang);
+    }
+
+    /** Get all resources for a property of a resource
+     *
+     * This method will return an empty array if the resource does not
+     * has any resources for that property.
+     *
+     * @param  string  $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @return array             An array of values associated with the property
+     */
+    public function allResources($resource, $property)
+    {
+        return $this->all($resource, $property, 'resource');
+    }
+
+    /** Get all the resources in the graph of a certain type
+     *
+     * If no resources of the type are available and empty
+     * array is returned.
+     *
+     * @param  string  $type   The type of the resource (e.g. foaf:Person)
+     * @return array The array of resources
+     */
+    public function allOfType($type)
+    {
+        return $this->all($type, '^rdf:type');
+    }
+
+    /** Count the number of values for a property of a resource
+     *
+     * @param  string  $resource The URI of the resource (e.g. http://example.com/joe#me)
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $type     The type of value to filter by (e.g. literal)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return integer           The number of values for this property
+     */
+    public function countValues($resource, $property, $type = null, $lang = null)
+    {
+        return count($this->all($resource, $property, $type, $lang));
+    }
+
+    /** Concatenate all values for a property of a resource into a string.
+     *
+     * The default is to join the values together with a space character.
+     * This method will return an empty string if the property does not exist.
+     *
+     * @param  mixed   $resource The resource to get the property on
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $glue     The string to glue the values together with.
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return string            Concatenation of all the values.
+     */
+    public function join($resource, $property, $glue = ' ', $lang = null)
+    {
+        return join($glue, $this->all($resource, $property, 'literal', $lang));
+    }
+
+    /** Add data to the graph
+     *
+     * The resource can either be a resource or the URI of a resource.
+     *
+     * Example:
+     *   $graph->add("http://www.example.com", 'dc:title', 'Title of Page');
+     *
+     * @param  mixed $resource   The resource to add data to
+     * @param  mixed $property   The property name
+     * @param  mixed $value      The new value for the property
+     * @return integer           The number of values added (1 or 0)
+     */
+    public function add($resource, $property, $value)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        // No value given?
+        if ($value === null) {
+            return 0;
+        }
+
+        // Check that the value doesn't already exist
+        if (isset($this->index[$resource][$property])) {
+            foreach ($this->index[$resource][$property] as $v) {
+                if ($v == $value) {
+                    return 0;
+                }
+            }
+        }
+        $this->index[$resource][$property][] = $value;
+
+        // Add to the reverse index if it is a resource
+        if ($value['type'] == 'uri' or $value['type'] == 'bnode') {
+            $uri = $value['value'];
+            $this->revIndex[$uri][$property][] = array(
+                'type' => substr($resource, 0, 2) == '_:' ? 'bnode' : 'uri',
+                'value' => $resource
+            );
+        }
+
+        // Success
+        return 1;
+    }
+
+    /** Add a literal value as a property of a resource
+     *
+     * The resource can either be a resource or the URI of a resource.
+     * The value can either be a single value or an array of values.
+     *
+     * Example:
+     *   $graph->add("http://www.example.com", 'dc:title', 'Title of Page');
+     *
+     * @param  mixed  $resource  The resource to add data to
+     * @param  mixed  $property  The property name
+     * @param  mixed  $value     The value or values for the property
+     * @param  string $lang      The language of the literal
+     * @return integer           The number of values added
+     */
+    public function addLiteral($resource, $property, $value, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+
+        if (is_array($value)) {
+            $added = 0;
+            foreach ($value as $v) {
+                $added += $this->addLiteral($resource, $property, $v, $lang);
+            }
+            return $added;
+        } elseif (!is_object($value) or !$value instanceof EasyRdf_Literal) {
+            $value = EasyRdf_Literal::create($value, $lang);
+        }
+        return $this->add($resource, $property, $value);
+    }
+
+    /** Add a resource as a property of another resource
+     *
+     * The resource can either be a resource or the URI of a resource.
+     *
+     * Example:
+     *   $graph->add("http://example.com/bob", 'foaf:knows', 'http://example.com/alice');
+     *
+     * @param  mixed $resource   The resource to add data to
+     * @param  mixed $property   The property name
+     * @param  mixed $resource2  The resource to be value of the property
+     * @return integer           The number of values added
+     */
+    public function addResource($resource, $property, $resource2)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkResourceParam($resource2);
+
+        return $this->add(
+            $resource,
+            $property,
+            array(
+                'type' => substr($resource2, 0, 2) == '_:' ? 'bnode' : 'uri',
+                'value' => $resource2
+            )
+        );
+    }
+
+    /** Set a value for a property
+     *
+     * The new value will replace the existing values for the property.
+     *
+     * @param  string  $resource The resource to set the property on
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value    The value for the property
+     * @return integer           The number of values added (1 or 0)
+     */
+    public function set($resource, $property, $value)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        // Delete the old values
+        $this->delete($resource, $property);
+
+        // Add the new values
+        return $this->add($resource, $property, $value);
+    }
+
+    /** Delete a property (or optionally just a specific value)
+     *
+     * @param  mixed   $resource The resource to delete the property from
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value The value to delete (null to delete all values)
+     * @return integer The number of values deleted
+     */
+    public function delete($resource, $property, $value = null)
+    {
+        $this->checkResourceParam($resource);
+
+        if (is_object($property) and $property instanceof EasyRdf_Resource) {
+            return $this->deleteSingleProperty($resource, $property->getUri(), $value);
+        } elseif (is_string($property) and preg_match('|^(\^?)<(.+)>|', $property, $matches)) {
+            return $this->deleteSingleProperty($resource, "$matches[1]$matches[2]", $value);
+        } elseif ($property === null or !is_string($property)) {
+            throw new InvalidArgumentException(
+                "\$property should be a string or EasyRdf_Resource and cannot be null"
+            );
+        } elseif ($property === '') {
+            throw new InvalidArgumentException(
+                "\$property cannot be an empty string"
+            );
+        }
+
+        // FIXME: finish implementing property paths for delete
+        return $this->deleteSingleProperty($resource, $property, $value);
+    }
+
+
+    /** Delete a property (or optionally just a specific value)
+     *
+     * @param  mixed   $resource The resource to delete the property from
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value The value to delete (null to delete all values)
+     * @return integer The number of values deleted
+     *
+     * @ignore
+     */
+    public function deleteSingleProperty($resource, $property, $value = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        $count = 0;
+        if (isset($this->index[$resource][$property])) {
+            foreach ($this->index[$resource][$property] as $k => $v) {
+                if (!$value or $v == $value) {
+                    unset($this->index[$resource][$property][$k]);
+                    $count++;
+                    if ($v['type'] == 'uri' or $v['type'] == 'bnode') {
+                        $this->deleteInverse($v['value'], $property, $resource);
+                    }
+                }
+            }
+
+            // Clean up the indexes - remove empty properties and resources
+            if ($count) {
+                if (count($this->index[$resource][$property]) == 0) {
+                    unset($this->index[$resource][$property]);
+                }
+                if (count($this->index[$resource]) == 0) {
+                    unset($this->index[$resource]);
+                }
+            }
+        }
+
+        return $count;
+    }
+
+    /** Delete a resource from a property of another resource
+     *
+     * The resource can either be a resource or the URI of a resource.
+     *
+     * Example:
+     *   $graph->delete("http://example.com/bob", 'foaf:knows', 'http://example.com/alice');
+     *
+     * @param  mixed $resource   The resource to delete data from
+     * @param  mixed $property   The property name
+     * @param  mixed $resource2  The resource value of the property to be deleted
+     */
+    public function deleteResource($resource, $property, $resource2)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkResourceParam($resource2);
+
+        return $this->delete(
+            $resource,
+            $property,
+            array(
+                'type' => substr($resource2, 0, 2) == '_:' ? 'bnode' : 'uri',
+                'value' => $resource2
+            )
+        );
+    }
+
+    /** Delete a literal value from a property of a resource
+     *
+     * Example:
+     *   $graph->delete("http://www.example.com", 'dc:title', 'Title of Page');
+     *
+     * @param  mixed  $resource  The resource to add data to
+     * @param  mixed  $property  The property name
+     * @param  mixed  $value     The value of the property
+     * @param  string $lang      The language of the literal
+     */
+    public function deleteLiteral($resource, $property, $value, $lang = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        if ($lang) {
+            $value['lang'] = $lang;
+        }
+
+        return $this->delete($resource, $property, $value);
+    }
+
+    /** This function is for internal use only.
+     *
+     * Deletes an inverse property from a resource.
+     *
+     * @ignore
+     */
+    protected function deleteInverse($resource, $property, $value)
+    {
+        if (isset($this->revIndex[$resource])) {
+            foreach ($this->revIndex[$resource][$property] as $k => $v) {
+                if ($v['value'] === $value) {
+                    unset($this->revIndex[$resource][$property][$k]);
+                }
+            }
+            if (count($this->revIndex[$resource][$property]) == 0) {
+                unset($this->revIndex[$resource][$property]);
+            }
+            if (count($this->revIndex[$resource]) == 0) {
+                unset($this->revIndex[$resource]);
+            }
+        }
+    }
+
+    /** Check if the graph contains any statements
+     *
+     * @return boolean True if the graph contains no statements
+     */
+    public function isEmpty()
+    {
+        return count($this->index) == 0;
+    }
+
+    /** Get a list of all the shortened property names (qnames) for a resource.
+     *
+     * This method will return an empty array if the resource has no properties.
+     *
+     * @return array            Array of shortened URIs
+     */
+    public function properties($resource)
+    {
+        $this->checkResourceParam($resource);
+
+        $properties = array();
+        if (isset($this->index[$resource])) {
+            foreach ($this->index[$resource] as $property => $value) {
+                $short = EasyRdf_Namespace::shorten($property);
+                if ($short) {
+                    $properties[] = $short;
+                }
+            }
+        }
+        return $properties;
+    }
+
+    /** Get a list of the full URIs for the properties of a resource.
+     *
+     * This method will return an empty array if the resource has no properties.
+     *
+     * @return array            Array of full URIs
+     */
+    public function propertyUris($resource)
+    {
+        $this->checkResourceParam($resource);
+
+        if (isset($this->index[$resource])) {
+            return array_keys($this->index[$resource]);
+        } else {
+            return array();
+        }
+    }
+
+    /** Get a list of the full URIs for the properties that point to a resource.
+     *
+     * @return array   Array of full property URIs
+     */
+    public function reversePropertyUris($resource)
+    {
+        $this->checkResourceParam($resource);
+
+        if (isset($this->revIndex[$resource])) {
+            return array_keys($this->revIndex[$resource]);
+        } else {
+            return array();
+        }
+    }
+
+    /** Check to see if a property exists for a resource.
+     *
+     * This method will return true if the property exists.
+     * If the value parameter is given, then it will only return true
+     * if the value also exists for that property.
+     *
+     * By providing a value parameter you can use this function to check
+     * to see if a triple exists in the graph.
+     *
+     * @param  mixed   $resource The resource to check
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value    An optional value of the property
+     * @return boolean           True if value the property exists.
+     */
+    public function hasProperty($resource, $property, $value = null)
+    {
+        $this->checkResourceParam($resource);
+        $this->checkSinglePropertyParam($property, $inverse);
+        $this->checkValueParam($value);
+
+        // Use the reverse index if it is an inverse property
+        if ($inverse) {
+            $index = &$this->revIndex;
+        } else {
+            $index = &$this->index;
+        }
+
+        if (isset($index[$resource][$property])) {
+            if (is_null($value)) {
+                return true;
+            } else {
+                foreach ($index[$resource][$property] as $v) {
+                    if ($v == $value) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /** Serialise the graph into RDF
+     *
+     * The $format parameter can be an EasyRdf_Format object, a
+     * format name, a mime type or a file extension.
+     *
+     * Example:
+     *   $turtle = $graph->serialise('turtle');
+     *
+     * @param  mixed  $format  The format to serialise to
+     * @return mixed  The serialised graph
+     */
+    public function serialise($format)
+    {
+        if (!$format instanceof EasyRdf_Format) {
+            $format = EasyRdf_Format::getFormat($format);
+        }
+        $serialiser = $format->newSerialiser();
+        return $serialiser->serialise($this, $format->getName());
+    }
+
+    /** Return a human readable view of all the resources in the graph
+     *
+     * This method is intended to be a debugging aid and will
+     * return a pretty-print view of all the resources and their
+     * properties.
+     *
+     * @param  string  $format  Either 'html' or 'text'
+     * @return string
+     */
+    public function dump($format = 'html')
+    {
+        $result = '';
+        if ($format == 'html') {
+            $result .= "<div style='font-family:arial; font-weight: bold; padding:0.5em; ".
+                   "color: black; background-color:lightgrey;border:dashed 1px grey;'>".
+                   "Graph: ". $this->uri . "</div>\n";
+        } else {
+            $result .= "Graph: ". $this->uri . "\n";
+        }
+
+        foreach ($this->index as $resource => $properties) {
+            $result .= $this->dumpResource($resource, $format);
+        }
+        return $result;
+    }
+
+    /** Return a human readable view of a resource and its properties
+     *
+     * This method is intended to be a debugging aid and will
+     * print a resource and its properties.
+     *
+     * @param  mixed    $resource  The resource to dump
+     * @param  string   $format    Either 'html' or 'text'
+     * @return string
+     */
+    public function dumpResource($resource, $format = 'html')
+    {
+        $this->checkResourceParam($resource, true);
+
+        if (isset($this->index[$resource])) {
+            $properties = $this->index[$resource];
+        } else {
+            return '';
+        }
+
+        $plist = array();
+        foreach ($properties as $property => $values) {
+            $olist = array();
+            foreach ($values as $value) {
+                if ($value['type'] == 'literal') {
+                    $olist []= EasyRdf_Utils::dumpLiteralValue($value, $format, 'black');
+                } else {
+                    $olist []= EasyRdf_Utils::dumpResourceValue($value['value'], $format, 'blue');
+                }
+            }
+
+            $pstr = EasyRdf_Namespace::shorten($property);
+            if ($pstr == null) {
+                $pstr = $property;
+            }
+            if ($format == 'html') {
+                $plist []= "<span style='font-size:130%'>&rarr;</span> ".
+                           "<span style='text-decoration:none;color:green'>".
+                           htmlentities($pstr) . "</span> ".
+                           "<span style='font-size:130%'>&rarr;</span> ".
+                           join(", ", $olist);
+            } else {
+                $plist []= "  -> $pstr -> " . join(", ", $olist);
+            }
+        }
+
+        if ($format == 'html') {
+            return "<div id='".htmlentities($resource, ENT_QUOTES)."' " .
+                   "style='font-family:arial; padding:0.5em; ".
+                   "background-color:lightgrey;border:dashed 1px grey;'>\n".
+                   "<div>".EasyRdf_Utils::dumpResourceValue($resource, $format, 'blue')." ".
+                   "<span style='font-size: 0.8em'>(".
+                   $this->classForResource($resource).")</span></div>\n".
+                   "<div style='padding-left: 3em'>\n".
+                   "<div>".join("</div>\n<div>", $plist)."</div>".
+                   "</div></div>\n";
+        } else {
+            return $resource." (".$this->classForResource($resource).")\n" .
+                   join("\n", $plist) . "\n\n";
+        }
+    }
+
+    /** Get the resource type of the graph
+     *
+     * The type will be a shortened URI as a string.
+     * If the graph has multiple types then the type returned
+     * may be arbitrary.
+     * This method will return null if the resource has no type.
+     *
+     * @return string A type assocated with the resource (e.g. foaf:Document)
+     */
+    public function type($resource = null)
+    {
+        $this->checkResourceParam($resource, true);
+
+        if ($resource) {
+            $type = $this->get($resource, 'rdf:type', 'resource');
+            if ($type) {
+                return EasyRdf_Namespace::shorten($type);
+            }
+        }
+
+        return null;
+    }
+
+    /** Get the resource type of the graph as a EasyRdf_Resource
+     *
+     * If the graph has multiple types then the type returned
+     * may be arbitrary.
+     * This method will return null if the resource has no type.
+     *
+     * @return object EasyRdf_Resource  A type assocated with the resource
+     */
+    public function typeAsResource($resource = null)
+    {
+        $this->checkResourceParam($resource, true);
+
+        if ($resource) {
+            return $this->get($resource, 'rdf:type', 'resource');
+        }
+
+        return null;
+    }
+
+    /** Get a list of types for a resource
+     *
+     * The types will each be a shortened URI as a string.
+     * This method will return an empty array if the resource has no types.
+     *
+     * If $resource is null, then it will get the types for the URI of the graph.
+     *
+     * @return array All types assocated with the resource (e.g. foaf:Person)
+     */
+    public function types($resource = null)
+    {
+        $this->checkResourceParam($resource, true);
+
+        $types = array();
+        if ($resource) {
+            foreach ($this->all($resource, 'rdf:type', 'resource') as $type) {
+                $types[] = EasyRdf_Namespace::shorten($type);
+            }
+        }
+
+        return $types;
+    }
+
+    /** Check if a resource is of the specified type
+     *
+     * @param  string  $resource The resource to check the type of
+     * @param  string  $type     The type to check (e.g. foaf:Person)
+     * @return boolean           True if resource is of specified type
+     */
+    public function isA($resource, $type)
+    {
+        $this->checkResourceParam($resource, true);
+
+        $type = EasyRdf_Namespace::expand($type);
+        foreach ($this->all($resource, 'rdf:type', 'resource') as $t) {
+            if ($t->getUri() == $type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Add one or more rdf:type properties to a resource
+     *
+     * @param  string  $resource The resource to add the type to
+     * @param  string  $types    One or more types to add (e.g. foaf:Person)
+     * @return integer           The number of types added
+     */
+    public function addType($resource, $types)
+    {
+        $this->checkResourceParam($resource, true);
+
+        if (!is_array($types)) {
+            $types = array($types);
+        }
+
+        $count = 0;
+        foreach ($types as $type) {
+            $type = EasyRdf_Namespace::expand($type);
+            $count += $this->add($resource, 'rdf:type', array('type' => 'uri', 'value' => $type));
+        }
+
+        return $count;
+    }
+
+    /** Change the rdf:type property for a resource
+     *
+     * Note that if the resource object has already previously
+     * been created, then the PHP class of the resource will not change.
+     *
+     * @param  string  $resource The resource to change the type of
+     * @param  string  $type     The new type (e.g. foaf:Person)
+     * @return integer           The number of types added
+     */
+    public function setType($resource, $type)
+    {
+        $this->checkResourceParam($resource, true);
+
+        $this->delete($resource, 'rdf:type');
+        return $this->addType($resource, $type);
+    }
+
+    /** Get a human readable label for a resource
+     *
+     * This method will check a number of properties for a resource
+     * (in the order: skos:prefLabel, rdfs:label, foaf:name, dc:title)
+     * and return an approriate first that is available. If no label
+     * is available then it will return null.
+     *
+     * @return string A label for the resource.
+     */
+    public function label($resource = null, $lang = null)
+    {
+        $this->checkResourceParam($resource, true);
+
+        if ($resource) {
+            return $this->get(
+                $resource,
+                'skos:prefLabel|rdfs:label|foaf:name|rss:title|dc:title|dc11:title',
+                'literal',
+                $lang
+            );
+        } else {
+            return null;
+        }
+    }
+
+    /** Get the primary topic of the graph
+     *
+     * @return EasyRdf_Resource The primary topic of the document.
+     */
+    public function primaryTopic($resource = null)
+    {
+        $this->checkResourceParam($resource, true);
+
+        if ($resource) {
+            return $this->get(
+                $resource,
+                'foaf:primaryTopic|^foaf:isPrimaryTopicOf',
+                'resource'
+            );
+        } else {
+            return null;
+        }
+    }
+
+    /** Returns the graph as a RDF/PHP associative array
+     *
+     * @return array The contents of the graph as an array.
+     */
+    public function toRdfPhp()
+    {
+        return $this->index;
+    }
+
+    /** Calculates the number of triples in the graph
+     *
+     * @return integer The number of triples in the graph.
+     */
+    public function countTriples()
+    {
+        $count = 0;
+        foreach ($this->index as $resource) {
+            foreach ($resource as $property => $values) {
+                $count += count($values);
+            }
+        }
+        return $count;
+    }
+
+    /** Magic method to return URI of resource when casted to string
+     *
+     * @return string The URI of the resource
+     */
+    public function __toString()
+    {
+        return $this->uri == null ? '' : $this->uri;
+    }
+
+    /** Magic method to get a property of the graph
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   $value = $graph->title;
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param  string $name The name of the property
+     * @return string       A single value for the named property
+     */
+    public function __get($name)
+    {
+        return $this->get($this->uri, $name);
+    }
+
+    /** Magic method to set the value for a property of the graph
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   $graph->title = 'Title';
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param  string $name The name of the property
+     * @param  string $value The value for the property
+     */
+    public function __set($name, $value)
+    {
+        return $this->set($this->uri, $name, $value);
+    }
+
+    /** Magic method to check if a property exists
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   if (isset($graph->title)) { blah(); }
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param string $name The name of the property
+     */
+    public function __isset($name)
+    {
+        return $this->hasProperty($this->uri, $name);
+    }
+
+    /** Magic method to delete a property of the graph
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   unset($graph->title);
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param string $name The name of the property
+     */
+    public function __unset($name)
+    {
+        return $this->delete($this->uri, $name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/GraphStore.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,215 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * A class for fetching, saving and deleting graphs to a Graph Store.
+ * Implementation of the SPARQL 1.1 Graph Store HTTP Protocol.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_GraphStore
+{
+    /** The address of the GraphStore endpoint */
+    private $uri = null;
+    private $parsedUri = null;
+
+
+    /** Create a new SPARQL Graph Store client
+     *
+     * @param string $uri The address of the graph store endpoint
+     */
+    public function __construct($uri)
+    {
+        $this->uri = $uri;
+        $this->parsedUri = new EasyRdf_ParsedUri($uri);
+    }
+
+    /** Get the URI of the graph store
+     *
+     * @return string The URI of the graph store
+     */
+    public function getUri()
+    {
+        return $this->uri;
+    }
+
+    /** Fetch a named graph from the graph store
+     *
+     * The URI can either be a full absolute URI or
+     * a URI relative to the URI of the graph store.
+     *
+     * @param string $uriRef The URI of graph desired
+     * @return object EasyRdf_Graph The graph requested
+     */
+    public function get($uriRef)
+    {
+        $graphUri = $this->parsedUri->resolve($uriRef)->toString();
+        $dataUrl = $this->urlForGraph($graphUri);
+        $graph = new EasyRdf_Graph($graphUri);
+        $graph->load($dataUrl);
+        return $graph;
+    }
+
+    /** Send some graph data to the graph store
+     *
+     * This method is used by insert() and replace()
+     *
+     * @ignore
+     */
+    protected function sendGraph($method, $graph, $uriRef, $format)
+    {
+        if (is_object($graph) and $graph instanceof EasyRdf_Graph) {
+            if ($uriRef == null) {
+                $uriRef = $graph->getUri();
+            }
+            $data = $graph->serialise($format);
+        } else {
+            $data = $graph;
+        }
+
+        $formatObj = EasyRdf_Format::getFormat($format);
+        $mimeType = $formatObj->getDefaultMimeType();
+
+        $graphUri = $this->parsedUri->resolve($uriRef)->toString();
+        $dataUrl = $this->urlForGraph($graphUri);
+
+        $client = EasyRdf_Http::getDefaultHttpClient();
+        $client->resetParameters(true);
+        $client->setUri($dataUrl);
+        $client->setMethod($method);
+        $client->setRawData($data);
+        $client->setHeaders('Content-Type', $mimeType);
+        $response = $client->request();
+        if (!$response->isSuccessful()) {
+            throw new EasyRdf_Exception(
+                "HTTP request for $dataUrl failed: ".$response->getMessage()
+            );
+        }
+        return $response;
+    }
+
+    /** Replace the contents of a graph in the graph store with new data
+     *
+     * The $graph parameter is the EasyRdf_Graph object to be sent to the
+     * graph store. Alternatively it can be a string, already serialised.
+     *
+     * The URI can either be a full absolute URI or
+     * a URI relative to the URI of the graph store.
+     *
+     * The $format parameter can be given to specify the serialisation
+     * used to send the graph data to the graph store.
+     *
+     * @param object EasyRdfGraph $graph The URI of graph desired
+     * @param string $uriRef The URI of graph to be replaced
+     * @param string $format The format of the data to send to the graph store
+     * @return object EasyRdf_Http_Response The response from the graph store
+     */
+    public function replace($graph, $uriRef = null, $format = 'ntriples')
+    {
+        return $this->sendGraph('PUT', $graph, $uriRef, $format);
+    }
+
+    /** Add data to a graph in the graph store
+     *
+     * The $graph parameter is the EasyRdf_Graph object to be sent to the
+     * graph store. Alternatively it can be a string, already serialised.
+     *
+     * The URI can either be a full absolute URI or
+     * a URI relative to the URI of the graph store.
+     *
+     * The $format parameter can be given to specify the serialisation
+     * used to send the graph data to the graph store.
+     *
+     * @param object EasyRdfGraph $graph The URI of graph desired
+     * @param string $uriRef The URI of graph to be added to
+     * @param string $format The format of the data to send to the graph store
+     * @return object EasyRdf_Http_Response The response from the graph store
+     */
+    public function insert($graph, $uriRef = null, $format = 'ntriples')
+    {
+        return $this->sendGraph('POST', $graph, $uriRef, $format);
+    }
+
+    /** Delete a graph from the graph store
+     *
+     * The URI can either be a full absolute URI or
+     * a URI relative to the URI of the graph store.
+     *
+     * @param string $uriRef The URI of graph to be added to
+     * @return object EasyRdf_Http_Response The response from the graph store
+     */
+    public function delete($uriRef)
+    {
+        $graphUri = $this->parsedUri->resolve($uriRef)->toString();
+        $dataUrl = $this->urlForGraph($graphUri);
+
+        $client = EasyRdf_Http::getDefaultHttpClient();
+        $client->resetParameters(true);
+        $client->setUri($dataUrl);
+        $client->setMethod('DELETE');
+        $response = $client->request();
+        if (!$response->isSuccessful()) {
+            throw new EasyRdf_Exception(
+                "HTTP request to delete $dataUrl failed: ".$response->getMessage()
+            );
+        }
+        return $response;
+    }
+
+    /** Work out the full URL for a graph store request.
+     *  by checking if if it is a direct or indirect request.
+     *  @ignore
+     */
+    protected function urlForGraph($url)
+    {
+        if (strpos($url, $this->uri) === false) {
+            $url = $this->uri."?graph=".urlencode($url);
+        }
+        return $url;
+    }
+
+    /** Magic method to return URI of the graph store when casted to string
+     *
+     * @return string The URI of the graph store
+     */
+    public function __toString()
+    {
+        return empty($this->uri) ? '' : $this->uri;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Http.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+
+/**
+ * Static class to set the HTTP client used by EasyRdf
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Http
+{
+    /** The default HTTP Client object */
+    private static $defaultHttpClient = null;
+
+    /** Set the HTTP Client object used to fetch RDF data
+     *
+     * @param  object mixed $httpClient The new HTTP client object
+     * @return object mixed The new HTTP client object
+     */
+    public static function setDefaultHttpClient($httpClient)
+    {
+        if (!is_object($httpClient) or
+            !($httpClient instanceof Zend_Http_Client or
+              $httpClient instanceof EasyRdf_Http_Client)) {
+            throw new InvalidArgumentException(
+                "\$httpClient should be an object of class Zend_Http_Client or EasyRdf_Http_Client"
+            );
+        }
+        return self::$defaultHttpClient = $httpClient;
+    }
+
+    /** Get the HTTP Client object used to fetch RDF data
+     *
+     * If no HTTP Client has previously been set, then a new
+     * default (EasyRdf_Http_Client) client will be created.
+     *
+     * @return object mixed The HTTP client object
+     */
+    public static function getDefaultHttpClient()
+    {
+        if (!isset(self::$defaultHttpClient)) {
+            self::$defaultHttpClient = new EasyRdf_Http_Client();
+        }
+        return self::$defaultHttpClient;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Http/Client.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,548 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ * Copyright (c) 2005-2009 Zend Technologies USA Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 2005-2009 Zend Technologies USA Inc.
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * This class is an implemetation of an HTTP client in PHP.
+ * It supports basic HTTP 1.0 and 1.1 requests. For a more complete
+ * implementation try Zend_Http_Client.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Http_Client
+{
+    /**
+     * Configuration array, set using the constructor or using ::setConfig()
+     *
+     * @var array
+     */
+    private $config = array(
+        'maxredirects'    => 5,
+        'useragent'       => 'EasyRdf_Http_Client',
+        'timeout'         => 10
+    );
+
+    /**
+     * Request URI
+     *
+     * @var string
+     */
+    private $uri = null;
+
+    /**
+     * Associative array of request headers
+     *
+     * @var array
+     */
+    private $headers = array();
+
+    /**
+     * HTTP request method
+     *
+     * @var string
+     */
+    private $method = 'GET';
+
+    /**
+     * Associative array of GET parameters
+     *
+     * @var array
+     */
+    private $paramsGet = array();
+
+    /**
+     * The raw post data to send. Could be set by setRawData($data).
+     *
+     * @var string
+     */
+    private $rawPostData = null;
+
+    /**
+     * Redirection counter
+     *
+     * @var int
+     */
+    private $redirectCounter = 0;
+
+    /**
+     * Constructor method. Will create a new HTTP client. Accepts the target
+     * URL and optionally configuration array.
+     *
+     * @param string $uri
+     * @param array $config Configuration key-value pairs.
+     */
+    public function __construct($uri = null, $config = null)
+    {
+        if ($uri !== null) {
+            $this->setUri($uri);
+        }
+        if ($config !== null) {
+            $this->setConfig($config);
+        }
+    }
+
+    /**
+     * Set the URI for the next request
+     *
+     * @param  string $uri
+     * @return EasyRdf_Http_Client
+     */
+    public function setUri($uri)
+    {
+        if (!is_string($uri)) {
+            $uri = strval($uri);
+        }
+
+        if (!preg_match('/^http(s?):/', $uri)) {
+            throw new InvalidArgumentException(
+                "EasyRdf_Http_Client only supports the 'http' and 'https' schemes."
+            );
+        }
+
+        $this->uri = $uri;
+
+        return $this;
+    }
+
+    /**
+     * Get the URI for the next request
+     *
+     * @return string
+     */
+    public function getUri($asString = true)
+    {
+        return $this->uri;
+    }
+
+    /**
+     * Set configuration parameters for this HTTP client
+     *
+     * @param  array $config
+     * @return EasyRdf_Http_Client
+     * @throws InvalidArgumentException
+     */
+    public function setConfig($config = array())
+    {
+        if ($config == null or !is_array($config)) {
+            throw new InvalidArgumentException(
+                "\$config should be an array and cannot be null"
+            );
+        }
+
+        foreach ($config as $k => $v) {
+            $this->config[strtolower($k)] = $v;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set a request header
+     *
+     * @param string $name Header name (e.g. 'Accept')
+     * @param string $value Header value or null
+     * @return EasyRdf_Http_Client
+     */
+    public function setHeaders($name, $value = null)
+    {
+        $normalizedName = strtolower($name);
+
+        // If $value is null or false, unset the header
+        if ($value === null || $value === false) {
+            unset($this->headers[$normalizedName]);
+        } else {
+            // Else, set the header
+            $this->headers[$normalizedName] = array($name, $value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set the next request's method
+     *
+     * Validated the passed method and sets it.
+     *
+     * @param string $method
+     * @return EasyRdf_Http_Client
+     * @throws InvalidArgumentException
+     */
+    public function setMethod($method)
+    {
+        if (!is_string($method) or !preg_match('/^[A-Z]+$/', $method)) {
+            throw new InvalidArgumentException("Invalid HTTP request method.");
+        }
+
+        $this->method = $method;
+
+        return $this;
+    }
+
+    /**
+     * Get the method for the next request
+     *
+     * @return string
+     */
+    public function getMethod()
+    {
+        return $this->method;
+    }
+
+    /**
+     * Get the value of a specific header
+     *
+     * Note that if the header has more than one value, an array
+     * will be returned.
+     *
+     * @param string $key
+     * @return string|array|null The header value or null if it is not set
+     */
+    public function getHeader($key)
+    {
+        $key = strtolower($key);
+        if (isset($this->headers[$key])) {
+            return $this->headers[$key][1];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set a GET parameter for the request.
+     *
+     * @param string $name
+     * @param string $value
+     * @return EasyRdf_Http_Client
+     */
+    public function setParameterGet($name, $value = null)
+    {
+        if ($value === null) {
+            if (isset($this->paramsGet[$name])) {
+                unset($this->paramsGet[$name]);
+            }
+        } else {
+            $this->paramsGet[$name] = $value;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get a GET parameter for the request.
+     *
+     * @param string $name
+     * @return string value
+     */
+    public function getParameterGet($name)
+    {
+        if (isset($this->paramsGet[$name])) {
+            return $this->paramsGet[$name];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get all the GET parameters
+     *
+     * @return array
+     */
+    public function getParametersGet()
+    {
+        return $this->paramsGet;
+    }
+
+    /**
+     * Get the number of redirections done on the last request
+     *
+     * @return int
+     */
+    public function getRedirectionsCount()
+    {
+        return $this->redirectCounter;
+    }
+
+    /**
+     * Set the raw (already encoded) POST data.
+     *
+     * This function is here for two reasons:
+     * 1. For advanced user who would like to set their own data, already encoded
+     * 2. For backwards compatibilty: If someone uses the old post($data) method.
+     *    this method will be used to set the encoded data.
+     *
+     * $data can also be stream (such as file) from which the data will be read.
+     *
+     * @param string|resource $data
+     * @return Zend_Http_Client
+     */
+    public function setRawData($data)
+    {
+        $this->rawPostData = $data;
+        return $this;
+    }
+
+    /**
+     * Get the raw (already encoded) POST data.
+     *
+     * @return string
+     */
+    public function getRawData()
+    {
+        return $this->rawPostData;
+    }
+
+    /**
+     * Clear all GET and POST parameters
+     *
+     * Should be used to reset the request parameters if the client is
+     * used for several concurrent requests.
+     *
+     * clearAll parameter controls if we clean just parameters or also
+     * headers
+     *
+     * @param bool $clearAll Should all data be cleared?
+     * @return EasyRdf_Http_Client
+     */
+    public function resetParameters($clearAll = false)
+    {
+        // Reset parameter data
+        $this->paramsGet   = array();
+        $this->rawPostData = null;
+        $this->method      = 'GET';
+
+        if ($clearAll) {
+            $this->headers = array();
+        } else {
+            // Clear outdated headers
+            if (isset($this->headers['content-type'])) {
+                unset($this->headers['content-type']);
+            }
+            if (isset($this->headers['content-length'])) {
+                unset($this->headers['content-length']);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Send the HTTP request and return an HTTP response object
+     *
+     * @return EasyRdf_Http_Response
+     * @throws EasyRdf_Exception
+     */
+    public function request($method = null)
+    {
+        if (!$this->uri) {
+            throw new EasyRdf_Exception(
+                "Set URI before calling EasyRdf_Http_Client->request()"
+            );
+        }
+
+        if ($method) {
+            $this->setMethod($method);
+        }
+        $this->redirectCounter = 0;
+        $response = null;
+
+        // Send the first request. If redirected, continue.
+        do {
+            // Clone the URI and add the additional GET parameters to it
+            $uri = parse_url($this->uri);
+            if ($uri['scheme'] === 'http') {
+                $host = $uri['host'];
+            } elseif ($uri['scheme'] === 'https') {
+                $host = 'ssl://'.$uri['host'];
+            } else {
+                throw new EasyRdf_Exception(
+                    "Unsupported URI scheme: ".$uri['scheme']
+                );
+            }
+
+            if (isset($uri['port'])) {
+                $port = $uri['port'];
+            } else {
+                if ($uri['scheme'] === 'https') {
+                    $port = 443;
+                } else {
+                    $port = 80;
+                }
+            }
+
+            if (!empty($this->paramsGet)) {
+                if (!empty($uri['query'])) {
+                    $uri['query'] .= '&';
+                } else {
+                    $uri['query'] = '';
+                }
+                $uri['query'] .= http_build_query($this->paramsGet, null, '&');
+            }
+
+            $headers = $this->prepareHeaders($uri['host'], $port);
+
+            // Open socket to remote server
+            $socket = @fsockopen($host, $port, $errno, $errstr, $this->config['timeout']);
+            if (!$socket) {
+                throw new EasyRdf_Exception("Unable to connect to $host:$port ($errstr)");
+            }
+
+            // Write the request
+            $path = $uri['path'];
+            if (isset($uri['query'])) {
+                $path .= '?' . $uri['query'];
+            }
+            fwrite($socket, "{$this->method} {$path} HTTP/1.1\r\n");
+            foreach ($headers as $k => $v) {
+                if (is_string($k)) {
+                    $v = ucfirst($k) . ": $v";
+                }
+                fwrite($socket, "$v\r\n");
+            }
+            fwrite($socket, "\r\n");
+
+            // Send the request body, if there is one set
+            if (isset($this->rawPostData)) {
+                fwrite($socket, $this->rawPostData);
+            }
+
+            // Read in the response
+            $content = '';
+            while (!feof($socket)) {
+                $content .= fgets($socket);
+            }
+
+            // FIXME: support HTTP/1.1 100 Continue
+
+            // Close the socket
+            @fclose($socket);
+
+            // Parse the response string
+            $response = EasyRdf_Http_Response::fromString($content);
+
+            // If we got redirected, look for the Location header
+            if ($response->isRedirect() &&
+                   ($location = $response->getHeader('location'))
+               ) {
+
+                // Avoid problems with buggy servers that add whitespace at the
+                // end of some headers (See ZF-11283)
+                $location = trim($location);
+
+                // Some servers return relative URLs in the location header
+                // resolve it in relation to previous request
+                $baseUri = new EasyRdf_ParsedUri($this->uri);
+                $location = $baseUri->resolve($location)->toString();
+
+                // If it is a 303 then drop the parameters and send a GET request
+                if ($response->getStatus() == 303) {
+                    $this->resetParameters();
+                    $this->setMethod('GET');
+                }
+
+                // If we got a well formed absolute URI
+                if (parse_url($location)) {
+                    $this->setHeaders('host', null);
+                    $this->setUri($location);
+                } else {
+                    throw new EasyRdf_Exception(
+                        "Failed to parse Location header returned by ".
+                        $this->uri
+                    );
+                }
+                ++$this->redirectCounter;
+
+            } else {
+                // If we didn't get any location, stop redirecting
+                break;
+            }
+
+
+        } while ($this->redirectCounter < $this->config['maxredirects']);
+
+        return $response;
+    }
+
+    /**
+     * Prepare the request headers
+     *
+     * @ignore
+     * @return array
+     */
+    protected function prepareHeaders($host, $port)
+    {
+        $headers = array();
+
+        // Set the host header
+        if (! isset($this->headers['host'])) {
+            // If the port is not default, add it
+            if ($port !== 80 and $port !== 443) {
+                $host .= ':' . $port;
+            }
+            $headers[] = "Host: {$host}";
+        }
+
+        // Set the connection header
+        if (! isset($this->headers['connection'])) {
+            $headers[] = "Connection: close";
+        }
+
+        // Set the user agent header
+        if (! isset($this->headers['user-agent'])) {
+            $headers[] = "User-Agent: {$this->config['useragent']}";
+        }
+
+        // If we have rawPostData set, set the content-length header
+        if (isset($this->rawPostData)) {
+            $headers[] = "Content-Length: ".strlen($this->rawPostData);
+        }
+
+        // Add all other user defined headers
+        foreach ($this->headers as $header) {
+            list($name, $value) = $header;
+            if (is_array($value)) {
+                $value = implode(', ', $value);
+            }
+
+            $headers[] = "$name: $value";
+        }
+
+        return $headers;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Http/Response.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,360 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.
+ * Copyright (c) 2005-2009 Zend Technologies USA Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc.
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an HTTP 1.0 / 1.1 response message.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 2005-2009 Zend Technologies USA Inc.
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Http_Response
+{
+
+    /**
+     * The HTTP response status code
+     *
+     * @var int
+     */
+    private $status;
+
+    /**
+     * The HTTP response code as string
+     * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500)
+     *
+     * @var string
+     */
+    private $message;
+
+    /**
+     * The HTTP response headers array
+     *
+     * @var array
+     */
+    private $headers = array();
+
+    /**
+     * The HTTP response body
+     *
+     * @var string
+     */
+    private $body;
+
+    /**
+     * Constructor.
+     *
+     * @param  int     $status HTTP Status code
+     * @param  array   $headers The HTTP response headers
+     * @param  string  $body The content of the response
+     * @param  string  $version The HTTP Version (1.0 or 1.1)
+     * @param  string  $message The HTTP response Message
+     * @return object  EasyRdf_Http_Response
+     */
+    public function __construct(
+        $status,
+        $headers,
+        $body = null,
+        $version = '1.1',
+        $message = null
+    ) {
+        $this->status = intval($status);
+        $this->body = $body;
+        $this->version = $version;
+        $this->message = $message;
+
+        foreach ($headers as $k => $v) {
+            $k = ucwords(strtolower($k));
+            $this->headers[$k] = $v;
+        }
+    }
+
+    /**
+     * Check whether the response in successful
+     *
+     * @return boolean
+     */
+    public function isSuccessful()
+    {
+        return ($this->status >= 200 && $this->status < 300);
+    }
+
+    /**
+     * Check whether the response is an error
+     *
+     * @return boolean
+     */
+    public function isError()
+    {
+        return ($this->status >= 400 && $this->status < 600);
+    }
+
+    /**
+     * Check whether the response is a redirection
+     *
+     * @return boolean
+     */
+    public function isRedirect()
+    {
+        return ($this->status >= 300 && $this->status < 400);
+    }
+
+    /**
+     * Get the HTTP response status code
+     *
+     * @return int
+     */
+    public function getStatus()
+    {
+        return $this->status;
+    }
+
+    /**
+     * Return a message describing the HTTP response code
+     * (Eg. "OK", "Not Found", "Moved Permanently")
+     *
+     * @return string
+     */
+    public function getMessage()
+    {
+        return $this->message;
+    }
+
+    /**
+     * Get the response body as string
+     *
+     * @return string
+     */
+    public function getBody()
+    {
+        // Decode the body if it was transfer-encoded
+        switch (strtolower($this->getHeader('transfer-encoding'))) {
+            // Handle chunked body
+            case 'chunked':
+                return self::decodeChunkedBody($this->body);
+                break;
+
+            // No transfer encoding, or unknown encoding extension:
+            // return body as is
+            default:
+                return $this->body;
+                break;
+        }
+    }
+
+    /**
+     * Get the raw response body (as transfered "on wire") as string
+     *
+     * If the body is encoded (with Transfer-Encoding, not content-encoding -
+     * IE "chunked" body), gzip compressed, etc. it will not be decoded.
+     *
+     * @return string
+     */
+    public function getRawBody()
+    {
+        return $this->body;
+    }
+
+    /**
+     * Get the HTTP version of the response
+     *
+     * @return string
+     */
+    public function getVersion()
+    {
+        return $this->version;
+    }
+
+    /**
+     * Get the response headers
+     *
+     * @return array
+     */
+    public function getHeaders()
+    {
+        return $this->headers;
+    }
+
+    /**
+     * Get a specific header as string, or null if it is not set
+     *
+     * @param string$header
+     * @return string|array|null
+     */
+    public function getHeader($header)
+    {
+        $header = ucwords(strtolower($header));
+        if (array_key_exists($header, $this->headers)) {
+            return $this->headers[$header];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get all headers as string
+     *
+     * @param boolean $statusLine Whether to return the first status line (ie "HTTP 200 OK")
+     * @param string  $br         Line breaks (eg. "\n", "\r\n", "<br />")
+     * @return string
+     */
+    public function getHeadersAsString($statusLine = true, $br = "\n")
+    {
+        $str = '';
+
+        if ($statusLine) {
+            $str = "HTTP/{$this->version} {$this->status} {$this->message}{$br}";
+        }
+
+        // Iterate over the headers and stringify them
+        foreach ($this->headers as $name => $value) {
+            if (is_string($value)) {
+                $str .= "{$name}: {$value}{$br}";
+            } elseif (is_array($value)) {
+                foreach ($value as $subval) {
+                    $str .= "{$name}: {$subval}{$br}";
+                }
+            }
+        }
+
+        return $str;
+    }
+
+    /**
+     * Create an EasyRdf_Http_Response object from a HTTP response string
+     *
+     * @param string $responseStr
+     * @return EasyRdf_Http_Response
+     */
+    public static function fromString($responseStr)
+    {
+        // First, split body and headers
+        $matches = preg_split('|(?:\r?\n){2}|m', $responseStr, 2);
+        if ($matches and sizeof($matches) == 2) {
+            list ($headerLines, $body) = $matches;
+        } else {
+            throw new EasyRdf_Exception(
+                "Failed to parse HTTP response."
+            );
+        }
+
+        // Split headers part to lines
+        $headerLines = preg_split('|[\r\n]+|m', $headerLines);
+        $status = array_shift($headerLines);
+        if (preg_match("|^HTTP/([\d\.x]+) (\d+) ([^\r\n]+)|", $status, $m)) {
+            $version = $m[1];
+            $status = $m[2];
+            $message = $m[3];
+        } else {
+            throw new EasyRdf_Exception(
+                "Failed to parse HTTP response status line."
+            );
+        }
+
+        // Process the rest of the header lines
+        $headers = array();
+        foreach ($headerLines as $line) {
+            if (preg_match("|^([\w-]+):\s+(.+)$|", $line, $m)) {
+                $hName = ucwords(strtolower($m[1]));
+                $hValue = $m[2];
+
+                if (isset($headers[$hName])) {
+                    if (! is_array($headers[$hName])) {
+                        $headers[$hName] = array($headers[$hName]);
+                    }
+                    $headers[$hName][] = $hValue;
+                } else {
+                    $headers[$hName] = $hValue;
+                }
+            }
+        }
+
+        return new EasyRdf_Http_Response($status, $headers, $body, $version, $message);
+    }
+
+
+    /**
+     * Decode a "chunked" transfer-encoded body and return the decoded text
+     *
+     * @param string $body
+     * @return string
+     */
+    public static function decodeChunkedBody($body)
+    {
+        $decBody = '';
+
+        while (trim($body)) {
+            if (preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) {
+                $length = hexdec(trim($m[1]));
+                $cut = strlen($m[0]);
+                $decBody .= substr($body, $cut, $length);
+                $body = substr($body, $cut + $length + 2);
+            } else {
+                throw new EasyRdf_Exception(
+                    "Failed to decode chunked body in HTTP response."
+                );
+            }
+        }
+
+        return $decBody;
+    }
+
+
+    /**
+     * Get the entire response as string
+     *
+     * @param string $br Line breaks (eg. "\n", "\r\n", "<br />")
+     * @return string
+     */
+    public function asString($br = "\n")
+    {
+        return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody();
+    }
+
+    /**
+     * Implements magic __toString()
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->asString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,327 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal
+{
+    /** @ignore a mapping from datatype uri to class name */
+    private static $datatypeMap = array();
+
+    /** @ignore A mapping from class name to datatype URI */
+    private static $classMap = array();
+
+    /** @ignore The string value for this literal */
+    protected $value = null;
+
+    /** @ignore The language of the literal (e.g. 'en') */
+    protected $lang = null;
+
+    /** @ignore The datatype URI of the literal */
+    protected $datatype = null;
+
+
+    /** Create a new literal object
+     *
+     * PHP values of type bool, int or float, will automatically be converted
+     * to the corresponding datatype and PHP sub-class.
+     *
+     * If a registered datatype is given, then the registered subclass of EasyRdf_Literal
+     * will instantiated.
+     *
+     * Note that literals are not required to have a language or datatype.
+     * Literals cannot have both a language and a datatype.
+     *
+     * @param  mixed  $value     The value of the literal or an associative array
+     * @param  string $lang      The natural language of the literal or null (e.g. 'en')
+     * @param  string $datatype  The datatype of the literal or null (e.g. 'xsd:integer')
+     * @return object EasyRdf_Literal (or subclass of EasyRdf_Literal)
+     */
+    public static function create($value, $lang = null, $datatype = null)
+    {
+        if (EasyRdf_Utils::isAssociativeArray($value)) {
+            if (isset($value['xml:lang'])) {
+                $lang = $value['xml:lang'];
+            } elseif (isset($value['lang'])) {
+                $lang = $value['lang'];
+            }
+            if (isset($value['datatype'])) {
+                $datatype = $value['datatype'];
+            }
+            $value = isset($value['value']) ? $value['value'] : null;
+        }
+
+        if (is_null($datatype) or $datatype === '') {
+            if (is_null($lang) or $lang === '') {
+                // Automatic datatype selection
+                $datatype = self::getDatatypeForValue($value);
+            }
+        } elseif (is_object($datatype)) {
+            $datatype = strval($datatype);
+        } else {
+            // Expand shortened URIs (qnames)
+            $datatype = EasyRdf_Namespace::expand($datatype);
+        }
+
+        // Work out what class to use for this datatype
+        if (isset(self::$datatypeMap[$datatype])) {
+            $class = self::$datatypeMap[$datatype];
+        } else {
+            $class = 'EasyRdf_Literal';
+        }
+        return new $class($value, $lang, $datatype);
+    }
+
+    /** Register an RDF datatype with a PHP class name
+     *
+     * When parsing registered class will be used whenever the datatype
+     * is seen.
+     *
+     * When serialising a registered class, the mapping will be used to
+     * set the datatype in the RDF.
+     *
+     * Example:
+     * EasyRdf_Literal::registerDatatype('xsd:dateTime', 'My_DateTime_Class');
+     *
+     * @param  string  $datatype   The RDF datatype (e.g. xsd:dateTime)
+     * @param  string  $class      The PHP class name (e.g. My_DateTime_Class)
+     */
+    public static function setDatatypeMapping($datatype, $class)
+    {
+        if (!is_string($datatype) or $datatype == null or $datatype == '') {
+            throw new InvalidArgumentException(
+                "\$datatype should be a string and cannot be null or empty"
+            );
+        }
+
+        if (!is_string($class) or $class == null or $class == '') {
+            throw new InvalidArgumentException(
+                "\$class should be a string and cannot be null or empty"
+            );
+        }
+
+        $datatype = EasyRdf_Namespace::expand($datatype);
+        self::$datatypeMap[$datatype] = $class;
+        self::$classMap[$class] = $datatype;
+    }
+
+    /** Remove the mapping between an RDF datatype and a PHP class name
+     *
+     * @param  string  $datatype   The RDF datatype (e.g. xsd:dateTime)
+     */
+    public static function deleteDatatypeMapping($datatype)
+    {
+        if (!is_string($datatype) or $datatype == null or $datatype == '') {
+            throw new InvalidArgumentException(
+                "\$datatype should be a string and cannot be null or empty"
+            );
+        }
+
+        $datatype = EasyRdf_Namespace::expand($datatype);
+        if (isset(self::$datatypeMap[$datatype])) {
+            $class = self::$datatypeMap[$datatype];
+            unset(self::$datatypeMap[$datatype]);
+            unset(self::$classMap[$class]);
+        }
+    }
+
+    /** Get datatype URI for a PHP value.
+     *
+     * This static function is intended for internal use.
+     * Given a PHP value, it will return an XSD datatype
+     * URI for that value, for example:
+     * http://www.w3.org/2001/XMLSchema#integer
+     *
+     * @return string  A URI for the datatype of $value.
+     */
+    public static function getDatatypeForValue($value)
+    {
+        if (is_float($value)) {
+            return 'http://www.w3.org/2001/XMLSchema#decimal';
+        } elseif (is_int($value)) {
+            return 'http://www.w3.org/2001/XMLSchema#integer';
+        } elseif (is_bool($value)) {
+            return 'http://www.w3.org/2001/XMLSchema#boolean';
+        } elseif (is_object($value) and $value instanceof DateTime) {
+            return 'http://www.w3.org/2001/XMLSchema#dateTime';
+        } else {
+            return null;
+        }
+    }
+
+
+
+    /** Constructor for creating a new literal
+     *
+     * @param  string $value     The value of the literal
+     * @param  string $lang      The natural language of the literal or null (e.g. 'en')
+     * @param  string $datatype  The datatype of the literal or null (e.g. 'xsd:string')
+     * @return object EasyRdf_Literal
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        $this->value = $value;
+        $this->lang = $lang ? $lang : null;
+        $this->datatype = $datatype ? $datatype : null;
+
+        if ($this->datatype) {
+            if (is_object($this->datatype)) {
+                // Convert objects to strings
+                $this->datatype = strval($this->datatype);
+            } else {
+                // Expand shortened URIs (CURIEs)
+                $this->datatype = EasyRdf_Namespace::expand($this->datatype);
+            }
+
+            // Literals can not have both a language and a datatype
+            $this->lang = null;
+        } else {
+            // Set the datatype based on the subclass
+            $class = get_class($this);
+            if (isset(self::$classMap[$class])) {
+                $this->datatype = self::$classMap[$class];
+                $this->lang = null;
+            }
+        }
+
+        // Cast value to string
+        settype($this->value, 'string');
+    }
+
+    /** Returns the value of the literal.
+     *
+     * @return string  Value of this literal.
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /** Returns the full datatype URI of the literal.
+     *
+     * @return string  Datatype URI of this literal.
+     */
+    public function getDatatypeUri()
+    {
+        return $this->datatype;
+    }
+
+    /** Returns the shortened datatype URI of the literal.
+     *
+     * @return string  Datatype of this literal (e.g. xsd:integer).
+     */
+    public function getDatatype()
+    {
+        if ($this->datatype) {
+            return EasyRdf_Namespace::shorten($this->datatype);
+        } else {
+            return null;
+        }
+    }
+
+    /** Returns the language of the literal.
+     *
+     * @return string  Language of this literal.
+     */
+    public function getLang()
+    {
+        return $this->lang;
+    }
+
+    /** Returns the properties of the literal as an associative array
+     *
+     * For example:
+     * array('type' => 'literal', 'value' => 'string value')
+     *
+     * @return array  The properties of the literal
+     */
+    public function toRdfPhp()
+    {
+        $array = array(
+            'type' => 'literal',
+            'value' => $this->value
+        );
+
+        if ($this->datatype) {
+            $array['datatype'] = $this->datatype;
+        }
+
+        if ($this->lang) {
+            $array['lang'] = $this->lang;
+        }
+
+        return $array;
+    }
+
+    /** Magic method to return the value of a literal as a string
+     *
+     * @return string The value of the literal
+     */
+    public function __toString()
+    {
+        return isset($this->value) ? $this->value : '';
+    }
+
+    /** Return pretty-print view of the literal
+     *
+     * @param  string $format Either 'html' or 'text'
+     * @param  string $color  The colour of the text
+     * @return string
+     */
+    public function dumpValue($format = 'html', $color = 'black')
+    {
+        return EasyRdf_Utils::dumpLiteralValue($this, $format, $color);
+    }
+}
+
+/*
+   Register default set of datatype classes
+*/
+
+EasyRdf_Literal::setDatatypeMapping('xsd:boolean', 'EasyRdf_Literal_Boolean');
+EasyRdf_Literal::setDatatypeMapping('xsd:date', 'EasyRdf_Literal_Date');
+EasyRdf_Literal::setDatatypeMapping('xsd:dateTime', 'EasyRdf_Literal_DateTime');
+EasyRdf_Literal::setDatatypeMapping('xsd:decimal', 'EasyRdf_Literal_Decimal');
+EasyRdf_Literal::setDatatypeMapping('xsd:hexBinary', 'EasyRdf_Literal_HexBinary');
+EasyRdf_Literal::setDatatypeMapping('rdf:HTML', 'EasyRdf_Literal_HTML');
+EasyRdf_Literal::setDatatypeMapping('xsd:integer', 'EasyRdf_Literal_Integer');
+EasyRdf_Literal::setDatatypeMapping('rdf:XMLLiteral', 'EasyRdf_Literal_XML');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/Boolean.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:boolean
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#boolean
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_Boolean extends EasyRdf_Literal
+{
+    /** Constructor for creating a new boolean literal
+     *
+     * If the value is not a string, then it will be converted to 'true' or 'false'.
+     *
+     * @param  mixed  $value     The value of the literal
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:boolean')
+     * @return object EasyRdf_Literal_Boolean
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        if (!is_string($value)) {
+            $value = $value ? 'true' : 'false';
+        }
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Return the value of the literal cast to a PHP bool
+     *
+     * If the value is 'true' or '1' return true, otherwise returns false.
+     *
+     * @return bool
+     */
+    public function getValue()
+    {
+        return strtolower($this->value) === 'true' or $this->value === '1';
+    }
+
+    /** Return true if the value of the literal is 'true' or '1'
+     *
+     * @return bool
+     */
+    public function isTrue()
+    {
+        return strtolower($this->value) === 'true' or $this->value === '1';
+    }
+
+    /** Return true if the value of the literal is 'false' or '0'
+     *
+     * @return bool
+     */
+    public function isFalse()
+    {
+        return strtolower($this->value) === 'false' or $this->value === '0';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/Date.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:date
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#date
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_Date extends EasyRdf_Literal
+{
+    /** Constructor for creating a new date literal
+     *
+     * If the value is a DateTime object, then it will be converted to the xsd:date format.
+     * If no value is given or is is null, then the current date is used.
+     *
+     * @see DateTime
+     *
+     * @param  mixed  $value     The value of the literal
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:date')
+     * @return object EasyRdf_Literal_Date
+     */
+    public function __construct($value = null, $lang = null, $datatype = null)
+    {
+        // If $value is null, use today's date
+        if (is_null($value)) {
+            $value = new DateTime('today');
+        }
+
+        // Convert DateTime object into string
+        if ($value instanceof DateTime) {
+            $value = $value->format('Y-m-d');
+        }
+
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Parses a string using DateTime and creates a new literal
+     *
+     * Example:
+     *   $date = EasyRdf_Literal_Date::parse('1 January 2011');
+     *
+     * @see DateTime
+     * @param string $value The date to parse
+     * @return object EasyRdf_Literal_Date
+     */
+    public static function parse($value)
+    {
+        $value = new DateTime($value);
+        return new EasyRdf_Literal_Date($value);
+    }
+
+    /** Returns the date as a PHP DateTime object
+     *
+     * @see DateTime::format
+     * @return string
+     */
+    public function getValue()
+    {
+        return new DateTime($this->value);
+    }
+
+    /** Returns date formatted according to given format
+     *
+     * @see DateTime::format
+     * @param string $format
+     * @return string
+     */
+    public function format($format)
+    {
+        return $this->getValue()->format($format);
+    }
+
+    /** A full integer representation of the year, 4 digits
+     *
+     * @return integer
+     */
+    public function year()
+    {
+        return (int)$this->format('Y');
+    }
+
+    /** Integer representation of the month
+     *
+     * @return integer
+     */
+    public function month()
+    {
+        return (int)$this->format('m');
+    }
+
+    /** Integer representation of the day of the month
+     *
+     * @return integer
+     */
+    public function day()
+    {
+        return (int)$this->format('d');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/DateTime.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:dateTime
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#date
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_DateTime extends EasyRdf_Literal_Date
+{
+    /** Constructor for creating a new date and time literal
+     *
+     * If the value is a DateTime object, then it will be converted to the xsd:dateTime format.
+     * If no value is given or is is null, then the current time is used.
+     *
+     * @see DateTime
+     *
+     * @param  mixed  $value     The value of the literal
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:dateTime')
+     * @return object EasyRdf_Literal_DateTime
+     */
+    public function __construct($value = null, $lang = null, $datatype = null)
+    {
+        // If $value is null, use 'now'
+        if (is_null($value)) {
+            $value = new DateTime('now');
+        }
+
+        // Convert DateTime objects into string
+        if ($value instanceof DateTime) {
+            $atom = $value->format(DateTime::ATOM);
+            $value = preg_replace('/[\+\-]00(\:?)00$/', 'Z', $atom);
+        }
+
+        EasyRdf_Literal::__construct($value, null, $datatype);
+    }
+
+    /** Parses a string using DateTime and creates a new literal
+     *
+     * Example:
+     *   $dt = EasyRdf_Literal_DateTime::parse('Mon 18 Jul 2011 18:45:43 BST');
+     *
+     * @see DateTime
+     * @param string $value The date and time to parse
+     * @return object EasyRdf_Literal_DateTime
+     */
+    public static function parse($value)
+    {
+        $value = new DateTime($value);
+        return new EasyRdf_Literal_DateTime($value);
+    }
+
+    /** 24-hour format of the hour as an integer
+     *
+     * @return integer
+     */
+    public function hour()
+    {
+        return (int)$this->format('H');
+    }
+
+    /** The minutes pasts the hour as an integer
+     *
+     * @return integer
+     */
+    public function min()
+    {
+        return (int)$this->format('i');
+    }
+
+    /** The seconds pasts the minute as an integer
+     *
+     * @return integer
+     */
+    public function sec()
+    {
+        return (int)$this->format('s');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/Decimal.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:decimal
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#decimal
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_Decimal extends EasyRdf_Literal
+{
+    /** Constructor for creating a new decimal literal
+     *
+     * @param  mixed  $value     The value of the literal
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:decimal')
+     * @return object EasyRdf_Literal_Decimal
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Return the value of the literal cast to a PHP double
+     *
+     * @return double
+     */
+    public function getValue()
+    {
+        return (double)$this->value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/HTML.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype rdf:HTML
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/rdf11-concepts/#section-html
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_HTML extends EasyRdf_Literal
+{
+    /** Constructor for creating a new rdf:HTML literal
+     *
+     * @param  mixed  $value     The HTML fragment
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'rdf:HTML')
+     * @return object EasyRdf_Literal_HTML
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Strip the HTML tags from the literal
+     *
+     * @link   http://php.net/manual/en/function.strip-tags.php
+     * @param  string $allowableTags  Optional allowed tag, not be be removed
+     * @return string The literal as plain text
+     */
+    public function stripTags($allowableTags = null)
+    {
+        return strip_tags($this->value, $allowableTags);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/HexBinary.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:hexBinary
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#hexBinary
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_HexBinary extends EasyRdf_Literal
+{
+    /** Constructor for creating a new xsd:hexBinary literal
+     *
+     * @param  mixed  $value     The value of the literal (already encoded as hexadecimal)
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:hexBinary')
+     * @return object EasyRdf_Literal_HexBinary
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        // Normalise the canonical representation, as specified here:
+        // http://www.w3.org/TR/xmlschema-2/#hexBinary-canonical-repr
+        $value = strtoupper($value);
+
+        // Validate the data
+        if (preg_match("/[^A-F0-9]/", $value)) {
+            throw new InvalidArgumentException(
+                "Literal of type xsd:hexBinary contains non-hexadecimal characters"
+            );
+        }
+
+        parent::__construct(strtoupper($value), null, 'xsd:hexBinary');
+    }
+
+    /** Constructor for creating a new literal object from a binary blob
+     *
+     * @param  string $binary  The binary data
+     * @return object EasyRdf_Literal_HexBinary
+     */
+    public static function fromBinary($binary)
+    {
+        return new self( bin2hex($binary) );
+    }
+
+    /** Decode the hexadecimal string into a binary blob
+     *
+     * @return string The binary blob
+     */
+    public function toBinary()
+    {
+        return pack("H*", $this->value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/Integer.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype xsd:integer
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/xmlschema-2/#integer
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_Integer extends EasyRdf_Literal
+{
+    /** Constructor for creating a new integer literal
+     *
+     * @param  mixed  $value     The value of the literal
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'xsd:integer')
+     * @return object EasyRdf_Literal_Integer
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Return the value of the literal cast to a PHP int
+     *
+     * @return double
+     */
+    public function getValue()
+    {
+        return (int)$this->value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Literal/XML.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF Literal of datatype rdf:XMLLiteral
+ *
+ * @package    EasyRdf
+ * @link       http://www.w3.org/TR/REC-rdf-syntax/#section-Syntax-XML-literals
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Literal_XML extends EasyRdf_Literal
+{
+    /** Constructor for creating a new rdf:XMLLiteral literal
+     *
+     * @param  mixed  $value     The XML fragment
+     * @param  string $lang      Should be null (literals with a datatype can't have a language)
+     * @param  string $datatype  Optional datatype (default 'rdf:XMLLiteral')
+     * @return object EasyRdf_Literal_XML
+     */
+    public function __construct($value, $lang = null, $datatype = null)
+    {
+        parent::__construct($value, null, $datatype);
+    }
+
+    /** Parse the XML literal into a DOMDocument
+     *
+     * @link   http://php.net/manual/en/domdocument.loadxml.php
+     * @return object DOMDocument
+     */
+    public function domParse()
+    {
+        $dom = new DOMDocument();
+        $dom->loadXML($this->value);
+        return $dom;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Namespace.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,350 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * A namespace registry and manipulation class.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Namespace
+{
+    /** Namespace registry
+     *
+     * List of default namespaces come from:
+     *  - http://www.w3.org/2011/rdfa-context/rdfa-1.1
+     *
+     * With a few extras added.
+     *
+     */
+    private static $namespaces = array(
+      'bibo' => 'http://purl.org/ontology/bibo/',
+      'cc' => 'http://creativecommons.org/ns#',
+      'cert' => 'http://www.w3.org/ns/auth/cert#',
+      'ctag' => 'http://commontag.org/ns#',
+      'dc' => 'http://purl.org/dc/terms/',
+      'dc11' => 'http://purl.org/dc/elements/1.1/',
+      'dcterms' => 'http://purl.org/dc/terms/',
+      'doap' => 'http://usefulinc.com/ns/doap#',
+      'exif' => 'http://www.w3.org/2003/12/exif/ns#',
+      'foaf' => 'http://xmlns.com/foaf/0.1/',
+      'geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#',
+      'gr' => 'http://purl.org/goodrelations/v1#',
+      'grddl' => 'http://www.w3.org/2003/g/data-view#',
+      'ical' => 'http://www.w3.org/2002/12/cal/icaltzd#',
+      'ma' => 'http://www.w3.org/ns/ma-ont#',
+      'og' => 'http://ogp.me/ns#',
+      'owl' => 'http://www.w3.org/2002/07/owl#',
+      'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+      'rdfa' => 'http://www.w3.org/ns/rdfa#',
+      'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
+      'rev' => 'http://purl.org/stuff/rev#',
+      'rif' => 'http://www.w3.org/2007/rif#',
+      'rss' => 'http://purl.org/rss/1.0/',
+      'schema' => 'http://schema.org/',
+      'sioc' => 'http://rdfs.org/sioc/ns#',
+      'skos' => 'http://www.w3.org/2004/02/skos/core#',
+      'skosxl' => 'http://www.w3.org/2008/05/skos-xl#',
+      'synd' => 'http://purl.org/rss/1.0/modules/syndication/',
+      'v' => 'http://rdf.data-vocabulary.org/#',
+      'vcard' => 'http://www.w3.org/2006/vcard/ns#',
+      'void' => 'http://rdfs.org/ns/void#',
+      'wdr' => 'http://www.w3.org/2007/05/powder#',
+      'wdrs' => 'http://www.w3.org/2007/05/powder-s#',
+      'wot' => 'http://xmlns.com/wot/0.1/',
+      'xhv' => 'http://www.w3.org/1999/xhtml/vocab#',
+      'xml' => 'http://www.w3.org/XML/1998/namespace',
+      'xsd' => 'http://www.w3.org/2001/XMLSchema#',
+    );
+
+    private static $default = null;
+
+    /** Counter for numbering anonymous namespaces */
+    private static $anonymousNamespaceCount = 0;
+
+    /**
+      * Return all the namespaces registered
+      *
+      * @return array Associative array of all the namespaces.
+      */
+    public static function namespaces()
+    {
+        return self::$namespaces;
+    }
+
+    /**
+      * Return a namespace given its prefix.
+      *
+      * @param string $prefix The namespace prefix (eg 'foaf')
+      * @return string The namespace URI (eg 'http://xmlns.com/foaf/0.1/')
+      */
+    public static function get($prefix)
+    {
+        if (!is_string($prefix) or $prefix === null or $prefix === '') {
+            throw new InvalidArgumentException(
+                "\$prefix should be a string and cannot be null or empty"
+            );
+        }
+
+        if (preg_match('/\W/', $prefix)) {
+            throw new InvalidArgumentException(
+                "\$prefix should only contain alpha-numeric characters"
+            );
+        }
+
+        $prefix = strtolower($prefix);
+        if (array_key_exists($prefix, self::$namespaces)) {
+            return self::$namespaces[$prefix];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+      * Register a new namespace.
+      *
+      * @param string $prefix The namespace prefix (eg 'foaf')
+      * @param string $long The namespace URI (eg 'http://xmlns.com/foaf/0.1/')
+      */
+    public static function set($prefix, $long)
+    {
+        if (!is_string($prefix) or $prefix === null or $prefix === '') {
+            throw new InvalidArgumentException(
+                "\$prefix should be a string and cannot be null or empty"
+            );
+        }
+
+        if (preg_match('/\W/', $prefix)) {
+            throw new InvalidArgumentException(
+                "\$prefix should only contain alpha-numeric characters"
+            );
+        }
+
+        if (!is_string($long) or $long === null or $long === '') {
+            throw new InvalidArgumentException(
+                "\$long should be a string and cannot be null or empty"
+            );
+        }
+
+        $prefix = strtolower($prefix);
+        self::$namespaces[$prefix] = $long;
+    }
+
+    /**
+      * Get the default namespace
+      *
+      * Returns the URI of the default namespace or null
+      * if no default namespace is defined.
+      *
+      * @return string The URI of the default namespace
+      */
+    public static function getDefault()
+    {
+        return self::$default;
+    }
+
+    /**
+      * Set the default namespace
+      *
+      * Set the default namespace to either a URI or the prefix of
+      * an already defined namespace.
+      *
+      * Example:
+      *   EasyRdf_Namespace::setDefault('http://schema.org/');
+      *
+      * @param string $namespace The URI or prefix of a namespace (eg 'og')
+      */
+    public static function setDefault($namespace)
+    {
+        if (is_null($namespace) or $namespace === '') {
+            self::$default = null;
+        } elseif (preg_match("/^\w+$/", $namespace)) {
+            if (isset(self::$namespaces[$namespace])) {
+                self::$default = self::$namespaces[$namespace];
+            } else {
+                throw new InvalidArgumentException(
+                    "Unable to set default namespace to unknown prefix: $namespace"
+                );
+            }
+        } else {
+            self::$default = $namespace;
+        }
+    }
+
+    /**
+      * Delete an existing namespace.
+      *
+      * @param string $prefix The namespace prefix (eg 'foaf')
+      */
+    public static function delete($prefix)
+    {
+        if (!is_string($prefix) or $prefix === null or $prefix === '') {
+            throw new InvalidArgumentException(
+                "\$prefix should be a string and cannot be null or empty"
+            );
+        }
+
+        $prefix = strtolower($prefix);
+        if (isset(self::$namespaces[$prefix])) {
+            unset(self::$namespaces[$prefix]);
+        }
+    }
+
+    /**
+      * Delete the anonymous namespaces and reset the counter to 0
+      */
+    public static function reset()
+    {
+        while (self::$anonymousNamespaceCount > 0) {
+            self::delete('ns'.(self::$anonymousNamespaceCount-1));
+            self::$anonymousNamespaceCount--;
+        }
+    }
+
+    /**
+      * Try and breakup a URI into a prefix and local part
+      *
+      * If $createNamespace is true, and the URI isn't part of an existing
+      * namespace, then EasyRdf will attempt to create a new namespace and
+      * return the name of the new prefix (for example 'ns0', 'term').
+      *
+      * If it isn't possible to split the URI, then null will be returned.
+      *
+      * @param string  $uri The full URI (eg 'http://xmlns.com/foaf/0.1/name')
+      * @param bool    $createNamespace If true, a new namespace will be created
+      * @return array  The split URI (eg 'foaf', 'name') or null
+      */
+    public static function splitUri($uri, $createNamespace = false)
+    {
+        if ($uri === null or $uri === '') {
+            throw new InvalidArgumentException(
+                "\$uri cannot be null or empty"
+            );
+        }
+
+        if (is_object($uri) and ($uri instanceof EasyRdf_Resource)) {
+            $uri = $uri->getUri();
+        } elseif (!is_string($uri)) {
+            throw new InvalidArgumentException(
+                "\$uri should be a string or EasyRdf_Resource"
+            );
+        }
+
+        foreach (self::$namespaces as $prefix => $long) {
+            if (substr($uri, 0, strlen($long)) == $long) {
+                return array($prefix, substr($uri, strlen($long)));
+            }
+        }
+
+        if ($createNamespace) {
+            // Try and create a new namespace
+            # FIXME: check the valid characters for an XML element name
+            if (preg_match("/^(.+?)([\w\-]+)$/", $uri, $matches)) {
+                $prefix = "ns".(self::$anonymousNamespaceCount++);
+                self::set($prefix, $matches[1]);
+                return array($prefix, $matches[2]);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+      * Return the prefix namespace that a URI belongs to.
+      *
+      * @param string $uri A full URI (eg 'http://xmlns.com/foaf/0.1/name')
+      * @return string The prefix namespace that it is a part of(eg 'foaf')
+      */
+    public static function prefixOfUri($uri)
+    {
+        if ($parts = self::splitUri($uri)) {
+            return $parts[0];
+        }
+    }
+
+    /**
+      * Shorten a URI by substituting in the namespace prefix.
+      *
+      * If $createNamespace is true, and the URI isn't part of an existing
+      * namespace, then EasyRdf will attempt to create a new namespace and
+      * use that namespace to shorten the URI (for example ns0:term).
+      *
+      * If it isn't possible to shorten the URI, then null will be returned.
+      *
+      * @param string  $uri The full URI (eg 'http://xmlns.com/foaf/0.1/name')
+      * @param bool    $createNamespace If true, a new namespace will be created
+      * @return string The shortened URI (eg 'foaf:name') or null
+      */
+    public static function shorten($uri, $createNamespace = false)
+    {
+        if ($parts = self::splitUri($uri, $createNamespace)) {
+            return implode(':', $parts);
+        }
+    }
+
+    /**
+      * Expand a shortened URI (qname) back into a full URI.
+      *
+      * If it isn't possible to expand the qname, for example if the namespace
+      * isn't registered, then the original string will be returned.
+      *
+      * @param string $shortUri The short URI (eg 'foaf:name')
+      * @return string The full URI (eg 'http://xmlns.com/foaf/0.1/name')
+      */
+    public static function expand($shortUri)
+    {
+        if (!is_string($shortUri) or $shortUri === '') {
+            throw new InvalidArgumentException(
+                "\$shortUri should be a string and cannot be null or empty"
+            );
+        }
+        
+        if ($shortUri === 'a') {
+            return self::$namespaces['rdf'] . 'type';
+        } elseif (preg_match("/^(\w+?):([\w\-]+)$/", $shortUri, $matches)) {
+            $long = self::get($matches[1]);
+            if ($long) {
+                return $long . $matches[2];
+            }
+        } elseif (preg_match("/^(\w+)$/", $shortUri) and isset(self::$default)) {
+            return self::$default . $shortUri;
+        }
+
+        return $shortUri;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/ParsedUri.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,340 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+
+/**
+ * A RFC3986 compliant URI parser
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ * @link       http://www.ietf.org/rfc/rfc3986.txt
+ */
+class EasyRdf_ParsedUri
+{
+    // For all URIs:
+    private $scheme = null;
+    private $fragment = null;
+
+    // For hierarchical URIs:
+    private $authority = null;
+    private $path = null;
+    private $query = null;
+
+    const URI_REGEX = "|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|";
+
+    /** Constructor for creating a new parsed URI
+     *
+     * The $uri parameter can either be a string or an
+     * associative array with the following keys:
+     * scheme, authority, path, query, fragment
+     *
+     * @param  mixed $uri  The URI as a string or an array
+     * @return object EasyRdf_ParsedUri
+     */
+    public function __construct($uri = null)
+    {
+        if (is_string($uri)) {
+            if (preg_match(self::URI_REGEX, $uri, $matches)) {
+                if (!empty($matches[1])) {
+                    $this->scheme = isset($matches[2]) ? $matches[2] : '';
+                }
+                if (!empty($matches[3])) {
+                    $this->authority = isset($matches[4]) ? $matches[4] : '';
+                }
+                $this->path = isset($matches[5]) ? $matches[5] : '';
+                if (!empty($matches[6])) {
+                    $this->query = isset($matches[7]) ? $matches[7] : '';
+                }
+                if (!empty($matches[8])) {
+                    $this->fragment = isset($matches[9]) ? $matches[9] : '';
+                }
+            }
+        } elseif (is_array($uri)) {
+            $this->scheme = isset($uri['scheme']) ? $uri['scheme'] : null;
+            $this->authority = isset($uri['authority']) ? $uri['authority'] : null;
+            $this->path = isset($uri['path']) ? $uri['path'] : null;
+            $this->query = isset($uri['query']) ? $uri['query'] : null;
+            $this->fragment = isset($uri['fragment']) ? $uri['fragment'] : null;
+        }
+    }
+
+
+    /** Returns true if this is an absolute (complete) URI
+     * @return boolean
+     */
+    public function isAbsolute()
+    {
+        return $this->scheme !== null;
+    }
+
+    /** Returns true if this is an relative (partial) URI
+     * @return boolean
+     */
+    public function isRelative()
+    {
+        return $this->scheme === null;
+    }
+
+    /** Returns the scheme of the URI (e.g. http)
+     * @return string
+     */
+    public function getScheme()
+    {
+        return $this->scheme;
+    }
+
+    /** Sets the scheme of the URI (e.g. http)
+     * @param string $scheme The new value for the scheme of the URI
+     */
+    public function setScheme($scheme)
+    {
+        $this->scheme = $scheme;
+    }
+
+    /** Returns the authority of the URI (e.g. www.example.com:8080)
+     * @return string
+     */
+    public function getAuthority()
+    {
+        return $this->authority;
+    }
+
+    /** Sets the authority of the URI (e.g. www.example.com:8080)
+     * @param string $authority The new value for the authority component of the URI
+     */
+    public function setAuthority($authority)
+    {
+        $this->authority = $authority;
+    }
+
+    /** Returns the path of the URI (e.g. /foo/bar)
+     * @return string
+     */
+    public function getPath()
+    {
+        return $this->path;
+    }
+
+    /** Set the path of the URI (e.g. /foo/bar)
+     * @param string $path The new value for the path component of the URI
+     */
+    public function setPath($path)
+    {
+        $this->path = $path;
+    }
+
+    /** Returns the query string part of the URI (e.g. foo=bar)
+     * @return string
+     */
+    public function getQuery()
+    {
+        return $this->query;
+    }
+
+    /** Set the query string of the URI (e.g. foo=bar)
+     * @param string $query The new value for the query string component of the URI
+     */
+    public function setQuery($query)
+    {
+        $this->query = $query;
+    }
+
+    /** Returns the fragment part of the URI (i.e. after the #)
+     * @return string
+     */
+    public function getFragment()
+    {
+        return $this->fragment;
+    }
+
+    /** Set the fragment of the URI (i.e. after the #)
+     * @param string $fragment The new value for the fragment component of the URI
+     */
+    public function setFragment($fragment)
+    {
+        $this->fragment = $fragment;
+    }
+
+
+    /**
+     * Normalises the path of this URI if it has one. Normalising a path means
+     * that any unnecessary '.' and '..' segments are removed. For example, the
+     * URI http://example.com/a/b/../c/./d would be normalised to
+     * http://example.com/a/c/d
+     *
+     * @return object EasyRdf_ParsedUri
+     */
+    public function normalise()
+    {
+        if (empty($this->path)) {
+            return $this;
+        }
+
+        // Remove ./ from the start
+        if (substr($this->path, 0, 2) == './') {
+            // Remove both characters
+            $this->path = substr($this->path, 2);
+        }
+
+        // Remove /. from the end
+        if (substr($this->path, -2) == '/.') {
+            // Remove only the last dot, not the slash!
+            $this->path = substr($this->path, 0, -1);
+        }
+
+        if (substr($this->path, -3) == '/..') {
+            $this->path .= '/';
+        }
+
+        // Split the path into its segments
+        $segments = explode('/', $this->path);
+        $newSegments = array();
+
+        // Remove all unnecessary '.' and '..' segments
+        foreach ($segments as $segment) {
+            if ($segment == '..') {
+                // Remove the previous part of the path
+                $count = count($newSegments);
+                if ($count > 0 && $newSegments[$count-1]) {
+                    array_pop($newSegments);
+                }
+            } elseif ($segment == '.') {
+                // Ignore
+                continue;
+            } else {
+                array_push($newSegments, $segment);
+            }
+        }
+
+        // Construct the new normalised path
+        $this->path = implode($newSegments, '/');
+
+        // Allow easy chaining of methods
+        return $this;
+    }
+
+    /**
+     * Resolves a relative URI using this URI as the base URI.
+     */
+    public function resolve($relUri)
+    {
+        // If it is a string, then convert it to a parsed object
+        if (is_string($relUri)) {
+            $relUri = new EasyRdf_ParsedUri($relUri);
+        }
+
+        // This code is based on the pseudocode in section 5.2.2 of RFC3986
+        $target = new EasyRdf_ParsedUri();
+        if ($relUri->scheme) {
+            $target->scheme = $relUri->scheme;
+            $target->authority = $relUri->authority;
+            $target->path = $relUri->path;
+            $target->query = $relUri->query;
+        } else {
+            if ($relUri->authority) {
+                $target->authority = $relUri->authority;
+                $target->path = $relUri->path;
+                $target->query = $relUri->query;
+            } else {
+                if (empty($relUri->path)) {
+                    $target->path = $this->path;
+                    if ($relUri->query) {
+                        $target->query = $relUri->query;
+                    } else {
+                        $target->query = $this->query;
+                    }
+                } else {
+                    if (substr($relUri->path, 0, 1) == '/') {
+                        $target->path = $relUri->path;
+                    } else {
+                        $path = $this->path;
+                        $lastSlash = strrpos($path, '/');
+                        if ($lastSlash !== false) {
+                            $path = substr($path, 0, $lastSlash + 1);
+                        } else {
+                            $path = '/';
+                        }
+
+                        $target->path .= $path . $relUri->path;
+                    }
+                    $target->query = $relUri->query;
+                }
+                $target->authority = $this->authority;
+            }
+            $target->scheme = $this->scheme;
+        }
+
+        $target->fragment = $relUri->fragment;
+
+        $target->normalise();
+
+        return $target;
+    }
+
+    /** Convert the parsed URI back into a string
+     *
+     * @return string The URI as a string
+     */
+    public function toString()
+    {
+        $str = '';
+        if ($this->scheme !== null) {
+            $str .= $this->scheme . ':';
+        }
+        if ($this->authority !== null) {
+            $str .= '//' . $this->authority;
+        }
+        $str .= $this->path;
+        if ($this->query !== null) {
+            $str .= '?' . $this->query;
+        }
+        if ($this->fragment !== null) {
+            $str .= '#' . $this->fragment;
+        }
+        return $str;
+    }
+
+    /** Magic method to convert the URI, when casted, back to a string
+     *
+     * @return string The URI as a string
+     */
+    public function __toString()
+    {
+        return $this->toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Parent class for the EasyRdf parsers
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser
+{
+    /** Mapping from source to graph bnode identifiers */
+    private $bnodeMap = array();
+
+    /** The current graph to insert triples into */
+    protected $graph = null;
+
+    /** The format of the document currently being parsed */
+    protected $format = null;
+
+    /** The base URI for the document currently being parsed */
+    protected $baseUri = null;
+
+    /**
+     * Create a new, unique bnode identifier from a source identifier.
+     * If the source identifier has previously been seen, the
+     * same new bnode identifier is returned.
+     * @ignore
+     */
+    protected function remapBnode($name)
+    {
+        if (!isset($this->bnodeMap[$name])) {
+            $this->bnodeMap[$name] = $this->graph->newBNodeId();
+        }
+        return $this->bnodeMap[$name];
+    }
+
+    /**
+     * Delete the bnode mapping - to be called at the start of a new parse
+     * @ignore
+     */
+    protected function resetBnodeMap()
+    {
+        $this->bnodeMap = array();
+    }
+
+    /**
+     * Check, cleanup parameters and prepare for parsing
+     * @ignore
+     */
+    protected function checkParseParams($graph, $data, $format, $baseUri)
+    {
+        if ($graph == null or !is_object($graph) or
+            !($graph instanceof EasyRdf_Graph)) {
+            throw new InvalidArgumentException(
+                "\$graph should be an EasyRdf_Graph object and cannot be null"
+            );
+        } else {
+            $this->graph = $graph;
+        }
+
+        if ($format == null or $format == '') {
+            throw new InvalidArgumentException(
+                "\$format cannot be null or empty"
+            );
+        } elseif (is_object($format) and $format instanceof EasyRdf_Format) {
+            $this->format = $format = $format->getName();
+        } elseif (!is_string($format)) {
+            throw new InvalidArgumentException(
+                "\$format should be a string or an EasyRdf_Format object"
+            );
+        } else {
+            $this->format = $format;
+        }
+
+        if ($baseUri) {
+            if (!is_string($baseUri)) {
+                throw new InvalidArgumentException(
+                    "\$baseUri should be a string"
+                );
+            } else {
+                $this->baseUri = new EasyRdf_ParsedUri($baseUri);
+            }
+        } else {
+            $this->baseUri = null;
+        }
+
+        // Prepare for parsing
+        $this->resetBnodeMap();
+        $this->tripleCount = 0;
+    }
+
+    /**
+     * Sub-classes must follow this protocol
+     * @ignore
+     */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        throw new EasyRdf_Exception(
+            "This method should be overridden by sub-classes."
+        );
+    }
+
+    /**
+     * Add a triple to the current graph, and keep count of the number of triples
+     * @ignore
+     */
+    protected function addTriple($resource, $property, $value)
+    {
+        $count = $this->graph->add($resource, $property, $value);
+        $this->tripleCount += $count;
+        return $count;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Arc.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse RDF using the ARC2 library.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Arc extends EasyRdf_Parser_RdfPhp
+{
+    private static $supportedTypes = array(
+        'rdfxml' => 'RDFXML',
+        'turtle' => 'Turtle',
+        'ntriples' => 'Turtle',
+        'rdfa' => 'SemHTML',
+    );
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_Arc
+     */
+    public function __construct()
+    {
+        require_once 'arc/ARC2.php';
+    }
+
+    /**
+      * Parse an RDF document into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        if (array_key_exists($format, self::$supportedTypes)) {
+            $className = self::$supportedTypes[$format];
+        } else {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_Arc does not support: $format"
+            );
+        }
+
+        $parser = ARC2::getParser($className);
+        if ($parser) {
+            $parser->parse($baseUri, $data);
+            $rdfphp = $parser->getSimpleIndex(false);
+            return parent::parse($graph, $rdfphp, 'php', $baseUri);
+        } else {
+            throw new EasyRdf_Exception(
+                "ARC2 failed to get a $className parser."
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Exception.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * EasyRdf Exception class
+ *
+ * All exceptions thrown by EasyRdf are an instance of this class.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Exception extends EasyRdf_Exception
+{
+    protected $parserLine;
+    protected $parserColumn;
+    
+    public function __construct($message, $line = null, $column = null)
+    {
+        $this->parserLine = $line;
+        $this->parserColumn = $column;
+
+        if (!is_null($line)) {
+            $message .= " on line $line";
+            if (!is_null($column)) {
+                $message .= ", column $column";
+            }
+        }
+
+        parent::__construct($message);
+    }
+    
+    public function getParserLine()
+    {
+        return $this->parserLine;
+    }
+    
+    public function getParserColumn()
+    {
+        return $this->parserColumn;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Json.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * A pure-php class to parse RDF/JSON with no dependancies.
+ *
+ * http://n2.talis.com/wiki/RDF_JSON_Specification
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Json extends EasyRdf_Parser_RdfPhp
+{
+    private $jsonLastErrorExists = false;
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_Json
+     */
+    public function __construct()
+    {
+        $this->jsonLastErrorExists = function_exists('json_last_error');
+    }
+
+    /** Return the last JSON parser error as a string
+     *
+     * If json_last_error() is not available a generic message will be returned.
+     *
+     * @ignore
+     */
+    protected function jsonLastErrorString()
+    {
+        if ($this->jsonLastErrorExists) {
+            switch (json_last_error()) {
+                case JSON_ERROR_NONE:
+                    return null;
+                case JSON_ERROR_DEPTH:
+                    return "JSON Parse error: the maximum stack depth has been exceeded";
+                case JSON_ERROR_STATE_MISMATCH:
+                    return "JSON Parse error: invalid or malformed JSON";
+                case JSON_ERROR_CTRL_CHAR:
+                    return "JSON Parse error: control character error, possibly incorrectly encoded";
+                case JSON_ERROR_SYNTAX:
+                    return "JSON Parse syntax error";
+                case JSON_ERROR_UTF8:
+                    return "JSON Parse error: malformed UTF-8 characters, possibly incorrectly encoded";
+                default:
+                    return "JSON Parse error: unknown";
+            }
+        } else {
+            return "JSON Parse error";
+        }
+    }
+
+    /** Parse the triple-centric JSON format, as output by libraptor
+     *
+     * http://librdf.org/raptor/api/serializer-json.html
+     *
+     * @ignore
+     */
+    protected function parseJsonTriples($data, $baseUri)
+    {
+        foreach ($data['triples'] as $triple) {
+            if ($triple['subject']['type'] == 'bnode') {
+                $subject = $this->remapBnode($triple['subject']['value']);
+            } else {
+                $subject = $triple['subject']['value'];
+            }
+
+            $predicate = $triple['predicate']['value'];
+
+            if ($triple['object']['type'] == 'bnode') {
+                $object = array(
+                    'type' => 'bnode',
+                    'value' => $this->remapBnode($triple['object']['value'])
+                );
+            } else {
+                $object = $triple['object'];
+            }
+
+            $this->addTriple($subject, $predicate, $object);
+        }
+
+        return $this->tripleCount;
+    }
+
+    /**
+      * Parse RDF/JSON into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        $this->checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'json') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_Json does not support: $format"
+            );
+        }
+
+        $decoded = @json_decode(strval($data), true);
+        if ($decoded === null) {
+            throw new EasyRdf_Parser_Exception(
+                $this->jsonLastErrorString()
+            );
+        }
+
+        if (array_key_exists('triples', $decoded)) {
+            return $this->parseJsonTriples($decoded, $baseUri);
+        } else {
+            return parent::parse($graph, $decoded, 'php', $baseUri);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Ntriples.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,211 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * A pure-php class to parse N-Triples with no dependancies.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Ntriples extends EasyRdf_Parser
+{
+    /**
+     * Decodes an encoded N-Triples string. Any \-escape sequences are substituted
+     * with their decoded value.
+     *
+     * @param  string $str An encoded N-Triples string.
+     * @return The unencoded string.
+     **/
+    protected function unescapeString($str)
+    {
+        if (strpos($str, '\\') === false) {
+            return $str;
+        }
+
+        $mappings = array(
+            't' => chr(0x09),
+            'b' => chr(0x08),
+            'n' => chr(0x0A),
+            'r' => chr(0x0D),
+            'f' => chr(0x0C),
+            '\"' => chr(0x22),
+            '\'' => chr(0x27)
+        );
+        foreach ($mappings as $in => $out) {
+            $str = preg_replace('/\x5c([' . $in . '])/', $out, $str);
+        }
+
+        if (stripos($str, '\u') === false) {
+            return $str;
+        }
+
+        while (preg_match('/\\\(U)([0-9A-F]{8})/', $str, $matches) ||
+               preg_match('/\\\(u)([0-9A-F]{4})/', $str, $matches)) {
+            $no = hexdec($matches[2]);
+            if ($no < 128) {                // 0x80
+                $char = chr($no);
+            } elseif ($no < 2048) {         // 0x800
+                $char = chr(($no >> 6) + 192) .
+                        chr(($no & 63) + 128);
+            } elseif ($no < 65536) {        // 0x10000
+                $char = chr(($no >> 12) + 224) .
+                        chr((($no >> 6) & 63) + 128) .
+                        chr(($no & 63) + 128);
+            } elseif ($no < 2097152) {      // 0x200000
+                $char = chr(($no >> 18) + 240) .
+                        chr((($no >> 12) & 63) + 128) .
+                        chr((($no >> 6) & 63) + 128) .
+                        chr(($no & 63) + 128);
+            } else {
+                # FIXME: throw an exception instead?
+                $char = '';
+            }
+            $str = str_replace('\\' . $matches[1] . $matches[2], $char, $str);
+        }
+        return $str;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function parseNtriplesSubject($sub, $lineNum)
+    {
+        if (preg_match('/<([^<>]+)>/', $sub, $matches)) {
+            return $this->unescapeString($matches[1]);
+        } elseif (preg_match('/_:([A-Za-z0-9]*)/', $sub, $matches)) {
+            if (empty($matches[1])) {
+                return $this->graph->newBNodeId();
+            } else {
+                $nodeid = $this->unescapeString($matches[1]);
+                return $this->remapBnode($nodeid);
+            }
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "Failed to parse subject: $sub",
+                $lineNum
+            );
+        }
+    }
+
+    /**
+     * @ignore
+     */
+    protected function parseNtriplesObject($obj, $lineNum)
+    {
+        if (preg_match('/"(.+)"\^\^<([^<>]+)>/', $obj, $matches)) {
+            return array(
+                'type' => 'literal',
+                'value' => $this->unescapeString($matches[1]),
+                'datatype' => $this->unescapeString($matches[2])
+            );
+        } elseif (preg_match('/"(.+)"@([\w\-]+)/', $obj, $matches)) {
+            return array(
+                'type' => 'literal',
+                'value' => $this->unescapeString($matches[1]),
+                'lang' => $this->unescapeString($matches[2])
+            );
+        } elseif (preg_match('/"(.*)"/', $obj, $matches)) {
+            return array('type' => 'literal', 'value' => $this->unescapeString($matches[1]));
+        } elseif (preg_match('/<([^<>]+)>/', $obj, $matches)) {
+            return array('type' => 'uri', 'value' => $matches[1]);
+        } elseif (preg_match('/_:([A-Za-z0-9]*)/', $obj, $matches)) {
+            if (empty($matches[1])) {
+                return array(
+                    'type' => 'bnode',
+                    'value' => $this->graph->newBNodeId()
+                );
+            } else {
+                $nodeid = $this->unescapeString($matches[1]);
+                return array(
+                    'type' => 'bnode',
+                    'value' => $this->remapBnode($nodeid)
+                );
+            }
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "Failed to parse object: $obj",
+                $lineNum
+            );
+        }
+    }
+
+    /**
+      * Parse an N-Triples document into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'ntriples') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_Ntriples does not support: $format"
+            );
+        }
+
+        $lines = preg_split("/\x0D?\x0A/", strval($data));
+        foreach ($lines as $index => $line) {
+            $lineNum = $index + 1;
+            if (preg_match("/^\s*#/", $line)) {
+                # Comment
+                continue;
+            } elseif (preg_match("/^\s*(.+?)\s+<([^<>]+?)>\s+(.+?)\s*\.\s*$/", $line, $matches)) {
+                $this->addTriple(
+                    $this->parseNtriplesSubject($matches[1], $lineNum),
+                    $this->unescapeString($matches[2]),
+                    $this->parseNtriplesObject($matches[3], $lineNum)
+                );
+            } elseif (preg_match("/^\s*$/", $line)) {
+                # Blank line
+                continue;
+            } else {
+                throw new EasyRdf_Parser_Exception(
+                    "Failed to parse statement",
+                    $lineNum
+                );
+            }
+        }
+
+        return $this->tripleCount;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Rapper.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse RDF using the 'rapper' command line tool.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Rapper extends EasyRdf_Parser_Json
+{
+    private $rapperCmd = null;
+
+    const MINIMUM_RAPPER_VERSION = '1.4.17';
+
+    /**
+     * Constructor
+     *
+     * @param string $rapperCmd Optional path to the rapper command to use.
+     * @return object EasyRdf_Parser_Rapper
+     */
+    public function __construct($rapperCmd = 'rapper')
+    {
+        $result = exec("$rapperCmd --version 2>/dev/null", $output, $status);
+        if ($status != 0) {
+            throw new EasyRdf_Exception(
+                "Failed to execute the command '$rapperCmd': $result"
+            );
+        } elseif (version_compare($result, self::MINIMUM_RAPPER_VERSION) < 0) {
+            throw new EasyRdf_Exception(
+                "Version ".self::MINIMUM_RAPPER_VERSION." or higher of rapper is required."
+            );
+        } else {
+            $this->rapperCmd = $rapperCmd;
+        }
+    }
+
+    /**
+      * Parse an RDF document into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        $json = EasyRdf_Utils::execCommandPipe(
+            $this->rapperCmd,
+            array(
+                '--quiet',
+                '--input', $format,
+                '--output', 'json',
+                '--ignore-errors',
+                '--input-uri', $baseUri,
+                '--output-uri', '-', '-'
+            ),
+            $data
+        );
+
+        // Parse in the JSON
+        return parent::parse($graph, $json, 'json', $baseUri);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/RdfPhp.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse RDF with no external dependancies.
+ *
+ * http://n2.talis.com/wiki/RDF_PHP_Specification
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_RdfPhp extends EasyRdf_Parser
+{
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_RdfPhp
+     */
+    public function __construct()
+    {
+    }
+
+    /**
+      * Parse RDF/PHP into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        $this->checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'php') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_RdfPhp does not support: $format"
+            );
+        }
+
+        foreach ($data as $subject => $properties) {
+            if (substr($subject, 0, 2) === '_:') {
+                $subject = $this->remapBnode($subject);
+            } elseif (preg_match('/^\w+$/', $subject)) {
+                # Cope with invalid RDF/JSON serialisations that
+                # put the node name in, without the _: prefix
+                # (such as net.fortytwo.sesametools.rdfjson)
+                $subject = $this->remapBnode($subject);
+            }
+
+            foreach ($properties as $property => $objects) {
+                foreach ($objects as $object) {
+                    if ($object['type'] === 'bnode') {
+                        $object['value'] = $this->remapBnode($object['value']);
+                    }
+                    $this->addTriple($subject, $property, $object);
+                }
+            }
+        }
+
+        return $this->tripleCount;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/RdfXml.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,808 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2010-2013 Nicholas J Humfrey
+ * Copyright (c) 2004-2010 Benjamin Nowack (based on ARC2_RDFXMLParser.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2010-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+
+/**
+ * A pure-php class to parse RDF/XML.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 2004-2010 Benjamin Nowack (based on ARC2_RDFXMLParser.php)
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_RdfXml extends EasyRdf_Parser
+{
+    private $state;
+    private $xLang;
+    private $xBase;
+    private $xml;
+    private $rdf;
+    private $nsp;
+    private $sStack;
+    private $sCount;
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_RdfXml
+     */
+    public function __construct()
+    {
+    }
+
+    /** @ignore */
+    protected function init($graph, $base)
+    {
+        $this->graph = $graph;
+        $this->state = 0;
+        $this->xLang = null;
+        $this->xBase = new EasyRdf_ParsedUri($base);
+        $this->xml = 'http://www.w3.org/XML/1998/namespace';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
+        $this->sStack = array();
+        $this->sCount = 0;
+    }
+
+    /** @ignore */
+    protected function initXMLParser()
+    {
+        if (!isset($this->xmlParser)) {
+            $parser = xml_parser_create_ns('UTF-8', '');
+            xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+            xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+            xml_set_element_handler($parser, 'startElementHandler', 'endElementHandler');
+            xml_set_character_data_handler($parser, 'cdataHandler');
+            xml_set_start_namespace_decl_handler($parser, 'newNamespaceHandler');
+            xml_set_object($parser, $this);
+            $this->xmlParser = $parser;
+        }
+    }
+
+    /** @ignore */
+    protected function pushS(&$s)
+    {
+        $s['pos'] = $this->sCount;
+        $this->sStack[$this->sCount] = $s;
+        $this->sCount++;
+    }
+
+    /** @ignore */
+    protected function popS()
+    {
+        $r = array();
+        $this->sCount--;
+        for ($i = 0, $iMax = $this->sCount; $i < $iMax; $i++) {
+            $r[$i] = $this->sStack[$i];
+        }
+        $this->sStack = $r;
+    }
+
+    /** @ignore */
+    protected function updateS($s)
+    {
+        $this->sStack[$s['pos']] = $s;
+    }
+
+    /** @ignore */
+    protected function getParentS()
+    {
+        if ($this->sCount && isset($this->sStack[$this->sCount - 1])) {
+            return $this->sStack[$this->sCount - 1];
+        } else {
+            return false;
+        }
+    }
+
+    /** @ignore */
+    protected function getParentXBase()
+    {
+        if ($p = $this->getParentS()) {
+            if (isset($p['p_x_base']) && $p['p_x_base']) {
+                return $p['p_x_base'];
+            } elseif (isset($p['x_base'])) {
+                return $p['x_base'];
+            } else {
+                return '';
+            }
+        } else {
+            return $this->xBase;
+        }
+    }
+
+    /** @ignore */
+    protected function getParentXLang()
+    {
+        if ($p = $this->getParentS()) {
+            if (isset($p['p_x_lang']) && $p['p_x_lang']) {
+                return $p['p_x_lang'];
+            } elseif (isset($p['x_lang'])) {
+                return $p['x_lang'];
+            } else {
+                return null;
+            }
+        } else {
+            return $this->xLang;
+        }
+    }
+
+    /** @ignore */
+    protected function splitURI($v)
+    {
+        /* auto-splitting on / or # */
+        if (preg_match('/^(.*[\/\#])([^\/\#]+)$/', $v, $m)) {
+            return array($m[1], $m[2]);
+        }
+        /* auto-splitting on last special char, e.g. urn:foo:bar */
+        if (preg_match('/^(.*[\:\/])([^\:\/]+)$/', $v, $m)) {
+            return array($m[1], $m[2]);
+        }
+        return array($v, '');
+    }
+
+    /** @ignore */
+    protected function add($s, $p, $o, $sType, $oType, $oDatatype = null, $oLang = null)
+    {
+        $this->addTriple(
+            $s,
+            $p,
+            array(
+                'type' => $oType,
+                'value' => $o,
+                'lang' => $oLang,
+                'datatype' => $oDatatype
+            )
+        );
+    }
+
+    /** @ignore */
+    protected function reify($t, $s, $p, $o, $sType, $oType, $oDatatype = null, $oLang = null)
+    {
+        $this->add($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
+        $this->add($t, $this->rdf.'subject', $s, 'uri', $sType);
+        $this->add($t, $this->rdf.'predicate', $p, 'uri', 'uri');
+        $this->add($t, $this->rdf.'object', $o, 'uri', $oType, $oDatatype, $oLang);
+    }
+
+    /** @ignore */
+    protected function startElementHandler($p, $t, $a)
+    {
+        switch($this->state) {
+            case 0:
+                return $this->startState0($t, $a);
+            case 1:
+                return $this->startState1($t, $a);
+            case 2:
+                return $this->startState2($t, $a);
+            case 4:
+                return $this->startState4($t, $a);
+            case 5:
+                return $this->startState5($t, $a);
+            case 6:
+                return $this->startState6($t, $a);
+            default:
+                throw new EasyRdf_Parser_Exception(
+                    'startElementHandler() called at state ' . $this->state . ' in '.$t
+                );
+        }
+    }
+
+    /** @ignore */
+    protected function endElementHandler($p, $t)
+    {
+        switch($this->state){
+            case 1:
+                return $this->endState1($t);
+            case 2:
+                return $this->endState2($t);
+            case 3:
+                return $this->endState3($t);
+            case 4:
+                return $this->endState4($t);
+            case 5:
+                return $this->endState5($t);
+            case 6:
+                return $this->endState6($t);
+            default:
+                throw new EasyRdf_Parser_Exception(
+                    'endElementHandler() called at state ' . $this->state . ' in '.$t
+                );
+        }
+    }
+
+    /** @ignore */
+    protected function cdataHandler($p, $d)
+    {
+        switch($this->state){
+            case 4:
+                return $this->cdataState4($d);
+            case 6:
+                return $this->cdataState6($d);
+            default:
+                return false;
+        }
+    }
+
+    /** @ignore */
+    protected function newNamespaceHandler($p, $prf, $uri)
+    {
+        $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+    }
+
+    /** @ignore */
+    protected function startState0($t, $a)
+    {
+        $this->state = 1;
+        if ($t !== $this->rdf.'RDF') {
+            $this->startState1($t, $a);
+        }
+    }
+
+    /** @ignore */
+    protected function startState1($t, $a)
+    {
+        $s = array(
+            'x_base' => $this->getParentXBase(),
+            'x_lang' => $this->getParentXLang(),
+            'li_count' => 0,
+        );
+
+        if (isset($a[$this->xml.'base'])) {
+            $s['x_base'] = $this->xBase->resolve($a[$this->xml.'base']);
+        }
+
+        if (isset($a[$this->xml.'lang'])) {
+            $s['x_lang'] = $a[$this->xml.'lang'];
+        }
+
+        /* ID */
+        if (isset($a[$this->rdf.'ID'])) {
+            $s['type'] = 'uri';
+            $s['value'] = $s['x_base']->resolve('#'.$a[$this->rdf.'ID']);
+            /* about */
+        } elseif (isset($a[$this->rdf.'about'])) {
+            $s['type'] = 'uri';
+            $s['value'] = $s['x_base']->resolve($a[$this->rdf.'about']);
+            /* bnode */
+        } else {
+            $s['type'] = 'bnode';
+            if (isset($a[$this->rdf.'nodeID'])) {
+                $s['value'] = $this->remapBnode($a[$this->rdf.'nodeID']);
+            } else {
+                $s['value'] = $this->graph->newBNodeId();
+            }
+        }
+
+        /* sub-node */
+        if ($this->state === 4) {
+            $supS = $this->getParentS();
+            /* new collection */
+            if (isset($supS['o_is_coll']) && $supS['o_is_coll']) {
+                $coll = array(
+                    'type' => 'bnode',
+                    'value' => $this->graph->newBNodeId(),
+                    'is_coll' => true,
+                    'x_base' => $s['x_base'],
+                    'x_lang' => $s['x_lang']
+                );
+                $this->add($supS['value'], $supS['p'], $coll['value'], $supS['type'], $coll['type']);
+                $this->add($coll['value'], $this->rdf.'first', $s['value'], $coll['type'], $s['type']);
+                $this->pushS($coll);
+
+            } elseif (isset($supS['is_coll']) && $supS['is_coll']) {
+                /* new entry in existing coll */
+                $coll = array(
+                'type' => 'bnode',
+                'value' => $this->graph->newBNodeId(),
+                'is_coll' => true,
+                'x_base' => $s['x_base'],
+                'x_lang' => $s['x_lang']
+                );
+                $this->add($supS['value'], $this->rdf.'rest', $coll['value'], $supS['type'], $coll['type']);
+                $this->add($coll['value'], $this->rdf.'first', $s['value'], $coll['type'], $s['type']);
+                $this->pushS($coll);
+                /* normal sub-node */
+            } elseif (isset($supS['p']) && $supS['p']) {
+                $this->add($supS['value'], $supS['p'], $s['value'], $supS['type'], $s['type']);
+            }
+        }
+        /* typed node */
+        if ($t !== $this->rdf.'Description') {
+            $this->add($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
+        }
+        /* (additional) typing attr */
+        if (isset($a[$this->rdf.'type'])) {
+            $this->add($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
+        }
+
+        /* Seq|Bag|Alt */
+        // if (in_array($t, array($this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'))) {
+        //     # FIXME: what is this?
+        //     $s['is_con'] = true;
+        // }
+
+        /* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
+        foreach ($a as $k => $v) {
+            if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) ||
+                preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
+                if (strpos($k, ':')) {
+                    $this->add($s['value'], $k, $v, $s['type'], 'literal', null, $s['x_lang']);
+                }
+            }
+        }
+        $this->pushS($s);
+        $this->state = 2;
+    }
+
+    /** @ignore */
+    protected function startState2($t, $a)
+    {
+        $s = $this->getParentS();
+        foreach (array('p_x_base', 'p_x_lang', 'p_id', 'o_is_coll') as $k) {
+            unset($s[$k]);
+        }
+        /* base */
+        if (isset($a[$this->xml.'base'])) {
+            $s['p_x_base'] = $s['x_base']->resolve($a[$this->xml.'base']);
+        }
+        $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
+        /* lang */
+        if (isset($a[$this->xml.'lang'])) {
+            $s['p_x_lang'] = $a[$this->xml.'lang'];
+        }
+        $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
+        /* adjust li */
+        if ($t === $this->rdf.'li') {
+            $s['li_count']++;
+            $t = $this->rdf.'_'.$s['li_count'];
+        }
+        /* set p */
+        $s['p'] = $t;
+        /* reification */
+        if (isset($a[$this->rdf.'ID'])) {
+            $s['p_id'] = $a[$this->rdf.'ID'];
+        }
+        $o = array('value' => null, 'type' => null, 'x_base' => $b, 'x_lang' => $l);
+        /* resource/rdf:resource */
+        if (isset($a['resource'])) {
+            $a[$this->rdf.'resource'] = $a['resource'];
+            unset($a['resource']);
+        }
+        if (isset($a[$this->rdf.'resource'])) {
+            $o['type'] = 'uri';
+            $o['value'] = $b->resolve($a[$this->rdf.'resource']);
+            $this->add($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+            /* type */
+            if (isset($a[$this->rdf.'type'])) {
+                $this->add(
+                    $o['value'],
+                    $this->rdf.'type',
+                    $a[$this->rdf.'type'],
+                    'uri',
+                    'uri'
+                );
+            }
+            /* reification */
+            if (isset($s['p_id'])) {
+                $this->reify(
+                    $b->resolve('#'.$s['p_id']),
+                    $s['value'],
+                    $s['p'],
+                    $o['value'],
+                    $s['type'],
+                    $o['type']
+                );
+                unset($s['p_id']);
+            }
+            $this->state = 3;
+        } elseif (isset($a[$this->rdf.'nodeID'])) {
+            /* named bnode */
+            $o['value'] = $this->remapBnode($a[$this->rdf.'nodeID']);
+            $o['type'] = 'bnode';
+            $this->add($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+            $this->state = 3;
+            /* reification */
+            if (isset($s['p_id'])) {
+                $this->reify(
+                    $b->resolve('#'.$s['p_id']),
+                    $s['value'],
+                    $s['p'],
+                    $o['value'],
+                    $s['type'],
+                    $o['type']
+                );
+            }
+            /* parseType */
+        } elseif (isset($a[$this->rdf.'parseType'])) {
+            if ($a[$this->rdf.'parseType'] === 'Literal') {
+                $s['o_xml_level'] = 0;
+                $s['o_xml_data'] = '';
+                $s['p_xml_literal_level'] = 0;
+                $s['ns'] = array();
+                $this->state = 6;
+            } elseif ($a[$this->rdf.'parseType'] === 'Resource') {
+                $o['value'] = $this->graph->newBNodeId();
+                $o['type'] = 'bnode';
+                $o['hasClosingTag'] = 0;
+                $this->add($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                $this->pushS($o);
+                /* reification */
+                if (isset($s['p_id'])) {
+                    $this->reify(
+                        $b->resolve('#'.$s['p_id']),
+                        $s['value'],
+                        $s['p'],
+                        $o['value'],
+                        $s['type'],
+                        $o['type']
+                    );
+                    unset($s['p_id']);
+                }
+                $this->state = 2;
+            } elseif ($a[$this->rdf.'parseType'] === 'Collection') {
+                $s['o_is_coll'] = true;
+                $this->state = 4;
+            }
+        } else {
+            /* sub-node or literal */
+            $s['o_cdata'] = '';
+            if (isset($a[$this->rdf.'datatype'])) {
+                $s['o_datatype'] = $a[$this->rdf.'datatype'];
+            }
+            $this->state = 4;
+        }
+        /* any other attrs (skip rdf and xml) */
+        foreach ($a as $k => $v) {
+            if (((strpos($k, $this->xml) === false) &&
+             (strpos($k, $this->rdf) === false)) ||
+             preg_match('/(\_[0-9]+|value)$/', $k)) {
+                if (strpos($k, ':')) {
+                    if (!$o['value']) {
+                        $o['value'] = $this->graph->newBNodeId();
+                        $o['type'] = 'bnode';
+                        $this->add($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                    }
+                    /* reification */
+                    if (isset($s['p_id'])) {
+                        $this->reify(
+                            $b->resolve('#'.$s['p_id']),
+                            $s['value'],
+                            $s['p'],
+                            $o['value'],
+                            $s['type'],
+                            $o['type']
+                        );
+                        unset($s['p_id']);
+                    }
+                    $this->add($o['value'], $k, $v, $o['type'], 'literal');
+                    $this->state = 3;
+                }
+            }
+        }
+        $this->updateS($s);
+    }
+
+    /** @ignore */
+    protected function startState4($t, $a)
+    {
+        return $this->startState1($t, $a);
+    }
+
+    /** @ignore */
+    protected function startState5($t, $a)
+    {
+        $this->state = 4;
+        return $this->startState4($t, $a);
+    }
+
+    /** @ignore */
+    protected function startState6($t, $a)
+    {
+        $s = $this->getParentS();
+        $data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
+        $ns = isset($s['ns']) ? $s['ns'] : array();
+        $parts = $this->splitURI($t);
+        if (count($parts) === 1) {
+            $data .= '<'.$t;
+        } else {
+            $nsUri = $parts[0];
+            $name = $parts[1];
+            if (!isset($this->nsp[$nsUri])) {
+                foreach ($this->nsp as $tmp1 => $tmp2) {
+                    if (strpos($t, $tmp1) === 0) {
+                        $nsUri = $tmp1;
+                        $name = substr($t, strlen($tmp1));
+                        break;
+                    }
+                }
+            }
+
+            $nsp = isset($this->nsp[$nsUri]) ? $this->nsp[$nsUri] : '';
+            $data .= $nsp ? '<' . $nsp . ':' . $name : '<' . $name;
+            /* ns */
+            if (!isset($ns[$nsp.'='.$nsUri]) || !$ns[$nsp.'='.$nsUri]) {
+                $data .= $nsp ? ' xmlns:'.$nsp.'="'.$nsUri.'"' : ' xmlns="'.$nsUri.'"';
+                $ns[$nsp.'='.$nsUri] = true;
+                $s['ns'] = $ns;
+            }
+        }
+        foreach ($a as $k => $v) {
+            $parts = $this->splitURI($k);
+            if (count($parts) === 1) {
+                $data .= ' '.$k.'="'.$v.'"';
+            } else {
+                $nsUri = $parts[0];
+                $name = $parts[1];
+                $nsp = isset($this->nsp[$nsUri]) ? $this->nsp[$nsUri] : '';
+                $data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"' ;
+            }
+        }
+        $data .= '>';
+        $s['o_xml_data'] = $data;
+        $s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
+        if ($t == $s['p']) {/* xml container prop */
+            $s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
+        }
+        $this->updateS($s);
+    }
+
+    /** @ignore */
+    protected function endState1($t)
+    {
+        /* end of doc */
+        $this->state = 0;
+    }
+
+    /** @ignore */
+    protected function endState2($t)
+    {
+        /* expecting a prop, getting a close */
+        if ($s = $this->getParentS()) {
+            $hasClosingTag = (isset($s['hasClosingTag']) && !$s['hasClosingTag']) ? 0 : 1;
+            $this->popS();
+            $this->state = 5;
+            if ($s = $this->getParentS()) {
+                /* new s */
+                if (!isset($s['p']) || !$s['p']) {
+                    /* p close after collection|parseType=Resource|node close after p close */
+                    $this->state = $this->sCount ? 4 : 1;
+                    if (!$hasClosingTag) {
+                        $this->state = 2;
+                    }
+                } elseif (!$hasClosingTag) {
+                    $this->state = 2;
+                }
+            }
+        }
+    }
+
+    /** @ignore */
+    protected function endState3($t)
+    {
+        /* p close */
+        $this->state = 2;
+    }
+
+    /** @ignore */
+    protected function endState4($t)
+    {
+        /* empty p | pClose after cdata | pClose after collection */
+        if ($s = $this->getParentS()) {
+            $b = isset($s['p_x_base']) && $s['p_x_base'] ?
+                $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
+            if (isset($s['is_coll']) && $s['is_coll']) {
+                $this->add($s['value'], $this->rdf.'rest', $this->rdf.'nil', $s['type'], 'uri');
+                /* back to collection start */
+                while ((!isset($s['p']) || ($s['p'] != $t))) {
+                    $subS = $s;
+                    $this->popS();
+                    $s = $this->getParentS();
+                }
+                /* reification */
+                if (isset($s['p_id']) && $s['p_id']) {
+                    $this->reify(
+                        $b->resolve('#'.$s['p_id']),
+                        $s['value'],
+                        $s['p'],
+                        $subS['value'],
+                        $s['type'],
+                        $subS['type']
+                    );
+                }
+                unset($s['p']);
+                $this->updateS($s);
+            } else {
+                $dt = isset($s['o_datatype']) ? $s['o_datatype'] : null;
+                $l = isset($s['p_x_lang']) && $s['p_x_lang'] ?
+                     $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : null);
+                $o = array('type' => 'literal', 'value' => $s['o_cdata']);
+                $this->add(
+                    $s['value'],
+                    $s['p'],
+                    $o['value'],
+                    $s['type'],
+                    $o['type'],
+                    $dt,
+                    $l
+                );
+                /* reification */
+                if (isset($s['p_id']) && $s['p_id']) {
+                    $this->reify(
+                        $b->resolve('#'.$s['p_id']),
+                        $s['value'],
+                        $s['p'],
+                        $o['value'],
+                        $s['type'],
+                        $o['type'],
+                        $dt,
+                        $l
+                    );
+                }
+                unset($s['o_cdata']);
+                unset($s['o_datatype']);
+                unset($s['p']);
+                $this->updateS($s);
+            }
+            $this->state = 2;
+        }
+    }
+
+    /** @ignore */
+    protected function endState5($t)
+    {
+        /* p close */
+        if ($s = $this->getParentS()) {
+            unset($s['p']);
+            $this->updateS($s);
+            $this->state = 2;
+        }
+    }
+
+    /** @ignore */
+    protected function endState6($t)
+    {
+        if ($s = $this->getParentS()) {
+            $l = isset($s['p_x_lang']) && $s['p_x_lang'] ?
+                $s['p_x_lang'] :
+                (isset($s['x_lang']) ? $s['x_lang'] : null);
+            $data = $s['o_xml_data'];
+            $level = $s['o_xml_level'];
+            if ($level === 0) {
+                /* pClose */
+                $this->add(
+                    $s['value'],
+                    $s['p'],
+                    trim($data, ' '),
+                    $s['type'],
+                    'literal',
+                    $this->rdf.'XMLLiteral',
+                    $l
+                );
+                unset($s['o_xml_data']);
+                $this->state = 2;
+            } else {
+                $parts = $this->splitURI($t);
+                if (count($parts) == 1) {
+                    $data .= '</'.$t.'>';
+                } else {
+                    $nsUri = $parts[0];
+                    $name = $parts[1];
+                    if (!isset($this->nsp[$nsUri])) {
+                        foreach ($this->nsp as $tmp1 => $tmp2) {
+                            if (strpos($t, $tmp1) === 0) {
+                                $nsUri = $tmp1;
+                                $name = substr($t, strlen($tmp1));
+                                break;
+                            }
+                        }
+                    }
+                    $nsp = isset($this->nsp[$nsUri]) ? $this->nsp[$nsUri] : '';
+                    $data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
+                }
+                $s['o_xml_data'] = $data;
+                $s['o_xml_level'] = $level - 1;
+                if ($t == $s['p']) {
+                    /* xml container prop */
+                    $s['p_xml_literal_level']--;
+                }
+            }
+            $this->updateS($s);
+        }
+    }
+
+    /** @ignore */
+    protected function cdataState4($d)
+    {
+        if ($s = $this->getParentS()) {
+            $s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'] . $d : $d;
+            $this->updateS($s);
+        }
+    }
+
+    /** @ignore */
+    protected function cdataState6($d)
+    {
+        if ($s = $this->getParentS()) {
+            if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
+                $d = htmlspecialchars($d, ENT_NOQUOTES);
+                $s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'] . $d : $d;
+            }
+            $this->updateS($s);
+        }
+    }
+
+    /**
+      * Parse an RDF/XML document into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'rdfxml') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_RdfXml does not support: $format"
+            );
+        }
+
+        $this->init($graph, $baseUri);
+        $this->resetBnodeMap();
+
+        /* xml parser */
+        $this->initXMLParser();
+
+        /* parse */
+        if (!xml_parse($this->xmlParser, $data, false)) {
+            $message = xml_error_string(xml_get_error_code($this->xmlParser));
+            throw new EasyRdf_Parser_Exception(
+                'XML error: "' . $message . '"',
+                xml_get_current_line_number($this->xmlParser),
+                xml_get_current_column_number($this->xmlParser)
+            );
+        }
+
+        xml_parser_free($this->xmlParser);
+
+        return $this->tripleCount;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Rdfa.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,709 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2012-2013 Nicholas J Humfrey.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 1997-2006 Aduna (http://www.aduna-software.com/)
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse RDFa 1.1 with no external dependancies.
+ *
+ * http://www.w3.org/TR/rdfa-core/
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2012-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Rdfa extends EasyRdf_Parser
+{
+    const XML_NS = 'http://www.w3.org/XML/1998/namespace';
+    const RDF_XML_LITERAL = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral';
+    const TERM_REGEXP = '/^([a-zA-Z_])([0-9a-zA-Z_\.-]*)$/';
+
+    public $debug = false;
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_Rdfa
+     */
+    public function __construct()
+    {
+    }
+
+    protected function addTriple($resource, $property, $value)
+    {
+        if ($this->debug) {
+            print "Adding triple: $resource -> $property -> ".$value['type'].':'.$value['value']."\n";
+        }
+        $count = $this->graph->add($resource, $property, $value);
+        $this->tripleCount += $count;
+        return $count;
+    }
+
+    protected function generateList($subject, $property, $list)
+    {
+        $current = $subject;
+        $prop = $property;
+
+        // Output a blank node for each item in the list
+        foreach ($list as $item) {
+            $newNode = $this->graph->newBNodeId();
+            $this->addTriple($current, $prop, array('type' => 'bnode', 'value' => $newNode));
+            $this->addTriple($newNode, 'rdf:first', $item);
+
+            $current = $newNode;
+            $prop = 'rdf:rest';
+        }
+
+        // Finally, terminate the list
+        $this->addTriple(
+            $current,
+            $prop,
+            array('type' => 'uri', 'value' => EasyRdf_Namespace::expand('rdf:nil'))
+        );
+    }
+
+    protected function addToList($listMapping, $property, $value)
+    {
+        if ($this->debug) {
+            print "Adding to list: $property -> ".$value['type'].':'.$value['value']."\n";
+        }
+
+        // Create property in the list mapping if it doesn't already exist
+        if (!isset($listMapping->$property)) {
+            $listMapping->$property = array();
+        }
+        array_push($listMapping->$property, $value);
+    }
+
+    protected function printNode($node, $depth)
+    {
+        $indent = str_repeat('  ', $depth);
+        print $indent;
+        switch($node->nodeType) {
+            case XML_ELEMENT_NODE:
+                print 'node';
+                break;
+            case XML_ATTRIBUTE_NODE:
+                print 'attr';
+                break;
+            case XML_TEXT_NODE:
+                print 'text';
+                break;
+            case XML_CDATA_SECTION_NODE:
+                print 'cdata';
+                break;
+            case XML_ENTITY_REF_NODE:
+                print 'entref';
+                break;
+            case XML_ENTITY_NODE:
+                print 'entity';
+                break;
+            case XML_PI_NODE:
+                print 'pi';
+                break;
+            case XML_COMMENT_NODE:
+                print 'comment';
+                break;
+            case XML_DOCUMENT_NODE:
+                print 'doc';
+                break;
+            case XML_DOCUMENT_TYPE_NODE:
+                print 'doctype';
+                break;
+            case XML_HTML_DOCUMENT_NODE:
+                print 'html';
+                break;
+            default:
+                throw new EasyRdf_Exception("unknown node type: ".$node->nodeType);
+                break;
+        }
+        print ' '.$node->nodeName."\n";
+
+        if ($node->hasAttributes()) {
+            foreach ($node->attributes as $attr) {
+                print $indent.' '.$attr->nodeName." => ".$attr->nodeValue."\n";
+            }
+        }
+    }
+
+    protected function guessTimeDatatype($value)
+    {
+        if (preg_match("/^-?\d{4}-\d{2}-\d{2}(Z|[\-\+]\d{2}:\d{2})?$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#date';
+        } elseif (preg_match("/^\d{2}:\d{2}:\d{2}(Z|[\-\+]\d{2}:\d{2})?$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#time';
+        } elseif (preg_match("/^-?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[\-\+]\d{2}:\d{2})?$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#dateTime';
+        } elseif (preg_match("/^P(\d+Y)?(\d+M)?(\d+D)?T?(\d+H)?(\d+M)?(\d+S)?$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#duration';
+        } elseif (preg_match("/^\d{4}$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#gYear';
+        } elseif (preg_match("/^\d{4}-\d{2}$/", $value)) {
+            return 'http://www.w3.org/2001/XMLSchema#gYearMonth';
+        } else {
+            return null;
+        }
+    }
+
+    protected function initialContext()
+    {
+        $context = array(
+            'prefixes' => array(),
+            'vocab' => null,
+            'subject' => $this->baseUri,
+            'property' => null,
+            'object' => null,
+            'terms' => array(),
+            'incompleteRels' => array(),
+            'incompleteRevs' => array(),
+            'listMapping' => null,
+            'lang' => null,
+            'path' => '',
+            'xmlns' => array(),
+        );
+
+        // Set the default prefix
+        $context['prefixes'][''] = 'http://www.w3.org/1999/xhtml/vocab#';
+
+        // RDFa 1.1 default term mapping
+        $context['terms']['describedby'] = 'http://www.w3.org/2007/05/powder-s#describedby';
+        $context['terms']['license'] = 'http://www.w3.org/1999/xhtml/vocab#license';
+        $context['terms']['role'] = 'http://www.w3.org/1999/xhtml/vocab#role';
+
+        return $context;
+    }
+
+    protected function expandCurie($node, &$context, $value)
+    {
+        if (preg_match("/^(\w*?):(.*)$/", $value, $matches)) {
+            list (, $prefix, $local) = $matches;
+            $prefix = strtolower($prefix);
+            if ($prefix === '_') {
+                // It is a bnode
+                return $this->remapBnode(substr($value, 2));
+            } elseif (empty($prefix) and $context['vocab']) {
+                // Empty prefix
+                return $context['vocab'] . $local;
+            } elseif (isset($context['prefixes'][$prefix])) {
+                return $context['prefixes'][$prefix] . $local;
+            } elseif ($uri = $node->lookupNamespaceURI($prefix)) {
+                return $uri . $local;
+            } elseif (!empty($prefix) and $uri = EasyRdf_Namespace::get($prefix)) {
+                // Expand using well-known prefixes
+                return $uri . $local;
+            }
+        }
+    }
+
+    protected function processUri($node, &$context, $value, $isProp = false)
+    {
+        if (preg_match("/^\[(.*)\]$/", $value, $matches)) {
+            // Safe CURIE
+            return $this->expandCurie($node, $context, $matches[1]);
+        } elseif (preg_match(self::TERM_REGEXP, $value) and $isProp) {
+            $term = strtolower($value);
+            if ($context['vocab']) {
+                return $context['vocab'] . $value;
+            } elseif (isset($context['terms'][$term])) {
+                return $context['terms'][$term];
+            }
+        } elseif (substr($value, 0, 2) === '_:' and $isProp) {
+            return null;
+        } else {
+            $uri = $this->expandCurie($node, $context, $value);
+            if ($uri) {
+                return $uri;
+            } else {
+                $parsed = new EasyRdf_ParsedUri($value);
+                if ($parsed->isAbsolute()) {
+                    return $value;
+                } elseif ($isProp) {
+                    // Properties can't be relative URIs
+                    return null;
+                } elseif ($this->baseUri) {
+                    return $this->baseUri->resolve($parsed);
+                }
+            }
+        }
+    }
+
+    protected function processUriList($node, $context, $values)
+    {
+        if (!$values) {
+            return array();
+        }
+
+        $uris = array();
+        foreach (preg_split("/\s+/", $values) as $value) {
+            $uri = $this->processUri($node, $context, $value, true);
+            if ($uri) {
+                array_push($uris, $uri);
+            }
+        }
+        return $uris;
+    }
+
+    protected function getUriAttribute($node, &$context, $attributes)
+    {
+        if (!is_array($attributes)) {
+            $attributes = array($attributes);
+        }
+
+        // Find the first attribute that returns a valid URI
+        foreach ($attributes as $attribute) {
+            if ($node->hasAttribute($attribute)) {
+                $value = $node->getAttribute($attribute);
+                $uri = $this->processUri($node, $context, $value);
+                if ($uri) {
+                    return $uri;
+                }
+            }
+        }
+    }
+
+    protected function processNode($node, &$context, $depth = 1)
+    {
+        if ($this->debug) {
+            $this->printNode($node, $depth);
+        }
+
+        // Step 1: establish local variables
+        $skip = false;
+        $subject = null;
+        $typedResource = null;
+        $object = null;
+        $rels = array();
+        $revs = array();
+        $lang = $context['lang'];
+        $incompleteRels = array();
+        $incompleteRevs = array();
+
+        if ($node->nodeType === XML_ELEMENT_NODE) {
+            $context['path'] .= '/' . $node->nodeName;
+
+            $content = $node->hasAttribute('content') ? $node->getAttribute('content') : null;
+            $datatype = $node->hasAttribute('datatype') ? $node->getAttribute('datatype') : null;
+            $property = $node->getAttribute('property') ? $node->getAttribute('property') : null;
+            $typeof = $node->getAttribute('typeof') ? $node->getAttribute('typeof') : null;
+
+            // Step 2: Default vocabulary
+            if ($node->hasAttribute('vocab')) {
+                $context['vocab'] = $node->getAttribute('vocab');
+                if ($context['vocab']) {
+                    $this->addTriple(
+                        $this->baseUri,
+                        'rdfa:usesVocabulary',
+                        array('type' => 'uri', 'value' => $context['vocab'])
+                    );
+                }
+            }
+
+            // Step 3: Set prefix mappings
+            // Support for deprecated xmlns if present in document
+            foreach ($context['xmlns'] as $prefix => $uri) {
+                if ($node->hasAttribute('xmlns:' . $prefix)) {
+                    $context['prefixes'][$prefix] = $node->getAttribute('xmlns:' . $prefix);
+                    if ($this->debug) {
+                        print "Prefix (xmlns): $prefix => $uri\n";
+                    }
+                }
+            }
+            if ($node->hasAttribute('prefix')) {
+                $mappings = preg_split("/\s+/", $node->getAttribute('prefix'));
+                while (count($mappings)) {
+                    $prefix = strtolower(array_shift($mappings));
+                    $uri = array_shift($mappings);
+
+                    if (substr($prefix, -1) === ':') {
+                        $prefix = substr($prefix, 0, -1);
+                    } else {
+                        continue;
+                    }
+
+                    if ($prefix === '_') {
+                        continue;
+                    } elseif (!empty($prefix)) {
+                        $context['prefixes'][$prefix] = $uri;
+                        if ($this->debug) {
+                            print "Prefix: $prefix => $uri\n";
+                        }
+                    }
+                }
+            }
+
+            // Step 4
+            if ($node->hasAttributeNS(self::XML_NS, 'lang')) {
+                $lang = $node->getAttributeNS(self::XML_NS, 'lang');
+            } elseif ($node->hasAttribute('lang')) {
+                $lang = $node->getAttribute('lang');
+            }
+
+            if (!$node->hasAttribute('rel') and !$node->hasAttribute('rev')) {
+                // Step 5: Establish a new subject if no rel/rev
+                if ($property and is_null($content) and is_null($datatype)) {
+                    $subject = $this->getUriAttribute($node, $context, 'about');
+                    if ($typeof and !$subject) {
+                        $typedResource = $this->getUriAttribute(
+                            $node,
+                            $context,
+                            array('resource', 'href', 'src')
+                        );
+                        if (!$typedResource) {
+                            $typedResource = $this->graph->newBNodeId();
+                        }
+                        $object = $typedResource;
+                    }
+                } else {
+                    $subject = $this->getUriAttribute(
+                        $node,
+                        $context,
+                        array('about', 'resource', 'href', 'src')
+                    );
+                }
+
+                // Establish a subject if there isn't one
+                # FIXME: refactor this
+                if (is_null($subject)) {
+                    if ($context['path'] === '/html/head') {
+                        $subject = $context['object'];
+                    } elseif ($depth <= 2) {
+                        $subject = $this->baseUri;
+                    } elseif ($typeof and !$property) {
+                        $subject = $this->graph->newBNodeId();
+                    } else {
+                        if (!$property) {
+                            $skip = true;
+                        }
+                        $subject = $context['object'];
+                    }
+                }
+
+            } else {
+                // Step 6
+                // If the current element does contain a @rel or @rev attribute, then the next step is to
+                // establish both a value for new subject and a value for current object resource:
+
+                $subject = $this->getUriAttribute($node, $context, 'about');
+
+                $object = $this->getUriAttribute(
+                    $node,
+                    $context,
+                    array('resource', 'href', 'src')
+                );
+
+                if ($typeof) {
+                    if (!$object and !$subject) {
+                        $object = $this->graph->newBNodeId();
+                    }
+                    $typedResource = $subject ? $subject : $object;
+                }
+
+                # FIXME: if the element is the root element of the document
+                # then act as if there is an empty @about present
+                if (!$subject) {
+                    $subject = $context['object'];
+                }
+
+                $rels = $this->processUriList($node, $context, $node->getAttribute('rel'));
+                $revs = $this->processUriList($node, $context, $node->getAttribute('rev'));
+            }
+
+            # FIXME: better place for this?
+            if ($typeof and $subject and !$typedResource) {
+                $typedResource = $subject;
+            }
+
+            // Step 7: Process @typeof if there is a subject
+            if ($typedResource) {
+                foreach ($this->processUriList($node, $context, $typeof) as $type) {
+                    $this->addTriple(
+                        $typedResource,
+                        'rdf:type',
+                        array('type' => 'uri', 'value' => $type)
+                    );
+                }
+            }
+
+            // Step 8: Create new List mapping if the subject has changed
+            if ($subject and $subject !== $context['subject']) {
+                $listMapping = new StdClass();
+            } else {
+                $listMapping = $context['listMapping'];
+            }
+
+            // Step 9: Generate triples with given object
+            if ($subject and $object) {
+                foreach ($rels as $prop) {
+                    $obj = array('type' => 'uri', 'value' => $object);
+                    if ($node->hasAttribute('inlist')) {
+                        $this->addToList($listMapping, $prop, $obj);
+                    } else {
+                        $this->addTriple($subject, $prop, $obj);
+                    }
+                }
+
+                foreach ($revs as $prop) {
+                    $this->addTriple(
+                        $object,
+                        $prop,
+                        array('type' => 'uri', 'value' => $subject)
+                    );
+                }
+            } elseif ($rels or $revs) {
+                // Step 10: Incomplete triples and bnode creation
+                $object = $this->graph->newBNodeId();
+                if ($rels) {
+                    if ($node->hasAttribute('inlist')) {
+                        foreach ($rels as $prop) {
+                            # FIXME: add support for incomplete lists
+                            if (!isset($listMapping->$prop)) {
+                                $listMapping->$prop = array();
+                            }
+                        }
+                    } else {
+                        $incompleteRels = $rels;
+                        if ($this->debug) {
+                            print "Incomplete rels: ".implode(',', $rels)."\n";
+                        }
+                    }
+                }
+
+                if ($revs) {
+                    $incompleteRevs = $revs;
+                    if ($this->debug) {
+                        print "Incomplete revs: ".implode(',', $revs)."\n";
+                    }
+                }
+            }
+
+            // Step 11: establish current property value
+            if ($subject and $property) {
+                $value = array();
+
+                if ($datatype) {
+                    $datatype = $this->processUri($node, $context, $datatype, true);
+                }
+
+                if ($node->nodeName === 'data' and $node->hasAttribute('value')) {
+                    $value['value'] = $node->getAttribute('value');
+                } elseif ($node->hasAttribute('datetime')) {
+                    $value['value'] = $node->getAttribute('datetime');
+                    $datetime = true;
+                } elseif ($datatype === '') {
+                    $value['value'] = $node->textContent;
+                } elseif ($datatype === self::RDF_XML_LITERAL) {
+                    $value['value'] = '';
+                    foreach ($node->childNodes as $child) {
+                        $value['value'] .= $child->C14N();
+                    }
+                } elseif ($content !== null) {
+                    $value['value'] = $content;
+                } elseif (is_null($datatype) and empty($rel) and empty($rev)) {
+                    $value['value'] = $this->getUriAttribute(
+                        $node,
+                        $context,
+                        array('resource', 'href', 'src')
+                    );
+
+                    if ($value['value']) {
+                        $value['type'] = 'uri';
+                    }
+                }
+
+                if (empty($value['value']) and $typedResource and !$node->hasAttribute('about')) {
+                    $value['type'] = 'uri';
+                    $value['value'] = $typedResource;
+                }
+
+                if (empty($value['value'])) {
+                    $value['value'] = $node->textContent;
+                }
+
+                if (empty($value['type'])) {
+                    $value['type'] = 'literal';
+                    if ($datatype) {
+                        $value['datatype'] = $datatype;
+                    } elseif (isset($datetime) or $node->nodeName === 'time') {
+                        $value['datatype'] = $this->guessTimeDatatype($value['value']);
+                    }
+
+                    if (empty($value['datatype']) and $lang) {
+                        $value['lang'] = $lang;
+                    }
+                }
+
+                // Add each of the properties
+                foreach ($this->processUriList($node, $context, $property) as $prop) {
+                    if ($node->hasAttribute('inlist')) {
+                        $this->addToList($listMapping, $prop, $value);
+                    } elseif ($subject) {
+                        $this->addTriple($subject, $prop, $value);
+                    }
+                }
+            }
+
+            // Step 12: Complete the incomplete triples from the evaluation context
+            if (!$skip and $subject and ($context['incompleteRels'] or $context['incompleteRevs'])) {
+                foreach ($context['incompleteRels'] as $prop) {
+                    $this->addTriple(
+                        $context['subject'],
+                        $prop,
+                        array('type' => 'uri', 'value' => $subject)
+                    );
+                }
+
+                foreach ($context['incompleteRevs'] as $prop) {
+                    $this->addTriple(
+                        $subject,
+                        $prop,
+                        array('type' => 'uri', 'value' => $context['subject'])
+                    );
+                }
+            }
+        }
+
+        // Step 13: create a new evaluation context and proceed recursively
+        if ($node->hasChildNodes()) {
+            if ($skip) {
+                $newContext = $context;
+            } else {
+                // Prepare a new evaluation context
+                $newContext = $context;
+                if ($object) {
+                    $newContext['object'] = $object;
+                } elseif ($subject) {
+                    $newContext['object'] = $subject;
+                } else {
+                    $newContext['object'] = $context['subject'];
+                }
+                if ($subject) {
+                    $newContext['subject'] = $subject;
+                }
+                $newContext['incompleteRels'] = $incompleteRels;
+                $newContext['incompleteRevs'] = $incompleteRevs;
+                if (isset($listMapping)) {
+                    $newContext['listMapping'] = $listMapping;
+                }
+            }
+
+            // The language is always updated, even if skip is set
+            $newContext['lang'] = $lang;
+
+            foreach ($node->childNodes as $child) {
+                if ($child->nodeType === XML_ELEMENT_NODE) {
+                    $this->processNode($child, $newContext, $depth+1);
+                }
+            }
+        }
+
+        // Step 14: create triples for lists
+        if (!empty($listMapping)) {
+            foreach ($listMapping as $prop => $list) {
+                if ($context['listMapping'] !== $listMapping) {
+                    if ($this->debug) {
+                        print "Need to create triples for $prop => ".count($list)." items\n";
+                    }
+                    $this->generateList($subject, $prop, $list);
+                }
+            }
+        }
+    }
+
+    /**
+     * Parse RDFa 1.1 into an EasyRdf_Graph
+     *
+     * @param object EasyRdf_Graph $graph   the graph to load the data into
+     * @param string               $data    the RDF document data
+     * @param string               $format  the format of the input data
+     * @param string               $baseUri the base URI of the data being parsed
+     * @return integer             The number of triples added to the graph
+     */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'rdfa') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_Rdfa does not support: $format"
+            );
+        }
+
+        // Initialise evaluation context.
+        $context = $this->initialContext();
+
+        libxml_use_internal_errors(true);
+
+        // Parse the document into DOM
+        $doc = new DOMDocument();
+        // Attempt to parse the document as strict XML, and fall back to HTML
+        // if XML parsing fails.
+        if ($doc->loadXML($data, LIBXML_NONET)) {
+            if ($this->debug) {
+                print "Document was parsed as XML.";
+            }
+            // Collect all xmlns namespaces defined throughout the document.
+            $sxe = simplexml_import_dom($doc);
+            $context['xmlns'] = $sxe->getDocNamespaces(true);
+            unset($context['xmlns']['']);
+        } else {
+            $doc->loadHTML($data);
+            if ($this->debug) {
+                print "Document was parsed as HTML.";
+            }
+        }
+
+        // Establish the base for both XHTML and HTML documents.
+        $xpath = new DOMXPath($doc);
+        $xpath->registerNamespace('xh', "http://www.w3.org/1999/xhtml");
+        $nodeList = $xpath->query('/xh:html/xh:head/xh:base');
+        if ($node = $nodeList->item(0) and $href = $node->getAttribute('href')) {
+            $this->baseUri = new EasyRdf_ParsedUri($href);
+        }
+        $nodeList = $xpath->query('/html/head/base');
+        if ($node = $nodeList->item(0) and $href = $node->getAttribute('href')) {
+            $this->baseUri = new EasyRdf_ParsedUri($href);
+        }
+
+        // Remove the fragment from the base URI
+        $this->baseUri->setFragment(null);
+
+        // Recursively process XML nodes
+        $this->processNode($doc, $context);
+
+        return $this->tripleCount;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Redland.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,246 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse RDF using Redland (librdf) C library.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Redland extends EasyRdf_Parser
+{
+    /** Variable set to the librdf world */
+    private $world = null;
+
+    /** Parser feature URI string for getting the error count of last parse. */
+    const LIBRDF_PARSER_FEATURE_ERROR_COUNT =
+        'http://feature.librdf.org/parser-error-count';
+
+    /*
+     *  Types supported by Redland:
+     *
+     *  ntriples: N-Triples
+     *  turtle: Turtle Terse RDF Triple Language
+     *  trig: TriG - Turtle with Named Graphs
+     *  rss-tag-soup: RSS Tag Soup
+     *  grddl: Gleaning Resource Descriptions from Dialects of Languages
+     *  guess: Pick the parser to use using content type and URI
+     *  rdfa: RDF/A via librdfa
+     *  raptor: (null)
+     *  rdfxml: RDF/XML
+     */
+
+
+    /**
+     * Convert a librdf node type into a string
+     * @ignore
+     */
+    protected function nodeTypeString($node)
+    {
+        switch(librdf_node_get_type($node)) {
+            case 1:
+                return 'uri';
+                break;
+            case 2:
+                return 'literal';
+                break;
+            case 4:
+                return 'bnode';
+                break;
+            default:
+                return 'unknown';
+                break;
+        }
+    }
+
+    /**
+     * Convert the URI for a node into a string
+     * @ignore
+     */
+    protected function nodeUriString($node)
+    {
+        $type = EasyRdf_Parser_Redland::nodeTypeString($node);
+        if ($type == 'uri') {
+            $uri = librdf_node_get_uri($node);
+            if (!$uri) {
+                throw new EasyRdf_Exception("Failed to get URI of node");
+            }
+            $str = librdf_uri_to_string($uri);
+            if (!$str) {
+                throw new EasyRdf_Exception(
+                    "Failed to convert librdf_uri to string"
+                );
+            }
+            return $str;
+        } elseif ($type == 'bnode') {
+            return $this->remapBnode(
+                librdf_node_get_blank_identifier($node)
+            );
+        } else {
+            throw new EasyRdf_Exception("Unsupported type: ".$type);
+        }
+    }
+
+    /**
+     * Convert a node into an associate array
+     * @ignore
+     */
+    protected function nodeToRdfPhp($node)
+    {
+        $object = array();
+        $object['type'] = EasyRdf_Parser_Redland::nodeTypeString($node);
+        if ($object['type'] == 'uri') {
+            $object['value'] = EasyRdf_Parser_Redland::nodeUriString($node);
+        } elseif ($object['type'] == 'bnode') {
+            $object['value'] = '_:'.librdf_node_get_blank_identifier($node);
+        } elseif ($object['type'] == 'literal') {
+            $object['value'] = librdf_node_get_literal_value($node);
+            $lang = librdf_node_get_literal_value_language($node);
+            if ($lang) {
+                $object['lang'] = $lang;
+            }
+            $datatype = librdf_node_get_literal_value_datatype_uri($node);
+            if ($datatype) {
+                $object['datatype'] = librdf_uri_to_string($datatype);
+            }
+        } else {
+            throw new EasyRdf_Exception("Unsupported type: ".$object['type']);
+        }
+        return $object;
+    }
+
+    /**
+     * Return the number of errors during parsing
+     * @ignore
+     */
+    protected function parserErrorCount($parser)
+    {
+        $errorUri = librdf_new_uri(
+            $this->world,
+            self::LIBRDF_PARSER_FEATURE_ERROR_COUNT
+        );
+        $errorNode = librdf_parser_get_feature($parser, $errorUri);
+        $errorCount = librdf_node_get_literal_value($errorNode);
+        librdf_free_uri($errorUri);
+        return $errorCount;
+    }
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_Redland
+     */
+    public function __construct()
+    {
+        if (extension_loaded('redland')) {
+            $this->world = librdf_php_get_world();
+            if (!$this->world) {
+                throw new EasyRdf_Exception(
+                    "Failed to initialise librdf world."
+                );
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "Redland PHP extension is not available."
+            );
+        }
+    }
+
+    /**
+      * Parse an RDF document into an EasyRdf_Graph
+      *
+      * @param object EasyRdf_Graph $graph   the graph to load the data into
+      * @param string               $data    the RDF document data
+      * @param string               $format  the format of the input data
+      * @param string               $baseUri the base URI of the data being parsed
+      * @return integer             The number of triples added to the graph
+      */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        $parser = librdf_new_parser($this->world, $format, null, null);
+        if (!$parser) {
+            throw new EasyRdf_Exception(
+                "Failed to create librdf_parser of type: $format"
+            );
+        }
+
+        $rdfUri = librdf_new_uri($this->world, $baseUri);
+        if (!$rdfUri) {
+            throw new EasyRdf_Exception(
+                "Failed to create librdf_uri from: $baseUri"
+            );
+        }
+
+        $stream = librdf_parser_parse_string_as_stream($parser, $data, $rdfUri);
+        if (!$stream) {
+            throw new EasyRdf_Parser_Exception(
+                "Failed to parse RDF stream"
+            );
+        }
+
+        do {
+            $statement = librdf_stream_get_object($stream);
+            if ($statement) {
+                $subject = EasyRdf_Parser_Redland::nodeUriString(
+                    librdf_statement_get_subject($statement)
+                );
+                $predicate = EasyRdf_Parser_Redland::nodeUriString(
+                    librdf_statement_get_predicate($statement)
+                );
+                $object = EasyRdf_Parser_Redland::nodeToRdfPhp(
+                    librdf_statement_get_object($statement)
+                );
+
+                $this->addTriple($subject, $predicate, $object);
+            }
+        } while (!librdf_stream_next($stream));
+
+        $errorCount = $this->parserErrorCount($parser);
+        if ($errorCount) {
+            throw new EasyRdf_Parser_Exception("$errorCount errors while parsing.");
+        }
+
+        librdf_free_uri($rdfUri);
+        librdf_free_stream($stream);
+        librdf_free_parser($parser);
+
+        return $this->tripleCount;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Parser/Turtle.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1311 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.
+ * Copyright (c) 1997-2013 Aduna (http://www.aduna-software.com/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 1997-2006 Aduna (http://www.aduna-software.com/)
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to parse Turtle with no external dependancies.
+ *
+ * It is a translation from Java to PHP of the Sesame Turtle Parser:
+ * http://bit.ly/TurtleParser
+ * 
+ * Lasted updated against version: 
+ * ecda6a15a200a2fc6a062e2e43081257c3ccd4e6   (Mon Jul 29 12:05:58 2013)
+ * 
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ *             Copyright (c) 1997-2013 Aduna (http://www.aduna-software.com/)
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Parser_Turtle extends EasyRdf_Parser_Ntriples
+{
+    protected $data;
+    protected $namespaces;
+    protected $subject;
+    protected $predicate;
+    protected $object;
+    
+    protected $line;
+    protected $column;
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Parser_Turtle
+     */
+    public function __construct()
+    {
+    }
+
+    /**
+     * Parse Turtle into an EasyRdf_Graph
+     *
+     * @param object EasyRdf_Graph $graph   the graph to load the data into
+     * @param string               $data    the RDF document data
+     * @param string               $format  the format of the input data
+     * @param string               $baseUri the base URI of the data being parsed
+     * @return integer             The number of triples added to the graph
+     */
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+
+        if ($format != 'turtle') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Parser_Turtle does not support: $format"
+            );
+        }
+
+        $this->data = $data;
+        $this->namespaces = array();
+        $this->subject = null;
+        $this->predicate = null;
+        $this->object = null;
+        
+        $this->line = 1;
+        $this->column = 1;
+
+        $this->resetBnodeMap();
+
+        $c = $this->skipWSC();
+        while ($c != -1) {
+            $this->parseStatement();
+            $c = $this->skipWSC();
+        }
+
+        return $this->tripleCount;
+    }
+
+
+    /**
+     * Parse a statement [2]
+     * @ignore
+     */
+    protected function parseStatement()
+    {
+        $directive = '';
+        while (true) {
+            $c = $this->read();
+            if ($c == -1 || self::isWhitespace($c)) {
+                $this->unread($c);
+                break;
+            } else {
+                $directive .= $c;
+            }
+        }
+
+        if (preg_match("/^(@|prefix$|base$)/i", $directive)) {
+            $this->parseDirective($directive);
+            $this->skipWSC();
+            // SPARQL BASE and PREFIX lines do not end in .
+            if ($directive[0] == "@") {
+                $this->verifyCharacterOrFail($this->read(), ".");
+            }
+        } else {
+            $this->unread($directive);
+            $this->parseTriples();
+            $this->skipWSC();
+            $this->verifyCharacterOrFail($this->read(), ".");
+        }
+    }
+
+    /**
+     * Parse a directive [3]
+     * @ignore
+     */
+    protected function parseDirective($directive)
+    {
+        $directive = strtolower($directive);
+        if ($directive == "prefix" || $directive == '@prefix') {
+            $this->parsePrefixID();
+        } elseif ($directive == "base" || $directive == '@base') {
+            $this->parseBase();
+        } elseif (mb_strlen($directive) == 0) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: directive name is missing, expected @prefix or @base",
+                $this->line,
+                $this->column
+            );
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: unknown directive \"$directive\"",
+                $this->line,
+                $this->column
+            );
+        }
+    }
+
+    /**
+     * Parse a prefixID [4]
+     * @ignore
+     */
+    protected function parsePrefixID()
+    {
+        $this->skipWSC();
+
+        // Read prefix ID (e.g. "rdf:" or ":")
+        $prefixID = '';
+
+        while (true) {
+            $c = $this->read();
+            if ($c == ':') {
+                $this->unread($c);
+                break;
+            } elseif (self::isWhitespace($c)) {
+                break;
+            } elseif ($c == -1) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: unexpected end of file while reading prefix id",
+                    $this->line,
+                    $this->column
+                );
+            }
+
+            $prefixID .= $c;
+        }
+
+        $this->skipWSC();
+        $this->verifyCharacterOrFail($this->read(), ":");
+        $this->skipWSC();
+
+        // Read the namespace URI
+        $namespace = $this->parseURI();
+
+        // Store local namespace mapping
+        $this->namespaces[$prefixID] = $namespace['value'];
+    }
+
+    /**
+     * Parse base [5]
+     * @ignore
+     */
+    protected function parseBase()
+    {
+        $this->skipWSC();
+
+        $baseUri = $this->parseURI();
+        $this->baseUri = new EasyRdf_ParsedUri($baseUri['value']);
+    }
+
+    /**
+     * Parse triples [6]
+     * @ignore
+     */
+    protected function parseTriples()
+    {
+        $c = $this->peek();
+
+        // If the first character is an open bracket we need to decide which of
+        // the two parsing methods for blank nodes to use
+        if ($c == '[') {
+            $c = $this->read();
+            $this->skipWSC();
+            $c = $this->peek();
+            if ($c == ']') {
+                $c = $this->read();
+                $this->subject = $this->createBNode();
+                $this->skipWSC();
+                $this->parsePredicateObjectList();
+            } else {
+                $this->unread('[');
+                $this->subject = $this->parseImplicitBlank();
+            }
+            $this->skipWSC();
+            $c = $this->peek();
+
+            // if this is not the end of the statement, recurse into the list of
+            // predicate and objects, using the subject parsed above as the subject
+            // of the statement.
+            if ($c != '.') {
+                $this->parsePredicateObjectList();
+            }
+        } else {
+            $this->parseSubject();
+            $this->skipWSC();
+            $this->parsePredicateObjectList();
+        }
+
+        $this->subject = null;
+        $this->predicate = null;
+        $this->object = null;
+    }
+
+    /**
+     * Parse a predicateObjectList [7]
+     * @ignore
+     */
+    protected function parsePredicateObjectList()
+    {
+        $this->predicate = $this->parsePredicate();
+
+        $this->skipWSC();
+        $this->parseObjectList();
+
+        while ($this->skipWSC() == ';') {
+            $this->read();
+
+            $c = $this->skipWSC();
+
+            if ($c == '.' || $c == ']') {
+                break;
+            } elseif ($c == ';') {
+                // empty predicateObjectList, skip to next
+                continue;
+            }
+
+            $this->predicate = $this->parsePredicate();
+
+            $this->skipWSC();
+
+            $this->parseObjectList();
+        }
+    }
+
+    /**
+     * Parse a objectList [8]
+     * @ignore
+     */
+    protected function parseObjectList()
+    {
+        $this->parseObject();
+
+        while ($this->skipWSC() == ',') {
+            $this->read();
+            $this->skipWSC();
+            $this->parseObject();
+        }
+    }
+
+    /**
+     * Parse a subject [10]
+     * @ignore
+     */
+    protected function parseSubject()
+    {
+        $c = $this->peek();
+        if ($c == '(') {
+            $this->subject = $this->parseCollection();
+        } elseif ($c == '[') {
+            $this->subject = $this->parseImplicitBlank();
+        } else {
+            $value = $this->parseValue();
+
+            if ($value['type'] == 'uri' or $value['type'] == 'bnode') {
+                $this->subject = $value;
+            } else {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: illegal subject type: ".$value['type'],
+                    $this->line,
+                    $this->column
+                );
+            }
+        }
+    }
+
+    /**
+     * Parse a predicate [11]
+     * @ignore
+     */
+    protected function parsePredicate()
+    {
+        // Check if the short-cut 'a' is used
+        $c1 = $this->read();
+
+        if ($c1 == 'a') {
+            $c2 = $this->read();
+
+            if (self::isWhitespace($c2)) {
+                // Short-cut is used, return the rdf:type URI
+                return array(
+                    'type' => 'uri',
+                    'value' => EasyRdf_Namespace::get('rdf') . 'type'
+                );
+            }
+
+            // Short-cut is not used, unread all characters
+            $this->unread($c2);
+        }
+        $this->unread($c1);
+
+        // Predicate is a normal resource
+        $predicate = $this->parseValue();
+        if ($predicate['type'] == 'uri') {
+            return $predicate;
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: Illegal predicate type: " . $predicate['type'],
+                $this->line,
+                $this->column
+            );
+        }
+    }
+
+    /**
+     * Parse a object [12]
+     * @ignore
+     */
+    protected function parseObject()
+    {
+        $c = $this->peek();
+
+        if ($c == '(') {
+            $this->object = $this->parseCollection();
+        } elseif ($c == '[') {
+            $this->object = $this->parseImplicitBlank();
+        } else {
+            $this->object = $this->parseValue();
+        }
+
+        $this->addTriple(
+            $this->subject['value'],
+            $this->predicate['value'],
+            $this->object
+        );
+    }
+
+    /**
+     * Parses a blankNodePropertyList [15]
+     *
+     * This method parses the token []
+     * and predicateObjectLists that are surrounded by square brackets.
+     *
+     * @ignore
+     */
+    protected function parseImplicitBlank()
+    {
+        $this->verifyCharacterOrFail($this->read(), "[");
+
+        $bnode = $this->createBNode();
+
+        $c = $this->read();
+        if ($c != ']') {
+            $this->unread($c);
+
+            // Remember current subject and predicate
+            $oldSubject = $this->subject;
+            $oldPredicate = $this->predicate;
+
+            // generated bNode becomes subject
+            $this->subject = $bnode;
+
+            // Enter recursion with nested predicate-object list
+            $this->skipWSC();
+
+            $this->parsePredicateObjectList();
+
+            $this->skipWSC();
+
+            // Read closing bracket
+            $this->verifyCharacterOrFail($this->read(), "]");
+
+            // Restore previous subject and predicate
+            $this->subject = $oldSubject;
+            $this->predicate = $oldPredicate;
+        }
+
+        return $bnode;
+    }
+
+    /**
+     * Parses a collection [16], e.g: ( item1 item2 item3 )
+     * @ignore
+     */
+    protected function parseCollection()
+    {
+        $this->verifyCharacterOrFail($this->read(), "(");
+
+        $c = $this->skipWSC();
+        if ($c == ')') {
+            // Empty list
+            $this->read();
+            return array(
+                'type' => 'uri',
+                'value' => EasyRdf_Namespace::get('rdf') . 'nil'
+            );
+        } else {
+            $listRoot = $this->createBNode();
+
+            // Remember current subject and predicate
+            $oldSubject = $this->subject;
+            $oldPredicate = $this->predicate;
+
+            // generated bNode becomes subject, predicate becomes rdf:first
+            $this->subject = $listRoot;
+            $this->predicate = array(
+                'type' => 'uri',
+                'value' => EasyRdf_Namespace::get('rdf') . 'first'
+            );
+
+            $this->parseObject();
+            $bNode = $listRoot;
+
+            while ($this->skipWSC() != ')') {
+                // Create another list node and link it to the previous
+                $newNode = $this->createBNode();
+
+                $this->addTriple(
+                    $bNode['value'],
+                    EasyRdf_Namespace::get('rdf') . 'rest',
+                    $newNode
+                );
+
+                // New node becomes the current
+                $this->subject = $bNode = $newNode;
+
+                $this->parseObject();
+            }
+
+            // Skip ')'
+            $this->read();
+
+            // Close the list
+            $this->addTriple(
+                $bNode['value'],
+                EasyRdf_Namespace::get('rdf') . 'rest',
+                array(
+                    'type' => 'uri',
+                    'value' => EasyRdf_Namespace::get('rdf') . 'nil'
+                )
+            );
+
+            // Restore previous subject and predicate
+            $this->subject = $oldSubject;
+            $this->predicate = $oldPredicate;
+
+            return $listRoot;
+        }
+    }
+
+    /**
+     * Parses an RDF value. This method parses uriref, qname, node ID, quoted
+     * literal, integer, double and boolean.
+     * @ignore
+     */
+    protected function parseValue()
+    {
+        $c = $this->peek();
+
+        if ($c == '<') {
+            // uriref, e.g. <foo://bar>
+            return $this->parseURI();
+        } elseif ($c == ':' || self::isPrefixStartChar($c)) {
+            // qname or boolean
+            return $this->parseQNameOrBoolean();
+        } elseif ($c == '_') {
+            // node ID, e.g. _:n1
+            return $this->parseNodeID();
+        } elseif ($c == '"' || $c == "'") {
+            // quoted literal, e.g. "foo" or """foo""" or 'foo' or '''foo'''
+            return $this->parseQuotedLiteral();
+        } elseif (ctype_digit($c) || $c == '.' || $c == '+' || $c == '-') {
+            // integer or double, e.g. 123 or 1.2e3
+            return $this->parseNumber();
+        } elseif ($c == -1) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: unexpected end of file while reading value",
+                $this->line,
+                $this->column
+            );
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: expected an RDF value here, found '$c'",
+                $this->line,
+                $this->column
+            );
+        }
+    }
+
+    /**
+     * Parses a quoted string, optionally followed by a language tag or datatype.
+     * @ignore
+     */
+    protected function parseQuotedLiteral()
+    {
+        $label = $this->parseQuotedString();
+
+        // Check for presence of a language tag or datatype
+        $c = $this->peek();
+
+        if ($c == '@') {
+            $this->read();
+
+            // Read language
+            $lang = '';
+            $c = $this->read();
+            if ($c == -1) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: unexpected end of file while reading language",
+                    $this->line,
+                    $this->column
+                );
+            } elseif (!self::isLanguageStartChar($c)) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: expected a letter, found '$c'",
+                    $this->line,
+                    $this->column
+                );
+            }
+
+            $lang .= $c;
+
+            $c = $this->read();
+            while (!self::isWhitespace($c)) {
+                if ($c == '.' || $c == ';' || $c == ',' || $c == ')' || $c == ']' || $c == -1) {
+                    break;
+                }
+                if (self::isLanguageChar($c)) {
+                    $lang .= $c;
+                } else {
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: illegal language tag char: '$c'",
+                        $this->line,
+                        $this->column
+                    );
+                }
+                $c = $this->read();
+            }
+
+            $this->unread($c);
+
+            return array(
+                'type' => 'literal',
+                'value' => $label,
+                'lang' => $lang
+            );
+        } elseif ($c == '^') {
+            $this->read();
+
+            // next character should be another '^'
+            $this->verifyCharacterOrFail($this->read(), "^");
+
+            // Read datatype
+            $datatype = $this->parseValue();
+            if ($datatype['type'] == 'uri') {
+                return array(
+                    'type' => 'literal',
+                    'value' => $label,
+                    'datatype' => $datatype['value']
+                );
+            } else {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: illegal datatype type: " . $datatype['type'],
+                    $this->line,
+                    $this->column
+                );
+            }
+        } else {
+            return array(
+                'type' => 'literal',
+                'value' => $label
+            );
+        }
+    }
+
+    /**
+     * Parses a quoted string, which is either a "normal string" or a """long string""".
+     * @ignore
+     */
+    protected function parseQuotedString()
+    {
+        $result = null;
+
+        $c1 = $this->read();
+
+        // First character should be ' or "
+        $this->verifyCharacterOrFail($c1, "\"\'");
+
+        // Check for long-string, which starts and ends with three double quotes
+        $c2 = $this->read();
+        $c3 = $this->read();
+
+        if ($c2 == $c1 && $c3 == $c1) {
+            // Long string
+            $result = $this->parseLongString($c2);
+        } else {
+            // Normal string
+            $this->unread($c3);
+            $this->unread($c2);
+
+            $result = $this->parseString($c1);
+        }
+
+        // Unescape any escape sequences
+        return $this->unescapeString($result);
+    }
+
+    /**
+     * Parses a "normal string". This method requires that the opening character
+     * has already been parsed.
+     * @param string  $closingCharacter  The type of quote to use (either ' or ")
+     * @ignore
+     */
+    protected function parseString($closingCharacter)
+    {
+        $str = '';
+
+        while (true) {
+            $c = $this->read();
+
+            if ($c == $closingCharacter) {
+                break;
+            } elseif ($c == -1) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: unexpected end of file while reading string",
+                    $this->line,
+                    $this->column
+                );
+            }
+
+            $str .= $c;
+
+            if ($c == '\\') {
+                // This escapes the next character, which might be a ' or a "
+                $c = $this->read();
+                if ($c == -1) {
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: unexpected end of file while reading string",
+                        $this->line,
+                        $this->column
+                    );
+                }
+                $str .= $c;
+            }
+        }
+
+        return $str;
+    }
+
+    /**
+     * Parses a """long string""". This method requires that the first three
+     * characters have already been parsed.
+     * @param string  $closingCharacter  The type of quote to use (either ' or ")
+     * @ignore
+     */
+    protected function parseLongString($closingCharacter)
+    {
+        $str = '';
+        $doubleQuoteCount = 0;
+
+        while ($doubleQuoteCount < 3) {
+            $c = $this->read();
+
+            if ($c == -1) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: unexpected end of file while reading long string",
+                    $this->line,
+                    $this->column
+                );
+            } elseif ($c == $closingCharacter) {
+                $doubleQuoteCount++;
+            } else {
+                $doubleQuoteCount = 0;
+            }
+
+            $str .= $c;
+
+            if ($c == '\\') {
+                // This escapes the next character, which might be a ' or "
+                $c = $this->read();
+                if ($c == -1) {
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: unexpected end of file while reading long string",
+                        $this->line,
+                        $this->column
+                    );
+                }
+                $str .= $c;
+            }
+        }
+
+        return mb_substr($str, 0, -3);
+    }
+
+    /**
+     * Parses a numeric value, either of type integer, decimal or double
+     * @ignore
+     */
+    protected function parseNumber()
+    {
+        $value = '';
+        $datatype = EasyRdf_Namespace::get('xsd').'integer';
+
+        $c = $this->read();
+
+        // read optional sign character
+        if ($c == '+' || $c == '-') {
+            $value .= $c;
+            $c = $this->read();
+        }
+
+        while (ctype_digit($c)) {
+            $value .= $c;
+            $c = $this->read();
+        }
+
+        if ($c == '.' || $c == 'e' || $c == 'E') {
+            // read optional fractional digits
+            if ($c == '.') {
+
+                if (self::isWhitespace($this->peek())) {
+                    // We're parsing an integer that did not have a space before the
+                    // period to end the statement
+                } else {
+                    $value .= $c;
+                    $c = $this->read();
+                    while (ctype_digit($c)) {
+                        $value .= $c;
+                        $c = $this->read();
+                    }
+
+                    if (mb_strlen($value) == 1) {
+                        // We've only parsed a '.'
+                        throw new EasyRdf_Parser_Exception(
+                            "Turtle Parse Error: object for statement missing",
+                            $this->line,
+                            $this->column
+                        );
+                    }
+
+                    // We're parsing a decimal or a double
+                    $datatype = EasyRdf_Namespace::get('xsd').'decimal';
+                }
+            } else {
+                if (mb_strlen($value) == 0) {
+                    // We've only parsed an 'e' or 'E'
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: object for statement missing",
+                        $this->line,
+                        $this->column
+                    );
+                }
+            }
+
+            // read optional exponent
+            if ($c == 'e' || $c == 'E') {
+                $datatype = EasyRdf_Namespace::get('xsd').'double';
+                $value .= $c;
+
+                $c = $this->read();
+                if ($c == '+' || $c == '-') {
+                    $value .= $c;
+                    $c = $this->read();
+                }
+
+                if (!ctype_digit($c)) {
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: exponent value missing",
+                        $this->line,
+                        $this->column
+                    );
+                }
+
+                $value .= $c;
+
+                $c = $this->read();
+                while (ctype_digit($c)) {
+                    $value .= $c;
+                    $c = $this->read();
+                }
+            }
+        }
+
+        // Unread last character, it isn't part of the number
+        $this->unread($c);
+
+        // Return result as a typed literal
+        return array(
+            'type' => 'literal',
+            'value' => $value,
+            'datatype' => $datatype
+        );
+    }
+
+    /**
+     * Parses a URI / IRI
+     * @ignore
+     */
+    protected function parseURI()
+    {
+        $uri = '';
+
+        // First character should be '<'
+        $this->verifyCharacterOrFail($this->read(), "<");
+
+        // Read up to the next '>' character
+        while (true) {
+            $c = $this->read();
+
+            if ($c == '>') {
+                break;
+            } elseif ($c == -1) {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: unexpected end of file while reading URI",
+                    $this->line,
+                    $this->column
+                );
+            }
+
+            $uri .= $c;
+
+            if ($c == '\\') {
+                // This escapes the next character, which might be a '>'
+                $c = $this->read();
+                if ($c == -1) {
+                    throw new EasyRdf_Parser_Exception(
+                        "Turtle Parse Error: unexpected end of file while reading URI",
+                        $this->line,
+                        $this->column
+                    );
+                }
+                $uri .= $c;
+            }
+        }
+
+        // Unescape any escape sequences
+        $uri = $this->unescapeString($uri);
+
+        return array(
+            'type' => 'uri',
+            'value' => $this->resolve($uri)
+        );
+    }
+
+    /**
+     * Parses qnames and boolean values, which have equivalent starting
+     * characters.
+     * @ignore
+     */
+    protected function parseQNameOrBoolean()
+    {
+        // First character should be a ':' or a letter
+        $c = $this->read();
+        if ($c == -1) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: unexpected end of file while readying value",
+                $this->line,
+                $this->column
+            );
+        }
+        if ($c != ':' && !self::isPrefixStartChar($c)) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: expected a ':' or a letter, found '$c'",
+                $this->line,
+                $this->column
+            );
+        }
+
+        $namespace = null;
+
+        if ($c == ':') {
+            // qname using default namespace
+            if (isset($this->namespaces[''])) {
+                $namespace = $this->namespaces[''];
+            } else {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: default namespace used but not defined",
+                    $this->line,
+                    $this->column
+                );
+            }
+        } else {
+            // $c is the first letter of the prefix
+            $prefix = $c;
+
+            $c = $this->read();
+            while (self::isPrefixChar($c)) {
+                $prefix .= $c;
+                $c = $this->read();
+            }
+
+            if ($c != ':') {
+                // prefix may actually be a boolean value
+                $value = $prefix;
+
+                if ($value == "true" || $value == "false") {
+                    return array(
+                        'type' => 'literal',
+                        'value' => $value,
+                        'datatype' => EasyRdf_Namespace::get('xsd') . 'boolean'
+                    );
+                }
+            }
+
+            $this->verifyCharacterOrFail($c, ":");
+
+            if (isset($this->namespaces[$prefix])) {
+                $namespace = $this->namespaces[$prefix];
+            } else {
+                throw new EasyRdf_Parser_Exception(
+                    "Turtle Parse Error: namespace prefix '$prefix' used but not defined",
+                    $this->line,
+                    $this->column
+                );
+            }
+        }
+
+        // $c == ':', read optional local name
+        $localName = '';
+        $c = $this->read();
+        if (self::isNameStartChar($c)) {
+            if ($c == '\\') {
+                $localName .= $this->readLocalEscapedChar();
+            } else {
+                $localName .= $c;
+            }
+
+            $c = $this->read();
+            while (self::isNameChar($c)) {
+                if ($c == '\\') {
+                    $localName .= $this->readLocalEscapedChar();
+                } else {
+                    $localName .= $c;
+                }
+                $c = $this->read();
+            }
+        }
+
+        // Unread last character
+        $this->unread($c);
+
+        // Note: namespace has already been resolved
+        return array(
+            'type' => 'uri',
+            'value' => $namespace . $localName
+        );
+    }
+
+    protected function readLocalEscapedChar()
+    {
+        $c = $this->read();
+
+        if (self::isLocalEscapedChar($c)) {
+            return $c;
+        } else {
+            throw new EasyRdf_Parser_Exception(
+                "found '" . $c . "', expected one of: " . implode(', ', self::$localEscapedChars),
+                $this->line,
+                $this->column
+            );
+        }
+    }
+
+    /**
+     * Parses a blank node ID, e.g: _:node1
+     * @ignore
+     */
+    protected function parseNodeID()
+    {
+        // Node ID should start with "_:"
+        $this->verifyCharacterOrFail($this->read(), "_");
+        $this->verifyCharacterOrFail($this->read(), ":");
+
+        // Read the node ID
+        $c = $this->read();
+        if ($c == -1) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: unexpected end of file while reading node id",
+                $this->line,
+                $this->column
+            );
+        } elseif (!self::isNameStartChar($c)) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: expected a letter, found '$c'",
+                $this->line,
+                $this->column
+            );
+        }
+
+        // Read all following letter and numbers, they are part of the name
+        $name = $c;
+        $c = $this->read();
+        while (self::isNameChar($c)) {
+            $name .= $c;
+            $c = $this->read();
+        }
+
+        $this->unread($c);
+
+        return array(
+            'type' => 'bnode',
+            'value' => $this->remapBnode($name)
+        );
+    }
+
+    protected function resolve($uri)
+    {
+        if ($this->baseUri) {
+            return $this->baseUri->resolve($uri)->toString();
+        } else {
+            return $uri;
+        }
+    }
+
+    /**
+     * Verifies that the supplied character $c is one of the expected
+     * characters specified in $expected. This method will throw a
+     * exception if this is not the case.
+     * @ignore
+     */
+    protected function verifyCharacterOrFail($c, $expected)
+    {
+        if ($c == -1) {
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: unexpected end of file",
+                $this->line,
+                $this->column
+            );
+        } elseif (strpbrk($c, $expected) === false) {
+            $msg = 'expected ';
+            for ($i = 0; $i < strlen($expected); $i++) {
+                if ($i > 0) {
+                    $msg .= " or ";
+                }
+                $msg .= '\''.$expected[$i].'\'';
+            }
+            $msg .= ", found '$c'";
+
+            throw new EasyRdf_Parser_Exception(
+                "Turtle Parse Error: $msg",
+                $this->line,
+                $this->column
+            );
+        }
+    }
+
+    /**
+     * Skip through whitespace and comments
+     * @ignore
+     */
+    protected function skipWSC()
+    {
+        $c = $this->read();
+        while (self::isWhitespace($c) || $c == '#') {
+            if ($c == '#') {
+                $this->processComment();
+            }
+
+            $c = $this->read();
+        }
+
+        $this->unread($c);
+        return $c;
+    }
+
+    /**
+     * Consumes characters from reader until the first EOL has been read.
+     * @ignore
+     */
+    protected function processComment()
+    {
+        $comment = '';
+        $c = $this->read();
+        while ($c != -1 && $c != "\r" && $c != "\n") {
+            $comment .= $c;
+            $c = $this->read();
+        }
+
+        // c is equal to -1, \r or \n.
+        // In case c is equal to \r, we should also read a following \n.
+        if ($c == "\r") {
+            $c = $this->read();
+            if ($c != "\n") {
+                $this->unread($c);
+            }
+        }
+    }
+
+    /**
+     * Read a single character from the input buffer.
+     * Returns -1 when the end of the file is reached.
+     * @ignore
+     */
+    protected function read()
+    {
+        if (!empty($this->data)) {
+            $c = mb_substr($this->data, 0, 1);
+            // Keep tracks of which line we are on (0A = Line Feed)
+            if ($c == "\x0A") {
+                $this->line += 1;
+                $this->column = 1;
+            } else {
+                $this->column += 1;
+            }
+            $this->data = mb_substr($this->data, 1);
+            return $c;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Gets the next character to be returned by read()
+     * without removing it from the input buffer.
+     * @ignore
+     */
+    protected function peek()
+    {
+        if (!empty($this->data)) {
+            return mb_substr($this->data, 0, 1);
+        } else {
+            return -1;
+        }
+    }
+
+
+    /**
+     * Steps back, restoring the previous character read() to the input buffer
+     * @ignore
+     */
+    protected function unread($c)
+    {
+        # FIXME: deal with unreading new lines
+        $this->column -= mb_strlen($c);
+        $this->data = $c . $this->data;
+    }
+
+    /** @ignore */
+    protected function createBNode()
+    {
+        return array(
+            'type' => 'bnode',
+            'value' => $this->graph->newBNodeId()
+        );
+    }
+
+    /**
+     * Returns true if $c is a whitespace character
+     * @ignore
+     */
+    public static function isWhitespace($c)
+    {
+        // Whitespace character are space, tab, newline and carriage return:
+        return $c == "\x20" || $c == "\x09" || $c == "\x0A" || $c == "\x0D";
+    }
+
+    /** @ignore */
+    public static function isPrefixStartChar($c)
+    {
+        $o = ord($c);
+        return
+            $o >= 0x41   && $o <= 0x5a ||     # A-Z
+            $o >= 0x61   && $o <= 0x7a ||     # a-z
+            $o >= 0x00C0 && $o <= 0x00D6 ||
+            $o >= 0x00D8 && $o <= 0x00F6 ||
+            $o >= 0x00F8 && $o <= 0x02FF ||
+            $o >= 0x0370 && $o <= 0x037D ||
+            $o >= 0x037F && $o <= 0x1FFF ||
+            $o >= 0x200C && $o <= 0x200D ||
+            $o >= 0x2070 && $o <= 0x218F ||
+            $o >= 0x2C00 && $o <= 0x2FEF ||
+            $o >= 0x3001 && $o <= 0xD7FF ||
+            $o >= 0xF900 && $o <= 0xFDCF ||
+            $o >= 0xFDF0 && $o <= 0xFFFD ||
+            $o >= 0x10000 && $o <= 0xEFFFF;
+    }
+
+    /** @ignore */
+    public static function isNameStartChar($c)
+    {
+        return
+            $c == '\\' ||
+            $c == '_' ||
+            $c == ':' ||
+            $c == '%' ||
+            ctype_digit($c) ||
+            self::isPrefixStartChar($c);
+    }
+
+    /** @ignore */
+    public static function isNameChar($c)
+    {
+        $o = ord($c);
+        return
+            self::isNameStartChar($c) ||
+            $o >= 0x30 && $o <= 0x39 ||     # 0-9
+            $c == '-' ||
+            $o == 0x00B7 ||
+            $o >= 0x0300 && $o <= 0x036F ||
+            $o >= 0x203F && $o <= 0x2040;
+    }
+
+    /** @ignore */
+    private static $localEscapedChars = array(
+        '_', '~', '.', '-', '!', '$', '&', '\'', '(', ')',
+        '*', '+', ',', ';', '=', '/', '?', '#', '@', '%'
+    );
+
+    /** @ignore */
+    public static function isLocalEscapedChar($c)
+    {
+        return in_array($c, self::$localEscapedChars);
+    }
+
+    /** @ignore */
+    public static function isPrefixChar($c)
+    {
+        $o = ord($c);
+        return
+            $c == '_' ||
+            $o >= 0x30 && $o <= 0x39 ||     # 0-9
+            self::isPrefixStartChar($c) ||
+            $c == '-' ||
+            $o == 0x00B7 ||
+            $c >= 0x0300 && $c <= 0x036F ||
+            $c >= 0x203F && $c <= 0x2040;
+    }
+
+    /** @ignore */
+    public static function isLanguageStartChar($c)
+    {
+        $o = ord($c);
+        return
+            $o >= 0x41 && $o <= 0x5a ||   # A-Z
+            $o >= 0x61 && $o <= 0x7a;     # a-z
+    }
+
+    /** @ignore */
+    public static function isLanguageChar($c)
+    {
+        $o = ord($c);
+        return
+            $o >= 0x41 && $o <= 0x5a ||   # A-Z
+            $o >= 0x61 && $o <= 0x7a ||   # a-z
+            $o >= 0x30 && $o <= 0x39 ||   # 0-9
+            $c == '-';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Resource.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,707 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class that represents an RDF resource
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Resource
+{
+    /** The URI for this resource */
+    protected $uri = null;
+
+    /** The Graph that this resource belongs to */
+    protected $graph = null;
+
+
+    /** Constructor
+     *
+     * * Please do not call new EasyRdf_Resource() directly *
+     *
+     * To create a new resource use the get method in a graph:
+     * $resource = $graph->resource('http://www.example.com/');
+     *
+     */
+    public function __construct($uri, $graph = null)
+    {
+        if (!is_string($uri) or $uri == null or $uri == '') {
+            throw new InvalidArgumentException(
+                "\$uri should be a string and cannot be null or empty"
+            );
+        }
+
+        $this->uri = $uri;
+
+        # Check that $graph is an EasyRdf_Graph object
+        if (is_object($graph) and $graph instanceof EasyRdf_Graph) {
+            $this->graph = $graph;
+        } elseif (!is_null($graph)) {
+            throw new InvalidArgumentException(
+                "\$graph should be an EasyRdf_Graph object"
+            );
+        }
+    }
+
+    /**
+     * Return the graph that this resource belongs to
+     *
+     * @return EasyRdf_Graph
+     */
+    public function getGraph()
+    {
+        return $this->graph;
+    }
+
+    /** Returns the URI for the resource.
+     *
+     * @return string  URI of this resource.
+     */
+    public function getUri()
+    {
+        return $this->uri;
+    }
+
+    /** Check to see if a resource is a blank node.
+     *
+     * @return bool True if this resource is a blank node.
+     */
+    public function isBNode()
+    {
+        if (substr($this->uri, 0, 2) == '_:') {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /** Get the identifier for a blank node
+     *
+     * Returns null if the resource is not a blank node.
+     *
+     * @return string The identifer for the bnode
+     */
+    public function getBNodeId()
+    {
+        if (substr($this->uri, 0, 2) == '_:') {
+            return substr($this->uri, 2);
+        } else {
+            return null;
+        }
+    }
+
+    /** Get a the prefix of the namespace that this resource is part of
+     *
+     * This method will return null the resource isn't part of any
+     * registered namespace.
+     *
+     * @return string The namespace prefix of the resource (e.g. foaf)
+     */
+    public function prefix()
+    {
+        return EasyRdf_Namespace::prefixOfUri($this->uri);
+    }
+
+    /** Get a shortened version of the resources URI.
+     *
+     * This method will return the full URI if the resource isn't part of any
+     * registered namespace.
+     *
+     * @return string The shortened URI of this resource (e.g. foaf:name)
+     */
+    public function shorten()
+    {
+        return EasyRdf_Namespace::shorten($this->uri);
+    }
+
+    /** Gets the local name of the URI of this resource
+     *
+     * The local name is defined as the part of the URI string
+     * after the last occurrence of the '#', ':' or '/' character.
+     *
+     * @return string The local name
+     */
+    public function localName()
+    {
+        if (preg_match("|([^#:/]+)$|", $this->uri, $matches)) {
+            return $matches[1];
+        }
+    }
+
+    /** Parse the URI of the resource and return as a ParsedUri object
+     *
+     * @return EasyRdf_ParsedUri
+     */
+    public function parseUri()
+    {
+        return new EasyRdf_ParsedUri($this->uri);
+    }
+
+    /** Generates an HTML anchor tag, linking to this resource.
+     *
+     * If no text is given, then the URI also uses as the link text.
+     *
+     * @param  string  $text    Text for the link.
+     * @param  array   $options Associative array of attributes for the anchor tag
+     * @return string  The HTML link string
+     */
+    public function htmlLink($text = null, $options = array())
+    {
+        $options = array_merge(array('href' => $this->uri), $options);
+        if ($text === null) {
+            $text = $this->uri;
+        }
+
+        $html = "<a";
+        foreach ($options as $key => $value) {
+            if (!preg_match('/^[-\w]+$/', $key)) {
+                throw new InvalidArgumentException(
+                    "\$options should use valid attribute names as keys"
+                );
+            }
+
+            $html .= " ".htmlspecialchars($key)."=\"".
+                         htmlspecialchars($value)."\"";
+        }
+        $html .= ">".htmlspecialchars($text)."</a>";
+
+        return $html;
+    }
+
+    /** Returns the properties of the resource as an RDF/PHP associative array
+     *
+     * For example:
+     * array('type' => 'uri', 'value' => 'http://www.example.com/')
+     *
+     * @return array  The properties of the resource
+     */
+    public function toRdfPhp()
+    {
+        if ($this->isBNode()) {
+            return array('type' => 'bnode', 'value' => $this->uri);
+        } else {
+            return array('type' => 'uri', 'value' => $this->uri);
+        }
+    }
+
+    /** Return pretty-print view of the resource
+     *
+     * @param  string $format Either 'html' or 'text'
+     * @param  string $color The colour of the text
+     * @return string
+     */
+    public function dumpValue($format = 'html', $color = 'blue')
+    {
+        return EasyRdf_Utils::dumpResourceValue($this, $format, $color);
+    }
+
+    /** Magic method to return URI of resource when casted to string
+     *
+     * @return string The URI of the resource
+     */
+    public function __toString()
+    {
+        return $this->uri;
+    }
+
+
+
+    /** Throw can exception if the resource does not belong to a graph
+     *  @ignore
+     */
+    protected function checkHasGraph()
+    {
+        if (!$this->graph) {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Resource is not part of a graph."
+            );
+        }
+    }
+
+    /** Perform a load (download of remote URI) of the resource into the graph
+     *
+     * The document type is optional but should be specified if it
+     * can't be guessed or got from the HTTP headers.
+     *
+     * @param  string  $format  Optional format of the data (eg. rdfxml)
+     */
+    public function load($format = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->load($this->uri, $format);
+    }
+
+    /** Delete a property (or optionally just a specific value)
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  object  $value The value to delete (null to delete all values)
+     * @return null
+     */
+    public function delete($property, $value = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->delete($this->uri, $property, $value);
+    }
+
+    /** Add values to for a property of the resource
+     *
+     * Example:
+     *   $resource->add('prefix:property', 'value');
+     *
+     * @param  mixed $property   The property name
+     * @param  mixed $value      The value for the property
+     * @return integer           The number of values added (1 or 0)
+     */
+    public function add($property, $value)
+    {
+        $this->checkHasGraph();
+        return $this->graph->add($this->uri, $property, $value);
+    }
+
+    /** Add a literal value as a property of the resource
+     *
+     * The value can either be a single value or an array of values.
+     *
+     * Example:
+     *   $resource->add('dc:title', 'Title of Page');
+     *
+     * @param  mixed  $property  The property name
+     * @param  mixed  $values    The value or values for the property
+     * @param  string $lang      The language of the literal
+     * @return integer           The number of values added
+     */
+    public function addLiteral($property, $values, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->addLiteral($this->uri, $property, $values, $lang);
+    }
+
+    /** Add a resource as a property of the resource
+     *
+     * Example:
+     *   $bob->add('foaf:knows', 'http://example.com/alice');
+     *
+     * @param  mixed $property   The property name
+     * @param  mixed $resource2  The resource to be the value of the property
+     * @return integer           The number of values added (1 or 0)
+     */
+    public function addResource($property, $resource2)
+    {
+        $this->checkHasGraph();
+        return $this->graph->addResource($this->uri, $property, $resource2);
+    }
+
+    /** Set value for a property
+     *
+     * The new value(s) will replace the existing values for the property.
+     * The name of the property should be a string.
+     * If you set a property to null or an empty array, then the property
+     * will be deleted.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value    The value for the property.
+     * @return integer           The number of values added (1 or 0)
+     */
+    public function set($property, $value)
+    {
+        $this->checkHasGraph();
+        return $this->graph->set($this->uri, $property, $value);
+    }
+
+    /** Get a single value for a property
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * If $property is an array, then the first item in the array that matches
+     * a property that exists is returned.
+     *
+     * This method will return null if the property does not exist.
+     *
+     * @param  string|array $property The name of the property (e.g. foaf:name)
+     * @param  string       $type     The type of value to filter by (e.g. literal or resource)
+     * @param  string       $lang     The language to filter by (e.g. en)
+     * @return mixed                  A value associated with the property
+     */
+    public function get($property, $type = null, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->get($this->uri, $property, $type, $lang);
+    }
+
+    /** Get a single literal value for a property of the resource
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * This method will return null if there is not literal value for the
+     * property.
+     *
+     * @param  string|array $property The name of the property (e.g. foaf:name)
+     * @param  string       $lang     The language to filter by (e.g. en)
+     * @return object EasyRdf_Literal Literal value associated with the property
+     */
+    public function getLiteral($property, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->get($this->uri, $property, 'literal', $lang);
+    }
+
+    /** Get a single resource value for a property of the resource
+     *
+     * If multiple values are set for a property then the value returned
+     * may be arbitrary.
+     *
+     * This method will return null if there is not resource for the
+     * property.
+     *
+     * @param  string|array $property The name of the property (e.g. foaf:name)
+     * @return object EasyRdf_Resource Resource associated with the property
+     */
+    public function getResource($property)
+    {
+        $this->checkHasGraph();
+        return $this->graph->get($this->uri, $property, 'resource');
+    }
+
+    /** Get all values for a property
+     *
+     * This method will return an empty array if the property does not exist.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $type     The type of value to filter by (e.g. literal)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return array             An array of values associated with the property
+     */
+    public function all($property, $type = null, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->all($this->uri, $property, $type, $lang);
+    }
+
+    /** Get all literal values for a property of the resource
+     *
+     * This method will return an empty array if the resource does not
+     * has any literal values for that property.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return array             An array of values associated with the property
+     */
+    public function allLiterals($property, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->all($this->uri, $property, 'literal', $lang);
+    }
+
+    /** Get all resources for a property of the resource
+     *
+     * This method will return an empty array if the resource does not
+     * has any resources for that property.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @return array             An array of values associated with the property
+     */
+    public function allResources($property)
+    {
+        $this->checkHasGraph();
+        return $this->graph->all($this->uri, $property, 'resource');
+    }
+
+    /** Count the number of values for a property of a resource
+     *
+     * This method will return 0 if the property does not exist.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $type     The type of value to filter by (e.g. literal)
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return integer           The number of values associated with the property
+     */
+    public function countValues($property, $type = null, $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->countValues($this->uri, $property, $type, $lang);
+    }
+
+    /** Concatenate all values for a property into a string.
+     *
+     * The default is to join the values together with a space character.
+     * This method will return an empty string if the property does not exist.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  string  $glue     The string to glue the values together with.
+     * @param  string  $lang     The language to filter by (e.g. en)
+     * @return string            Concatenation of all the values.
+     */
+    public function join($property, $glue = ' ', $lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->join($this->uri, $property, $glue, $lang);
+    }
+
+    /** Get a list of the full URIs for the properties of this resource.
+     *
+     * This method will return an empty array if the resource has no properties.
+     *
+     * @return array            Array of full URIs
+     */
+    public function propertyUris()
+    {
+        $this->checkHasGraph();
+        return $this->graph->propertyUris($this->uri);
+    }
+
+    /** Get a list of all the shortened property names (qnames) for a resource.
+     *
+     * This method will return an empty array if the resource has no properties.
+     *
+     * @return array            Array of shortened URIs
+     */
+    public function properties()
+    {
+        $this->checkHasGraph();
+        return $this->graph->properties($this->uri);
+    }
+
+    /** Get a list of the full URIs for the properties that point to this resource.
+     *
+     * @return array   Array of full property URIs
+     */
+    public function reversePropertyUris()
+    {
+        $this->checkHasGraph();
+        return $this->graph->reversePropertyUris($this->uri);
+    }
+
+    /** Check to see if a property exists for this resource.
+     *
+     * This method will return true if the property exists.
+     * If the value parameter is given, then it will only return true
+     * if the value also exists for that property.
+     *
+     * @param  string  $property The name of the property (e.g. foaf:name)
+     * @param  mixed   $value    An optional value of the property
+     * @return bool              True if value the property exists.
+     */
+    public function hasProperty($property, $value = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->hasProperty($this->uri, $property, $value);
+    }
+
+    /** Get a list of types for a resource.
+     *
+     * The types will each be a shortened URI as a string.
+     * This method will return an empty array if the resource has no types.
+     *
+     * @return array All types assocated with the resource (e.g. foaf:Person)
+     */
+    public function types()
+    {
+        $this->checkHasGraph();
+        return $this->graph->types($this->uri);
+    }
+
+    /** Get a single type for a resource.
+     *
+     * The type will be a shortened URI as a string.
+     * If the resource has multiple types then the type returned
+     * may be arbitrary.
+     * This method will return null if the resource has no type.
+     *
+     * @return string A type assocated with the resource (e.g. foaf:Person)
+     */
+    public function type()
+    {
+        $this->checkHasGraph();
+        return $this->graph->type($this->uri);
+    }
+
+    /** Get a single type for a resource, as a resource.
+     *
+     * The type will be returned as an EasyRdf_Resource.
+     * If the resource has multiple types then the type returned
+     * may be arbitrary.
+     * This method will return null if the resource has no type.
+     *
+     * @return EasyRdf_Resource A type assocated with the resource.
+     */
+    public function typeAsResource()
+    {
+        return $this->graph->typeAsResource($this->uri);
+    }
+
+    /** Check if a resource is of the specified type
+     *
+     * @param  string  $type The type to check (e.g. foaf:Person)
+     * @return boolean       True if resource is of specified type.
+     */
+    public function isA($type)
+    {
+        $this->checkHasGraph();
+        return $this->graph->isA($this->uri, $type);
+    }
+
+    /** Add one or more rdf:type properties to the resource
+     *
+     * @param  string  $types    One or more types to add (e.g. foaf:Person)
+     * @return integer           The number of types added
+     */
+    public function addType($types)
+    {
+        $this->checkHasGraph();
+        return $this->graph->addType($this->uri, $types);
+    }
+
+    /** Change the rdf:type property for the resource
+     *
+     * Note that the PHP class of the resource will not change.
+     *
+     * @param  string  $type     The new type (e.g. foaf:Person)
+     * @return integer           The number of types added
+     */
+    public function setType($type)
+    {
+        $this->checkHasGraph();
+        return $this->graph->setType($this->uri, $type);
+    }
+
+    /** Get the primary topic of this resource.
+     *
+     * Returns null if no primary topic is available.
+     *
+     * @return EasyRdf_Resource The primary topic of this resource.
+     */
+    public function primaryTopic()
+    {
+        $this->checkHasGraph();
+        return $this->graph->primaryTopic($this->uri);
+    }
+
+    /** Get a human readable label for this resource
+     *
+     * This method will check a number of properties for the resource
+     * (in the order: skos:prefLabel, rdfs:label, foaf:name, dc:title)
+     * and return an approriate first that is available. If no label
+     * is available then it will return null.
+     *
+     * @return string A label for the resource.
+     */
+    public function label($lang = null)
+    {
+        $this->checkHasGraph();
+        return $this->graph->label($this->uri, $lang);
+    }
+
+    /** Return a human readable view of the resource and its properties
+     *
+     * This method is intended to be a debugging aid and will
+     * print a resource and its properties.
+     *
+     * @param  string $format   Either 'html' or 'text'
+     * @return string
+     */
+    public function dump($format = 'html')
+    {
+        $this->checkHasGraph();
+        return $this->graph->dumpResource($this->uri, $format);
+    }
+
+    /** Magic method to get a property of a resource
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   $value = $resource->title;
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param  string $name The name of the property
+     * @return string       A single value for the named property
+     */
+    public function __get($name)
+    {
+        return $this->graph->get($this->uri, $name);
+    }
+
+    /** Magic method to set the value for a property of a resource
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   $resource->title = 'Title';
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param  string $name The name of the property
+     * @param  string $value The value for the property
+     */
+    public function __set($name, $value)
+    {
+        return $this->graph->set($this->uri, $name, $value);
+    }
+
+    /** Magic method to check if a property exists
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   if (isset($resource->title)) { blah(); }
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param string $name The name of the property
+     */
+    public function __isset($name)
+    {
+        return $this->graph->hasProperty($this->uri, $name);
+    }
+
+    /** Magic method to delete a property of the resource
+     *
+     * Note that only properties in the default namespace can be accessed in this way.
+     *
+     * Example:
+     *   unset($resource->title);
+     *
+     * @see EasyRdf_Namespace::setDefault()
+     * @param string $name The name of the property
+     */
+    public function __unset($name)
+    {
+        return $this->graph->delete($this->uri, $name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Parent class for the EasyRdf serialiser
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser
+{
+    protected $prefixes = array();
+
+    public function __construct()
+    {
+    }
+
+    /**
+     * Keep track of the prefixes used while serialising
+     * @ignore
+     */
+    protected function addPrefix($qname)
+    {
+        list ($prefix) = explode(':', $qname);
+        $this->prefixes[$prefix] = true;
+    }
+
+    /**
+     * Check and cleanup parameters passed to serialise() method
+     * @ignore
+     */
+    protected function checkSerialiseParams(&$graph, &$format)
+    {
+        if (is_null($graph) or !is_object($graph) or !($graph instanceof EasyRdf_Graph)) {
+            throw new InvalidArgumentException(
+                "\$graph should be an EasyRdf_Graph object and cannot be null"
+            );
+        }
+
+        if (is_null($format) or $format == '') {
+            throw new InvalidArgumentException(
+                "\$format cannot be null or empty"
+            );
+        } elseif (is_object($format) and ($format instanceof EasyRdf_Format)) {
+            $format = $format->getName();
+        } elseif (!is_string($format)) {
+            throw new InvalidArgumentException(
+                "\$format should be a string or an EasyRdf_Format object"
+            );
+        }
+    }
+
+    /**
+     * Protected method to get the number of reverse properties for a resource
+     * If a resource only has a single property, the number of values for that
+     * property is returned instead.
+     * @ignore
+     */
+    protected function reversePropertyCount($resource)
+    {
+        $properties = $resource->reversePropertyUris();
+        $count = count($properties);
+        if ($count == 1) {
+            $property = $properties[0];
+            return $resource->countValues("^<$property>");
+        } else {
+            return $count;
+        }
+    }
+
+    /**
+     * Sub-classes must follow this protocol
+     * @ignore
+     */
+    public function serialise($graph, $format)
+    {
+        throw new EasyRdf_Exception(
+            "This method should be overridden by sub-classes."
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/Arc.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise RDF using the ARC2 library.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_Arc extends EasyRdf_Serialiser_RdfPhp
+{
+    private static $supportedTypes = array(
+        'rdfxml' => 'RDFXML',
+        'turtle' => 'Turtle',
+        'ntriples' => 'NTriples',
+        'posh' => 'POSHRDF'
+    );
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Serialiser_Arc
+     */
+    public function __construct()
+    {
+        require_once 'arc/ARC2.php';
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph into RDF format of choice.
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string               $format  The name of the format to convert to.
+     * @return string              The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if (array_key_exists($format, self::$supportedTypes)) {
+            $className = self::$supportedTypes[$format];
+        } else {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_Arc does not support: $format"
+            );
+        }
+
+        $serialiser = ARC2::getSer($className);
+        if ($serialiser) {
+            return $serialiser->getSerializedIndex(
+                parent::serialise($graph, 'php')
+            );
+        } else {
+            throw new EasyRdf_Exception(
+                "ARC2 failed to get a $className serialiser."
+            );
+        }
+    }
+}
+
+EasyRdf_Format::register('posh', 'poshRDF');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/GraphViz.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,390 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2012-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to GraphViz
+ *
+ * Depends upon the GraphViz 'dot' command line tools to render images.
+ *
+ * See http://www.graphviz.org/ for more information.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2012-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_GraphViz extends EasyRdf_Serialiser
+{
+    private $dotCommand = 'dot';
+    private $useLabels = false;
+    private $onlyLabelled = false;
+    private $attributes = array('charset' => 'utf-8');
+
+    /**
+     * Constructor
+     *
+     * @return object EasyRdf_Serialiser_GraphViz
+     */
+    public function __construct()
+    {
+    }
+
+    /**
+     * Set the path to the GraphViz 'dot' command
+     *
+     * Default is to search PATH for the command 'dot'.
+     *
+     * @param string $cmd   The path to the 'dot' command.
+     * @return object EasyRdf_Serialiser_GraphViz
+     */
+    public function setDotCommand($cmd)
+    {
+        $this->dotCommand = $cmd;
+        return $this;
+    }
+
+    /**
+     * Get the path to the GraphViz 'dot' command
+     *
+     * The default value is simply 'dot'
+     *
+     * @return string The path to the 'dot' command.
+     */
+    public function getDotCommand()
+    {
+        return $this->dotCommand;
+    }
+
+    /**
+     * Turn on/off the option to display labels instead of URIs.
+     *
+     * When this option is turned on, then labels for resources will
+     * be displayed instead of the full URI of a resource. This makes
+     * it simpler to create friendly diagrams that non-technical people
+     * can understand.
+     *
+     * This option is turned off by default.
+     *
+     * @param bool $useLabels   A boolean value to turn labels on and off
+     * @return object EasyRdf_Serialiser_GraphViz
+     */
+    public function setUseLabels($useLabels)
+    {
+        $this->useLabels = $useLabels;
+        return $this;
+    }
+
+    /**
+     * Get the state of the use labels option
+     *
+     * @return bool The current state of the use labels option
+     */
+    public function getUseLabels()
+    {
+        return $this->useLabels;
+    }
+
+    /**
+     * Turn on/off the option to only display nodes and edges with labels
+     *
+     * When this option is turned on, then only nodes (resources and literals)
+     * and edges (properties) will only be displayed if they have a label. You
+     * can use this option, to create concise, diagrams of your data, rather than
+     * the RDF.
+     *
+     * This option is turned off by default.
+     *
+     * @param bool $onlyLabelled   A boolean value to enable/display only labelled items
+     * @return object EasyRdf_Serialiser_GraphViz
+     */
+    public function setOnlyLabelled($onlyLabelled)
+    {
+        $this->onlyLabelled = $onlyLabelled;
+        return $this;
+    }
+
+    /**
+     * Get the state of the only Only Labelled option
+     *
+     * @return bool The current state of the Only Labelled option
+     */
+    public function getOnlyLabelled()
+    {
+        return $this->onlyLabelled;
+    }
+
+    /**
+     * Set an attribute on the GraphViz graph
+     *
+     * Example:
+     *     $serialiser->setAttribute('rotate', 90);
+     *
+     * See the GraphViz tool documentation for information about the
+     * available attributes.
+     *
+     * @param string $name    The name of the attribute
+     * @param string $value   The value for the attribute
+     * @return object EasyRdf_Serialiser_GraphViz
+     */
+    public function setAttribute($name, $value)
+    {
+        $this->attributes[$name] = $value;
+        return $this;
+    }
+
+    /**
+     * Get an attribute of the GraphViz graph
+     *
+     * @param string $name    Attribute name
+     * @return string The value of the graph attribute
+     */
+    public function getAttribute($name)
+    {
+        return $this->attributes[$name];
+    }
+
+    /**
+     * Convert an EasyRdf object into a GraphViz node identifier
+     *
+     * @ignore
+     */
+    protected function nodeName($entity)
+    {
+        if ($entity instanceof EasyRdf_Resource) {
+            if ($entity->isBNode()) {
+                return "B".$entity->getUri();
+            } else {
+                return "R".$entity->getUri();
+            }
+        } else {
+            return "L".$entity;
+        }
+    }
+
+    /**
+     * Internal function to escape a string into DOT safe syntax
+     *
+     * @ignore
+     */
+    protected function escape($input)
+    {
+        if (preg_match('/^([a-z_][a-z_0-9]*|-?(\.[0-9]+|[0-9]+(\.[0-9]*)?))$/i', $input)) {
+            return $input;
+        } else {
+            return '"'.str_replace(
+                array("\r\n", "\n", "\r", '"'),
+                array('\n',   '\n', '\n', '\"'),
+                $input
+            ).'"';
+        }
+    }
+
+    /**
+     * Internal function to escape an associate array of attributes and
+     * turns it into a DOT notation string
+     *
+     * @ignore
+     */
+    protected function escapeAttributes($array)
+    {
+        $items = '';
+        foreach ($array as $k => $v) {
+            $items[] = $this->escape($k).'='.$this->escape($v);
+        }
+        return '['.implode(',', $items).']';
+    }
+
+    /**
+     * Internal function to create dot syntax line for either a node or an edge
+     *
+     * @ignore
+     */
+    protected function serialiseRow($node1, $node2 = null, $attributes = array())
+    {
+        $result = '  '.$this->escape($node1);
+        if ($node2) {
+            $result .= ' -> '.$this->escape($node2);
+        }
+        if (count($attributes)) {
+            $result .= ' '.$this->escapeAttributes($attributes);
+        }
+        return $result.";\n";
+    }
+
+    /**
+     * Internal function to serialise an EasyRdf_Graph into a DOT formatted string
+     *
+     * @ignore
+     */
+    protected function serialiseDot($graph)
+    {
+        $result = "digraph {\n";
+
+        // Write the graph attributes
+        foreach ($this->attributes as $k => $v) {
+            $result .= '  '.$this->escape($k).'='.$this->escape($v).";\n";
+        }
+
+        // Go through each of the properties and write the edges
+        $nodes = array();
+        $result .= "\n  // Edges\n";
+        foreach ($graph->resources() as $resource) {
+            $name1 = $this->nodeName($resource);
+            foreach ($resource->propertyUris() as $property) {
+                $label = null;
+                if ($this->useLabels) {
+                    $label = $graph->resource($property)->label();
+                }
+                if ($label === null) {
+                    if ($this->onlyLabelled == true) {
+                        continue;
+                    } else {
+                        $label = EasyRdf_Namespace::shorten($property);
+                    }
+                }
+                foreach ($resource->all("<$property>") as $value) {
+                    $name2 = $this->nodeName($value);
+                    $nodes[$name1] = $resource;
+                    $nodes[$name2] = $value;
+                    $result .= $this->serialiseRow(
+                        $name1,
+                        $name2,
+                        array('label' => $label)
+                    );
+                }
+            }
+        }
+
+        ksort($nodes);
+
+        $result .= "\n  // Nodes\n";
+        foreach ($nodes as $name => $node) {
+            $type = substr($name, 0, 1);
+            $label = '';
+            if ($type == 'R') {
+                if ($this->useLabels) {
+                    $label = $node->label();
+                }
+                if (!$label) {
+                    $label = $node->shorten();
+                }
+                if (!$label) {
+                    $label = $node->getURI();
+                }
+                $result .= $this->serialiseRow(
+                    $name,
+                    null,
+                    array(
+                        'URL'   => $node->getURI(),
+                        'label' => $label,
+                        'shape' => 'ellipse',
+                        'color' => 'blue'
+                    )
+                );
+            } elseif ($type == 'B') {
+                if ($this->useLabels) {
+                    $label = $node->label();
+                }
+                $result .= $this->serialiseRow(
+                    $name,
+                    null,
+                    array(
+                        'label' => $label,
+                        'shape' => 'circle',
+                        'color' => 'green'
+                    )
+                );
+            } else {
+                $result .= $this->serialiseRow(
+                    $name,
+                    null,
+                    array(
+                        'label' => strval($node),
+                        'shape' => 'record',
+                    )
+                );
+            }
+
+        }
+
+        $result .= "}\n";
+
+        return $result;
+    }
+
+    /**
+     * Internal function to render a graph into an image
+     *
+     * @ignore
+     */
+    public function renderImage($graph, $format = 'png')
+    {
+        $dot = $this->serialiseDot($graph);
+
+        return EasyRdf_Utils::execCommandPipe(
+            $this->dotCommand,
+            array("-T$format"),
+            $dot
+        );
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph into a GraphViz dot document.
+     *
+     * Supported output format names: dot, gif, png, svg
+     *
+     * @param string $graph An EasyRdf_Graph object.
+     * @param string $format The name of the format to convert to.
+     * @return string The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        switch($format) {
+            case 'dot':
+                return $this->serialiseDot($graph);
+            case 'png':
+            case 'gif':
+            case 'svg':
+                return $this->renderImage($graph, $format);
+            default:
+                throw new EasyRdf_Exception(
+                    "EasyRdf_Serialiser_GraphViz does not support: $format"
+                );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/Json.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to RDF/JSON
+ * with no external dependancies.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_Json extends EasyRdf_Serialiser_RdfPhp
+{
+    /**
+     * Method to serialise an EasyRdf_Graph to RDF/JSON
+     *
+     * http://n2.talis.com/wiki/RDF_JSON_Specification
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format != 'json') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_Json does not support: $format"
+            );
+        }
+
+        return json_encode(parent::serialise($graph, 'php'));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/JsonLd.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to JSON-LD
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Alexey Zakhlestin
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_JsonLd extends EasyRdf_Serialiser
+{
+    public function __construct()
+    {
+        if (PHP_MAJOR_VERSION < 5 or (PHP_MAJOR_VERSION >= 5 and PHP_MINOR_VERSION < 3)) {
+            throw new LogicException("JSON-LD support requires PHP 5.3+");
+        }
+
+        if (!class_exists('\ML\JsonLD\JsonLD')) {
+            throw new LogicException('Please install "ml/json-ld" dependency to use JSON-LD serialisation');
+        }
+
+        parent::__construct();
+    }
+
+    /**
+     * @param EasyRdf_Graph $graph
+     * @param string $format
+     * @throws EasyRdf_Exception
+     * @return string
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format != 'jsonld') {
+            throw new EasyRdf_Exception(__CLASS__.' does not support: '.$format);
+        }
+
+
+        $ld_graph = new \ML\JsonLD\Graph();
+        $nodes = array(); // cache for id-to-node association
+
+        foreach ($graph->toRdfPhp() as $resource => $properties) {
+            if (array_key_exists($resource, $nodes)) {
+                $node = $nodes[$resource];
+            } else {
+                $node = $ld_graph->createNode($resource);
+                $nodes[$resource] = $node;
+            }
+
+            foreach ($properties as $property => $values) {
+                foreach ($values as $value) {
+                    if ($value['type'] == 'bnode' or $value['type'] == 'uri') {
+                        if (array_key_exists($value['value'], $nodes)) {
+                            $_value = $nodes[$value['value']];
+                        } else {
+                            $_value = $ld_graph->createNode($value['value']);
+                            $nodes[$value['value']] = $_value;
+                        }
+                    } elseif ($value['type'] == 'literal') {
+                        if (isset($value['lang'])) {
+                            $_value = new \ML\JsonLD\LanguageTaggedString($value['value'], $value['lang']);
+                        } elseif (isset($value['datatype'])) {
+                            $_value = new \ML\JsonLD\TypedValue($value['value'], $value['datatype']);
+                        } else {
+                            $_value = $value['value'];
+                        }
+                    } else {
+                        throw new EasyRdf_Exception(
+                            "Unable to serialise object to JSON-LD: ".$value['type']
+                        );
+                    }
+
+                    $node->addPropertyValue($property, $_value);
+                }
+            }
+        }
+
+        return \ML\JsonLD\JsonLD::toString($ld_graph->toJsonLd());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/Ntriples.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,208 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to N-Triples
+ * with no external dependancies.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_Ntriples extends EasyRdf_Serialiser
+{
+    private $escChars = array();   // Character encoding cache
+
+    /**
+     * @ignore
+     */
+    protected function escapeString($str)
+    {
+        if (strpos(utf8_decode(str_replace('?', '', $str)), '?') === false) {
+            $str = utf8_decode($str);
+        }
+
+        $result = '';
+        $strLen = strlen($str);
+        for ($i = 0; $i < $strLen; $i++) {
+            $c = $str[$i];
+            if (!isset($this->escChars[$c])) {
+                $this->escChars[$c] = $this->escapedChar($c);
+            }
+            $result .= $this->escChars[$c];
+        }
+        return $result;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function unicodeCharNo($c)
+    {
+        $cUtf = utf8_encode($c);
+        $bl = strlen($cUtf); /* binary length */
+        $r = 0;
+        switch ($bl) {
+            case 1: /* 0####### (0-127) */
+                $r = ord($cUtf);
+                break;
+            case 2: /* 110##### 10###### = 192+x 128+x */
+                $r = ((ord($cUtf[0]) - 192) * 64) +
+                     (ord($cUtf[1]) - 128);
+                break;
+            case 3: /* 1110#### 10###### 10###### = 224+x 128+x 128+x */
+                $r = ((ord($cUtf[0]) - 224) * 4096) +
+                     ((ord($cUtf[1]) - 128) * 64) +
+                     (ord($cUtf[2]) - 128);
+                break;
+            case 4: /* 1111#### 10###### 10###### 10###### = 240+x 128+x 128+x 128+x */
+                $r = ((ord($cUtf[0]) - 240) * 262144) +
+                     ((ord($cUtf[1]) - 128) * 4096) +
+                     ((ord($cUtf[2]) - 128) * 64) +
+                     (ord($cUtf[3]) - 128);
+                break;
+        }
+        return $r;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function escapedChar($c)
+    {
+        $no = $this->unicodeCharNo($c);
+
+        /* see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
+        if ($no < 9) {
+            return "\\u" . sprintf('%04X', $no);  /* #x0-#x8 (0-8) */
+        } elseif ($no == 9) {
+            return '\t';                          /* #x9 (9) */
+        } elseif ($no == 10) {
+            return '\n';                          /* #xA (10) */
+        } elseif ($no < 13) {
+            return "\\u" . sprintf('%04X', $no);  /* #xB-#xC (11-12) */
+        } elseif ($no == 13) {
+            return '\r';                          /* #xD (13) */
+        } elseif ($no < 32) {
+            return "\\u" . sprintf('%04X', $no);  /* #xE-#x1F (14-31) */
+        } elseif ($no < 34) {
+            return $c;                            /* #x20-#x21 (32-33) */
+        } elseif ($no == 34) {
+            return '\"';                          /* #x22 (34) */
+        } elseif ($no < 92) {
+            return $c;                            /* #x23-#x5B (35-91) */
+        } elseif ($no == 92) {
+            return '\\';                          /* #x5C (92) */
+        } elseif ($no < 127) {
+            return $c;                            /* #x5D-#x7E (93-126) */
+        } elseif ($no < 65536) {
+            return "\\u" . sprintf('%04X', $no);  /* #x7F-#xFFFF (128-65535) */
+        } elseif ($no < 1114112) {
+            return "\\U" . sprintf('%08X', $no);  /* #x10000-#x10FFFF (65536-1114111) */
+        } else {
+            return '';                            /* not defined => ignore */
+        }
+    }
+
+    /**
+     * @ignore
+     */
+    protected function ntriplesResource($res)
+    {
+        $escaped = $this->escapeString($res);
+        if (substr($res, 0, 2) == '_:') {
+            return $escaped;
+        } else {
+            return "<$escaped>";
+        }
+    }
+
+    /**
+     * @ignore
+     */
+    protected function ntriplesValue($value)
+    {
+        if ($value['type'] == 'uri' or $value['type'] == 'bnode') {
+            return $this->ntriplesResource($value['value']);
+        } elseif ($value['type'] == 'literal') {
+            $escaped = $this->escapeString($value['value']);
+            if (isset($value['lang'])) {
+                $lang = $this->escapeString($value['lang']);
+                return '"' . $escaped . '"' . '@' . $lang;
+            } elseif (isset($value['datatype'])) {
+                $datatype = $this->escapeString($value['datatype']);
+                return '"' . $escaped . '"' . "^^<$datatype>";
+            } else {
+                return '"' . $escaped . '"';
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "Unable to serialise object to ntriples: ".$value['type']
+            );
+        }
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph into N-Triples
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format == 'ntriples') {
+            $nt = '';
+            foreach ($graph->toRdfPhp() as $resource => $properties) {
+                foreach ($properties as $property => $values) {
+                    foreach ($values as $value) {
+                        $nt .= $this->ntriplesResource($resource)." ";
+                        $nt .= "<" . $this->escapeString($property) . "> ";
+                        $nt .= $this->ntriplesValue($value)." .\n";
+                    }
+                }
+            }
+            return $nt;
+        } else {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_Ntriples does not support: $format"
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/Rapper.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to RDF
+ * using the 'rapper' command line tool.
+ *
+ * Note: the built-in N-Triples serialiser is used to pass data to Rapper.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_Rapper extends EasyRdf_Serialiser_Ntriples
+{
+    private $rapperCmd = null;
+
+    /**
+     * Constructor
+     *
+     * @param string $rapperCmd Optional path to the rapper command to use.
+     * @return object EasyRdf_Serialiser_Rapper
+     */
+    public function __construct($rapperCmd = 'rapper')
+    {
+        $result = exec("$rapperCmd --version 2>/dev/null", $output, $status);
+        if ($status != 0) {
+            throw new EasyRdf_Exception(
+                "Failed to execute the command '$rapperCmd': $result"
+            );
+        } else {
+            $this->rapperCmd = $rapperCmd;
+        }
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph to the RDF format of choice.
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        $ntriples = parent::serialise($graph, 'ntriples');
+
+        // Hack to produce more concise RDF/XML
+        if ($format == 'rdfxml') {
+            $format = 'rdfxml-abbrev';
+        }
+
+        return EasyRdf_Utils::execCommandPipe(
+            $this->rapperCmd,
+            array(
+                '--quiet',
+                '--input', 'ntriples',
+                '--output', $format,
+                '-', 'unknown://'
+            ),
+            $ntriples
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/RdfPhp.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to RDF/PHP
+ * with no external dependancies.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_RdfPhp extends EasyRdf_Serialiser
+{
+    /**
+     * Method to serialise an EasyRdf_Graph to RDF/PHP
+     *
+     * http://n2.talis.com/wiki/RDF_PHP_Specification
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format != 'php') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_RdfPhp does not support: $format"
+            );
+        }
+
+        // Graph is already stored as RDF/PHP resource-centric array internally within the EasyRdf_Graph object
+        return $graph->toRdfPhp();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/RdfXml.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,234 @@
+<?php
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to RDF/XML
+ * with no external dependancies.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_RdfXml extends EasyRdf_Serialiser
+{
+    private $outputtedResources = array();
+
+    /** A constant for the RDF Type property URI */
+    const RDF_XML_LITERAL = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral';
+
+    /**
+     * Protected method to serialise an object node into an XML object
+     * @ignore
+     */
+    protected function rdfxmlObject($property, $obj, $depth)
+    {
+        $indent = str_repeat('  ', $depth);
+        if (is_object($obj) and $obj instanceof EasyRdf_Resource) {
+            $pcount = count($obj->propertyUris());
+            $rpcount = $this->reversePropertyCount($obj);
+            $alreadyOutput = isset($this->outputtedResources[$obj->getUri()]);
+
+            $tag = "$indent<$property";
+            if ($obj->isBNode()) {
+                if ($alreadyOutput or $rpcount > 1 or $pcount == 0) {
+                    $tag .= " rdf:nodeID=\"".htmlspecialchars($obj->getBNodeId()).'"';
+                }
+            } else {
+                if ($alreadyOutput or $rpcount != 1 or $pcount == 0) {
+                    $tag .= " rdf:resource=\"".htmlspecialchars($obj->getURI()).'"';
+                }
+            }
+
+            if ($alreadyOutput == false and $rpcount == 1 and $pcount > 0) {
+                $xml = $this->rdfxmlResource($obj, false, $depth+1);
+                if ($xml) {
+                    return "$tag>$xml$indent</$property>\n\n";
+                } else {
+                    return '';
+                }
+            } else {
+                return $tag."/>\n";
+            }
+
+        } elseif (is_object($obj) and $obj instanceof EasyRdf_Literal) {
+            $atrributes = "";
+            $datatype = $obj->getDatatypeUri();
+            if ($datatype) {
+                if ($datatype == self::RDF_XML_LITERAL) {
+                    $atrributes .= " rdf:parseType=\"Literal\"";
+                    $value = strval($obj);
+                } else {
+                    $datatype = htmlspecialchars($datatype);
+                    $atrributes .= " rdf:datatype=\"$datatype\"";
+                }
+            } elseif ($obj->getLang()) {
+                $atrributes .= ' xml:lang="'.
+                               htmlspecialchars($obj->getLang()).'"';
+            }
+
+            // Escape the value
+            if (!isset($value)) {
+                $value = htmlspecialchars(strval($obj));
+            }
+
+            return "$indent<$property$atrributes>$value</$property>\n";
+        } else {
+            throw new EasyRdf_Exception(
+                "Unable to serialise object to xml: ".getType($obj)
+            );
+        }
+    }
+
+    /**
+     * Protected method to serialise a whole resource and its properties
+     * @ignore
+     */
+    protected function rdfxmlResource($res, $showNodeId, $depth = 1)
+    {
+        // Keep track of the resources we have already serialised
+        if (isset($this->outputtedResources[$res->getUri()])) {
+            return '';
+        } else {
+            $this->outputtedResources[$res->getUri()] = true;
+        }
+
+        // If the resource has no properties - don't serialise it
+        $properties = $res->propertyUris();
+        if (count($properties) == 0) {
+            return '';
+        }
+
+        $type = $res->type();
+        if ($type) {
+            $this->addPrefix($type);
+        } else {
+            $type = 'rdf:Description';
+        }
+
+        $indent = str_repeat('  ', $depth);
+        $xml = "\n$indent<$type";
+        if ($res->isBNode()) {
+            if ($showNodeId) {
+                $xml .= ' rdf:nodeID="'.htmlspecialchars($res->getBNodeId()).'"';
+            }
+        } else {
+            $xml .= ' rdf:about="'.htmlspecialchars($res->getUri()).'"';
+        }
+        $xml .= ">\n";
+
+        if ($res instanceof EasyRdf_Container) {
+            foreach ($res as $item) {
+                $xml .= $this->rdfxmlObject('rdf:li', $item, $depth+1);
+            }
+        } else {
+            foreach ($properties as $property) {
+                $short = EasyRdf_Namespace::shorten($property, true);
+                if ($short) {
+                    $this->addPrefix($short);
+                    $objects = $res->all("<$property>");
+                    if ($short == 'rdf:type') {
+                        array_shift($objects);
+                    }
+                    foreach ($objects as $object) {
+                        $xml .= $this->rdfxmlObject($short, $object, $depth+1);
+                    }
+                } else {
+                    throw new EasyRdf_Exception(
+                        "It is not possible to serialse the property ".
+                        "'$property' to RDF/XML."
+                    );
+                }
+            }
+        }
+        $xml .= "$indent</$type>\n";
+
+        return $xml;
+    }
+
+
+    /**
+     * Method to serialise an EasyRdf_Graph to RDF/XML
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format != 'rdfxml') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_RdfXml does not support: $format"
+            );
+        }
+
+        // store of namespaces to be appended to the rdf:RDF tag
+        $this->prefixes = array('rdf' => true);
+
+        // store of the resource URIs we have serialised
+        $this->outputtedResources = array();
+
+        $xml = '';
+
+        // Serialise URIs first
+        foreach ($graph->resources() as $resource) {
+            if (!$resource->isBnode()) {
+                $xml .= $this->rdfxmlResource($resource, true);
+            }
+        }
+
+        // Serialise bnodes afterwards
+        foreach ($graph->resources() as $resource) {
+            if ($resource->isBnode()) {
+                $xml .= $this->rdfxmlResource($resource, true);
+            }
+        }
+
+        // iterate through namepsaces array prefix and output a string.
+        $namespaceStr = '';
+        foreach ($this->prefixes as $prefix => $count) {
+            $url = EasyRdf_Namespace::get($prefix);
+            if (strlen($namespaceStr)) {
+                $namespaceStr .= "\n        ";
+            }
+            $namespaceStr .= ' xmlns:'.$prefix.'="'.htmlspecialchars($url).'"';
+        }
+
+        return "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+               "<rdf:RDF". $namespaceStr . ">\n" . $xml . "\n</rdf:RDF>\n";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Serialiser/Turtle.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,358 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to Turtle
+ * with no external dependancies.
+ *
+ * http://www.w3.org/TR/turtle/
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_Turtle extends EasyRdf_Serialiser
+{
+    private $outputtedBnodes = array();
+
+    /**
+     * Given a IRI string, escape and enclose in angle brackets.
+     *
+     * @param  string $resourceIri
+     * @return string
+     */
+    public static function escapeIri($resourceIri)
+    {
+        $escapedIri = str_replace('>', '\\>', $resourceIri);
+        return "<$escapedIri>";
+    }
+
+    /**
+     * Given a string, enclose in quotes and escape any quotes in the string.
+     * Strings containing tabs, linefeeds or carriage returns will be
+     * enclosed in three double quotes (""").
+     *
+     * @param  string $value
+     * @return string
+     */
+    public static function quotedString($value)
+    {
+        if (preg_match("/[\t\n\r]/", $value)) {
+            $escaped = str_replace(array('\\', '"""'), array('\\\\', '\\"""'), $value);
+            return '"""'.$escaped.'"""';
+        } else {
+            $escaped = str_replace(array('\\', '"'), array('\\\\', '\\"'), $value);
+            return '"'.$escaped.'"';
+        }
+    }
+
+    /**
+     * Given a an EasyRdf_Resource or URI, convert it into a string, suitable to
+     * be written to a Turtle document. URIs will be shortened into CURIES
+     * where possible.
+     *
+     * @param  EasyRdf_Resource $resource   The resource to convert to a Turtle string
+     * @param  boolean $createNamespace     If true, a new namespace may be created
+     * @return string
+     */
+    public function serialiseResource($resource, $createNamespace = false)
+    {
+        if (is_object($resource)) {
+            if ($resource->isBNode()) {
+                return $resource->getUri();
+            } else {
+                $resource = $resource->getUri();
+            }
+        }
+
+        $short = EasyRdf_Namespace::shorten($resource, $createNamespace);
+        if ($short) {
+            $this->addPrefix($short);
+            return $short;
+        } else {
+            return self::escapeIri($resource);
+        }
+    }
+
+    /**
+     * Given an EasyRdf_Literal object, convert it into a string, suitable to
+     * be written to a Turtle document. Supports multiline literals and literals with
+     * datatypes or languages.
+     *
+     * @param  EasyRdf_Literal $literal
+     * @return string
+     */
+    public function serialiseLiteral($literal)
+    {
+        $value = strval($literal);
+        $quoted = self::quotedString($value);
+
+        if ($datatype = $literal->getDatatypeUri()) {
+            $escaped = $this->serialiseResource($datatype, true);
+            if ($escaped == 'xsd:integer') {
+                return sprintf('%d', $value);
+            } elseif ($escaped == 'xsd:decimal') {
+                return sprintf('%g', $value);
+            } elseif ($escaped == 'xsd:double') {
+                return sprintf('%e', $value);
+            } elseif ($escaped == 'xsd:boolean') {
+                return sprintf('%s', $value ? 'true' : 'false');
+            } else {
+                return sprintf('%s^^%s', $quoted, $escaped);
+            }
+        } elseif ($lang = $literal->getLang()) {
+            return $quoted . '@' . $lang;
+        } else {
+            return $quoted;
+        }
+    }
+
+    /**
+     * Convert an EasyRdf object into a string suitable to
+     * be written to a Turtle document.
+     *
+     * @param  EasyRdf_Resource|EasyRdf_Literal $object
+     * @return string
+     */
+    public function serialiseObject($object)
+    {
+        if ($object instanceof EasyRdf_Resource) {
+            return $this->serialiseResource($object);
+        } elseif ($object instanceof EasyRdf_Literal) {
+            return $this->serialiseLiteral($object);
+        } else {
+            throw new InvalidArgumentException(
+                "serialiseObject() requires \$object to be ".
+                "of type EasyRdf_Resource or EasyRdf_Literal"
+            );
+        }
+    }
+
+
+    /**
+     * Protected method to serialise a RDF collection
+     * @ignore
+     */
+    protected function serialiseCollection($node, $indent)
+    {
+        $turtle = '(';
+        $count = 0;
+        while ($node) {
+            if ($id = $node->getBNodeId()) {
+                $this->outputtedBnodes[$id] = true;
+            }
+
+            $value = $node->get('rdf:first');
+            $node = $node->get('rdf:rest');
+            if ($node and $node->hasProperty('rdf:first')) {
+                $count++;
+            }
+
+            if ($value !== null) {
+                $serialised = $this->serialiseObject($value);
+                if ($count) {
+                    $turtle .= "\n$indent  $serialised";
+                } else {
+                    $turtle .= " ".$serialised;
+                }
+            }
+        }
+        if ($count) {
+            $turtle .= "\n$indent)";
+        } else {
+            $turtle .= " )";
+        }
+        return $turtle;
+    }
+
+    /**
+     * Protected method to serialise the properties of a resource
+     * @ignore
+     */
+    protected function serialiseProperties($res, $depth = 1)
+    {
+        $properties = $res->propertyUris();
+        $indent = str_repeat(' ', ($depth*2)-1);
+
+        $turtle = '';
+        if (count($properties) > 1) {
+            $turtle .= "\n$indent";
+        }
+
+        $pCount = 0;
+        foreach ($properties as $property) {
+            if ($property === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') {
+                $pStr = 'a';
+            } else {
+                $pStr = $this->serialiseResource($property, true);
+            }
+
+            if ($pCount) {
+                $turtle .= " ;\n$indent";
+            }
+
+            $turtle .= ' ' . $pStr;
+
+            $oCount = 0;
+            foreach ($res->all("<$property>") as $object) {
+                if ($oCount) {
+                    $turtle .= ',';
+                }
+
+                if ($object instanceof EasyRdf_Collection) {
+                    $turtle .= ' ' . $this->serialiseCollection($object, $indent);
+                } elseif ($object instanceof EasyRdf_Resource and $object->isBNode()) {
+                    $id = $object->getBNodeId();
+                    $rpcount = $this->reversePropertyCount($object);
+                    if ($rpcount <= 1 and !isset($this->outputtedBnodes[$id])) {
+                        // Nested unlabelled Blank Node
+                        $this->outputtedBnodes[$id] = true;
+                        $turtle .= ' [';
+                        $turtle .= $this->serialiseProperties($object, $depth+1);
+                        $turtle .= ' ]';
+                    } else {
+                        // Multiple properties pointing to this blank node
+                        $turtle .= ' ' . $this->serialiseObject($object);
+                    }
+                } else {
+                    $turtle .= ' ' . $this->serialiseObject($object);
+                }
+                $oCount++;
+            }
+            $pCount++;
+        }
+
+        if ($depth == 1) {
+            $turtle .= " .";
+            if ($pCount > 1) {
+                $turtle .= "\n";
+            }
+        } elseif ($pCount > 1) {
+            $turtle .= "\n" . str_repeat(' ', (($depth-1)*2)-1);
+        }
+
+        return $turtle;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function serialisePrefixes()
+    {
+        $turtle = '';
+        foreach ($this->prefixes as $prefix => $count) {
+            $url = EasyRdf_Namespace::get($prefix);
+            $turtle .= "@prefix $prefix: <$url> .\n";
+        }
+        return $turtle;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function serialiseSubjects($graph, $filterType)
+    {
+        $turtle = '';
+        foreach ($graph->resources() as $resource) {
+            /** @var $resource EasyRdf_Resource */
+            // If the resource has no properties - don't serialise it
+            $properties = $resource->propertyUris();
+            if (count($properties) == 0) {
+                continue;
+            }
+
+            // Is this node of the right type?
+            $thisType = $resource->isBNode() ? 'bnode' : 'uri';
+            if ($thisType != $filterType) {
+                continue;
+            }
+
+            if ($thisType == 'bnode') {
+                $id = $resource->getBNodeId();
+                if (isset($this->outputtedBnodes[$id])) {
+                    // Already been serialised
+                    continue;
+                } else {
+                    $this->outputtedBnodes[$id] = true;
+                    $rpcount = $this->reversePropertyCount($resource);
+                    if ($rpcount == 0) {
+                        $turtle .= '[]';
+                    } else {
+                        $turtle .= $this->serialiseResource($resource);
+                    }
+                }
+            } else {
+                $turtle .= $this->serialiseResource($resource);
+            }
+
+            $turtle .= $this->serialiseProperties($resource);
+            $turtle .= "\n";
+        }
+        return $turtle;
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph to Turtle.
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        if ($format != 'turtle' and $format != 'n3') {
+            throw new EasyRdf_Exception(
+                "EasyRdf_Serialiser_Turtle does not support: $format"
+            );
+        }
+
+        $this->prefixes = array();
+        $this->outputtedBnodes = array();
+
+        $turtle = '';
+        $turtle .= $this->serialiseSubjects($graph, 'uri');
+        $turtle .= $this->serialiseSubjects($graph, 'bnode');
+
+        if (count($this->prefixes)) {
+            return $this->serialisePrefixes() . "\n" . $turtle;
+        } else {
+            return $turtle;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Sparql/Client.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class for making SPARQL queries using the SPARQL 1.1 Protocol
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Sparql_Client
+{
+    /** The query/read address of the SPARQL Endpoint */
+    private $queryUri = null;
+
+    /** The update/write address of the SPARQL Endpoint */
+    private $updateUri = null;
+
+    /** Configuration settings */
+    private $config = array();
+
+
+    /** Create a new SPARQL endpoint client
+     * 
+     * If the query and update endpoints are the same, then you 
+     * only need to give a single URI.
+     *
+     * @param string $queryUri The address of the SPARQL Query Endpoint
+     * @param string $updateUri Optional address of the SPARQL Update Endpoint
+     */
+    public function __construct($queryUri, $updateUri = null)
+    {
+        $this->queryUri = $queryUri;
+        if ($updateUri) {
+            $this->updateUri = $updateUri;
+        } else {
+            $this->updateUri = $queryUri;
+        }
+    }
+
+    /** Get the URI of the SPARQL query endpoint
+     *
+     * @return string The query URI of the SPARQL endpoint
+     */
+    public function getQueryUri()
+    {
+        return $this->queryUri;
+    }
+
+    /** Get the URI of the SPARQL update endpoint
+     *
+     * @return string The query URI of the SPARQL endpoint
+     */
+    public function getUpdateUri()
+    {
+        return $this->updateUri;
+    }
+
+    /**
+     * @depredated
+     * @ignore
+     */
+    public function getUri()
+    {
+        return $this->queryUri;
+    }
+
+    /** Make a query to the SPARQL endpoint
+     *
+     * SELECT and ASK queries will return an object of type
+     * EasyRdf_Sparql_Result.
+     *
+     * CONSTRUCT and DESCRIBE queries will return an object
+     * of type EasyRdf_Graph.
+     *
+     * @param string $query The query string to be executed
+     * @return object EasyRdf_Sparql_Result|EasyRdf_Graph Result of the query.
+     */
+    public function query($query)
+    {
+        return $this->request('query', $query);
+    }
+
+    /** Count the number of triples in a SPARQL 1.1 endpoint
+     *
+     * Performs a SELECT query to estriblish the total number of triples.
+     *
+     * Counts total number of triples by default but a conditional triple pattern
+     * can be given to count of a subset of all triples.
+     *
+     * @param string $condition Triple-pattern condition for the count query
+     * @return integer The number of triples
+     */
+    public function countTriples($condition = '?s ?p ?o')
+    {
+        $result = $this->query('SELECT (COUNT(*) AS ?count) {'.$condition.'}');
+        return $result[0]->count->getValue();
+    }
+    
+    /** Get a list of named graphs from a SPARQL 1.1 endpoint
+     *
+     * Performs a SELECT query to get a list of the named graphs
+     *
+     * @param string $limit Optional limit to the number of results
+     * @return array Array of EasyRdf_Resource objects for each named graph
+     */
+    public function listNamedGraphs($limit = null)
+    {
+        $query = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s ?p ?o}}";
+        if (!is_null($limit)) {
+            $query .= " LIMIT ".(int)$limit;
+        }
+        $result = $this->query($query);
+        
+        // Convert the result object into an array of resources
+        $graphs = array();
+        foreach ($result as $row) {
+            array_push($graphs, $row->g);
+        }
+        return $graphs;
+    }
+
+    /** Make an update request to the SPARQL endpoint
+     *
+     * Successful responses will return the HTTP response object
+     *
+     * Unsuccessful responses will throw an exception
+     *
+     * @param string $query The update query string to be executed
+     * @return object EasyRdf_Http_Response HTTP response
+     */
+    public function update($query)
+    {
+        return $this->request('update', $query);
+    }
+
+    /*
+     * Internal function to make an HTTP request to SPARQL endpoint
+     *
+     * @ignore
+     */
+    protected function request($type, $query)
+    {
+        // Check for undefined prefixes
+        $prefixes = '';
+        foreach (EasyRdf_Namespace::namespaces() as $prefix => $uri) {
+            if (strpos($query, "$prefix:") !== false and
+                strpos($query, "PREFIX $prefix:") === false) {
+                $prefixes .=  "PREFIX $prefix: <$uri>\n";
+            }
+        }
+
+        $client = EasyRdf_Http::getDefaultHttpClient();
+        $client->resetParameters();
+
+        // Tell the server which response formats we can parse
+        $accept = EasyRdf_Format::getHttpAcceptHeader(
+            array(
+              'application/sparql-results+json' => 1.0,
+              'application/sparql-results+xml' => 0.8
+            )
+        );
+        $client->setHeaders('Accept', $accept);
+
+        if ($type == 'update') {
+            $client->setMethod('POST');
+            $client->setUri($this->updateUri);
+            $client->setRawData($prefixes . $query);
+            $client->setHeaders('Content-Type', 'application/sparql-update');
+        } elseif ($type == 'query') {
+            // Use GET if the query is less than 2kB
+            // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server
+            $encodedQuery = 'query='.urlencode($prefixes . $query);
+            if (strlen($encodedQuery) + strlen($this->queryUri) <= 2046) {
+                $client->setMethod('GET');
+                $client->setUri($this->queryUri.'?'.$encodedQuery);
+            } else {
+                // Fall back to POST instead (which is un-cacheable)
+                $client->setMethod('POST');
+                $client->setUri($this->queryUri);
+                $client->setRawData($encodedQuery);
+                $client->setHeaders('Content-Type', 'application/x-www-form-urlencoded');
+            }
+        }
+
+        $response = $client->request();
+        if ($response->getStatus() == 204) {
+            // No content
+            return $response;
+        } elseif ($response->isSuccessful()) {
+            list($type, $params) = EasyRdf_Utils::parseMimeType(
+                $response->getHeader('Content-Type')
+            );
+            if (strpos($type, 'application/sparql-results') === 0) {
+                return new EasyRdf_Sparql_Result($response->getBody(), $type);
+            } else {
+                return new EasyRdf_Graph($this->queryUri, $response->getBody(), $type);
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "HTTP request for SPARQL query failed: ".$response->getBody()
+            );
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Sparql/Result.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,384 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class for returned for SPARQL SELECT and ASK query responses.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Sparql_Result extends ArrayIterator
+{
+    private $type = null;
+    private $boolean = null;
+
+    private $ordered = null;
+    private $distinct = null;
+    private $fields = array();
+
+    /** A constant for the SPARQL Query Results XML Format namespace */
+    const SPARQL_XML_RESULTS_NS = 'http://www.w3.org/2005/sparql-results#';
+
+    /** Create a new SPARQL Result object
+     *
+     * You should not normally need to create a SPARQL result
+     * object directly - it will be constructed automatically
+     * for you by EasyRdf_Sparql_Client.
+     *
+     * @param string $data      The SPARQL result body
+     * @param string $mimeType  The MIME type of the result
+     */
+    public function __construct($data, $mimeType)
+    {
+        if ($mimeType == 'application/sparql-results+xml') {
+            return $this->parseXml($data);
+        } elseif ($mimeType == 'application/sparql-results+json') {
+            return $this->parseJson($data);
+        } else {
+            throw new EasyRdf_Exception(
+                "Unsupported SPARQL Query Results format: $mimeType"
+            );
+        }
+    }
+
+    /** Get the query result type (boolean/bindings)
+     *
+     * ASK queries return a result of type 'boolean'.
+     * SELECT query return a result of type 'bindings'.
+     *
+     * @return string The query result type.
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /** Return the boolean value of the query result
+     *
+     * If the query was of type boolean then this method will
+     * return either true or false. If the query was of some other
+     * type then this method will return null.
+     *
+     * @return boolean The result of the query.
+     */
+    public function getBoolean()
+    {
+        return $this->boolean;
+    }
+
+    /** Return true if the result of the query was true.
+     *
+     * @return boolean True if the query result was true.
+     */
+    public function isTrue()
+    {
+        return $this->boolean == true;
+    }
+
+    /** Return false if the result of the query was false.
+     *
+     * @return boolean True if the query result was false.
+     */
+    public function isFalse()
+    {
+        return $this->boolean == false;
+    }
+
+    /** Return the number of fields in a query result of type bindings.
+     *
+     * @return integer The number of fields.
+     */
+    public function numFields()
+    {
+        return count($this->fields);
+    }
+
+    /** Return the number of rows in a query result of type bindings.
+     *
+     * @return integer The number of rows.
+     */
+    public function numRows()
+    {
+        return count($this);
+    }
+
+    /** Get the field names in a query result of type bindings.
+     *
+     * @return array The names of the fields in the result.
+     */
+    public function getFields()
+    {
+        return $this->fields;
+    }
+
+    /** Return a human readable view of the query result.
+     *
+     * This method is intended to be a debugging aid and will
+     * return a pretty-print view of the query result.
+     *
+     * @param  string  $format  Either 'text' or 'html'
+     */
+    public function dump($format = 'html')
+    {
+        if ($this->type == 'bindings') {
+            $result = '';
+            if ($format == 'html') {
+                $result .= "<table class='sparql-results' style='border-collapse:collapse'>";
+                $result .= "<tr>";
+                foreach ($this->fields as $field) {
+                    $result .= "<th style='border:solid 1px #000;padding:4px;".
+                               "vertical-align:top;background-color:#eee;'>".
+                               "?$field</th>";
+                }
+                $result .= "</tr>";
+                foreach ($this as $row) {
+                    $result .= "<tr>";
+                    foreach ($this->fields as $field) {
+                        if (isset($row->$field)) {
+                            $result .= "<td style='border:solid 1px #000;padding:4px;".
+                                       "vertical-align:top'>".
+                                       $row->$field->dumpValue($format)."</td>";
+                        } else {
+                            $result .= "<td>&nbsp;</td>";
+                        }
+                    }
+                    $result .= "</tr>";
+                }
+                $result .= "</table>";
+            } else {
+                // First calculate the width of each comment
+                $colWidths = array();
+                foreach ($this->fields as $field) {
+                    $colWidths[$field] = strlen($field);
+                }
+
+                $textData = array();
+                foreach ($this as $row) {
+                    $textRow = array();
+                    foreach ($row as $k => $v) {
+                        $textRow[$k] = $v->dumpValue('text');
+                        $width = strlen($textRow[$k]);
+                        if ($colWidths[$k] < $width) {
+                            $colWidths[$k] = $width;
+                        }
+                    }
+                    $textData[] = $textRow;
+                }
+
+                // Create a horizontal rule
+                $hr = "+";
+                foreach ($colWidths as $k => $v) {
+                    $hr .= "-".str_repeat('-', $v).'-+';
+                }
+
+                // Output the field names
+                $result .= "$hr\n|";
+                foreach ($this->fields as $field) {
+                    $result .= ' '.str_pad("?$field", $colWidths[$field]).' |';
+                }
+
+                // Output each of the rows
+                $result .= "\n$hr\n";
+                foreach ($textData as $textRow) {
+                    $result .= '|';
+                    foreach ($textRow as $k => $v) {
+                        $result .= ' '.str_pad($v, $colWidths[$k]).' |';
+                    }
+                    $result .= "\n";
+                }
+                $result .= "$hr\n";
+
+            }
+            return $result;
+        } elseif ($this->type == 'boolean') {
+            $str = ($this->boolean ? 'true' : 'false');
+            if ($format == 'html') {
+                return "<p>Result: <span style='font-weight:bold'>$str</span></p>";
+            } else {
+                return "Result: $str";
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "Failed to dump SPARQL Query Results format, unknown type: ". $this->type
+            );
+        }
+    }
+
+    /** Create a new EasyRdf_Resource or EasyRdf_Literal depending
+     *  on the type of data passed in.
+     *
+     * @ignore
+     */
+    protected function newTerm($data)
+    {
+        switch($data['type']) {
+            case 'bnode':
+                return new EasyRdf_Resource('_:'.$data['value']);
+            case 'uri':
+                return new EasyRdf_Resource($data['value']);
+            case 'literal':
+            case 'typed-literal':
+                return EasyRdf_Literal::create($data);
+            default:
+                throw new EasyRdf_Exception(
+                    "Failed to parse SPARQL Query Results format, unknown term type: ".
+                    $data['type']
+                );
+        }
+    }
+
+    /** Parse a SPARQL result in the XML format into the object.
+     *
+     * @ignore
+     */
+    protected function parseXml($data)
+    {
+        $doc = new DOMDocument();
+        $doc->loadXML($data);
+
+        # Check for valid root node.
+        if ($doc->hasChildNodes() == false or
+            $doc->childNodes->length != 1 or
+            $doc->firstChild->nodeName != 'sparql' or
+            $doc->firstChild->namespaceURI != self::SPARQL_XML_RESULTS_NS) {
+            throw new EasyRdf_Exception(
+                "Incorrect root node in SPARQL XML Query Results format"
+            );
+        }
+
+        # Is it the result of an ASK query?
+        $boolean = $doc->getElementsByTagName('boolean');
+        if ($boolean->length) {
+            $this->type = 'boolean';
+            $value = $boolean->item(0)->nodeValue;
+            $this->boolean = $value == 'true' ? true : false;
+            return;
+        }
+
+        # Get a list of variables from the header
+        $head = $doc->getElementsByTagName('head');
+        if ($head->length) {
+            $variables = $head->item(0)->getElementsByTagName('variable');
+            foreach ($variables as $variable) {
+                $this->fields[] = $variable->getAttribute('name');
+            }
+        }
+
+        # Is it the result of a SELECT query?
+        $resultstag = $doc->getElementsByTagName('results');
+        if ($resultstag->length) {
+            $this->type = 'bindings';
+            $results = $resultstag->item(0)->getElementsByTagName('result');
+            foreach ($results as $result) {
+                $bindings = $result->getElementsByTagName('binding');
+                $t = new stdClass();
+                foreach ($bindings as $binding) {
+                    $key = $binding->getAttribute('name');
+                    foreach ($binding->childNodes as $node) {
+                        if ($node->nodeType != XML_ELEMENT_NODE) {
+                            continue;
+                        }
+                        $t->$key = $this->newTerm(
+                            array(
+                                'type' => $node->nodeName,
+                                'value' => $node->nodeValue,
+                                'lang' => $node->getAttribute('xml:lang'),
+                                'datatype' => $node->getAttribute('datatype')
+                            )
+                        );
+                        break;
+                    }
+                }
+                $this[] = $t;
+            }
+            return $this;
+        }
+
+        throw new EasyRdf_Exception(
+            "Failed to parse SPARQL XML Query Results format"
+        );
+    }
+
+    /** Parse a SPARQL result in the JSON format into the object.
+     *
+     * @ignore
+     */
+    protected function parseJson($data)
+    {
+        // Decode JSON to an array
+        $data = json_decode($data, true);
+
+        if (isset($data['boolean'])) {
+            $this->type = 'boolean';
+            $this->boolean = $data['boolean'];
+        } elseif (isset($data['results'])) {
+            $this->type = 'bindings';
+            if (isset($data['head']['vars'])) {
+                $this->fields = $data['head']['vars'];
+            }
+
+            foreach ($data['results']['bindings'] as $row) {
+                $t = new stdClass();
+                foreach ($row as $key => $value) {
+                    $t->$key = $this->newTerm($value);
+                }
+                $this[] = $t;
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "Failed to parse SPARQL JSON Query Results format"
+            );
+        }
+    }
+
+    /** Magic method to return value of the result to string
+     *
+     * If this is a boolean result then it will return 'true' or 'false'.
+     * If it is a bindings type, then it will dump as a text based table.
+     *
+     * @return string A string representation of the result.
+     */
+    public function __toString()
+    {
+        if ($this->type == 'boolean') {
+            return $this->boolean ? 'true' : 'false';
+        } else {
+            return $this->dump('text');
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/TypeMapper.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to map between RDF Types and PHP Classes
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_TypeMapper
+{
+    /** The type map registry */
+    private static $map = array();
+
+    /** Get the registered class for an RDF type
+     *
+     * If a type is not registered, then this method will return null.
+     *
+     * @param  string  $type   The RDF type (e.g. foaf:Person)
+     * @return string          The class name (e.g. Model_Foaf_Name)
+     */
+    public static function get($type)
+    {
+        if (!is_string($type) or $type == null or $type == '') {
+            throw new InvalidArgumentException(
+                "\$type should be a string and cannot be null or empty"
+            );
+        }
+
+        $type = EasyRdf_Namespace::expand($type);
+        if (array_key_exists($type, self::$map)) {
+            return self::$map[$type];
+        } else {
+            return null;
+        }
+    }
+
+    /** Register an RDF type with a PHP Class name
+     *
+     * @param  string  $type   The RDF type (e.g. foaf:Person)
+     * @param  string  $class  The PHP class name (e.g. Model_Foaf_Name)
+     * @return string          The PHP class name
+     */
+    public static function set($type, $class)
+    {
+        if (!is_string($type) or $type == null or $type == '') {
+            throw new InvalidArgumentException(
+                "\$type should be a string and cannot be null or empty"
+            );
+        }
+
+        if (!is_string($class) or $class == null or $class == '') {
+            throw new InvalidArgumentException(
+                "\$class should be a string and cannot be null or empty"
+            );
+        }
+
+        $type = EasyRdf_Namespace::expand($type);
+        return self::$map[$type] = $class;
+    }
+
+    /**
+      * Delete an existing RDF type mapping.
+      *
+      * @param  string  $type   The RDF type (e.g. foaf:Person)
+      */
+    public static function delete($type)
+    {
+        if (!is_string($type) or $type == null or $type == '') {
+            throw new InvalidArgumentException(
+                "\$type should be a string and cannot be null or empty"
+            );
+        }
+
+        $type = EasyRdf_Namespace::expand($type);
+        if (isset(self::$map[$type])) {
+            unset(self::$map[$type]);
+        }
+    }
+}
+
+
+/*
+   Register default set of mapped types
+*/
+
+EasyRdf_TypeMapper::set('rdf:Alt', 'EasyRdf_Container');
+EasyRdf_TypeMapper::set('rdf:Bag', 'EasyRdf_Container');
+EasyRdf_TypeMapper::set('rdf:List', 'EasyRdf_Collection');
+EasyRdf_TypeMapper::set('rdf:Seq', 'EasyRdf_Container');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/lib/EasyRdf/Utils.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,291 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+
+/**
+ * Class containing static utility functions
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Utils
+{
+
+    /**
+     * Convert a string into CamelCase
+     *
+     * A capital letter is inserted for any non-letter (including userscore).
+     * For example:
+     * 'hello world' becomes HelloWorld
+     * 'rss-tag-soup' becomes RssTagSoup
+     * 'FOO//BAR' becomes FooBar
+     *
+     * @param string The input string
+     * @return string The input string converted to CamelCase
+     */
+    public static function camelise($str)
+    {
+        $cc = '';
+        foreach (preg_split("/[\W_]+/", $str) as $part) {
+            $cc .= ucfirst(strtolower($part));
+        }
+        return $cc;
+    }
+
+    /**
+     * Check if something is an associative array
+     *
+     * Note: this method only checks the key of the first value in the array.
+     *
+     * @param mixed $param The variable to check
+     * @return bool true if the variable is an associative array
+     */
+    public static function isAssociativeArray($param)
+    {
+        if (is_array($param)) {
+            $keys = array_keys($param);
+            if ($keys[0] === 0) {
+                return false;
+            } else {
+                return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Remove the fragment from a URI (if it has one)
+     *
+     * @param mixed $uri A URI
+     * @return string The same URI with the fragment removed
+     */
+    public static function removeFragmentFromUri($uri)
+    {
+        $pos = strpos($uri, '#');
+        if ($pos === false) {
+            return $uri;
+        } else {
+            return substr($uri, 0, $pos);
+        }
+    }
+
+    /** Return pretty-print view of a resource URI
+     *
+     * This method is mainly intended for internal use and is used by
+     * EasyRdf_Graph and EasyRdf_Sparql_Result to format a resource
+     * for display.
+     *
+     * @param  mixed  $resource An EasyRdf_Resource object or an associative array
+     * @param  string $format   Either 'html' or 'text'
+     * @param  string $color    The colour of the text
+     * @return string
+     */
+    public static function dumpResourceValue($resource, $format = 'html', $color = 'blue')
+    {
+        if (!preg_match('/^#?[-\w]+$/', $color)) {
+            throw new InvalidArgumentException(
+                "\$color must be a legal color code or name"
+            );
+        }
+
+        if (is_object($resource)) {
+            $resource = strval($resource);
+        } elseif (is_array($resource)) {
+            $resource = $resource['value'];
+        }
+
+        $short = EasyRdf_Namespace::shorten($resource);
+        if ($format == 'html') {
+            $escaped = htmlentities($resource, ENT_QUOTES);
+            if (substr($resource, 0, 2) == '_:') {
+                $href = '#' . $escaped;
+            } else {
+                $href = $escaped;
+            }
+            if ($short) {
+                return "<a href='$href' style='text-decoration:none;color:$color'>$short</a>";
+            } else {
+                return "<a href='$href' style='text-decoration:none;color:$color'>$escaped</a>";
+            }
+        } else {
+            if ($short) {
+                return $short;
+            } else {
+                return $resource;
+            }
+        }
+    }
+
+    /** Return pretty-print view of a literal
+     *
+     * This method is mainly intended for internal use and is used by
+     * EasyRdf_Graph and EasyRdf_Sparql_Result to format a literal
+     * for display.
+     *
+     * @param  mixed  $literal  An EasyRdf_Literal object or an associative array
+     * @param  string $format   Either 'html' or 'text'
+     * @param  string $color    The colour of the text
+     * @return string
+     */
+    public static function dumpLiteralValue($literal, $format = 'html', $color = 'black')
+    {
+        if (!preg_match('/^#?[-\w]+$/', $color)) {
+            throw new InvalidArgumentException(
+                "\$color must be a legal color code or name"
+            );
+        }
+
+        if (is_object($literal)) {
+            $literal = $literal->toRdfPhp();
+        } elseif (!is_array($literal)) {
+            $literal = array('value' => $literal);
+        }
+
+        $text = '"'.$literal['value'].'"';
+        if (isset($literal['lang'])) {
+            $text .= '@' . $literal['lang'];
+        }
+        if (isset($literal['datatype'])) {
+            $short = EasyRdf_Namespace::shorten($literal['datatype']);
+            if ($short) {
+                $text .= "^^$short";
+            } else {
+                $text .= "^^<".$literal['datatype'].">";
+            }
+        }
+
+        if ($format == 'html') {
+            return "<span style='color:$color'>".
+                   htmlentities($text, ENT_COMPAT, "UTF-8").
+                   "</span>";
+        } else {
+            return $text;
+        }
+    }
+
+    /** Clean up and split a mime-type up into its parts
+     *
+     * @param  string $mimeType   A MIME Type, optionally with parameters
+     * @return array  $type, $parameters
+     */
+    public static function parseMimeType($mimeType)
+    {
+        $parts = explode(';', strtolower($mimeType));
+        $type = trim(array_shift($parts));
+        $params = array();
+        foreach ($parts as $part) {
+            if (preg_match("/^\s*(\w+)\s*=\s*(.+?)\s*$/", $part, $matches)) {
+                $params[$matches[1]] = $matches[2];
+            }
+        }
+        return array($type, $params);
+    }
+
+    /** Execute a command as a pipe
+     *
+     * The proc_open() function is used to open a pipe to a
+     * a command line process, writing $input to STDIN, returning STDOUT
+     * and throwing an exception if anything is written to STDERR or the
+     * process returns non-zero.
+     *
+     * @param  string $command   The command to execute
+     * @param  array  $args      Optional list of arguments to pass to the command
+     * @param  string $input     Optional buffer to send to the command
+     * @param  string $dir       Path to directory to run command in (defaults to /tmp)
+     * @return string The result of the command, printed to STDOUT
+     */
+    public static function execCommandPipe($command, $args = null, $input = null, $dir = null)
+    {
+        $descriptorspec = array(
+            0 => array('pipe', 'r'),
+            1 => array('pipe', 'w'),
+            2 => array('pipe', 'w')
+        );
+
+        // Use the system tmp directory by default
+        if (!$dir) {
+            $dir = sys_get_temp_dir();
+        }
+
+        if (is_array($args)) {
+            $fullCommand = implode(
+                ' ',
+                array_map('escapeshellcmd', array_merge(array($command), $args))
+            );
+        } else {
+            $fullCommand = escapeshellcmd($command);
+            if ($args) {
+                $fullCommand .= ' '.escapeshellcmd($args);
+            }
+        }
+
+        $process = proc_open($fullCommand, $descriptorspec, $pipes, $dir);
+        if (is_resource($process)) {
+            // $pipes now looks like this:
+            // 0 => writeable handle connected to child stdin
+            // 1 => readable handle connected to child stdout
+            // 2 => readable handle connected to child stderr
+
+            if ($input) {
+                fwrite($pipes[0], $input);
+            }
+            fclose($pipes[0]);
+
+            $output = stream_get_contents($pipes[1]);
+            fclose($pipes[1]);
+            $error = stream_get_contents($pipes[2]);
+            fclose($pipes[2]);
+
+            // It is important that you close any pipes before calling
+            // proc_close in order to avoid a deadlock
+            $returnValue = proc_close($process);
+            if ($returnValue) {
+                throw new EasyRdf_Exception(
+                    "Error while executing command $command: ".$error
+                );
+            }
+        } else {
+            throw new EasyRdf_Exception(
+                "Failed to execute command $command"
+            );
+        }
+
+        return $output;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/scripts/copyright_updater.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,64 @@
+<?php
+
+$ROOT = realpath(__DIR__ . '/..');
+
+function process_file($path) {
+    $year = date('Y', filemtime($path));
+    $contents = file_get_contents($path);
+
+    $copy_statements = 0;
+    $output = '';
+    foreach (preg_split("/[\r\n]/", $contents) as $line) {
+        if (preg_match("/^(.+)Copyright\s+\(c\)\s+(\d+)-?(\d*) (Nicholas.+)$/", $line, $m)) {
+            $copy_statements++;
+            
+            if ($m[2] != $year and $m[3] != $year) {
+                // Change the line
+                $line = "$m[1]Copyright (c) $m[2]-$year $m[4]";
+            }
+        }
+        
+        // Remove trailing whitespace
+        $line = rtrim($line);
+        $output .= "$line\n";
+    }
+    
+    // Remove surplus line endings
+    while (substr($output, -2) == "\n\n") {
+        $output = substr($output, 0, -1);
+    }
+
+    if ($copy_statements == 0) {
+        print "Warning: $path does not contain any copyright statements\n";
+    } else {
+        file_put_contents($path, $output);
+    }
+}
+
+
+function process_directory($path) {
+    $dir = opendir($path);
+    
+    while ($file = readdir($dir)) {
+        if (substr($file, 0, 1) == '.') {
+            continue;
+        }
+
+        $filepath = $path . '/' . $file;
+        if (is_dir($filepath)) {
+            process_directory($filepath);
+        } elseif (is_file($filepath)) {
+            if (substr($file, -4) == '.php') {
+                process_file($filepath);
+            }
+        } else {
+            print "Unknown type: $filepath\n";
+        }
+    }
+    
+    closedir($dir);   
+}
+
+process_directory($ROOT . '/examples');
+process_directory($ROOT . '/lib');
+process_directory($ROOT . '/test');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/CollectionTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,514 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_CollectionTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        EasyRdf_Namespace::set('ex', 'http://example.org/');
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Namespace::delete('ex');
+    }
+
+    public function testParseCollection()
+    {
+        $count = $this->graph->parse(readFixture('rdf-collection.rdf'), 'rdfxml');
+
+        $owner = $this->graph->resource('ex:owner');
+        $pets = $owner->get('ex:pets');
+        $this->assertClass('EasyRdf_Collection', $pets);
+
+        $this->assertTrue($pets->valid());
+        $this->assertSame(1, $pets->key());
+        $this->assertStringEquals('http://example.org/rat', $pets->current());
+
+        $pets->next();
+
+        $this->assertTrue($pets->valid());
+        $this->assertSame(2, $pets->key());
+        $this->assertStringEquals('http://example.org/cat', $pets->current());
+
+        $pets->next();
+
+        $this->assertTrue($pets->valid());
+        $this->assertSame(3, $pets->key());
+        $this->assertStringEquals('http://example.org/goat', $pets->current());
+
+        $pets->next();
+
+        $this->assertFalse($pets->valid());
+        $this->assertSame(4, $pets->key());
+        $this->assertSame(null, $pets->current());
+
+        $pets->next();
+
+        $this->assertFalse($pets->valid());
+        $this->assertSame(5, $pets->key());
+        $this->assertSame(null, $pets->current());
+
+        $pets->rewind();
+
+        $this->assertTrue($pets->valid());
+        $this->assertSame(1, $pets->key());
+        $this->assertStringEquals('http://example.org/rat', $pets->current());
+    }
+
+    public function testForeach()
+    {
+        $this->graph->parse(readFixture('rdf-collection.rdf'), 'rdfxml');
+
+        $owner = $this->graph->resource('ex:owner');
+        $pets = $owner->get('ex:pets');
+
+        $list = array();
+        foreach ($pets as $pet) {
+            $list[] = $pet->getUri();
+        }
+
+        $this->assertEquals(
+            array(
+                'http://example.org/rat',
+                'http://example.org/cat',
+                'http://example.org/goat'
+            ),
+            $list
+        );
+    }
+
+    public function testSeek()
+    {
+        $this->graph->parse(readFixture('rdf-collection.rdf'), 'rdfxml');
+
+        $owner = $this->graph->resource('ex:owner');
+        $pets = $owner->get('ex:pets');
+
+        $pets->seek(1);
+        $this->assertTrue($pets->valid());
+        $this->assertStringEquals('http://example.org/rat', $pets->current());
+
+        $pets->seek(2);
+        $this->assertTrue($pets->valid());
+        $this->assertStringEquals('http://example.org/cat', $pets->current());
+
+        $pets->seek(3);
+        $this->assertTrue($pets->valid());
+        $this->assertStringEquals('http://example.org/goat', $pets->current());
+    }
+
+    public function testSeekInvalid()
+    {
+        $this->setExpectedException(
+            'OutOfBoundsException',
+            'Unable to seek to position 2 in the collection'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list->addLiteral('rdf:first', 'Item 1');
+        $list->addResource('rdf:rest', 'rdf:nil');
+        $list->seek(2);
+    }
+
+    public function testSeekZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection position must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list->seek(0);
+    }
+
+    public function testSeekMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection position must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list->seek(-1);
+    }
+
+    public function testSeekNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection position must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list->seek('foo');
+    }
+
+    public function testCountEmpty()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $this->assertSame(0, count($list));
+    }
+
+    public function testCountOne()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->append('Item');
+        $this->assertSame(1, count($list));
+    }
+
+    public function testCountTwo()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->append('Item 1');
+        $list->append('Item 2');
+        $this->assertSame(2, count($list));
+    }
+
+    public function testCountThree()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->append('Item 1');
+        $list->append('Item 2');
+        $list->append('Item 3');
+        $this->assertSame(3, count($list));
+    }
+
+    public function testArrayOffsetExists()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->addLiteral('rdf:first', 'Item');
+        $list->addResource('rdf:rest', 'rdf:nil');
+
+        $this->assertTrue(isset($list[1]));
+    }
+
+    public function testArrayOffsetDoesntExist()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->addLiteral('rdf:first', 'Item');
+        $list->addResource('rdf:rest', 'rdf:nil');
+
+        $this->assertFalse(isset($list[2]));
+    }
+
+    public function testArrayOffsetDoesntExistEmpty()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $this->assertFalse(isset($list[1]));
+    }
+
+    public function testArrayOffsetExistsZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        isset($list[0]);
+    }
+
+    public function testArrayOffsetExistsMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        isset($list[-1]);
+    }
+
+    public function testArrayOffsetExistsNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        isset($list['foo']);
+    }
+
+
+    public function testArrayOffsetGet()
+    {
+        $count = $this->graph->parse(readFixture('rdf-collection.rdf'), 'rdfxml');
+
+        $owner = $this->graph->resource('ex:owner');
+        $pets = $owner->get('ex:pets');
+
+        $this->assertStringEquals('http://example.org/rat', $pets[1]);
+        $this->assertStringEquals('http://example.org/cat', $pets[2]);
+        $this->assertStringEquals('http://example.org/goat', $pets[3]);
+    }
+
+    public function testArrayOffsetGetNonexistent()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->append('foo');
+        $this->assertNull($list[2]);
+    }
+
+    public function testArrayOffsetGetEmptyNonexistent()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $this->assertNull($list[1]);
+    }
+
+    public function testArrayOffsetGetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list[0];
+    }
+
+    public function testArrayOffsetGetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list[-1];
+    }
+
+    public function testArrayOffsetGetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list['foo'];
+    }
+
+    public function testArrayOffsetSet()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+
+        $list[1] = 'Item 1';
+        $list[2] = 'Item 2';
+        $list[3] = 'Item 3';
+
+        $strings = array();
+        foreach ($list as $item) {
+            $strings[] = strval($item);
+        }
+
+        $this->assertEquals(
+            array('Item 1', 'Item 2', 'Item 3'),
+            $strings
+        );
+    }
+
+    public function testArrayOffsetSetReplace()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->add('rdf:first', 'Item 1');
+        $list->addResource('rdf:rest', 'rdf:nil');
+
+        $this->assertStringEquals('Item 1', $list->get('rdf:first'));
+        $list[1] = 'Replace';
+        $this->assertStringEquals('Replace', $list->get('rdf:first'));
+    }
+
+    public function testArrayOffsetAppend()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+
+        $list[] = 'Item 1';
+        $list[] = 'Item 2';
+        $list[] = 'Item 3';
+
+        $cur = $list;
+        $this->assertStringEquals('Item 1', $cur->get('rdf:first'));
+        $cur = $cur->get('rdf:rest');
+        $this->assertStringEquals('Item 2', $cur->get('rdf:first'));
+        $cur = $cur->get('rdf:rest');
+        $this->assertStringEquals('Item 3', $cur->get('rdf:first'));
+    }
+
+    public function testArrayOffsetSetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list[0] = 'Item 1';
+    }
+
+    public function testArrayOffsetSetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list[-1] = 'Item 1';
+    }
+
+    public function testArrayOffsetSetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        $list['foo'] = 'Item 1';
+    }
+
+    public function testArrayOffsetUnsetFirst()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+
+        $list->append('Item 1');
+        $list->append('Item 2');
+        $list->append('Item 3');
+        unset($list[1]);
+
+        $this->assertStringEquals('Item 2', $list[1]);
+        $this->assertStringEquals('Item 3', $list[2]);
+        $this->assertNull($list[3]);
+    }
+
+    public function testArrayOffsetUnsetSingle()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->addResource('rdf:first', 'Item 1');
+        unset($list[1]);
+
+        $this->assertNull($list[1]);
+    }
+
+    public function testArrayOffsetUnsetUnterminated()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+        $list->addResource('rdf:first', 'Item 1');
+        $next = $this->graph->newBnode();
+        $list->addResource('rdf:rest', $next);
+        $next->add('rdf:first', 'Item 2');
+
+        $this->assertStringEquals('Item 1', $list[1]);
+        $this->assertStringEquals('Item 2', $list[2]);
+
+        unset($list[2]);
+
+        $this->assertStringEquals('Item 1', $list[1]);
+        $this->assertNull($list[2]);
+    }
+
+    public function testArrayOffsetUnsetMiddle()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+
+        $list->append('Item 1');
+        $list->append('Item 2');
+        $list->append('Item 3');
+        unset($list[2]);
+
+        $this->assertStringEquals('Item 1', $list[1]);
+        $this->assertStringEquals('Item 3', $list[2]);
+        $this->assertNull($list[3]);
+    }
+
+    public function testArrayOffsetUnsetLast()
+    {
+        $list = $this->graph->newBnode('rdf:List');
+
+        $list->append('Item 1');
+        $list->append('Item 2');
+        $list->append('Item 3');
+        unset($list[3]);
+
+        $this->assertStringEquals('Item 1', $list[1]);
+        $this->assertStringEquals('Item 2', $list[2]);
+        $this->assertNull($list[3]);
+    }
+
+    public function testArrayOffsetUnsetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        unset($list[0]);
+    }
+
+    public function testArrayOffsetUnsetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        unset($list[-1]);
+    }
+
+    public function testArrayOffsetUnsetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Collection offset must be a positive integer'
+        );
+        $list = $this->graph->newBnode('rdf:List');
+        unset($list['foo']);
+    }
+
+    public function testAppend()
+    {
+        $animals = $this->graph->newBnode('rdf:List');
+        $this->assertSame('rdf:List', $animals->type());
+        $this->assertClass('EasyRdf_Collection', $animals);
+
+        $this->assertEquals(1, $animals->append('Rat'));
+        $this->assertEquals(1, $animals->append('Cat'));
+        $this->assertEquals(1, $animals->append('Dog'));
+
+        $list = array();
+        foreach ($animals as $animal) {
+            $list[] = strval($animal);
+        }
+
+        $this->assertEquals(
+            array('Rat', 'Cat', 'Dog'),
+            $list
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/ContainerTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,428 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_ContainerTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        EasyRdf_Namespace::set('ex', 'http://example.org/');
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Namespace::delete('ex');
+    }
+
+    public function testParseSeq()
+    {
+        $count = $this->graph->parse(
+            readFixture('rdf-seq.rdf'),
+            'rdfxml',
+            'http://www.w3.org/TR/REC-rdf-syntax/'
+        );
+
+        $favourites = $this->graph->resource('ex:favourite-fruit');
+        $this->assertSame('rdf:Seq', $favourites->type());
+        $this->assertClass('EasyRdf_Container', $favourites);
+
+        $this->assertSame(true, $favourites->valid());
+        $this->assertSame(1, $favourites->key());
+        $this->assertStringEquals('http://example.org/banana', $favourites->current());
+
+        $favourites->next();
+
+        $this->assertSame(true, $favourites->valid());
+        $this->assertSame(2, $favourites->key());
+        $this->assertStringEquals('http://example.org/apple', $favourites->current());
+
+        $favourites->next();
+
+        $this->assertSame(true, $favourites->valid());
+        $this->assertSame(3, $favourites->key());
+        $this->assertStringEquals('http://example.org/pear', $favourites->current());
+
+        $favourites->next();
+
+        $this->assertSame(true, $favourites->valid());
+        $this->assertSame(4, $favourites->key());
+        $this->assertStringEquals('http://example.org/pear', $favourites->current());
+
+        $favourites->next();
+
+        $this->assertSame(false, $favourites->valid());
+
+        $favourites->rewind();
+
+        $this->assertSame(true, $favourites->valid());
+        $this->assertSame(1, $favourites->key());
+        $this->assertStringEquals('http://example.org/banana', $favourites->current());
+    }
+
+    public function testForeach()
+    {
+        $this->graph->parse(
+            readFixture('rdf-seq.rdf'),
+            'rdfxml',
+            'http://www.w3.org/TR/REC-rdf-syntax/'
+        );
+
+        $favourites = $this->graph->resource('ex:favourite-fruit');
+
+        $list = array();
+        foreach ($favourites as $fruit) {
+            $list[] = $fruit->getUri();
+        }
+
+        $this->assertEquals(
+            array(
+                'http://example.org/banana',
+                'http://example.org/apple',
+                'http://example.org/pear',
+                'http://example.org/pear'
+            ),
+            $list
+        );
+    }
+
+    public function testSeek()
+    {
+        $this->graph->parse(
+            readFixture('rdf-seq.rdf'),
+            'rdfxml',
+            'http://www.w3.org/TR/REC-rdf-syntax/'
+        );
+
+        $favourites = $this->graph->resource('ex:favourite-fruit');
+
+        $favourites->seek(1);
+        $this->assertTrue($favourites->valid());
+        $this->assertStringEquals('http://example.org/banana', $favourites->current());
+
+        $favourites->seek(2);
+        $this->assertTrue($favourites->valid());
+        $this->assertStringEquals('http://example.org/apple', $favourites->current());
+
+        $favourites->seek(3);
+        $this->assertTrue($favourites->valid());
+        $this->assertStringEquals('http://example.org/pear', $favourites->current());
+
+        $favourites->seek(4);
+        $this->assertTrue($favourites->valid());
+        $this->assertStringEquals('http://example.org/pear', $favourites->current());
+    }
+
+    public function testSeekInvalid()
+    {
+        $this->setExpectedException(
+            'OutOfBoundsException',
+            'Unable to seek to position 2 in the container'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->add('rdf:_1', 'Item 1');
+        $seq->seek(2);
+    }
+
+    public function testSeekZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->seek(0);
+    }
+
+    public function testSeekMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->seek(-1);
+    }
+
+    public function testSeekNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->seek('foo');
+    }
+
+    public function testCountEmpty()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $this->assertSame(0, count($seq));
+    }
+
+    public function testCountOne()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->add('rdf:_1', 'Item');
+        $this->assertSame(1, count($seq));
+    }
+
+    public function testCountTwo()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->add('rdf:_1', 'Item 1');
+        $seq->add('rdf:_2', 'Item 2');
+        $this->assertSame(2, count($seq));
+    }
+
+    public function testArrayOffsetExists()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->add('rdf:_1', 'Item');
+        $this->assertTrue(isset($seq[1]));
+    }
+
+    public function testArrayOffsetDoesntExist()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq->add('rdf:_1', 'Item');
+        $this->assertFalse(isset($seq[2]));
+    }
+
+    public function testArrayOffsetExistsZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        isset($seq[0]);
+    }
+
+    public function testArrayOffsetExistsMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        isset($seq[-1]);
+    }
+
+    public function testArrayOffsetExistsNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        isset($seq['foo']);
+    }
+
+    public function testArrayOffsetGet()
+    {
+        $this->graph->parse(
+            readFixture('rdf-seq.rdf'),
+            'rdfxml',
+            'http://www.w3.org/TR/REC-rdf-syntax/'
+        );
+
+        $favourites = $this->graph->resource('ex:favourite-fruit');
+        $this->assertStringEquals('http://example.org/banana', $favourites[1]);
+        $this->assertStringEquals('http://example.org/apple', $favourites[2]);
+        $this->assertStringEquals('http://example.org/pear', $favourites[3]);
+        $this->assertStringEquals('http://example.org/pear', $favourites[4]);
+    }
+
+    public function testArrayOffsetGetNonexistent()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $this->assertNull($seq[5]);
+    }
+
+    public function testArrayOffsetGetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq[0];
+    }
+
+    public function testArrayOffsetGetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq[-1];
+    }
+
+    public function testArrayOffsetGetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq['foo'];
+    }
+
+    public function testArrayOffsetSet()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+
+        $seq[1] = 'Item 1';
+        $this->assertStringEquals('Item 1', $seq->get('rdf:_1'));
+
+        $seq[2] = 'Item 2';
+        $this->assertStringEquals('Item 2', $seq->get('rdf:_2'));
+
+        $seq[3] = 'Item 3';
+        $this->assertStringEquals('Item 3', $seq->get('rdf:_3'));
+    }
+
+    public function testArrayOffsetSetReplace()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+
+        $seq->add('rdf:_1', 'Item 1');
+        $seq[1] = 'Replace';
+        $this->assertStringEquals('Replace', $seq->get('rdf:_1'));
+    }
+
+    public function testArrayOffsetAppend()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+
+        $seq[] = 'Item 1';
+        $seq[] = 'Item 2';
+        $seq[] = 'Item 3';
+
+        $this->assertStringEquals('Item 1', $seq->get('rdf:_1'));
+        $this->assertStringEquals('Item 2', $seq->get('rdf:_2'));
+        $this->assertStringEquals('Item 3', $seq->get('rdf:_3'));
+    }
+
+    public function testArrayOffsetSetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq[0] = 'Item 1';
+    }
+
+    public function testArrayOffsetSetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq[-1] = 'Item 1';
+    }
+
+    public function testArrayOffsetSetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        $seq['foo'] = 'Item 1';
+    }
+
+    public function testArrayOffsetUnset()
+    {
+        $seq = $this->graph->newBnode('rdf:Seq');
+
+        $seq->add('rdf:_1', 'Item 1');
+        $this->assertStringEquals('Item 1', $seq->get('rdf:_1'));
+        unset($seq[1]);
+        $this->assertNull($seq->get('rdf:_1'));
+    }
+
+    public function testArrayOffsetUnsetZero()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        unset($seq[0]);
+    }
+
+    public function testArrayOffsetUnsetMinusOne()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        unset($seq[-1]);
+    }
+
+    public function testArrayOffsetUnsetNonInteger()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Container position must be a positive integer'
+        );
+        $seq = $this->graph->newBnode('rdf:Seq');
+        unset($seq['foo']);
+    }
+
+    public function testAppend()
+    {
+        $animals = $this->graph->newBnode('rdf:Seq');
+        $this->assertSame('rdf:Seq', $animals->type());
+        $this->assertClass('EasyRdf_Container', $animals);
+
+        $this->assertEquals(1, $animals->append('Cat'));
+        $this->assertEquals(1, $animals->append('Dog'));
+        $this->assertEquals(1, $animals->append('Rat'));
+
+        $this->assertEquals('Cat', $animals[1]);
+        $this->assertEquals('Dog', $animals[2]);
+        $this->assertEquals('Rat', $animals[3]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/ExceptionTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_ExceptionTest extends EasyRdf_TestCase
+{
+    public function testException()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Test'
+        );
+        throw new EasyRdf_Exception('Test');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/FormatTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,650 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class MockParserClass
+{
+}
+
+class MockSerialiserClass
+{
+}
+
+class EasyRdf_FormatTest extends EasyRdf_TestCase
+{
+    /**
+     * Set up the test suite before each test
+     */
+    public function setUp()
+    {
+        $this->format = EasyRdf_Format::register(
+            'my',
+            'My Format',
+            'http://example.com/myformat',
+            array('my/mime' => 1.0, 'my/x-mime' => 0.9),
+            array('mext')
+        );
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Format::unregister('my');
+    }
+
+    public function testRegisterNameNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$name should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::register(null);
+    }
+
+    public function testRegisterNameEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$name should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::register('');
+    }
+
+    public function testRegisterNameNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$name should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::register(array());
+    }
+
+    public function testGetFormats()
+    {
+        $formats = EasyRdf_Format::getFormats();
+        $this->assertInternalType('array', $formats);
+        $this->assertGreaterThan(0, count($formats));
+        foreach ($formats as $format) {
+            $this->assertClass('EasyRdf_Format', $format);
+        }
+    }
+
+    public function testGetHttpAcceptHeader()
+    {
+        $accept = EasyRdf_Format::getHttpAcceptHeader();
+        $this->assertContains('application/json', $accept);
+        $this->assertContains('application/rdf+xml;q=0.8', $accept);
+    }
+
+    public function testGetHttpAcceptHeaderWithExtra()
+    {
+        $accept = EasyRdf_Format::getHttpAcceptHeader(array('extra/header' => 0.5));
+        $this->assertContains('application/json', $accept);
+        $this->assertContains('extra/header;q=0.5', $accept);
+    }
+
+    public function testFormatExistsTrue()
+    {
+        $this->assertTrue(EasyRdf_Format::formatExists('my'));
+    }
+
+    public function testFormatExistsFalse()
+    {
+        $this->assertFalse(EasyRdf_Format::formatExists('testFormatExistsFalse'));
+    }
+
+    public function testUnRegister()
+    {
+        EasyRdf_Format::unregister('my');
+        $this->assertFalse(EasyRdf_Format::formatExists('my'));
+    }
+
+    public function testGetFormatByName()
+    {
+        $format = EasyRdf_Format::getFormat('my');
+        $this->assertNotNull($format);
+        $this->assertClass('EasyRdf_Format', $format);
+        $this->assertSame('my', $format->getName());
+        $this->assertSame('My Format', $format->getLabel());
+        $this->assertSame('http://example.com/myformat', $format->getUri());
+    }
+
+    public function testGetFormatByUri()
+    {
+        $format = EasyRdf_Format::getFormat('http://example.com/myformat');
+        $this->assertNotNull($format);
+        $this->assertClass('EasyRdf_Format', $format);
+        $this->assertSame('my', $format->getName());
+        $this->assertSame('My Format', $format->getLabel());
+        $this->assertSame('http://example.com/myformat', $format->getUri());
+    }
+
+    public function testGetFormatByMime()
+    {
+        $format = EasyRdf_Format::getFormat('my/mime');
+        $this->assertNotNull($format);
+        $this->assertClass('EasyRdf_Format', $format);
+        $this->assertSame('my', $format->getName());
+        $this->assertSame('My Format', $format->getLabel());
+        $this->assertSame('http://example.com/myformat', $format->getUri());
+    }
+
+    public function testGetFormatByMime2()
+    {
+        $format = EasyRdf_Format::getFormat('my/x-mime');
+        $this->assertNotNull($format);
+        $this->assertClass('EasyRdf_Format', $format);
+        $this->assertSame('my', $format->getName());
+        $this->assertSame('My Format', $format->getLabel());
+        $this->assertSame('http://example.com/myformat', $format->getUri());
+    }
+
+    public function testGetFormatByExtension()
+    {
+        $format = EasyRdf_Format::getFormat('mext');
+        $this->assertNotNull($format);
+        $this->assertClass('EasyRdf_Format', $format);
+        $this->assertSame('my', $format->getName());
+        $this->assertSame('My Format', $format->getLabel());
+        $this->assertSame('http://example.com/myformat', $format->getUri());
+    }
+
+    public function testGetFormatNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$query should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::getFormat(null);
+    }
+
+    public function testGetFormatEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$query should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::getFormat('');
+    }
+
+    public function testGetFormatNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$query should be a string and cannot be null or empty'
+        );
+        EasyRdf_Format::getFormat(array());
+    }
+
+    public function testGetFormatUnknown()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Format is not recognised: unknown'
+        );
+        $this->assertSame(null, EasyRdf_Format::getFormat('unknown'));
+    }
+
+    public function testGetNames()
+    {
+        $names = EasyRdf_Format::getNames();
+        $this->assertTrue(is_array($names));
+        $this->assertTrue(in_array('ntriples', $names));
+    }
+
+    public function testGetName()
+    {
+        $this->assertSame('my', $this->format->getName());
+    }
+
+    public function testGetLabel()
+    {
+        $this->assertSame('My Format', $this->format->getLabel());
+    }
+
+    public function testSetLabel()
+    {
+        $this->format->setLabel('testSetLabel');
+        $this->assertSame('testSetLabel', $this->format->getLabel());
+    }
+
+    public function testSetLabelNull()
+    {
+        $this->format->setLabel(null);
+        $this->assertSame(null, $this->format->getLabel());
+    }
+
+    public function testSetLabelEmpty()
+    {
+        $this->format->setLabel('');
+        $this->assertSame(null, $this->format->getLabel());
+    }
+
+    public function testSetLabelNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$label should be a string'
+        );
+        $this->format->setLabel($this);
+    }
+
+    public function testSetUri()
+    {
+        $this->format->setUri('testSetUri');
+        $this->assertSame('testSetUri', $this->format->getUri());
+    }
+
+    public function testSetUriNull()
+    {
+        $this->format->setUri(null);
+        $this->assertSame(null, $this->format->getUri());
+    }
+
+    public function testSetUriEmpty()
+    {
+        $this->format->setUri('');
+        $this->assertSame(null, $this->format->getUri());
+    }
+
+    public function testSetUriNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string'
+        );
+        $this->format->setUri($this);
+    }
+
+    public function testGetUri()
+    {
+        $this->assertSame(
+            'http://example.com/myformat',
+            $this->format->getUri()
+        );
+    }
+
+    public function testGetDefaultMimeType()
+    {
+        $this->assertSame(
+            'my/mime',
+            $this->format->getDefaultMimeType()
+        );
+    }
+
+    public function testGetDefaultMimeTypeNoDefault()
+    {
+        $format2 = EasyRdf_Format::register('my2', 'Other Format');
+        $this->assertNull(
+            $format2->getDefaultMimeType()
+        );
+    }
+
+    public function testGetMimeTypes()
+    {
+        $this->assertSame(
+            array('my/mime' => 1.0, 'my/x-mime' => 0.9),
+            $this->format->getMimeTypes()
+        );
+    }
+
+    public function testSetMimeType()
+    {
+        $this->format->setMimeTypes('testSetMimeType');
+        $this->assertSame(
+            array('testSetMimeType'),
+            $this->format->getMimeTypes()
+        );
+    }
+
+    public function testSetMimeTypes()
+    {
+        $this->format->setMimeTypes(
+            array('testSetMimeTypes1', 'testSetMimeTypes2')
+        );
+        $this->assertSame(
+            array('testSetMimeTypes1', 'testSetMimeTypes2'),
+            $this->format->getMimeTypes()
+        );
+    }
+
+    public function testSetMimeTypeNull()
+    {
+        $this->format->setMimeTypes(null);
+        $this->assertSame(array(), $this->format->getMimeTypes());
+    }
+
+    public function testGetDefaultExtension()
+    {
+        $this->assertSame(
+            'mext',
+            $this->format->getDefaultExtension()
+        );
+    }
+
+    public function testGetExtensionNoDefault()
+    {
+        $format2 = EasyRdf_Format::register('my2', 'Other Format');
+        $this->assertNull(
+            $format2->getDefaultExtension()
+        );
+    }
+
+    public function testGetExtensions()
+    {
+        $this->assertSame(
+            array('mext'),
+            $this->format->getExtensions()
+        );
+    }
+
+    public function testSetExtension()
+    {
+        $this->format->setExtensions('testSetExtension');
+        $this->assertSame(
+            array('testSetExtension'),
+            $this->format->getExtensions()
+        );
+    }
+
+    public function testSetExtensions()
+    {
+        $this->format->setExtensions(
+            array('ext1', 'ext2')
+        );
+        $this->assertSame(
+            array('ext1', 'ext2'),
+            $this->format->getExtensions()
+        );
+    }
+
+    public function testSetExtensionsNull()
+    {
+        $this->format->setExtensions(null);
+        $this->assertSame(array(), $this->format->getExtensions());
+    }
+
+    public function testToString()
+    {
+        $this->assertStringEquals('my', $this->format);
+    }
+
+    public function testSetParserClass()
+    {
+        $this->format->setParserClass('MockParserClass');
+        $this->assertSame(
+            'MockParserClass',
+            $this->format->getParserClass()
+        );
+    }
+
+    public function testSetParserClassNull()
+    {
+        $this->format->setParserClass(null);
+        $this->assertSame(null, $this->format->getParserClass());
+    }
+
+    public function testSetParserClassEmpty()
+    {
+        $this->format->setParserClass('');
+        $this->assertSame(null, $this->format->getParserClass());
+    }
+
+    public function testSetParserClassNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string'
+        );
+        $this->format->setParserClass($this);
+    }
+
+    public function testRegisterParser()
+    {
+        EasyRdf_Format::registerParser('my', 'MockParserClass');
+        $this->assertSame(
+            'MockParserClass',
+            $this->format->getParserClass()
+        );
+    }
+
+    public function testRegisterParserForUnknownFormat()
+    {
+        EasyRdf_Format::registerParser('testRegisterParser', 'MockParserClass');
+        $format = EasyRdf_Format::getFormat('testRegisterParser');
+        $this->assertNotNull($format);
+        $this->assertSame('MockParserClass', $format->getParserClass());
+    }
+
+    public function testNewParser()
+    {
+        $this->format->setParserClass('MockParserClass');
+        $parser = $this->format->newParser();
+        $this->assertInternalType('object', $parser);
+        $this->assertClass('MockParserClass', $parser);
+    }
+
+    public function testNewParserNull()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'No parser class available for format: my'
+        );
+        $this->format->setParserClass(null);
+        $parser = $this->format->newParser();
+    }
+
+    public function testSetSerialiserClass()
+    {
+        $this->format->setSerialiserClass('MockSerialiserClass');
+        $this->assertSame(
+            'MockSerialiserClass',
+            $this->format->getSerialiserClass()
+        );
+    }
+
+    public function testSetSerialiserClassNull()
+    {
+        $this->format->setSerialiserClass(null);
+        $this->assertSame(null, $this->format->getSerialiserClass());
+    }
+
+    public function testSetSerialiserClassEmpty()
+    {
+        $this->format->setSerialiserClass('');
+         $this->assertSame(null, $this->format->getSerialiserClass());
+    }
+
+    public function testSetSerialiserClassNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string'
+        );
+        $this->format->setSerialiserClass($this);
+    }
+
+    public function testNewSerialiser()
+    {
+        $this->format->setSerialiserClass('MockSerialiserClass');
+        $serialiser = $this->format->newSerialiser();
+        $this->assertInternalType('object', $serialiser);
+        $this->assertClass('MockSerialiserClass', $serialiser);
+    }
+
+    public function testNewSerialiserNull()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'No serialiser class available for format: my'
+        );
+        $this->format->setSerialiserClass(null);
+        $serialiser = $this->format->newSerialiser();
+    }
+
+    public function testRegisterSerialiser()
+    {
+        EasyRdf_Format::registerSerialiser('my', 'MockSerialiserClass');
+        $this->assertSame(
+            'MockSerialiserClass',
+            $this->format->getSerialiserClass()
+        );
+    }
+
+    public function testRegisterSerialiserForUnknownFormat()
+    {
+        EasyRdf_Format::registerSerialiser(
+            'testRegisterSerialiser',
+            'MockSerialiserClass'
+        );
+        $format = EasyRdf_Format::getFormat('testRegisterSerialiser');
+        $this->assertNotNull($format);
+        $this->assertSame(
+            'MockSerialiserClass',
+            $format->getSerialiserClass()
+        );
+    }
+
+    public function testGuessFormatPhp()
+    {
+        $data = array('http://www.example.com' => array());
+        $this->assertStringEquals('php', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatRdfXml()
+    {
+        $data = readFixture('foaf.rdf');
+        $this->assertStringEquals('rdfxml', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatJson()
+    {
+        $data = readFixture('foaf.json');
+        $this->assertStringEquals('json', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatTurtle()
+    {
+        $data = readFixture('foaf.ttl');
+        $this->assertStringEquals('turtle', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatTurtleWithComments()
+    {
+        $data = readFixture('webid.ttl');
+        $this->assertStringEquals('turtle', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatNtriples()
+    {
+        $data = readFixture('foaf.nt');
+        $this->assertStringEquals('ntriples', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatNtriplesWithComments()
+    {
+        $format = EasyRdf_Format::guessFormat(
+            "# This is a comment before the first triple\n".
+            " <http://example.com> <http://example.com> <http://example.com> .\n"
+        );
+        $this->assertStringEquals('ntriples', $format);
+    }
+
+    public function testGuessFormatSparqlXml()
+    {
+        $data = readFixture('sparql_select_all.xml');
+        $this->assertStringEquals('sparql-xml', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatRdfa()
+    {
+        $data = readFixture('foaf.html');
+        $this->assertStringEquals('rdfa', EasyRdf_Format::guessFormat($data));
+    }
+
+    public function testGuessFormatHtml()
+    {
+        # We don't support any other microformats embedded in HTML
+        $format = EasyRdf_Format::guessFormat(
+            '<html><head><title>Hello</title></head><body><h1>Hello World</h1></body></html>'
+        );
+        $this->assertStringEquals('rdfa', $format);
+    }
+
+    public function testGuessFormatXml()
+    {
+        # We support several different XML formats, don't know which one this is...
+        $format = EasyRdf_Format::guessFormat(
+            '<?xml version="1.0" encoding="UTF-8"?>'
+        );
+        $this->assertSame(null, $format);
+    }
+
+    public function testGuessFormatByFilenameTtl()
+    {
+        $format = EasyRdf_Format::guessFormat(
+            '# This is a comment',
+            'http://example.com/filename.ttl'
+        );
+        $this->assertStringEquals('turtle', $format);
+    }
+
+    public function testGuessFormatByFilenameRdf()
+    {
+        $format = EasyRdf_Format::guessFormat(
+            '                    <!-- lots of whitespace ',
+            'file://../data/foaf.rdf'
+        );
+        $this->assertStringEquals('rdfxml', $format);
+    }
+
+    public function testGuessFormatByFilenameUnknown()
+    {
+        $format = EasyRdf_Format::guessFormat(
+            '<http://example.com> <http://example.com> <http://example.com> .',
+            'http://example.com/foaf.foobar'
+        );
+        $this->assertStringEquals('ntriples', $format);
+    }
+
+    public function testGuessFormatUnknown()
+    {
+        $this->assertNull(
+            EasyRdf_Format::guessFormat('blah blah blah')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/GraphStoreTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,244 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+
+class EasyRdf_GraphStoreTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        EasyRdf_Http::setDefaultHttpClient(
+            $this->client = new EasyRdf_Http_MockClient()
+        );
+        $this->graphStore = new EasyRdf_GraphStore('http://localhost:8080/data/');
+
+        // Ensure that the built-in n-triples parser is used
+        EasyRdf_Format::registerSerialiser('ntriples', 'EasyRdf_Serialiser_Ntriples');
+    }
+
+    public function testGetUri()
+    {
+        $this->assertSame(
+            'http://localhost:8080/data/',
+            $this->graphStore->getUri()
+        );
+    }
+
+    public function testGetDirect()
+    {
+        $this->client->addMock(
+            'GET',
+            'http://localhost:8080/data/foaf.rdf',
+            readFixture('foaf.json')
+        );
+        $graph = $this->graphStore->get('foaf.rdf');
+        $this->assertClass('EasyRdf_Graph', $graph);
+        $this->assertSame('http://localhost:8080/data/foaf.rdf', $graph->getUri());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testGetIndirect()
+    {
+        $this->client->addMock(
+            'GET',
+            'http://localhost:8080/data/?graph=http%3A%2F%2Ffoo.com%2Fbar.rdf',
+            readFixture('foaf.json')
+        );
+        $graph = $this->graphStore->get('http://foo.com/bar.rdf');
+        $this->assertClass('EasyRdf_Graph', $graph);
+        $this->assertSame('http://foo.com/bar.rdf', $graph->getUri());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testDeleteDirect()
+    {
+        $this->client->addMock(
+            'DELETE',
+            'http://localhost:8080/data/foaf.rdf',
+            'OK'
+        );
+        $response = $this->graphStore->delete('foaf.rdf');
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function testDeleteIndirect()
+    {
+        $this->client->addMock(
+            'DELETE',
+            'http://localhost:8080/data/?graph=http%3A%2F%2Ffoo.com%2Fbar.rdf',
+            'OK'
+        );
+        $response = $this->graphStore->delete('http://foo.com/bar.rdf');
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function testDeleteHttpError()
+    {
+        $this->client->addMock(
+            'DELETE',
+            'http://localhost:8080/data/filenotfound',
+            'Graph not found.',
+            array('status' => 404)
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'HTTP request to delete http://localhost:8080/data/filenotfound failed'
+        );
+        $response = $this->graphStore->delete('filenotfound');
+    }
+
+    public function checkNtriplesRequest($client)
+    {
+        $this->assertSame(
+            "<urn:subject> <urn:predicate> \"object\" .\n",
+            $client->getRawData()
+        );
+        $this->assertSame("application/n-triples", $client->getHeader('Content-Type'));
+        return true;
+    }
+
+    public function testInsertDirect()
+    {
+        $graph = new EasyRdf_Graph('http://localhost:8080/data/new.rdf');
+        $graph->add('urn:subject', 'urn:predicate', 'object');
+        $this->client->addMock(
+            'POST',
+            'http://localhost:8080/data/new.rdf',
+            'OK',
+            array('callback' => array($this, 'checkNtriplesRequest'))
+        );
+        $response = $this->graphStore->insert($graph);
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function testInsertIndirect()
+    {
+        $data = "<urn:subject> <urn:predicate> \"object\" .\n";
+        $this->client->addMock(
+            'POST',
+            '/data/?graph=http%3A%2F%2Ffoo.com%2Fbar.rdf',
+            'OK',
+            array('callback' => array($this, 'checkNtriplesRequest'))
+        );
+        $response = $this->graphStore->insert($data, "http://foo.com/bar.rdf");
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function testInsertHttpError()
+    {
+        $data = "<urn:subject> <urn:predicate> \"object\" .\n";
+        $this->client->addMock(
+            'POST',
+            '/data/new.rdf',
+            'Internal Server Error',
+            array('status' => 500)
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'HTTP request for http://localhost:8080/data/new.rdf failed'
+        );
+        $response = $this->graphStore->insert($data, 'new.rdf');
+    }
+
+    public function testReplaceIndirect()
+    {
+        $data = "<urn:subject> <urn:predicate> \"object\" .\n";
+        $this->client->addMock(
+            'PUT',
+            '/data/?graph=http%3A%2F%2Ffoo.com%2Fbar.rdf',
+            'OK',
+            array('callback' => array($this, 'checkNtriplesRequest'))
+        );
+        $response = $this->graphStore->replace($data, "http://foo.com/bar.rdf");
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function checkTurtleRequest($client)
+    {
+        $this->assertSame(
+            '{"urn:subject":{"urn:predicate":[{"type":"literal","value":"object"}]}}',
+            $client->getRawData()
+        );
+        $this->assertSame("application/json", $client->getHeader('Content-Type'));
+        return true;
+    }
+
+    public function testReplaceDirectJson()
+    {
+        $graph = new EasyRdf_Graph('http://localhost:8080/data/new.rdf');
+        $graph->add('urn:subject', 'urn:predicate', 'object');
+        $this->client->addMock(
+            'PUT',
+            '/data/?graph=http%3A%2F%2Ffoo.com%2Fbar.rdf',
+            'OK',
+            array('callback' => array($this, 'checkTurtleRequest'))
+        );
+        $response = $this->graphStore->replace($graph, "http://foo.com/bar.rdf", 'json');
+        $this->assertSame(200, $response->getStatus());
+    }
+
+    public function testReplaceHttpError()
+    {
+        $data = "<urn:subject> <urn:predicate> \"object\" .\n";
+        $this->client->addMock(
+            'PUT',
+            '/data/existing.rdf',
+            'Internal Server Error',
+            array('status' => 500)
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'HTTP request for http://localhost:8080/data/existing.rdf failed'
+        );
+        $response = $this->graphStore->replace($data, 'existing.rdf');
+    }
+
+    public function testToString()
+    {
+        $this->assertStringEquals(
+            'http://localhost:8080/data/',
+            $this->graphStore
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/GraphTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2071 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Mock_RdfParser
+{
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        $graph->add(
+            'http://www.example.com/joe#me',
+            'foaf:name',
+            'Joseph Bloggs'
+        );
+        return true;
+    }
+}
+
+class Mock_RdfSerialiser
+{
+    public function serialise($graph, $format = null)
+    {
+        return "<rdf></rdf>";
+    }
+}
+
+class EasyRdf_GraphTest extends EasyRdf_TestCase
+{
+    /**
+     * Set up the test suite before each test
+     */
+    public function setUp()
+    {
+        // Reset to built-in parsers
+        EasyRdf_Format::registerParser('ntriples', 'EasyRdf_Parser_Ntriples');
+        EasyRdf_Format::registerParser('rdfxml', 'EasyRdf_Parser_RdfXml');
+        EasyRdf_Format::registerParser('turtle', 'EasyRdf_Parser_Turtle');
+
+        // Reset default namespace
+        EasyRdf_Namespace::setDefault(null);
+
+        EasyRdf_Http::setDefaultHttpClient(
+            $this->client = new EasyRdf_Http_MockClient()
+        );
+        $this->graph = new EasyRdf_Graph('http://example.com/graph');
+        $this->uri = 'http://example.com/#me';
+        $this->graph->setType($this->uri, 'foaf:Person');
+        $this->graph->add($this->uri, 'rdf:test', 'Test A');
+        $this->graph->add($this->uri, 'rdf:test', new EasyRdf_Literal('Test B', 'en'));
+    }
+
+    public function testGetUri()
+    {
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf.rdf');
+        $this->assertSame(
+            'http://example.com/joe/foaf.rdf',
+            $graph->getUri()
+        );
+    }
+
+    public function testNewBNode()
+    {
+        $graph = new EasyRdf_Graph();
+
+        $bnodeOne = $graph->newBNode();
+        $this->assertSame(
+            '_:genid1',
+            $bnodeOne->getUri()
+        );
+
+        $bnodeTwo = $graph->newBNode();
+        $this->assertSame(
+            '_:genid2',
+            $bnodeTwo->getUri()
+        );
+    }
+
+    public function testParseData()
+    {
+        $graph = new EasyRdf_Graph();
+        $data = readFixture('foaf.json');
+        $count = $graph->parse($data, 'json');
+        $this->assertSame(14, $count);
+
+        $name = $graph->get('http://www.example.com/joe#me', 'foaf:name');
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+    }
+
+    public function testParseDataGuess()
+    {
+        $graph = new EasyRdf_Graph();
+        $data = readFixture('foaf.json');
+        $count = $graph->parse($data, 'guess');
+        $this->assertSame(14, $count);
+
+        $name = $graph->get('http://www.example.com/joe#me', 'foaf:name');
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+    }
+
+    public function testParseFile()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $graph->parseFile(fixturePath('foaf.json'));
+        $this->assertSame(14, $count);
+
+        $name = $graph->get('http://www.example.com/joe#me', 'foaf:name');
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+    }
+
+    public function testParseFileRelativeUri()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $graph->parseFile(fixturePath('foaf.rdf'));
+        $this->assertSame(14, $count);
+
+        $doc = $graph->get('foaf:PersonalProfileDocument', '^rdf:type');
+        $this->assertClass('EasyRdf_Resource', $doc);
+        $this->assertRegExp('|^file://.+/fixtures/foaf\.rdf$|', $doc->getUri());
+    }
+
+    public function testParseUnknownFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Unable to parse data of an unknown format.'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->parse('unknown');
+    }
+
+    public function testMockParser()
+    {
+        EasyRdf_Format::registerParser('mock', 'Mock_RdfParser');
+
+        $graph = new EasyRdf_Graph();
+        $graph->parse('data', 'mock');
+        $this->assertStringEquals(
+            'Joseph Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoad()
+    {
+        $this->client->addMockOnce('GET', 'http://www.example.com/', readFixture('foaf.json'));
+        $graph = new EasyRdf_Graph();
+        $count = $graph->load('http://www.example.com/', 'json');
+        $this->assertSame(14, $count);
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoadNullUri()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'No URI given to load() and the graph does not have a URI.'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->load(null);
+    }
+
+    public function testLoadEmptyUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource cannot be an empty string'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->load('');
+    }
+
+    public function testLoadNonStringUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource should be a string or an EasyRdf_Resource'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->load(array());
+    }
+
+    public function testLoadUnknownFormat()
+    {
+        $this->client->addMockOnce('GET', 'http://www.example.com/foaf.unknown', 'unknown');
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Unable to parse data of an unknown format.'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->load('http://www.example.com/foaf.unknown');
+    }
+
+    public function testLoadHttpError()
+    {
+        $this->client->addMockOnce(
+            'GET',
+            'http://www.example.com/404',
+            'Not Found',
+            array('status' => 404)
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'HTTP request for http://www.example.com/404 failed'
+        );
+        $graph = new EasyRdf_Graph('http://www.example.com/404');
+        $graph->load();
+    }
+
+    public function testLoadGraphUri()
+    {
+        $this->client->addMockOnce('GET', 'http://www.example.com/', readFixture('foaf.json'));
+        $graph = new EasyRdf_Graph('http://www.example.com/');
+        $this->assertSame(14, $graph->load());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoadWithContentType()
+    {
+        $this->client->addMockOnce(
+            'GET',
+            'http://www.example.com/',
+            readFixture('foaf.json'),
+            array('headers' => array('Content-Type' => 'application/json'))
+        );
+        $graph = new EasyRdf_Graph('http://www.example.com/');
+        $this->assertSame(14, $graph->load());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoadWithContentTypeAndCharset()
+    {
+        $this->client->addMockOnce(
+            'GET',
+            'http://www.example.com/',
+            readFixture('foaf.nt'),
+            array('headers' => array('Content-Type' => 'text/plain; charset=utf8'))
+        );
+        $graph = new EasyRdf_Graph('http://www.example.com/');
+        $this->assertSame(14, $graph->load());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoadSameUrl()
+    {
+        // Check that loading the same URL multiple times
+        // doesn't result in multiple HTTP GETs
+        $this->client->addMockOnce('GET', 'http://www.example.com/', readFixture('foaf.json'));
+        $graph = new EasyRdf_Graph();
+        $this->assertSame(0, $graph->countTriples());
+        $this->assertSame(
+            14,
+            $graph->load('http://www.example.com/#foo', 'json')
+        );
+        $this->assertSame(14, $graph->countTriples());
+        $this->assertSame(
+            0,
+            $graph->load('http://www.example.com/#bar', 'json')
+        );
+        $this->assertSame(14, $graph->countTriples());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testLoadRedirect()
+    {
+        // Check that loading the same URL as a redirected request
+        // doesn't result in multiple HTTP GETs
+        $this->client->addMockRedirect('GET', 'http://www.example.org/', 'http://www.example.com/', 301);
+        $this->client->addMockRedirect('GET', 'http://www.example.com/', 'http://www.example.com/foaf.rdf', 303);
+        $this->client->addMockOnce('GET', 'http://www.example.com/foaf.rdf', readFixture('foaf.json'));
+        $graph = new EasyRdf_Graph();
+        $this->assertSame(0, $graph->countTriples());
+        $this->assertSame(
+            14,
+            $graph->load('http://www.example.org/', 'json')
+        );
+        $this->assertSame(14, $graph->countTriples());
+        $this->assertSame(
+            0,
+            $graph->load('http://www.example.com/foaf.rdf', 'json')
+        );
+        $this->assertSame(14, $graph->countTriples());
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testNewAndLoad()
+    {
+        $this->client->addMockOnce('GET', 'http://www.example.com/', readFixture('foaf.json'));
+        $graph = EasyRdf_Graph::newAndLoad('http://www.example.com/', 'json');
+        $this->assertClass('EasyRdf_Graph', $graph);
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testGetResourceSameGraph()
+    {
+        $graph = new EasyRdf_Graph();
+        $resource1 = $graph->resource('http://example.com/');
+        $this->assertClass('EasyRdf_Resource', $resource1);
+        $this->assertStringEquals('http://example.com/', $resource1->getUri());
+        $resource2 = $graph->resource('http://example.com/');
+        $this->assertTrue($resource1 === $resource2);
+    }
+
+    public function testGetResourceDifferentGraph()
+    {
+        $graph1 = new EasyRdf_Graph();
+        $resource1 = $graph1->resource('http://example.com/');
+        $graph2 = new EasyRdf_Graph();
+        $resource2 = $graph2->resource('http://example.com/');
+        $this->assertFalse($resource1 === $resource2);
+    }
+
+    public function testGetShortenedResource()
+    {
+        $graph = new EasyRdf_Graph();
+        $person = $graph->resource('foaf:Person');
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/Person',
+            $person->getUri()
+        );
+    }
+
+    public function testGetRelativeResource()
+    {
+        $graph = new EasyRdf_Graph('http://example.com/foo');
+        $res = $graph->resource('#bar');
+        $this->assertSame(
+            'http://example.com/foo#bar',
+            $res->getUri()
+        );
+    }
+
+    public function testGetResourceForGraphUri()
+    {
+        $graph = new EasyRdf_Graph('http://testGetResourceForGraphUri/');
+        $resource = $graph->resource();
+        $this->assertClass('EasyRdf_Resource', $resource);
+        $this->assertSame(
+            'http://testGetResourceForGraphUri/',
+            $resource->getUri()
+        );
+    }
+
+    public function testGetResourceUnknown()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertSame(
+            'http://www.foo.com/bar',
+            $graph->resource('http://www.foo.com/bar')->getUri()
+        );
+    }
+
+    public function testGetNullResourceForNullGraphUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri is null and EasyRdf_Graph object has no URI either.'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->resource(null);
+    }
+
+    public function testGetResourceEmptyUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource cannot be an empty string'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->resource('');
+    }
+
+    public function testGetResourceNonStringUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource should be a string or an EasyRdf_Resource'
+        );
+        $graph = new EasyRdf_Graph();
+        $graph->resource(array());
+    }
+
+    public function testResourceWithType()
+    {
+        $graph = new EasyRdf_Graph();
+        $resource = $graph->resource(
+            'http://www.foo.com/bar',
+            'foaf:Person'
+        );
+        $type = $graph->type('http://www.foo.com/bar');
+        $this->assertStringEquals('foaf:Person', $type);
+    }
+
+    public function testResourceWithTypeUri()
+    {
+        $graph = new EasyRdf_Graph();
+        $resource = $graph->resource(
+            'http://www.foo.com/bar',
+            'http://xmlns.com/foaf/0.1/Person'
+        );
+        $type = $graph->type('http://www.foo.com/bar');
+        $this->assertStringEquals('foaf:Person', $type);
+    }
+
+    public function testResourceWithMultipleTypes()
+    {
+        $graph = new EasyRdf_Graph();
+        $resource = $graph->resource(
+            'http://www.foo.com/bar',
+            array('rdf:Type1', 'rdf:Type2')
+        );
+
+        $types = $resource->types();
+        $this->assertCount(2, $types);
+        $this->assertStringEquals('rdf:Type1', $types[0]);
+        $this->assertStringEquals('rdf:Type2', $types[1]);
+    }
+
+    public function testResources()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf', $data);
+        $resources = $graph->resources();
+        $this->assertTrue(is_array($resources));
+        $this->assertClass('EasyRdf_Resource', $resources['_:genid1']);
+
+        $urls = array_keys($resources);
+        sort($urls);
+
+        $this->assertSame(
+            array(
+                '_:genid1',
+                'http://www.example.com/joe#me',
+                'http://www.example.com/joe/',
+                'http://www.example.com/joe/foaf.rdf',
+                'http://www.example.com/project',
+                'http://xmlns.com/foaf/0.1/Person',
+                'http://xmlns.com/foaf/0.1/PersonalProfileDocument',
+                'http://xmlns.com/foaf/0.1/Project'
+            ),
+            $urls
+        );
+    }
+
+    public function testResourcesMatching()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf', $data);
+        $matched = $graph->resourcesMatching('foaf:name');
+        $this->assertCount(2, $matched);
+        $this->assertSame(
+            'http://www.example.com/joe#me',
+            $matched[0]->getUri()
+        );
+        $this->assertSame(
+            '_:genid1',
+            $matched[1]->getUri()
+        );
+    }
+
+    public function testResourcesMatchingValue()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf', $data);
+        $matched = $graph->resourcesMatching('foaf:name', 'Joe Bloggs');
+        $this->assertCount(1, $matched);
+        $this->assertSame(
+            'http://www.example.com/joe#me',
+            $matched[0]->getUri()
+        );
+    }
+
+    public function testResourcesMatchingObject()
+    {
+        $matched = $this->graph->resourcesMatching(
+            'rdf:test',
+            new EasyRdf_Literal('Test B', 'en')
+        );
+        $this->assertCount(1, $matched);
+        $this->assertStringEquals(
+            'http://example.com/#me',
+            $matched[0]
+        );
+    }
+
+    public function testResourcesMatchingInverse()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf', $data);
+        $matched = $graph->resourcesMatching('^foaf:homepage');
+        $this->assertCount(2, $matched);
+        $this->assertSame(
+            'http://www.example.com/joe/',
+            $matched[0]->getUri()
+        );
+        $this->assertSame(
+            'http://www.example.com/project',
+            $matched[1]->getUri()
+        );
+    }
+
+    public function testGet()
+    {
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get($this->uri, 'rdf:test')
+        );
+    }
+
+    public function testGetWithFullUri()
+    {
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get(
+                '<http://example.com/#me>',
+                '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+            )
+        );
+    }
+
+    public function testGetResourceAngleBrackets()
+    {
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get(
+                '<'.$this->uri.'>',
+                'rdf:test'
+            )
+        );
+    }
+
+    public function testGetWithLanguage()
+    {
+        $this->assertStringEquals(
+            'Test B',
+            $this->graph->get($this->uri, 'rdf:test', 'literal', 'en')
+        );
+    }
+
+    public function testGetInverse()
+    {
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->assertStringEquals(
+            $this->uri,
+            $this->graph->get('http://example.com/', '^foaf:homepage')
+        );
+    }
+
+    public function testGetPropertyPath()
+    {
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->graph->addLiteral('http://example.com/', 'dc:title', 'My Homepage');
+        $this->assertStringEquals(
+            'My Homepage',
+            $this->graph->get($this->uri, 'foaf:homepage/dc11:title|dc:title')
+        );
+    }
+
+    public function testGetPropertyPath2()
+    {
+        $this->graph->addResource('http://example.com/person1', 'foaf:knows', 'http://example.com/person2');
+        $this->graph->addResource('http://example.com/person2', 'foaf:knows', 'http://example.com/person3');
+        $this->graph->addLiteral('http://example.com/person3', 'foaf:name', 'Person 3');
+        $this->assertStringEquals(
+            'Person 3',
+            $this->graph->get('http://example.com/person1', 'foaf:knows/foaf:knows/foaf:name')
+        );
+    }
+
+    public function testGetPropertyPath3()
+    {
+        $this->graph->addResource('http://example.com/person1', 'foaf:knows', 'http://example.com/person2');
+        $this->graph->addResource('http://example.com/person2', 'foaf:knows', 'http://example.com/person3');
+        $this->graph->addResource('http://example.com/person3', 'foaf:knows', 'http://example.com/person4');
+        $this->assertSame(
+            $this->graph->resource('http://example.com/person4'),
+            $this->graph->get('http://example.com/person1', 'foaf:knows/foaf:knows/foaf:knows')
+        );
+    }
+
+    public function testGetPropertyPath4()
+    {
+        $this->graph->addResource('http://example.com/person1', 'foaf:homepage', 'http://example.com/');
+        $this->graph->addResource('http://example.com/person1', 'foaf:knows', 'http://example.com/person2');
+        $this->graph->addResource('http://example.com/person2', 'foaf:knows', 'http://example.com/person3');
+        $this->graph->addLiteral('http://example.com/person3', 'foaf:name', 'Person 3');
+        $this->assertStringEquals(
+            'Person 3',
+            $this->graph->get('http://example.com/', '^foaf:homepage/foaf:knows/foaf:knows/rdfs:label|foaf:name')
+        );
+    }
+
+    public function testGetMultipleProperties()
+    {
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get($this->uri, 'rdf:test|rdf:foobar')
+        );
+    }
+
+    public function testGetMultipleProperties2()
+    {
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get($this->uri, 'rdf:foobar|rdf:test')
+        );
+    }
+
+    public function testGetPropertyWithBadLiteral()
+    {
+        $this->graph->addLiteral($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->graph->addLiteral('http://example.com/', 'dc:title', 'My Homepage');
+        $this->assertNull(
+            $this->graph->get($this->uri, 'foaf:homepage/dc:title')
+        );
+    }
+
+    public function testPropertyAsResource()
+    {
+        $rdfTest = $this->graph->resource('rdf:test');
+        $this->assertStringEquals(
+            'Test A',
+            $this->graph->get($this->uri, $rdfTest)
+        );
+    }
+
+    public function testGetLiteral()
+    {
+        $this->graph->addResource($this->uri, 'foaf:name', 'http://example.com/');
+        $this->graph->addLiteral($this->uri, 'foaf:name', 'Joe');
+        $this->assertStringEquals(
+            'Joe',
+            $this->graph->getLiteral($this->uri, 'foaf:name')
+        );
+    }
+
+    public function testGetUriResource()
+    {
+        $this->graph->addLiteral($this->uri, 'foaf:homepage', 'Joe');
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->assertStringEquals(
+            'http://example.com/',
+            $this->graph->getResource($this->uri, 'foaf:homepage')
+        );
+    }
+
+    public function testGetBnodeResource()
+    {
+        $bnode = $this->graph->newBnode('foaf:Project');
+        $this->graph->addLiteral($this->uri, 'foaf:homepage', 'A Rubbish Project');
+        $this->graph->addResource($this->uri, 'foaf:currentProject', $bnode);
+        $this->assertSame(
+            $bnode,
+            $this->graph->getResource($this->uri, 'foaf:currentProject')
+        );
+    }
+
+    public function testGetNonExistantLiteral()
+    {
+        $this->assertNull(
+            $this->graph->getLiteral($this->uri, 'rdf:type')
+        );
+    }
+
+    public function testGetNonExistantResource()
+    {
+        $this->assertNull(
+            $this->graph->get('foo:bar', 'foo:bar')
+        );
+    }
+
+    public function testGetNonExistantProperty()
+    {
+        $this->assertNull($this->graph->get($this->uri, 'foo:bar'));
+    }
+
+    public function testGetNullResource()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource cannot be null'
+        );
+        $this->graph->get(null, 'rdf:test');
+    }
+
+    public function testGetEmptyResource()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource cannot be an empty string'
+        );
+        $this->graph->get('', 'rdf:test');
+    }
+
+    public function testGetNullProperty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->get($this->uri, null);
+    }
+
+    public function testGetEmptyProperty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->graph->get($this->uri, '');
+    }
+
+    public function testGetNonStringProperty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->get($this->uri, $this);
+    }
+
+    public function testAll()
+    {
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithPropertyUri()
+    {
+        $all = $this->graph->all(
+            $this->uri,
+            '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+        );
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithPropertyResource()
+    {
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $all = $this->graph->all($this->uri, $prop);
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithLang()
+    {
+        $all = $this->graph->all($this->uri, 'rdf:test', 'literal', 'en');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('Test B', $all[0]);
+    }
+
+    public function testAllInverse()
+    {
+        $all = $this->graph->all('foaf:Person', '^rdf:type');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals($this->uri, $all[0]);
+    }
+
+    public function testAllPropertyPath()
+    {
+        $this->graph->addResource($this->uri, 'foaf:knows', 'http://example.com/bob');
+        $this->graph->addLiteral('http://example.com/bob', 'foaf:name', 'Bob');
+        $this->graph->addResource($this->uri, 'foaf:knows', 'http://example.com/alice');
+        $this->graph->addLiteral('http://example.com/alice', 'foaf:name', 'Alice');
+        $all = $this->graph->all($this->uri, 'foaf:knows/foaf:name');
+
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Bob', $all[0]);
+        $this->assertStringEquals('Alice', $all[1]);
+    }
+
+    public function testAllMultipleProperties()
+    {
+        $this->graph->addLiteral($this->uri, 'rdf:foobar', 'Test C');
+        $all = $this->graph->all($this->uri, 'rdf:test|rdf:foobar');
+        $this->assertCount(3, $all);
+
+        $strings = array_map("strval", $all);
+        $this->assertSame(
+            array('Test A', 'Test B', 'Test C'),
+            $strings
+        );
+    }
+
+    public function testAllPropertyPathIgnoreLiterals()
+    {
+        $this->graph->addResource('http://example.com/person', 'foaf:homepage', 'http://example.com/');
+        $this->graph->addLiteral('http://example.com/person', 'foaf:homepage', 'http://literal.com/');
+        $this->graph->addLiteral('http://example.com/', 'rdfs:label', 'My Homepage');
+        $this->graph->addLiteral('http://literal.com/', 'rdfs:label', 'Not My Homepage');
+        $this->assertEquals(
+            array(new EasyRdf_Literal('My Homepage')),
+            $this->graph->all('http://example.com/person', 'foaf:homepage/rdfs:label')
+        );
+    }
+
+    public function testAllPropertyPathNoMatch()
+    {
+        $this->assertEquals(
+            array(),
+            $this->graph->all('http://example.com/person', 'foaf:homepage/rdfs:label')
+        );
+    }
+
+    public function testAllNonExistantResource()
+    {
+        $this->assertSame(
+            array(),
+            $this->graph->all('foo:bar', 'foo:bar')
+        );
+    }
+
+    public function testAllNonExistantProperty()
+    {
+        $this->assertSame(
+            array(),
+            $this->graph->all($this->uri, 'foo:bar')
+        );
+    }
+
+    public function testAllNullKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->all($this->uri, null);
+    }
+
+    public function testAllEmptyKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->graph->all($this->uri, '');
+    }
+
+    public function testAllNonStringKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->all($this->uri, array());
+    }
+
+    public function testAllOfType()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf', $data);
+        $resources = $graph->allOfType('foaf:Person');
+        $this->assertTrue(is_array($resources));
+        $this->assertCount(1, $resources);
+        $this->assertSame(
+            'http://www.example.com/joe#me',
+            $resources[0]->getUri()
+        );
+    }
+
+    public function testAllOfTypeUnknown()
+    {
+        $graph = new EasyRdf_Graph();
+        $resources = $graph->allOfType('unknown:type');
+        $this->assertTrue(is_array($resources));
+        $this->assertCount(0, $resources);
+    }
+
+    public function testAllLiterals()
+    {
+        $all = $this->graph->allLiterals($this->uri, 'rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllLiteralsEmpty()
+    {
+        $all = $this->graph->allLiterals($this->uri, 'rdf:type');
+        $this->assertTrue(is_array($all));
+        $this->assertCount(0, $all);
+    }
+
+    public function testAllResources()
+    {
+        $this->graph->addResource($this->uri, 'rdf:test', 'http://example.com/thing');
+        $this->graph->addResource($this->uri, 'rdf:test', '_:bnode1');
+        $all = $this->graph->allResources($this->uri, 'rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('http://example.com/thing', $all[0]);
+        $this->assertFalse($all[0]->isBNode());
+        $this->assertStringEquals('_:bnode1', $all[1]);
+        $this->assertTrue($all[1]->isBNode());
+    }
+
+    public function testCountValues()
+    {
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test'));
+    }
+
+    public function testCountValuesWithUri()
+    {
+        $this->assertSame(
+            2,
+            $this->graph->countValues(
+                $this->uri,
+                '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+            )
+        );
+    }
+
+    public function testCountValuesWithResource()
+    {
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $this->assertSame(
+            2,
+            $this->graph->countValues($this->uri, $prop)
+        );
+    }
+
+    public function testCountValuesWithType()
+    {
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'rdf:test', 'uri'));
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test', 'literal'));
+    }
+
+    public function testCountValuesWithLang()
+    {
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'rdf:test', 'literal', 'en'));
+    }
+
+    public function testCountValuesNonExistantProperty()
+    {
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'foo:bar'));
+    }
+
+    public function testJoinDefaultGlue()
+    {
+        $this->assertSame(
+            'Test A Test B',
+            $this->graph->join($this->uri, 'rdf:test')
+        );
+    }
+
+    public function testJoinWithUri()
+    {
+        $this->assertSame(
+            'Test A Test B',
+            $this->graph->join(
+                $this->uri,
+                '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+            )
+        );
+    }
+
+    public function testJoinWithResource()
+    {
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $this->assertSame(
+            'Test A Test B',
+            $this->graph->join($this->uri, $prop)
+        );
+    }
+
+    public function testJoinWithLang()
+    {
+        $this->assertSame(
+            'Test B',
+            $this->graph->join($this->uri, 'rdf:test', ' ', 'en')
+        );
+    }
+
+    public function testJoinNonExistantProperty()
+    {
+        $this->assertSame('', $this->graph->join($this->uri, 'foo:bar'));
+    }
+
+    public function testJoinCustomGlue()
+    {
+        $this->assertSame(
+            'Test A:Test B',
+            $this->graph->join($this->uri, 'rdf:test', ':')
+        );
+    }
+
+    public function testJoinMultipleProperties()
+    {
+        $this->graph->addLiteral($this->uri, 'rdf:foobar', 'Test C');
+        $str = $this->graph->join($this->uri, 'rdf:test|rdf:foobar', ', ');
+        $this->assertSame('Test A, Test B, Test C', $str);
+    }
+
+    public function testJoinNullKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->join($this->uri, null, 'Test C');
+    }
+
+    public function testJoinEmptyKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->graph->join($this->uri, '', 'Test C');
+    }
+
+    public function testJoinNonStringKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->join($this->uri, array(), 'Test C');
+    }
+
+    public function testAdd()
+    {
+        $count = $this->graph->add($this->uri, 'rdf:test', 'Test C');
+        $this->assertSame(1, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(3, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+    }
+
+    public function testAddWithUri()
+    {
+        $count = $this->graph->add(
+            $this->uri,
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#test',
+            'Test C'
+        );
+        $this->assertSame(1, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(3, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+    }
+
+    public function testAddLiteralWithLanguage()
+    {
+        $count = $this->graph->addLiteral($this->uri, 'dc:title', 'English Title', 'en');
+        $this->assertSame(1, $count);
+        $title = $this->graph->get($this->uri, 'dc:title');
+        $this->assertSame('English Title', $title->getValue());
+        $this->assertSame('en', $title->getLang());
+        $this->assertSame(null, $title->getDataType());
+    }
+
+    public function testAddMultipleLiterals()
+    {
+        $count = $this->graph->addLiteral($this->uri, 'rdf:test', array('Test C', 'Test D'));
+        $this->assertSame(2, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(4, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+        $this->assertStringEquals('Test D', $all[3]);
+    }
+
+    public function testAddLiteralMultipleTimes()
+    {
+        $count = $this->graph->add($this->uri, 'rdf:test2', 'foobar');
+        $this->assertSame(1, $count);
+        $count = $this->graph->add($this->uri, 'rdf:test2', 'foobar');
+        $this->assertSame(0, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test2');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('foobar', $all[0]);
+    }
+
+    public function testAddLiteralDifferentLanguages()
+    {
+        $count = $this->graph->set($this->uri, 'rdf:test', new EasyRdf_Literal('foobar', 'en'));
+        $this->assertSame(1, $count);
+        $count = $this->graph->add($this->uri, 'rdf:test', new EasyRdf_Literal('foobar', 'fr'));
+        $this->assertSame(1, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('foobar', $all[0]);
+        $this->assertStringEquals('foobar', $all[1]);
+    }
+
+    public function testAddDateTime()
+    {
+        $dt = new DateTime("Fri 25 Jan 2013 19:43:19 GMT");
+        $count = $this->graph->add($this->uri, 'rdf:test2', $dt);
+        $this->assertSame(1, $count);
+
+        $literal = $this->graph->get($this->uri, 'rdf:test2');
+        $this->assertClass('EasyRdf_Literal_DateTime', $literal);
+        $this->assertStringEquals('2013-01-25T19:43:19Z', $literal);
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDataType());
+    }
+
+    public function testAddLiteralDateTime()
+    {
+        $dt = new DateTime("Fri 25 Jan 2013 19:43:19 GMT");
+        $this->graph->addLiteral($this->uri, 'rdf:test2', $dt);
+        $this->assertStringEquals(
+            '2013-01-25T19:43:19Z',
+            $this->graph->get($this->uri, 'rdf:test2')
+        );
+    }
+
+    public function testAddNull()
+    {
+        $count = $this->graph->add($this->uri, 'rdf:test', null);
+        $this->assertSame(0, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAddNullKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->add($this->uri, null, 'Test C');
+    }
+
+    public function testAddEmptyKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be an empty string'
+        );
+        $this->graph->add($this->uri, '', 'Test C');
+    }
+
+    public function testAddNonStringKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->add($this->uri, array(), 'Test C');
+    }
+
+    public function testAddInvalidObject()
+    {
+        $this->setExpectedException(
+            'PHPUnit_Framework_Error',
+            'Object of class EasyRdf_GraphTest could not be converted to string'
+        );
+        $this->graph->add($this->uri, 'rdf:foo', $this);
+    }
+
+    public function testAddMissingArrayType()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$value is missing a \'type\' key'
+        );
+        $this->graph->add($this->uri, 'rdf:foo', array('value' => 'bar'));
+    }
+
+    public function testAddMissingArrayValue()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$value is missing a \'value\' key'
+        );
+        $this->graph->add($this->uri, 'rdf:foo', array('type' => 'literal'));
+    }
+
+    public function testAddInvalidArrayType()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$value does not have a valid type (foo)'
+        );
+        $this->graph->add($this->uri, 'rdf:foo', array('type' => 'foo', 'value' => 'bar'));
+    }
+
+    public function testAddArrayWithLangAndDatatype()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$value cannot have both and language and a datatype'
+        );
+        $this->graph->add(
+            $this->uri,
+            'rdf:foo',
+            array(
+                'type' => 'literal',
+                'value' => 'Rat',
+                'lang' => 'en',
+                'datatype' => 'http://www.w3.org/2001/XMLSchema#string'
+            )
+        );
+    }
+
+    public function testAddSingleValueToString()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $graph->add('http://www.example.com/joe#me', 'foaf:name', 'Joe');
+        $this->assertSame(1, $count);
+        $this->assertStringEquals('Joe', $graph->get('http://www.example.com/joe#me', 'foaf:name'));
+    }
+
+    public function testAddSingleValueToResource()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $graph->add('http://www.example.com/joe#me', 'foaf:name', 'Joe');
+        $this->assertSame(1, $count);
+        $this->assertStringEquals('Joe', $graph->get('http://www.example.com/joe#me', 'foaf:name'));
+    }
+
+    public function testAddPropertriesInvalidResourceClass()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$resource should be a string or an EasyRdf_Resource'
+        );
+        $graph = new EasyRdf_Graph();
+        $invalidResource = new EasyRdf_Utils();
+        $graph->add($invalidResource, 'foaf:name', 'value');
+    }
+
+    public function testAddZero()
+    {
+        $this->assertNull($this->graph->get($this->uri, 'rdf:test2'));
+        $count = $this->graph->add($this->uri, 'rdf:test2', 0);
+        $this->assertSame(1, $count);
+        $this->assertStringEquals('0', $this->graph->get($this->uri, 'rdf:test2'));
+    }
+
+    public function testAddLiteralZero()
+    {
+        $this->assertNull($this->graph->get($this->uri, 'rdf:test2'));
+        $count = $this->graph->addLiteral($this->uri, 'rdf:test2', 0);
+        $this->assertSame(1, $count);
+        $this->assertStringEquals('0', $this->graph->get($this->uri, 'rdf:test2'));
+    }
+
+    public function testAddResource()
+    {
+        $count = $this->graph->addResource($this->uri, 'foaf:homepage', 'http://www.example.com/');
+        $this->assertSame(1, $count);
+        $res = $this->graph->get($this->uri, 'foaf:homepage');
+        $this->assertClass('EasyRdf_Resource', $res);
+        $this->assertStringEquals('http://www.example.com/', $res);
+    }
+
+    public function testAddBnodeResource()
+    {
+        $count = $this->graph->addResource($this->uri, 'foaf:interest', '_:abc');
+        $this->assertSame(1, $count);
+        $res = $this->graph->get($this->uri, 'foaf:interest');
+        $this->assertClass('EasyRdf_Resource', $res);
+        $this->assertTrue($res->isBNode());
+        $this->assertStringEquals('_:abc', $res);
+    }
+
+    public function testAddDulicateTriple()
+    {
+        $homepage = $this->graph->resource('http://example.com/');
+        $count = $this->graph->add($this->uri, 'foaf:homepage', $homepage);
+        $this->assertSame(1, $count);
+        $count = $this->graph->addResource($this->uri, 'foaf:homepage', $homepage);
+        $this->assertSame(0, $count);
+        $count = $this->graph->addResource($this->uri, 'foaf:homepage', $homepage);
+        $this->assertSame(0, $count);
+        $all = $this->graph->all($this->uri, 'foaf:homepage');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals($homepage, $all[0]);
+
+        # Check inverse too
+        $all = $this->graph->all($homepage, '^foaf:homepage');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('http://example.com/#me', $all[0]);
+    }
+
+    public function testSet()
+    {
+        $count = $this->graph->set($this->uri, 'rdf:foobar', 'baz');
+        $this->assertSame(1, $count);
+        $all = $this->graph->all($this->uri, 'rdf:foobar');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('baz', $all[0]);
+    }
+
+    public function testSetReplaces()
+    {
+        $count = $this->graph->add($this->uri, 'rdf:test', 'Test D');
+        $this->assertSame(1, $count);
+        $count = $this->graph->set($this->uri, 'rdf:test', 'Test E');
+        $this->assertSame(1, $count);
+        $all = $this->graph->all($this->uri, 'rdf:test');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('Test E', $all[0]);
+    }
+
+    public function testDelete()
+    {
+        $this->assertStringEquals('Test A', $this->graph->get($this->uri, 'rdf:test'));
+        $this->assertSame(2, $this->graph->delete($this->uri, 'rdf:test'));
+        $this->assertSame(array(), $this->graph->all($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteWithPropertyUri()
+    {
+        $this->assertStringEquals('Test A', $this->graph->get($this->uri, 'rdf:test'));
+        $this->assertSame(2, $this->graph->delete($this->uri, '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'));
+        $this->assertSame(array(), $this->graph->all($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteWithPropertyResource()
+    {
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $this->assertStringEquals('Test A', $this->graph->get($this->uri, 'rdf:test'));
+        $this->assertSame(2, $this->graph->delete($this->uri, $prop));
+        $this->assertSame(array(), $this->graph->all($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteWithUri()
+    {
+        $this->assertStringEquals('Test A', $this->graph->get($this->uri, 'rdf:test'));
+        $this->assertSame(
+            2,
+            $this->graph->delete(
+                $this->uri,
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#test'
+            )
+        );
+        $this->assertSame(array(), $this->graph->all($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteNonExistantProperty()
+    {
+        $this->assertSame(0, $this->graph->delete($this->uri, 'foo:bar'));
+    }
+
+    public function testDeleteNullKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->delete($this->uri, null);
+    }
+
+    public function testDeleteEmptyKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be an empty string'
+        );
+        $this->graph->delete($this->uri, '');
+    }
+
+    public function testDeleteNonStringKey()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->graph->delete($this->uri, array());
+    }
+
+    public function testDeletePropertyResource()
+    {
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://example.com/');
+        $this->assertTrue($this->graph->hasProperty($this->uri, 'foaf:homepage'));
+        $this->assertTrue($this->graph->hasProperty('http://example.com/', '^foaf:homepage'));
+        $this->assertSame(1, $this->graph->delete($this->uri, 'foaf:homepage'));
+        $this->assertFalse($this->graph->hasProperty($this->uri, 'foaf:homepage'));
+        $this->assertFalse($this->graph->hasProperty('http://example.com/', '^foaf:homepage'));
+    }
+
+    public function testDeleteLiteralValue()
+    {
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test'));
+        $this->assertSame(1, $this->graph->delete($this->uri, 'rdf:test', 'Test A'));
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'rdf:test'));
+        $this->assertSame(
+            1,
+            $this->graph->delete(
+                $this->uri,
+                'rdf:test',
+                new EasyRdf_Literal('Test B', 'en')
+            )
+        );
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteResourceValue()
+    {
+        $res = $this->graph->resource('http://www.example.com/');
+        $this->graph->add($this->uri, 'foaf:homepage', $res);
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'foaf:homepage'));
+        $this->assertSame(1, $this->graph->delete($this->uri, 'foaf:homepage', $res));
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'foaf:homepage'));
+    }
+
+    public function testDeleteLiteralArrayValue()
+    {
+        // Keys are deliberately in the wrong order
+        $testa = array('value' => 'Test A', 'type' => 'literal');
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test'));
+        $this->assertSame(1, $this->graph->delete($this->uri, 'rdf:test', $testa));
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteResourceArrayValue()
+    {
+        // Keys are deliberately in the wrong order
+        $res = array('value' => 'http://www.example.com/', 'type' => 'uri');
+        $this->graph->addResource($this->uri, 'foaf:homepage', 'http://www.example.com/');
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'foaf:homepage'));
+        $this->assertSame(1, $this->graph->delete($this->uri, 'foaf:homepage', $res));
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'foaf:homepage'));
+    }
+
+    public function testDeleteResource()
+    {
+        $res = $this->graph->resource('http://www.example.com/');
+        $this->graph->addResource($this->uri, 'foaf:homepage', $res);
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'foaf:homepage'));
+        $this->assertSame(1, $this->graph->deleteResource($this->uri, 'foaf:homepage', $res));
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'foaf:homepage'));
+    }
+
+    public function testDeleteResourceString()
+    {
+        $res = 'http://www.example.com/';
+        $this->graph->addResource($this->uri, 'foaf:homepage', $res);
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'foaf:homepage'));
+        $this->assertSame(1, $this->graph->deleteResource($this->uri, 'foaf:homepage', $res));
+        $this->assertSame(0, $this->graph->countValues($this->uri, 'foaf:homepage'));
+    }
+
+    public function testDeleteLiteral()
+    {
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test'));
+        $this->assertSame(1, $this->graph->deleteLiteral($this->uri, 'rdf:test', 'Test A'));
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'rdf:test'));
+    }
+
+    public function testDeleteLiteralWithLang()
+    {
+        $this->assertSame(2, $this->graph->countValues($this->uri, 'rdf:test'));
+        $this->assertSame(1, $this->graph->deleteLiteral($this->uri, 'rdf:test', 'Test B', 'en'));
+        $this->assertSame(1, $this->graph->countValues($this->uri, 'rdf:test'));
+    }
+
+    public function testGetType()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph('http://www.example.com/joe/foaf.rdf', $data, 'json');
+        $this->assertStringEquals(
+            'foaf:PersonalProfileDocument',
+            $graph->type()
+        );
+    }
+
+    public function testTypeUnknown()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertNull($graph->type());
+    }
+
+    public function testPrimaryTopic()
+    {
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph(
+            'http://www.example.com/joe/foaf.rdf',
+            $data,
+            'json'
+        );
+        $this->assertStringEquals(
+            'http://www.example.com/joe#me',
+            $graph->primaryTopic()
+        );
+    }
+
+    public function testPrimaryTopicUnknown()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertNull($graph->primaryTopic());
+    }
+
+    public function testSerialise()
+    {
+        EasyRdf_Format::registerSerialiser('mock', 'Mock_RdfSerialiser');
+        $graph = new EasyRdf_Graph();
+        $this->assertSame("<rdf></rdf>", $graph->serialise('mock'));
+    }
+
+    public function testSerialiseByMime()
+    {
+        EasyRdf_Format::registerSerialiser('mock', 'Mock_RdfSerialiser');
+        EasyRdf_Format::register('mock', 'Mock', null, array('mock/mime' => 1.0));
+        $graph = new EasyRdf_Graph();
+        $this->assertSame(
+            "<rdf></rdf>",
+            $graph->serialise('mock/mime')
+        );
+    }
+
+    public function testSerialiseByFormatObject()
+    {
+        $format = EasyRdf_Format::register('mock', 'Mock Format');
+        $format->setSerialiserClass('Mock_RdfSerialiser');
+        $graph = new EasyRdf_Graph();
+        $this->assertSame("<rdf></rdf>", $graph->serialise($format));
+    }
+
+    public function testIsEmpty()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertTrue($graph->isEmpty());
+    }
+
+    public function testIsNotEmpty()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->add('http://example.com/', 'rdfs:label', 'Example');
+        $this->assertFalse($graph->isEmpty());
+    }
+
+    public function testIsEmptyAfterDelete()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->add('http://example.com/', 'rdfs:label', 'Example');
+        $graph->delete('http://example.com/', 'rdfs:label');
+        $this->assertTrue($graph->isEmpty());
+    }
+
+    public function testProperties()
+    {
+        $this->assertSame(
+            array('rdf:type', 'rdf:test'),
+            $this->graph->properties($this->uri)
+        );
+    }
+
+    public function testPropertiesForNonExistantResource()
+    {
+        $this->assertSame(
+            array(),
+            $this->graph->properties('http://doesnotexist.com/')
+        );
+    }
+
+    public function testPropertyUris()
+    {
+        $this->assertSame(
+            array(
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#test'
+            ),
+            $this->graph->propertyUris($this->uri)
+        );
+    }
+
+    public function testNoReversePropertyUris()
+    {
+        $this->assertSame(
+            array(),
+            $this->graph->reversePropertyUris('foaf:Document')
+        );
+    }
+
+    public function testReversePropertyUris()
+    {
+        $this->assertSame(
+            array(
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'
+            ),
+            $this->graph->reversePropertyUris('foaf:Person')
+        );
+    }
+
+    public function testPropertyUrisForNonExistantResource()
+    {
+        $this->assertSame(
+            array(),
+            $this->graph->propertyUris('http://doesnotexist.com/')
+        );
+    }
+
+    public function testHasProperty()
+    {
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, 'rdf:type')
+        );
+    }
+
+    public function testHasPropertyWithLiteralValue()
+    {
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, 'rdf:test', 'Test A')
+        );
+    }
+
+    public function testHasPropertyWithLangValue()
+    {
+        $literal = new EasyRdf_Literal('Test B', 'en');
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, 'rdf:test', $literal)
+        );
+    }
+
+    public function testHasPropertyWithResourceValue()
+    {
+        $person = $this->graph->resource('foaf:Person');
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, 'rdf:type', $person)
+        );
+    }
+
+    public function testHasResourceProperty()
+    {
+        $property = new EasyRdf_Resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, $property)
+        );
+    }
+
+    public function testHasParsedUriProperty()
+    {
+        $property = new EasyRdf_ParsedUri('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
+        $this->assertTrue(
+            $this->graph->hasProperty($this->uri, $property)
+        );
+    }
+
+    public function testHasInverseProperty()
+    {
+        $this->assertTrue(
+            $this->graph->hasProperty('foaf:Person', '^rdf:type')
+        );
+    }
+
+    public function testHasInversePropertyWithValue()
+    {
+        $resource = $this->graph->resource($this->uri);
+        $this->assertTrue(
+            $this->graph->hasProperty('foaf:Person', '^rdf:type', $resource)
+        );
+    }
+
+    public function testDoesntHaveProperty()
+    {
+        $this->assertFalse(
+            $this->graph->hasProperty($this->uri, 'rdf:doesntexist')
+        );
+    }
+
+    public function testDoesntHavePropertyWithLiteralValue()
+    {
+        $this->assertFalse(
+            $this->graph->hasProperty($this->uri, 'rdf:test', 'Test Z')
+        );
+    }
+
+    public function testDoesntHavePropertyWithLangValue()
+    {
+        $literal = new EasyRdf_Literal('Test A', 'fr');
+        $this->assertFalse(
+            $this->graph->hasProperty($this->uri, 'rdf:test', $literal)
+        );
+    }
+
+    public function testDoesntHaveInverseProperty()
+    {
+        $this->assertFalse(
+            $this->graph->hasProperty($this->uri, '^rdf:doesntexist')
+        );
+    }
+
+    public function testDoesntHasBnodeProperty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be a blank node'
+        );
+        $this->graph->hasProperty($this->uri, '_:foo');
+    }
+
+    public function testDumpText()
+    {
+        $text = $this->graph->dump('text');
+        $this->assertContains('Graph: http://example.com/graph', $text);
+        $this->assertContains('http://example.com/#me (EasyRdf_Resource)', $text);
+        $this->assertContains('  -> rdf:type -> foaf:Person', $text);
+        $this->assertContains('  -> rdf:test -> "Test A"', $text);
+    }
+
+    public function testDumpEmptyGraph()
+    {
+        $graph = new EasyRdf_Graph('http://example.com/graph2');
+        $this->assertSame("Graph: http://example.com/graph2\n", $graph->dump('text'));
+        $this->assertContains('>Graph: http://example.com/graph2</div>', $graph->dump('html'));
+    }
+
+    public function testDumpHtml()
+    {
+        $html = $this->graph->dump('html');
+        $this->assertContains('Graph: http://example.com/graph', $html);
+        $this->assertContains('http://example.com/#me', $html);
+        $this->assertContains('>rdf:test</span>', $html);
+        $this->assertContains('>&quot;Test A&quot;</span>', $html);
+    }
+
+    public function testDumpLiterals()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->add('http://example.com/joe#me', 'foaf:name', 'Joe');
+        $graph->add('http://example.com/joe#me', 'foaf:age', EasyRdf_Literal::create(52));
+        $deutschland = new EasyRdf_Literal('Deutschland', 'de');
+        $graph->add('http://example.com/joe#me', 'foaf:birthPlace', $deutschland);
+        $graph->add('http://example.com/joe#me', '<http://v.example.com/foo>', 'bar');
+
+        $text = $graph->dump('text');
+        $this->assertContains('http://example.com/joe#me', $text);
+        $this->assertContains('-> foaf:name -> "Joe"', $text);
+        $this->assertContains('-> foaf:age -> "52"^^xsd:integer', $text);
+        $this->assertContains('-> foaf:birthPlace -> "Deutschland"@de', $text);
+        $this->assertContains('-> <http://v.example.com/foo> -> "bar"', $text);
+
+        $html = $graph->dump('html');
+        $this->assertContains('http://example.com/joe#me', $html);
+        $this->assertContains('>foaf:name</span>', $html);
+        $this->assertContains('>&quot;Joe&quot;</span>', $html);
+        $this->assertContains('>foaf:age</span>', $html);
+        $this->assertContains('>&quot;52&quot;^^xsd:integer</span>', $html);
+        $this->assertContains('>foaf:birthPlace</span>', $html);
+        $this->assertContains('>&quot;Deutschland&quot;@de</span>', $html);
+        $this->assertContains('>&lt;http://v.example.com/foo&gt;</span>', $html);
+        $this->assertContains('>&quot;bar&quot;</span>', $html);
+    }
+
+    public function testDumpResource()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->addResource('http://example.com/joe#me', 'rdf:type', 'foaf:Person');
+        $graph->addResource('http://example.com/joe#me', 'foaf:homepage', 'http://example.com/');
+        $graph->add('http://example.com/joe#me', 'foaf:knows', $graph->newBnode());
+
+        $text = $graph->dumpResource('http://example.com/joe#me', 'text');
+        $this->assertContains('http://example.com/joe#me', $text);
+        $this->assertContains('-> rdf:type -> foaf:Person', $text);
+        $this->assertContains('-> foaf:homepage -> http://example.com/', $text);
+        $this->assertContains('-> foaf:knows -> _:genid1', $text);
+
+        $html = $graph->dumpResource('http://example.com/joe#me', 'html');
+        $this->assertContains('http://example.com/joe#me', $html);
+        $this->assertContains('>rdf:type</span>', $html);
+        $this->assertContains('>foaf:Person</a>', $html);
+        $this->assertContains('>foaf:homepage</span>', $html);
+        $this->assertContains('>http://example.com/</a>', $html);
+        $this->assertContains('>foaf:knows</span>', $html);
+        $this->assertContains('>_:genid1</a>', $html);
+    }
+
+    public function testDumpResourceWithNoProperties()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertSame('', $graph->dumpResource('http://example.com/empty', 'text'));
+        $this->assertSame('', $graph->dumpResource('http://example.com/empty', 'html'));
+    }
+
+    public function testDumpResourceInjectJavascript()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->addType("wikibase_id:Q' onload='alert(1234)", 'foaf:Person');
+        $this->assertContains(
+            "<div id='wikibase_id:Q&#039; onload=&#039;alert(1234)' ".
+            "style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>",
+            $graph->dumpResource("wikibase_id:Q' onload='alert(1234)")
+        );
+    }
+
+    public function testTypes()
+    {
+        $types = $this->graph->types($this->uri);
+        $this->assertCount(1, $types);
+        $this->assertStringEquals('foaf:Person', $types[0]);
+    }
+
+    public function testTypesNotLiteral()
+    {
+        $this->graph->addResource($this->uri, 'rdf:type', "foaf:Rat");
+        $this->graph->addLiteral($this->uri, 'rdf:type', "Literal");
+        $types = $this->graph->types($this->uri);
+        $this->assertCount(2, $types);
+        $this->assertStringEquals('foaf:Person', $types[0]);
+        $this->assertStringEquals('foaf:Rat', $types[1]);
+    }
+
+    public function testType()
+    {
+        $this->assertStringEquals('foaf:Person', $this->graph->type($this->uri));
+    }
+
+    public function testTypeForResourceWithNoType()
+    {
+        $resource = $this->graph->resource('http://example.com/notype');
+        $this->assertNull($resource->type());
+    }
+
+    public function testTypeForUnamedGraph()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertNull($graph->type());
+    }
+
+    public function testTypeAsResource()
+    {
+        $type = $this->graph->typeAsResource($this->uri);
+        $this->assertClass('EasyRdf_Resource', $type);
+        $this->assertStringEquals('http://xmlns.com/foaf/0.1/Person', $type);
+    }
+
+    public function testTypeAsResourceForUnamedGraph()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertNull($graph->typeAsResource());
+    }
+
+    public function testIsA()
+    {
+        $this->assertTrue($this->graph->isA($this->uri, 'foaf:Person'));
+    }
+
+    public function testIsAFullUri()
+    {
+        $this->assertTrue(
+            $this->graph->isA($this->uri, 'http://xmlns.com/foaf/0.1/Person')
+        );
+    }
+
+    public function testIsntA()
+    {
+        $this->assertFalse($this->graph->isA($this->uri, 'foaf:Rat'));
+    }
+
+    public function testAddType()
+    {
+        $count = $this->graph->addType($this->uri, 'rdf:newType');
+        $this->assertSame(1, $count);
+        $this->assertTrue(
+            $this->graph->isA($this->uri, 'rdf:newType')
+        );
+    }
+
+    public function testSetType()
+    {
+        $count = $this->graph->setType($this->uri, 'foaf:Rat');
+        $this->assertSame(1, $count);
+        $this->assertTrue(
+            $this->graph->isA($this->uri, 'foaf:Rat')
+        );
+        $this->assertFalse(
+            $this->graph->isA($this->uri, 'http://xmlns.com/foaf/0.1/Person')
+        );
+    }
+
+    public function testLabelForUnnamedGraph()
+    {
+        $graph = new EasyRdf_Graph();
+        $this->assertNull($graph->label());
+    }
+
+    public function testLabelWithSkosPrefLabel()
+    {
+        $this->graph->addLiteral($this->uri, 'skos:prefLabel', 'Preferred Label');
+        $this->graph->addLiteral($this->uri, 'rdfs:label', 'Label Text');
+        $this->graph->addLiteral($this->uri, 'foaf:name', 'Foaf Name');
+        $this->graph->addLiteral($this->uri, 'dc:title', 'Dc Title');
+        $this->assertStringEquals('Preferred Label', $this->graph->label($this->uri));
+    }
+
+    public function testLabelWithRdfsLabel()
+    {
+        $this->graph->addLiteral($this->uri, 'rdfs:label', 'Label Text');
+        $this->graph->addLiteral($this->uri, 'foaf:name', 'Foaf Name');
+        $this->graph->addLiteral($this->uri, 'dc:title', 'Dc Title');
+        $this->assertStringEquals('Label Text', $this->graph->label($this->uri));
+    }
+
+    public function testLabelWithFoafName()
+    {
+        $this->graph->addLiteral($this->uri, 'foaf:name', 'Foaf Name');
+        $this->graph->addLiteral($this->uri, 'dc:title', 'Dc Title');
+        $this->assertStringEquals('Foaf Name', $this->graph->label($this->uri));
+    }
+
+    public function testLabelWithDc11Title()
+    {
+        $this->graph->addLiteral($this->uri, 'dc11:title', 'Dc11 Title');
+        $this->assertStringEquals('Dc11 Title', $this->graph->label($this->uri));
+    }
+
+    public function testLabelNoRdfsLabel()
+    {
+        $this->assertNull($this->graph->label($this->uri));
+    }
+
+    public function testCountTriples()
+    {
+        $this->assertSame(3, $this->graph->countTriples());
+        $this->graph->add($this->uri, 'foaf:nick', 'Nick');
+        $this->assertSame(4, $this->graph->countTriples());
+    }
+
+    public function testToRdfPhp()
+    {
+        $this->assertSame(
+            array(
+                'http://example.com/#me' => array(
+                    'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => array(
+                        array(
+                            'type' => 'uri',
+                            'value' => 'http://xmlns.com/foaf/0.1/Person'
+                        )
+                    ),
+                    'http://www.w3.org/1999/02/22-rdf-syntax-ns#test' => array(
+                        array(
+                            'type' => 'literal',
+                            'value' => 'Test A'
+                        ),
+                        array(
+                            'type' => 'literal',
+                            'value' => 'Test B',
+                            'lang' => 'en'
+                        )
+                    )
+                )
+            ),
+            $this->graph->toRdfPhp()
+        );
+    }
+
+    public function testToString()
+    {
+        $graph = new EasyRdf_Graph('http://example.com/joe/foaf.rdf');
+        $this->assertStringEquals('http://example.com/joe/foaf.rdf', $graph);
+    }
+
+    public function testMagicGet()
+    {
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->graph->add($this->graph->getUri(), 'rdf:test', 'testMagicGet');
+        $this->assertStringEquals(
+            'testMagicGet',
+            $this->graph->test
+        );
+    }
+
+    public function testMagicGetNonExistant()
+    {
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->assertSame(
+            null,
+            $this->graph->foobar
+        );
+    }
+
+    public function testMagicSet()
+    {
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->graph->test = 'testMagicSet';
+        $this->assertStringEquals(
+            'testMagicSet',
+            $this->graph->get($this->graph->getUri(), 'rdf:test')
+        );
+    }
+
+    public function testMagicIsSet()
+    {
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->assertFalse(isset($this->graph->test));
+        $this->graph->add($this->graph->getUri(), 'rdf:test', 'testMagicIsSet');
+        $this->assertTrue(isset($this->graph->test));
+    }
+
+    public function testMagicUnset()
+    {
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->graph->add($this->graph->getUri(), 'rdf:test', 'testMagicUnset');
+        unset($this->graph->test);
+        $this->assertStringEquals(
+            null,
+            $this->graph->get($this->graph->getUri(), 'rdf:test')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Http/ClientTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,276 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Http_ClientTest extends EasyRdf_TestCase
+{
+    /**
+     * Common HTTP client
+     *
+     * @var EasyRdf_Http_Client
+     */
+    protected $client = null;
+
+    /**
+     * Set up the test suite before each test
+     *
+     */
+    public function setUp()
+    {
+        $this->client = new EasyRdf_Http_Client('http://www.example.com/');
+    }
+
+    public function testConstructWithConfig()
+    {
+        $client = new EasyRdf_Http_Client(
+            'http://www.example.com/',
+            array('foo' => 'bar')
+        );
+        $this->assertClass('EasyRdf_Http_Client', $client);
+    }
+
+    /**
+     * Test we can SET and GET a URI as string
+     *
+     */
+    public function testSetGetUriString()
+    {
+        $uristr = 'http://www.bbc.co.uk:80/';
+        $this->client->setUri($uristr);
+
+        $this->assertSame(
+            $uristr,
+            $this->client->getUri(),
+            'Returned Uri object does not hold the expected URI'
+        );
+
+        $uri = $this->client->getUri(true);
+        $this->assertTrue(
+            is_string($uri),
+            'Returned value expected to be a string, ' .
+            gettype($uri) . ' returned'
+        );
+        $this->assertSame(
+            $uri,
+            $uristr,
+            'Returned string is not the expected URI'
+        );
+    }
+
+    public function testSetGetUriHttpsString()
+    {
+        $uristr = 'https://example.com/';
+        $this->client->setUri($uristr);
+
+        $this->assertStringEquals(
+            $uristr,
+            $this->client->getUri(),
+            'Returned Uri object does not hold the expected URI'
+        );
+    }
+
+    public function testSetGopherUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            "EasyRdf_Http_Client only supports the 'http' and 'https' schemes."
+        );
+        $uristr = 'gopher://g.example.com/';
+        $this->client->setUri($uristr);
+    }
+
+    /**
+     * Test we can SET and GET a URI as object
+     *
+     */
+    public function testSetGetUriObject()
+    {
+        $uristr = 'http://www.bbc.co.uk:80/';
+        $obj = new EasyRdf_Resource($uristr);
+        $this->client->setUri($obj);
+
+        $uri = $this->client->getUri();
+        $this->assertSame($uristr, $uri);
+    }
+
+    public function testSetConfig()
+    {
+        $result = $this->client->setConfig(array('foo' => 'bar'));
+        $this->assertClass('EasyRdf_Http_Client', $result);
+    }
+
+    public function testSetConfigNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$config should be an array and cannot be null'
+        );
+        $result = $this->client->setConfig(null);
+    }
+
+    public function testSetConfigNonArray()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$config should be an array and cannot be null'
+        );
+        $result = $this->client->setConfig('foo');
+    }
+
+    /**
+     * Test we can get already set headers
+     *
+     */
+    public function testGetHeader()
+    {
+        $this->client->setHeaders('Accept-language', 'en,de,*');
+        $this->assertSame(
+            $this->client->getHeader('Accept-language'),
+            'en,de,*',
+            'Returned value of header is not as expected'
+        );
+        $this->assertSame(
+            $this->client->getHeader('X-Fake-Header'),
+            null,
+            'Non-existing header should not return a value'
+        );
+    }
+
+    public function testUnsetHeader()
+    {
+        $this->client->setHeaders('Accept-Encoding', 'gzip,deflate');
+        $this->client->setHeaders('Accept-Encoding', null);
+        $this->assertNull(
+            $this->client->getHeader('Accept-encoding'),
+            'Returned value of header is expected to be null'
+        );
+    }
+
+    public function testSetGetMethod()
+    {
+        $this->client->setMethod('POST');
+        $method = $this->client->getMethod();
+        $this->assertSame('POST', $method);
+    }
+
+    public function testSetNonStringMethod()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Invalid HTTP request method.'
+        );
+        $this->client->setMethod($this);
+    }
+
+    public function testSetNumericMethod()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Invalid HTTP request method.'
+        );
+        $this->client->setMethod(1234);
+    }
+
+    public function testRedirectionCounterShouldStartAtZero()
+    {
+        $this->client->setHeaders('Accept-Encoding', null);
+        $this->assertSame(0, $this->client->getRedirectionsCount());
+    }
+
+    public function testSetParameterGet()
+    {
+        $this->client->setParameterGet('key1', 'value1');
+        $this->assertSame('value1', $this->client->getParameterGet('key1'));
+    }
+
+    public function testUnSetParameterGet()
+    {
+        $this->client->setParameterGet('key1', 'value1');
+        $this->client->setParameterGet('key2', 'value2');
+        $this->client->setParameterGet('key1', null);
+        $this->assertSame(null, $this->client->getParameterGet('key1'));
+        $this->assertSame('value2', $this->client->getParameterGet('key2'));
+    }
+
+    public function testSetRawData()
+    {
+        $this->client->setRawData('Foo Bar');
+        $this->assertSame('Foo Bar', $this->client->getRawData());
+    }
+
+    public function testRequestNoUri()
+    {
+        $client = new EasyRdf_Http_Client();
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Set URI before calling EasyRdf_Http_Client->request()'
+        );
+        $client->request();
+    }
+
+    public function testResetParameters()
+    {
+        $this->client->setMethod('POST');
+        $this->client->setRawData('Foo Bar');
+        $this->client->setHeaders('Content-Length', 7);
+        $this->client->setHeaders('Content-Type', 'text/plain');
+        $this->client->setHeaders('Accept-Language', 'en');
+        $this->client->resetParameters();
+        $this->assertSame('GET', $this->client->getMethod());
+        $this->assertSame(null, $this->client->getRawData());
+        $this->assertSame(null, $this->client->getHeader('Content-Length'));
+        $this->assertSame(null, $this->client->getHeader('Content-Type'));
+        $this->assertSame('en', $this->client->getHeader('Accept-Language'));
+    }
+
+    public function testResetParametersClearAll()
+    {
+        $this->client->setMethod('POST');
+        $this->client->setRawData('Foo Bar');
+        $this->client->setHeaders('Content-Length', 7);
+        $this->client->setHeaders('Content-Type', 'text/plain');
+        $this->client->setHeaders('Accept-Language', 'en');
+        $this->client->resetParameters(true);
+        $this->assertSame('GET', $this->client->getMethod());
+        $this->assertSame(null, $this->client->getRawData());
+        $this->assertSame(null, $this->client->getHeader('Content-Length'));
+        $this->assertSame(null, $this->client->getHeader('Content-Type'));
+        $this->assertSame(null, $this->client->getHeader('Accept-Language'));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Http/MockClient.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+class EasyRdf_Http_MockClient extends EasyRdf_Http_Client
+{
+    private $mocks = array();
+
+    public function request($method = null)
+    {
+        if ($method) {
+            $this->setMethod($method);
+        }
+
+        $uri = parse_url($this->getUri());
+        $params = $this->getParametersGet();
+        if (!empty($params)) {
+            if (!empty($uri['query'])) {
+                $uri['query'] .= '&';
+            } else {
+                $uri['query'] = '';
+            }
+            $uri['query'] .= http_build_query($params, null, '&');
+        }
+
+        # Try and find a matching response
+        $n = sizeof($this->mocks);
+        for ($i = 0; $i < $n; $i++) {
+            list($m, $response, $once) = $this->mocks[$i];
+            if (isset($m['uri']) && !$this->matchUri($m['uri'], $uri)) {
+                continue;
+            } elseif (isset($m['method']) && $m['method'] !== $this->getMethod()) {
+                continue;
+            } elseif (isset($m['callback'])) {
+                $args = array_merge($m['callbackArgs'], array($this));
+                $test = call_user_func_array($m['callback'], $args);
+                if (!$test) {
+                    continue;
+                }
+            }
+            if ($once) {
+                array_splice($this->mocks, $i, 1);
+            }
+            return $response;
+        }
+
+        # FIXME: change to a different type of exception?
+        throw new EasyRdf_Exception(
+            'Unexpected request: ' . $this->getMethod() . ' ' . $this->getUri()
+        );
+    }
+
+    public function addMock($method, $uri, $body, $options = array())
+    {
+        $match = array();
+        $match['method'] = $method;
+        $match['uri'] = array();
+        if (isset($options['callback'])) {
+            $match['callback'] = $options['callback'];
+            if (isset($options['callbackArgs'])) {
+                $match['callbackArgs'] = $options['callbackArgs'];
+            } else {
+                $match['callbackArgs'] = array();
+            }
+        }
+        if (!isset($uri)) {
+            $match['uri'] = null;
+        } else {
+            $match['uri'] = strval($uri);
+        }
+
+        if ($body instanceof EasyRdf_Http_Response) {
+            $response = $body;
+        } else {
+            if (isset($options['status'])) {
+                $status = $options['status'];
+            } else {
+                $status = 200;
+            }
+            if (isset($options['headers'])) {
+                $headers = $options['headers'];
+            } else {
+                $headers = array();
+                $format = EasyRdf_Format::guessFormat($body);
+                if (isset($format)) {
+                    $headers['Content-Type'] = $format->getDefaultMimeType();
+                }
+                if (isset($body)) {
+                    $headers['Content-Length'] = strlen($body);
+                }
+            }
+            $response = new EasyRdf_Http_Response($status, $headers, $body);
+        }
+        $once = isset($options['once']) ? $options['once'] : false;
+
+        $this->mocks[] = array($match, $response, $once);
+    }
+
+    public function addMockOnce($method, $uri, $body, $options = array())
+    {
+        $options = array('once' => true) + $options;
+        return $this->addMock($method, $uri, $body, $options);
+    }
+
+    public function addMockRedirect($method, $uri, $location, $status = 302, $options = array())
+    {
+        $options = array('status' => $status, 'headers' => array('Location' => $location)) + $options;
+        $body = "$status redirect to $location";
+        return $this->addMock($method, $uri, $body, $options);
+    }
+
+    protected function buildUrl($parts)
+    {
+        $url = $parts['scheme'] . '://';
+        $url .= $parts['host'];
+        if (isset($parts['port'])) {
+            $url .= ':' . $parts['port'];
+        }
+        if (isset($parts['path'])) {
+            $url .= $parts['path'];
+        } else {
+            $url .= '/';
+        }
+        if (isset($parts['query'])) {
+            $url .= '?' . $parts['query'];
+        }
+        return $url;
+    }
+
+    private function matchUri($match, $parts)
+    {
+        # FIXME: Ugh, this is nasty
+        $url = $this->buildUrl($parts);
+        if ($match == $url) {
+            return true;
+        } else {
+            if (isset($parts['query'])) {
+                return ($match == $parts['path'].'?'.$parts['query']);
+            } else {
+                return ($match == $parts['path']);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Http/MockClientTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,268 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+require_once 'EasyRdf/Http/MockClient.php';
+
+
+class EasyRdf_Http_MockClientTest extends EasyRdf_TestCase
+{
+
+    public function setUp()
+    {
+        $this->client = new EasyRdf_Http_MockClient();
+    }
+
+    protected function get($uri)
+    {
+        $this->client->setUri($uri);
+        return $this->client->request('GET');
+    }
+
+    public function testUrlMatch()
+    {
+        $this->client->addMock('GET', 'http://foo.com/test', 'A');
+        $this->client->addMock('GET', 'http://www.bar.com/test', 'B');
+
+        $response = $this->get('http://foo.com/test');
+        $this->assertSame('A', $response->getBody());
+        $response = $this->get('http://www.bar.com/test');
+        $this->assertSame('B', $response->getBody());
+    }
+
+    public function testPathMatch()
+    {
+        $this->client->addMock('GET', '/testA', 'A');
+        $this->client->addMock('GET', '/testB', 'B');
+        $response = $this->get('http://example.com/testA');
+        $this->assertSame('A', $response->getBody());
+        $response = $this->get('http://example.org/testB');
+        $this->assertSame('B', $response->getBody());
+    }
+
+    public function testPathAndQueryMatch()
+    {
+        $this->client->addMock('GET', '/testA', '10');
+        $this->client->addMock('GET', '/testA?foo=bar', '20');
+        $this->client->addMock('GET', '/testA?bar=foo', '30');
+        $response = $this->get('http://example.com/testA?foo=bar');
+        $this->assertSame('20', $response->getBody());
+        $response = $this->get('http://example.org/testA');
+        $this->assertSame('10', $response->getBody());
+    }
+
+    public function testSettingGetParameter()
+    {
+        $this->client->addMock('GET', '/testA', '10');
+        $this->client->addMock('GET', '/testA?a=1', '20');
+        $this->client->addMock('GET', '/testA?a=1&b=2', '30');
+
+        $this->client->setParameterGet('a', '1');
+        $this->client->setParameterGet('b', '2');
+        $response = $this->get('http://example.org/testA');
+        $this->assertSame('30', $response->getBody());
+
+        $this->client->resetParameters();
+        $this->client->setParameterGet('b', '2');
+        $response = $this->get('http://example.com/testA?a=1');
+        $this->assertSame('30', $response->getBody());
+    }
+
+    public function testUnknownUrl()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Unexpected request: GET http://example.com/test'
+        );
+        $this->get('http://example.com/test');
+    }
+
+    public function testMethodUnknownMatch()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Unexpected request: GET http://example.com/test'
+        );
+        $this->client->addMock('PUT', '/test', '10');
+        $this->get('http://example.com/test');
+    }
+
+    public function testWildcardMethod()
+    {
+        $this->client->addMock(null, '/test', 'testWildcardMethod');
+        $response = $this->get('http://example.com/test');
+        $this->assertSame('testWildcardMethod', $response->getBody());
+    }
+
+    public function testWildcardUrl()
+    {
+        $this->client->addMock('GET', null, 'testWildcardUrl');
+        $response = $this->get('http://example.com/foo');
+        $this->assertSame('testWildcardUrl', $response->getBody());
+    }
+
+    public function testSetStatus()
+    {
+        $this->client->addMock('GET', '/test', 'x', array('status' => 404));
+        $response = $this->get('http://example.com/test');
+        $this->assertSame(404, $response->getStatus());
+    }
+
+    public function testSetHeaders()
+    {
+        $h = array('Content-Type' => 'text/html');
+        $this->client->addMock('GET', '/test', 'x', array('headers' => $h));
+        $response = $this->get('http://example.com/test');
+        $this->assertSame('text/html', $response->getHeader('Content-Type'));
+    }
+
+    public function testSetResponse()
+    {
+        $response = new EasyRdf_Http_Response(234, array('Foo' => 'bar'), 'x');
+        $this->client->addMock('GET', '/test', $response);
+        $r = $this->get('http://example.com/test', array('throw' => false));
+        $this->assertSame(234, $r->getStatus());
+        $this->assertSame('bar', $r->getHeader('Foo'));
+        $this->assertSame('x', $r->getBody());
+    }
+
+    public function testOnce()
+    {
+        $this->client->addMock('GET', '/test', '10', array('once' => true));
+        $this->client->addMockOnce('GET', '/test', '20');
+        $this->client->addMock('GET', '/test', '30');
+        $r = $this->get('http://example.com/test');
+        $this->assertSame('10', $r->getBody());
+        $r = $this->get('http://example.com/test');
+        $this->assertSame('20', $r->getBody());
+        $r = $this->get('http://example.com/test');
+        $this->assertSame('30', $r->getBody());
+        $r = $this->get('http://example.com/test');
+        $this->assertSame('30', $r->getBody());
+    }
+
+    public function testRedirect()
+    {
+        $this->client->addMockRedirect('GET', '/', 'http://example.com/test');
+        $r = $this->get('http://example.com/');
+        $this->assertSame('302 redirect to http://example.com/test', $r->getBody());
+        $this->assertSame(302, $r->getStatus());
+        $this->assertSame('http://example.com/test', $r->getHeader('Location'));
+    }
+
+    public function testRedirectSeeOther()
+    {
+        $this->client->addMockRedirect('GET', '/', 'http://example.com/test', 303);
+        $r = $this->get('http://example.com/');
+        $this->assertSame('303 redirect to http://example.com/test', $r->getBody());
+        $this->assertSame(303, $r->getStatus());
+        $this->assertSame('http://example.com/test', $r->getHeader('Location'));
+    }
+
+    public function testCallbackWithoutArgs()
+    {
+        $alwaysTrue = array('callback' => array($this, 'alwaysTrue'));
+        $alwaysFalse = array('callback' => array($this, 'alwaysFalse'));
+
+        $this->client->addMock('GET', '/test1', '10', $alwaysTrue);
+        $r = $this->get('http://example.com/test1');
+        $this->assertSame('10', $r->getBody());
+
+        $this->client->addMock('GET', '/test2', '10', $alwaysFalse);
+        $this->client->addMock('GET', '/test2', '20', $alwaysFalse);
+        $this->client->addMock('GET', '/test2', '30', $alwaysTrue);
+        $r = $this->get('http://example.com/test2');
+        $this->assertSame('30', $r->getBody());
+    }
+
+    public function alwaysTrue()
+    {
+        return true;
+    }
+
+    public function alwaysFalse()
+    {
+        return false;
+    }
+
+    public function testCallbackWithArgs()
+    {
+        $echoTrue = array('callback' => array($this, 'echoValue'),
+                          'callbackArgs' => array(true));
+        $echoFalse = array('callback' => array($this, 'echoValue'),
+                           'callbackArgs' => array(false));
+
+        $this->client->addMock('GET', '/test1', '10', $echoTrue);
+        $r = $this->get('http://example.com/test1');
+        $this->assertSame('10', $r->getBody());
+
+        $this->client->addMock('GET', '/test2', '10', $echoFalse);
+        $this->client->addMock('GET', '/test2', '20', $echoTrue);
+        $this->client->addMock('GET', '/test2', '30', $echoFalse);
+        $r = $this->get('http://example.com/test2');
+        $this->assertSame('20', $r->getBody());
+    }
+
+    public function echoValue($value)
+    {
+        return $value;
+    }
+
+    public function testCallbackWithMockHttp()
+    {
+        $isMockHttp = array('callback' => array($this, 'isMockHttp'));
+        $this->client->addMock('GET', '/test1', '10', $isMockHttp);
+        $r = $this->get('http://example.com/test1');
+        $this->assertSame('10', $r->getBody());
+    }
+
+    public function isMockHttp($value)
+    {
+        return ($value instanceof EasyRdf_Http_MockClient);
+    }
+
+    public function testGuessJsonContentType()
+    {
+        $this->client->addMockOnce('GET', null, '{"a":1}');
+        $r = $this->get('http://example.com');
+        $this->assertSame('application/json', $r->getHeader('Content-Type'));
+
+        $this->client->addMockOnce('GET', null, "\n{\"a\"\n:\n1\n}\n");
+        $r = $this->get('http://example.com');
+        $this->assertSame('application/json', $r->getHeader('Content-Type'));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Http/ResponseTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,278 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Test helper
+ */
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+/**
+ * PHPUnit test case
+ */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+class EasyRdf_Http_ResponseTest extends EasyRdf_TestCase
+{
+    public function testGetVersion()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200')
+        );
+        $this->assertSame(
+            '1.1',
+            $response->getVersion(),
+            'Version is expected to be 1.1'
+        );
+    }
+
+    public function testGetMessage()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200')
+        );
+        $this->assertSame(
+            'OK',
+            $response->getMessage(),
+            'Message is expected to be OK'
+        );
+    }
+
+    public function testGetBody()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200')
+        );
+        $this->assertSame(
+            "Hello World\n",
+            $response->getBody()
+        );
+    }
+
+    public function testInvalidResponse()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to parse HTTP response.'
+        );
+        $response = EasyRdf_Http_Response::fromString('foobar');
+    }
+
+    public function testInvalidStatusLine()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to parse HTTP response status line.'
+        );
+        $response = EasyRdf_Http_Response::fromString(
+            "HTTP1.0 200 OK\r\nConnection: close\r\n\r\nBody"
+        );
+    }
+
+    public function testGetBodyChunked()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200_chunked')
+        );
+        $this->assertSame(
+            "Hello World",
+            $response->getBody()
+        );
+    }
+
+    public function testInvalidChunkedBody()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to decode chunked body in HTTP response.'
+        );
+        $response = EasyRdf_Http_Response::fromString(
+            "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nINVALID"
+        );
+        $response->getBody();
+    }
+
+    public function test200Ok()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200')
+        );
+
+        $this->assertSame(
+            200,
+            $response->getStatus(),
+            'Response code is expected to be 200, but it\'s not.'
+        );
+        $this->assertFalse(
+            $response->isError(),
+            'Response is OK, but isError() returned true'
+        );
+        $this->assertTrue(
+            $response->isSuccessful(),
+            'Response is OK, but isSuccessful() returned false'
+        );
+        $this->assertFalse(
+            $response->isRedirect(),
+            'Response is OK, but isRedirect() returned true'
+        );
+    }
+
+    public function test404IsError()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_404')
+        );
+
+        $this->assertSame(
+            404,
+            $response->getStatus(),
+            'Response code is expected to be 404, but it\'s not.'
+        );
+        $this->assertTrue(
+            $response->isError(),
+            'Response is an error, but isError() returned false'
+        );
+        $this->assertFalse(
+            $response->isSuccessful(),
+            'Response is an error, but isSuccessful() returned true'
+        );
+        $this->assertFalse(
+            $response->isRedirect(),
+            'Response is an error, but isRedirect() returned true'
+        );
+    }
+
+    public function test500isError()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_500')
+        );
+
+        $this->assertSame(
+            500,
+            $response->getStatus(),
+            'Response code is expected to be 500, but it\'s not.'
+        );
+        $this->assertTrue(
+            $response->isError(),
+            'Response is an error, but isError() returned false'
+        );
+        $this->assertFalse(
+            $response->isSuccessful(),
+            'Response is an error, but isSuccessful() returned true'
+        );
+        $this->assertFalse(
+            $response->isRedirect(),
+            'Response is an error, but isRedirect() returned true'
+        );
+    }
+
+    public function test300isRedirect()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_302')
+        );
+
+        $this->assertSame(
+            302,
+            $response->getStatus(),
+            'Response code is expected to be 302, but it\'s not.'
+        );
+        $this->assertSame(
+            'http://localhost/new/location',
+            $response->getHeader('Location'),
+            'Response code is expected to be 302, but it\'s not.'
+        );
+        $this->assertTrue(
+            $response->isRedirect(),
+            'Response is a redirection, but isRedirect() returned false'
+        );
+        $this->assertFalse(
+            $response->isError(),
+            'Response is a redirection, but isError() returned true'
+        );
+        $this->assertFalse(
+            $response->isSuccessful(),
+            'Response is a redirection, but isSuccessful() returned true'
+        );
+    }
+
+    public function testGetHeaders()
+    {
+        $response = EasyRdf_Http_Response::fromString(
+            readFixture('http_response_200')
+        );
+
+        $this->assertCount(
+            8,
+            $response->getHeaders(),
+            'Header count is not as expected'
+        );
+        $this->assertSame(
+            'Apache/2.2.9 (Unix) PHP/5.2.6',
+            $response->getHeader('Server'),
+            'Server header is not as expected'
+        );
+        $this->assertSame(
+            'text/plain',
+            $response->getHeader('Content-Type'),
+            'Content-type header is not as expected'
+        );
+        $this->assertSame(
+            array('foo','bar'),
+            $response->getHeader('X-Multiple'),
+            'Header with multiple values is not as expected'
+        );
+    }
+
+
+    public function testAsString()
+    {
+        $responseStr = readFixture('http_response_404');
+        $response = EasyRdf_Http_Response::fromString($responseStr);
+
+        $this->assertSame(
+            strtolower($responseStr),
+            strtolower($response->asString()),
+            'Response convertion to string does not match original string'
+        );
+        $this->assertSame(
+            strtolower($responseStr),
+            strtolower((string)$response),
+            'Response convertion to string does not match original string'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/HttpTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_HttpTest extends EasyRdf_TestCase
+{
+    // FIXME: this test needs to run before the first call to setDefaultHttpClient()
+    //     public function testGetDefaultHttpClient()
+    //     {
+    //         $this->assertClass(
+    //             'EasyRdf_Http_Client',
+    //             EasyRdf_Http::getDefaultHttpClient()
+    //         );
+    //     }
+
+    public function testSetDefaultHttpClient()
+    {
+        EasyRdf_Http::setDefaultHttpClient(new EasyRdf_Http_MockClient());
+        $this->assertClass(
+            'EasyRdf_Http_MockClient',
+            EasyRdf_Http::getDefaultHttpClient()
+        );
+    }
+
+    public function testSetDefaultHttpClientNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$httpClient should be an object of class Zend_Http_Client or EasyRdf_Http_Client'
+        );
+        EasyRdf_Http::setDefaultHttpClient(null);
+    }
+
+    public function testSetDefaultHttpClientString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$httpClient should be an object of class Zend_Http_Client or EasyRdf_Http_Client'
+        );
+        EasyRdf_Http::setDefaultHttpClient('foobar');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/BooleanTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_BooleanTest extends EasyRdf_TestCase
+{
+    public function testConstructStringTrue()
+    {
+        $literal = new EasyRdf_Literal_Boolean('true');
+        $this->assertStringEquals('true', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstructStringFalse()
+    {
+        $literal = new EasyRdf_Literal_Boolean('false');
+        $this->assertStringEquals('false', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstructString1()
+    {
+        $literal = new EasyRdf_Literal_Boolean('1');
+        $this->assertStringEquals('1', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstructString0()
+    {
+        $literal = new EasyRdf_Literal_Boolean('0');
+        $this->assertStringEquals('0', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstructTrue()
+    {
+        $literal = new EasyRdf_Literal_Boolean(true);
+        $this->assertStringEquals('true', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstructFalse()
+    {
+        $literal = new EasyRdf_Literal_Boolean(false);
+        $this->assertStringEquals('false', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstruct1()
+    {
+        $literal = new EasyRdf_Literal_Boolean(1);
+        $this->assertStringEquals('true', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testConstruct0()
+    {
+        $literal = new EasyRdf_Literal_Boolean(0);
+        $this->assertStringEquals('false', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+    }
+
+    public function testIsTrue()
+    {
+        $true = new EasyRdf_Literal_Boolean(true);
+        $this->assertSame(true, $true->isTrue());
+
+        $false = new EasyRdf_Literal_Boolean(false);
+        $this->assertSame(false, $false->isTrue());
+    }
+
+    public function testIsFalse()
+    {
+        $false = new EasyRdf_Literal_Boolean(false);
+        $this->assertSame(true, $false->isFalse());
+
+        $true = new EasyRdf_Literal_Boolean(true);
+        $this->assertSame(false, $true->isFalse());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/DateTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_DateTest extends EasyRdf_TestCase
+{
+    public function testConstructFromString()
+    {
+        $literal = new EasyRdf_Literal_Date('2011-08-05Z');
+        $this->assertStringEquals('2011-08-05Z', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:date', $literal->getDatatype());
+    }
+
+    public function testConstructFromDateTime()
+    {
+        $dt = new DateTime('2011-07-18');
+        $literal = new EasyRdf_Literal_Date($dt);
+        $this->assertStringEquals('2011-07-18', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertEquals($dt, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:date', $literal->getDatatype());
+    }
+
+    public function testConstructNoValue()
+    {
+        // Would be very unlucky if this ran at midnight and failed
+        // (but it is possible)
+        $today = new DateTime('today');
+        $literal = new EasyRdf_Literal_Date();
+        $this->assertEquals($today, $literal->getValue());
+        $this->assertRegExp('|^\d{4}-\d{2}-\d{2}$|', strval($literal));
+    }
+
+    public function testParse()
+    {
+        $literal = EasyRdf_Literal_Date::parse('5th August 2011');
+        $this->assertStringEquals('2011-08-05', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:date', $literal->getDatatype());
+    }
+
+    public function testFormat()
+    {
+        $literal = new EasyRdf_Literal_Date('2011-08-05');
+        $this->assertSame('05 Aug 11', $literal->format('d M y'));
+    }
+
+    public function testYear()
+    {
+        $literal = new EasyRdf_Literal_Date('2011-08-05');
+        $this->assertSame(2011, $literal->year());
+    }
+
+    public function testMonth()
+    {
+        $literal = new EasyRdf_Literal_Date('2011-08-05');
+        $this->assertSame(8, $literal->month());
+    }
+
+    public function testDate()
+    {
+        $literal = new EasyRdf_Literal_Date('2011-08-05');
+        $this->assertSame(5, $literal->day());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/DateTimeTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_DateTimeTest extends EasyRdf_TestCase
+{
+
+    public function testConstruct()
+    {
+        $literal = new EasyRdf_Literal_DateTime('2011-07-18T18:45:43Z');
+        $this->assertStringEquals('2011-07-18T18:45:43Z', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+    public function testConstructNoValue()
+    {
+        $now = strtotime('now');
+        $literal = new EasyRdf_Literal_DateTime();
+        $check = strtotime(strval($literal));
+        $this->assertLessThan(2, $check-$now);
+    }
+
+    public function testConstructFromDateTimeBST()
+    {
+        $dt = new DateTime('2010-09-08T07:06:05+0100');
+        $literal = new EasyRdf_Literal_DateTime($dt);
+        $this->assertStringEquals('2010-09-08T07:06:05+01:00', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertEquals($dt, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+    public function testConstructFromDateTimeUTC()
+    {
+        $dt = new DateTime('2010-09-08T07:06:05Z');
+        $literal = new EasyRdf_Literal_DateTime($dt);
+        $this->assertStringEquals('2010-09-08T07:06:05Z', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertEquals($dt, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+    public function testParseUTC()
+    {
+        $literal = EasyRdf_Literal_DateTime::parse('Mon 18 Jul 2011 18:45:43 UTC');
+        $this->assertStringEquals('2011-07-18T18:45:43Z', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+    public function testParseBST()
+    {
+        $literal = EasyRdf_Literal_DateTime::parse('Mon 18 Jul 2011 18:45:43 BST');
+        $this->assertStringEquals('2011-07-18T18:45:43+01:00', $literal);
+        $this->assertClass('DateTime', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+
+
+    public function setUp()
+    {
+        $this->dt = new EasyRdf_Literal_DateTime('2010-09-08T07:06:05Z');
+    }
+
+    public function testFormat()
+    {
+        $this->assertSame(
+            'Wed, 08 Sep 10 07:06:05 +0000',
+            $this->dt->format(DateTime::RFC822)
+        );
+    }
+
+    public function testYear()
+    {
+        $this->assertSame(2010, $this->dt->year());
+    }
+
+    public function testMonth()
+    {
+        $this->assertSame(9, $this->dt->month());
+    }
+
+    public function testDay()
+    {
+        $this->assertSame(8, $this->dt->day());
+    }
+
+    public function testHour()
+    {
+        $this->assertSame(7, $this->dt->hour());
+    }
+
+    public function testMin()
+    {
+        $this->assertSame(6, $this->dt->min());
+    }
+
+    public function testSec()
+    {
+        $this->assertSame(5, $this->dt->sec());
+    }
+
+    public function testToString()
+    {
+        $this->assertStringEquals(
+            '2010-09-08T07:06:05Z',
+            $this->dt
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/DecimalTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_DecimalTest extends EasyRdf_TestCase
+{
+    public function testConstruct15()
+    {
+        $literal = new EasyRdf_Literal_Decimal(1.5);
+        $this->assertClass('EasyRdf_Literal_Decimal', $literal);
+        $this->assertStringEquals('1.5', $literal);
+        $this->assertInternalType('float', $literal->getValue());
+        $this->assertSame(1.5, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:decimal', $literal->getDatatype());
+    }
+
+    public function testConstructString100()
+    {
+        $literal = new EasyRdf_Literal_Decimal('100.00');
+        $this->assertClass('EasyRdf_Literal_Decimal', $literal);
+        $this->assertStringEquals('100.00', $literal);
+        $this->assertInternalType('float', $literal->getValue());
+        $this->assertSame(100.0, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:decimal', $literal->getDatatype());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/HTMLTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_HTMLTest extends EasyRdf_TestCase
+{
+    public function testConstruct()
+    {
+        $literal = new EasyRdf_Literal_HTML('<p>Hello World</p>');
+        $this->assertClass('EasyRdf_Literal_HTML', $literal);
+        $this->assertStringEquals('<p>Hello World</p>', $literal);
+        $this->assertInternalType('string', $literal->getValue());
+        $this->assertSame('<p>Hello World</p>', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('rdf:HTML', $literal->getDatatype());
+    }
+
+    public function testStripTags()
+    {
+        $literal = new EasyRdf_Literal_HTML('<p>Hello World</p>');
+        $this->assertSame('Hello World', $literal->stripTags());
+    }
+
+    public function testStripTagsWithAllowable()
+    {
+        $literal = new EasyRdf_Literal_HTML(
+            '<script src="foo"></script><p>Hello World</p><foo>'
+        );
+        $this->assertSame(
+            '<p>Hello World</p>',
+            $literal->stripTags('<p>')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/HexBinaryTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2012-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_HexBinaryTest extends EasyRdf_TestCase
+{
+    public function setup()
+    {
+        // Reset to built-in parsers
+        EasyRdf_Format::registerParser('ntriples', 'EasyRdf_Parser_Ntriples');
+        EasyRdf_Format::registerParser('rdfxml', 'EasyRdf_Parser_RdfXml');
+        EasyRdf_Format::registerParser('turtle', 'EasyRdf_Parser_Turtle');
+    }
+
+    public function testConstruct()
+    {
+        $literal = new EasyRdf_Literal_HexBinary('48656C6C6F');
+        $this->assertStringEquals('48656C6C6F', $literal);
+        $this->assertInternalType('string', $literal->getValue());
+        $this->assertSame('48656C6C6F', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:hexBinary', $literal->getDatatype());
+        $this->assertSame('Hello', $literal->toBinary());
+    }
+
+    public function testConstructLowercase()
+    {
+        $literal = new EasyRdf_Literal_HexBinary('48656c6C6f');
+        $this->assertSame('48656C6C6F', $literal->getValue());
+        $this->assertStringEquals('48656C6C6F', $literal);
+        $this->assertSame('Hello', $literal->toBinary());
+    }
+
+    public function testContructInvalid()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Literal of type xsd:hexBinary contains non-hexadecimal characters'
+        );
+        $literal = new EasyRdf_Literal_HexBinary('48FZ');
+    }
+
+    public function testFromBinary()
+    {
+        $literal = EasyRdf_Literal_HexBinary::fromBinary(
+            '<?xml version="1.0" encoding="UTF-8"?>'
+        );
+        $this->assertSame('xsd:hexBinary', $literal->getDatatype());
+        $this->assertStringEquals(
+            '3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E',
+            $literal
+        );
+    }
+
+    public function testToRdfPhp()
+    {
+        $literal = new EasyRdf_Literal_HexBinary('48656C6C6F');
+        $this->assertSame(
+            array(
+                'type' => 'literal',
+                'value' => '48656C6C6F',
+                'datatype' => 'http://www.w3.org/2001/XMLSchema#hexBinary'
+            ),
+            $literal->toRdfPhp()
+        );
+    }
+
+    public function testDumpValue()
+    {
+        $literal = new EasyRdf_Literal_HexBinary('48656C6C6F');
+        $this->assertSame(
+            '"48656C6C6F"^^xsd:hexBinary',
+            $literal->dumpValue('text')
+        );
+    }
+
+    public function testParseWebId()
+    {
+        $graph = new EasyRdf_Graph();
+        $graph->parseFile(fixturePath('webid.ttl'), 'turtle');
+        $me = $graph->resource('http://www.example.com/myfoaf#me');
+        $modulus = $me->get('cert:key')->get('cert:modulus');
+        $this->assertStringEquals(
+            'CB24ED85D64D794B69C701C186ACC059501E856000F661C93204D8380E07191C'.
+            '5C8B368D2AC32A428ACB970398664368DC2A867320220F755E99CA2EECDAE62E'.
+            '8D15FB58E1B76AE59CB7ACE8838394D59E7250B449176E51A494951A1C366C62'.
+            '17D8768D682DDE78DD4D55E613F8839CF275D4C8403743E7862601F3C49A6366'.
+            'E12BB8F498262C3C77DE19BCE40B32F89AE62C3780F5B6275BE337E2B3153AE2'.
+            'BA72A9975AE71AB724649497066B660FCF774B7543D980952D2E8586200EDA41'.
+            '58B014E75465D91ECF93EFC7AC170C11FC7246FC6DED79C37780000AC4E079F6'.
+            '71FD4F207AD770809E0E2D7B0EF5493BEFE73544D8E1BE3DDDB52455C61391A1',
+            $modulus
+        );
+        $this->assertInternalType('string', $modulus->getValue());
+        $this->assertSame(null, $modulus->getLang());
+        $this->assertSame('xsd:hexBinary', $modulus->getDatatype());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/IntegerTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2011-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_IntegerTest extends EasyRdf_TestCase
+{
+    public function testConstruct0()
+    {
+        $literal = new EasyRdf_Literal_Integer(0);
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertStringEquals('0', $literal);
+        $this->assertInternalType('int', $literal->getValue());
+        $this->assertSame(0, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testConstruct1()
+    {
+        $literal = new EasyRdf_Literal_Integer(1);
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertStringEquals('1', $literal);
+        $this->assertInternalType('int', $literal->getValue());
+        $this->assertSame(1, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testConstructString100()
+    {
+        $literal = new EasyRdf_Literal_Integer('100');
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertStringEquals('100', $literal);
+        $this->assertInternalType('int', $literal->getValue());
+        $this->assertSame(100, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testConstructString0100()
+    {
+        $literal = new EasyRdf_Literal_Integer('0100');
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertStringEquals('0100', $literal);
+        $this->assertInternalType('int', $literal->getValue());
+        $this->assertSame(100, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Literal/XMLTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Literal_XMLTest extends EasyRdf_TestCase
+{
+    public function testConstruct()
+    {
+        $literal = new EasyRdf_Literal_XML('<tag>Hello World</tag>');
+        $this->assertClass('EasyRdf_Literal_XML', $literal);
+        $this->assertStringEquals('<tag>Hello World</tag>', $literal);
+        $this->assertInternalType('string', $literal->getValue());
+        $this->assertSame('<tag>Hello World</tag>', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('rdf:XMLLiteral', $literal->getDatatype());
+    }
+
+    public function testDomParse()
+    {
+        $literal = new EasyRdf_Literal_XML('<tag>Hello World</tag>');
+        $dom = $literal->domParse();
+        $this->assertClass('DOMDocument', $dom);
+        $this->assertSame(
+            "<?xml version=\"1.0\"?>\n<tag>Hello World</tag>\n",
+            $dom->saveXML()
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/LiteralTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,502 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class MyDatatype_Class extends EasyRdf_Literal
+{
+    public function __toString()
+    {
+        return "!".strval($this->value)."!";
+    }
+}
+
+class EasyRdf_LiteralTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        EasyRdf_Namespace::set('ex', 'http://www.example.com/');
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Literal::deleteDatatypeMapping('ex:mytype');
+        EasyRdf_Namespace::delete('ex');
+    }
+
+    public function testCreate()
+    {
+        $literal = EasyRdf_Literal::create('Rat');
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testCreateWithLanguage()
+    {
+        $literal = EasyRdf_Literal::create('Rat', 'en');
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame('en', $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testCreateWithDatatype()
+    {
+        $literal = EasyRdf_Literal::create(1, null, 'xsd:integer');
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertSame(1, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testCreateWithLanguageAndDatatype()
+    {
+        $literal = EasyRdf_Literal::create('Rat', 'en', 'http://www.w3.org/2001/XMLSchema#string');
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:string', $literal->getDatatype());
+    }
+
+    public function testCreateIntegerLiteralWithLanguage()
+    {
+        $literal = EasyRdf_Literal::create(10, 'en');
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('10', $literal->getValue());
+        $this->assertSame('en', $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testCreateWithObjectDatatype()
+    {
+        $datatype = new EasyRdf_ParsedUri('http://www.w3.org/2001/XMLSchema#integer');
+        $literal = EasyRdf_Literal::create(1, null, $datatype);
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertSame(1, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testCreateWithUriDatatype()
+    {
+        $literal = EasyRdf_Literal::create(
+            1,
+            null,
+            'http://www.w3.org/2001/XMLSchema#integer'
+        );
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertSame(1, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testCreateWithUnshortenableUriDatatype()
+    {
+        $literal = EasyRdf_Literal::create(
+            1,
+            null,
+            'http://example.com/integer'
+        );
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('1', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testCreateWithAssociativeArray()
+    {
+        $literal = EasyRdf_Literal::create(array('value' => 'Rat'));
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testCreateWithAssociativeArrayWithLang()
+    {
+        $literal = EasyRdf_Literal::create(array( 'value' => 'Rat', 'lang' => 'en'));
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame(null, $literal->getDatatype());
+        $this->assertSame('en', $literal->getLang());
+    }
+
+    public function testCreateWithAssociativeArrayWithXmlLang()
+    {
+        $literal = EasyRdf_Literal::create(array( 'value' => 'Rattus', 'xml:lang' => 'fr'));
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rattus', $literal->getValue());
+        $this->assertSame(null, $literal->getDatatype());
+        $this->assertSame('fr', $literal->getLang());
+    }
+
+    public function testCreateWithAssociativeArrayWithDatatype()
+    {
+        $literal = EasyRdf_Literal::create(array('value' => 'Rat','datatype' => 'xsd:string'));
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame('xsd:string', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateWithInteger()
+    {
+        $literal = EasyRdf_Literal::create(10);
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertSame(10, $literal->getValue());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateWithFloat()
+    {
+        $literal = EasyRdf_Literal::create(1.5);
+        $this->assertClass('EasyRdf_Literal_Decimal', $literal);
+        $this->assertSame(1.5, $literal->getValue());
+        $this->assertSame('xsd:decimal', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateWithBooleanTrue()
+    {
+        $literal = EasyRdf_Literal::create(true);
+        $this->assertClass('EasyRdf_Literal_Boolean', $literal);
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateWithBooleanFalse()
+    {
+        $literal = EasyRdf_Literal::create(false);
+        $this->assertClass('EasyRdf_Literal_Boolean', $literal);
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateWithDateTime()
+    {
+        $dt = new DateTime('2010-09-08T07:06:05Z');
+        $literal = EasyRdf_Literal::create($dt);
+        $this->assertStringEquals('2010-09-08T07:06:05Z', $literal);
+        $this->assertEquals($dt, $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:dateTime', $literal->getDatatype());
+    }
+
+    public function testCreateConvertToBooleanTrue()
+    {
+        $literal = EasyRdf_Literal::create(1, null, 'xsd:boolean');
+        $this->assertClass('EasyRdf_Literal_Boolean', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(true, $literal->getValue());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateConvertToBooleanFalse()
+    {
+        $literal = EasyRdf_Literal::create(0, null, 'xsd:boolean');
+        $this->assertClass('EasyRdf_Literal_Boolean', $literal);
+        $this->assertInternalType('bool', $literal->getValue());
+        $this->assertSame(false, $literal->getValue());
+        $this->assertSame('xsd:boolean', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateConvertToInteger()
+    {
+        $literal = EasyRdf_Literal::create('100.00', null, 'xsd:integer');
+        $this->assertClass('EasyRdf_Literal_Integer', $literal);
+        $this->assertInternalType('integer', $literal->getValue());
+        $this->assertSame(100, $literal->getValue());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateConvertToDecimal()
+    {
+        $literal = EasyRdf_Literal::create('1', null, 'xsd:decimal');
+        $this->assertClass('EasyRdf_Literal_Decimal', $literal);
+        $this->assertInternalType('float', $literal->getValue());
+        $this->assertSame(1.0, $literal->getValue());
+        $this->assertSame('xsd:decimal', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateConvertToString()
+    {
+        $literal = EasyRdf_Literal::create(true, null, 'xsd:string');
+        $this->assertClass('EasyRdf_Literal', $literal);
+        $this->assertInternalType('string', $literal->getValue());
+        # Hmm, not sure about this, but PHP does the conversion not me:
+        $this->assertSame('1', $literal->getValue());
+        $this->assertSame('xsd:string', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testConstruct()
+    {
+        $literal = new EasyRdf_Literal('Rat');
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testConstructWithLanguage()
+    {
+        $literal = new EasyRdf_Literal('Rat', 'en');
+        $this->assertSame('Rat', $literal->getValue());
+        $this->assertSame('en', $literal->getLang());
+        $this->assertSame(null, $literal->getDatatype());
+    }
+
+    public function testConstructWithDatatype()
+    {
+        $literal = new EasyRdf_Literal(1, null, 'xsd:integer');
+        $this->assertSame('1', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testConstructWithObjectDatatype()
+    {
+        $datatype = new EasyRdf_ParsedUri('http://www.w3.org/2001/XMLSchema#integer');
+        $literal = new EasyRdf_Literal(1, null, $datatype);
+        $this->assertSame('1', $literal->getValue());
+        $this->assertSame(null, $literal->getLang());
+        $this->assertSame('xsd:integer', $literal->getDatatype());
+    }
+
+    public function testGetDatatypeUri()
+    {
+        $literal = EasyRdf_Literal::create(1);
+        $this->assertSame(
+            'http://www.w3.org/2001/XMLSchema#integer',
+            $literal->getDatatypeUri()
+        );
+    }
+
+    public function testToString()
+    {
+        $literal = EasyRdf_Literal::create('Rat');
+        $this->assertSame('Rat', strval($literal));
+    }
+
+    public function testToRdfPhp()
+    {
+        $literal = EasyRdf_Literal::create('Rat');
+        $this->assertSame(
+            array(
+               'type' => 'literal',
+               'value' => 'Rat'
+            ),
+            $literal->toRdfPhp()
+        );
+    }
+
+    public function testToRdfPhpWithLang()
+    {
+        $literal = new EasyRdf_Literal('Chat', 'fr');
+        $this->assertSame(
+            array(
+               'type' => 'literal',
+               'value' => 'Chat',
+               'lang' => 'fr'
+            ),
+            $literal->toRdfPhp()
+        );
+    }
+
+    public function testToRdfPhpWithDatatype()
+    {
+        $literal = EasyRdf_Literal::create(44);
+        $this->assertSame(
+            array(
+               'type' => 'literal',
+               'value' => '44',
+               'datatype' => 'http://www.w3.org/2001/XMLSchema#integer'
+            ),
+            $literal->toRdfPhp()
+        );
+    }
+
+    public function testDumpValue()
+    {
+        $literal = EasyRdf_Literal::create("hello & world");
+        $this->assertSame(
+            '"hello & world"',
+            $literal->dumpValue('text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;hello &amp; world&quot;</span>",
+            $literal->dumpValue('html')
+        );
+    }
+
+    public function testDumpValueWithLanguage()
+    {
+        $literal = new EasyRdf_Literal('Nick', 'en');
+        $this->assertSame(
+            '"Nick"@en',
+            $literal->dumpValue('text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;Nick&quot;@en</span>",
+            $literal->dumpValue('html')
+        );
+    }
+
+    public function testDumpValueWithDatatype()
+    {
+        $literal = EasyRdf_Literal::create(1, null, 'xsd:integer');
+        $this->assertSame(
+            '"1"^^xsd:integer',
+            $literal->dumpValue('text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;1&quot;^^xsd:integer</span>",
+            $literal->dumpValue('html')
+        );
+    }
+
+    public function testConstructCustomClass()
+    {
+        EasyRdf_Literal::setDatatypeMapping('ex:mytype', 'MyDatatype_Class');
+        $literal = new MyDatatype_Class('foobar');
+        $this->assertClass('MyDatatype_Class', $literal);
+        $this->assertStringEquals('!foobar!', $literal);
+        $this->assertSame('foobar', $literal->getValue());
+        $this->assertSame('ex:mytype', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testCreateCustomClass()
+    {
+        EasyRdf_Literal::setDatatypeMapping('ex:mytype', 'MyDatatype_Class');
+        $literal = EasyRdf_Literal::create('foobar', null, 'ex:mytype');
+        $this->assertClass('MyDatatype_Class', $literal);
+        $this->assertStringEquals('!foobar!', $literal);
+        $this->assertSame('foobar', $literal->getValue());
+        $this->assertSame('ex:mytype', $literal->getDatatype());
+        $this->assertSame(null, $literal->getLang());
+    }
+
+    public function testSetDatatypeMappingNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping(null, 'MyDatatype_Class');
+    }
+
+    public function testSetDatatypeMappingEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping('', 'MyDatatype_Class');
+    }
+
+    public function testSetDatatypeMappingNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping(array(), 'MyDatatype_Class');
+    }
+
+    public function testSetDatatypeMappingClassNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping('ex:mytype', null);
+    }
+
+    public function testSetDatatypeMappingClassEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping('ex:mytype', '');
+    }
+
+    public function testSetDatatypeMappingClassNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::setDatatypeMapping('ex:mytype', array());
+    }
+
+    public function testDeleteDatatypeMappingNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::deleteDatatypeMapping(null);
+    }
+
+    public function testDeleteDatatypeMappingEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::deleteDatatypeMapping('');
+    }
+
+    public function testDeleteDatatypeMappingNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$datatype should be a string and cannot be null or empty'
+        );
+        EasyRdf_Literal::deleteDatatypeMapping(array());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/NamespaceTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,625 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_NamespaceTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        EasyRdf_Namespace::setDefault(null);
+        $this->graph = new EasyRdf_Graph();
+        $this->resource = $this->graph->resource('http://xmlns.com/foaf/0.1/name');
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Namespace::delete('po');
+        EasyRdf_Namespace::reset();
+    }
+
+    public function testNamespaces()
+    {
+        $ns = EasyRdf_Namespace::namespaces();
+        $this->assertSame('http://purl.org/dc/terms/', $ns['dc']);
+        $this->assertSame('http://xmlns.com/foaf/0.1/', $ns['foaf']);
+    }
+
+    public function testGetDcNamespace()
+    {
+        $this->assertSame(
+            'http://purl.org/dc/terms/',
+            EasyRdf_Namespace::get('dc')
+        );
+    }
+
+    public function testGetFoafNamespace()
+    {
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/',
+            EasyRdf_Namespace::get('foaf')
+        );
+    }
+
+    public function testGetRdfNamespace()
+    {
+        $this->assertSame(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+            EasyRdf_Namespace::get('rdf')
+        );
+    }
+
+    public function testGetRdfsNamespace()
+    {
+        $this->assertSame(
+            'http://www.w3.org/2000/01/rdf-schema#',
+            EasyRdf_Namespace::get('rdfs')
+        );
+    }
+
+    public function testGetXsdNamespace()
+    {
+        $this->assertSame(
+            'http://www.w3.org/2001/XMLSchema#',
+            EasyRdf_Namespace::get('xsd')
+        );
+    }
+
+    public function testGetUpperCaseFoafNamespace()
+    {
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/',
+            EasyRdf_Namespace::get('FOAF')
+        );
+    }
+
+    public function testGetNullNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::get(null);
+    }
+
+    public function testGetEmptyNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::get('');
+    }
+
+    public function testGetNonStringNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::get(array());
+    }
+
+    public function testGetNonAlphanumeric()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should only contain alpha-numeric characters'
+        );
+        EasyRdf_Namespace::get('/K.O/');
+    }
+
+    public function testAddNamespace()
+    {
+        EasyRdf_Namespace::set('po', 'http://purl.org/ontology/po/');
+        $this->assertSame(
+            'http://purl.org/ontology/po/',
+            EasyRdf_Namespace::get('po')
+        );
+    }
+
+    public function testAddUppercaseNamespace()
+    {
+        EasyRdf_Namespace::set('PO', 'http://purl.org/ontology/po/');
+        $this->assertSame(
+            'http://purl.org/ontology/po/',
+            EasyRdf_Namespace::get('po')
+        );
+    }
+
+    public function testAddNamespaceShortNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set(null, 'http://purl.org/ontology/ko/');
+    }
+
+    public function testAddNamespaceShortEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set('', 'http://purl.org/ontology/ko/');
+    }
+
+    public function testAddNamespaceShortNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set(array(), 'http://purl.org/ontology/ko/');
+    }
+
+    public function testAddNamespaceShortNonAlphanumeric()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should only contain alpha-numeric characters'
+        );
+        EasyRdf_Namespace::set('/K.O/', 'http://purl.org/ontology/ko/');
+    }
+
+    public function testAddNamespaceLongNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$long should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set('ko', null);
+    }
+
+    public function testAddNamespaceLongEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$long should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set('ko', '');
+    }
+
+    public function testAddNamespaceLongNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$long should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::set('ko', array());
+    }
+
+    public function testDeleteNamespace()
+    {
+        EasyRdf_Namespace::set('po', 'http://purl.org/ontology/po/');
+        $this->assertNotNull(EasyRdf_Namespace::get('po'));
+        EasyRdf_Namespace::delete('po');
+        $this->assertNull(EasyRdf_Namespace::get('po'));
+    }
+
+    public function testDeleteEmptyNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::delete('');
+    }
+
+    public function testDeleteNullNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::delete(null);
+    }
+
+    public function testDeleteNonStringNamespace()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$prefix should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::delete($this);
+    }
+
+    public function testSetDefaultUri()
+    {
+        EasyRdf_Namespace::setDefault('http://ogp.me/ns#');
+        $this->assertSame(
+            'http://ogp.me/ns#',
+            EasyRdf_Namespace::getDefault()
+        );
+    }
+
+    public function testSetDefaultPrefix()
+    {
+        EasyRdf_Namespace::setDefault('foaf');
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/',
+            EasyRdf_Namespace::getDefault()
+        );
+    }
+
+    public function testSetDefaultEmpty()
+    {
+        EasyRdf_Namespace::setDefault('http://ogp.me/ns#');
+        EasyRdf_Namespace::setDefault('');
+        $this->assertSame(null, EasyRdf_Namespace::getDefault());
+    }
+
+    public function testSetDefaultUnknown()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'Unable to set default namespace to unknown prefix: foobar'
+        );
+        EasyRdf_Namespace::setDefault('foobar');
+    }
+
+    public function testSplitUriFoafName()
+    {
+        $this->assertSame(
+            array('foaf', 'name'),
+            EasyRdf_Namespace::splitUri('http://xmlns.com/foaf/0.1/name')
+        );
+    }
+
+    public function testSplitUriResource()
+    {
+        $this->assertSame(
+            array('foaf','name'),
+            EasyRdf_Namespace::splitUri($this->resource)
+        );
+    }
+
+    public function testSlitUriUnknown()
+    {
+        $this->assertSame(
+            null,
+            EasyRdf_Namespace::splitUri('http://example.com/ns/foo/bar')
+        );
+    }
+
+    public function testSplitUriAndCreateOneUnknown()
+    {
+        $this->assertSame(
+            array('ns0', 'bar'),
+            EasyRdf_Namespace::splitUri('http://example.com/ns/foo/bar', true)
+        );
+    }
+
+    public function testSplitUriAndCreateTwice()
+    {
+        $this->assertSame(
+            array('ns0', 'bar'),
+            EasyRdf_Namespace::splitUri('http://example.com/ns/foo/bar', true)
+        );
+        $this->assertSame(
+            array('ns0', 'bar'),
+            EasyRdf_Namespace::splitUri('http://example.com/ns/foo/bar', true)
+        );
+    }
+
+    public function testSplitUriAndCreateTwoUnknown()
+    {
+        $this->assertSame(
+            array('ns0', 'bar'),
+            EasyRdf_Namespace::splitUri('http://example1.org/ns/foo/bar', true)
+        );
+        $this->assertSame(
+            array('ns1', 'bar'),
+            EasyRdf_Namespace::splitUri('http://example2.org/ns/foo/bar', true)
+        );
+    }
+
+    public function testSplitUriUnsplitable()
+    {
+        $this->assertSame(
+            null,
+            EasyRdf_Namespace::splitUri('http://example.com/foo/', true)
+        );
+    }
+
+    public function testSplitUriNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::splitUri(null);
+    }
+
+    public function testSplitUriEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::splitUri('');
+    }
+
+    public function testSplitUriNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string or EasyRdf_Resource'
+        );
+        EasyRdf_Namespace::splitUri($this);
+    }
+
+
+    public function testShortenFoafName()
+    {
+        $this->assertSame(
+            'foaf:name',
+            EasyRdf_Namespace::shorten('http://xmlns.com/foaf/0.1/name')
+        );
+    }
+
+    public function testShortenResource()
+    {
+        $this->assertSame('foaf:name', EasyRdf_Namespace::shorten($this->resource));
+    }
+
+    public function testShortenUnknown()
+    {
+        $this->assertSame(
+            null,
+            EasyRdf_Namespace::shorten('http://example.com/ns/foo/bar')
+        );
+    }
+
+    public function testShortenAndCreateOneUnknown()
+    {
+        $this->assertSame(
+            'ns0:bar',
+            EasyRdf_Namespace::shorten('http://example.com/ns/foo/bar', true)
+        );
+    }
+
+    public function testShortenAndCreateTwoUnknown()
+    {
+        $this->assertSame(
+            'ns0:bar',
+            EasyRdf_Namespace::shorten('http://example.com/ns/foo/bar', true)
+        );
+        $this->assertSame(
+            'ns1:bar',
+            EasyRdf_Namespace::shorten('http://example.org/ns/foo/bar', true)
+        );
+    }
+
+    public function testShortenUnshortenable()
+    {
+        $this->assertSame(
+            null,
+            EasyRdf_Namespace::shorten('http://example.com/foo/', true)
+        );
+    }
+
+    public function testShortenNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::shorten(null);
+    }
+
+    public function testShortenEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::shorten('');
+    }
+
+    public function testShortenNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string or EasyRdf_Resource'
+        );
+        EasyRdf_Namespace::shorten($this);
+    }
+
+    public function testPrefixOfUriFoafName()
+    {
+        $this->assertSame(
+            'foaf',
+            EasyRdf_Namespace::prefixOfUri('http://xmlns.com/foaf/0.1/name')
+        );
+    }
+
+    public function testrefixOfUriForResource()
+    {
+        $this->assertSame(
+            'foaf',
+            EasyRdf_Namespace::prefixOfUri($this->resource)
+        );
+    }
+
+    public function testPrefixOfUnknownUrl()
+    {
+        $this->assertSame(
+            null,
+            EasyRdf_Namespace::prefixOfUri('http://www.aelius.com/njh/')
+        );
+    }
+
+    public function testPrefixOfUriNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::prefixOfUri(null);
+    }
+
+    public function testPrefixOfUriEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri cannot be null or empty'
+        );
+        EasyRdf_Namespace::prefixOfUri('');
+    }
+
+    public function testPrefixOfUriNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string or EasyRdf_Resource'
+        );
+        EasyRdf_Namespace::prefixOfUri(array());
+    }
+
+    public function testExpandFoafName()
+    {
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/name',
+            EasyRdf_Namespace::expand('foaf:name')
+        );
+    }
+
+    public function testExpandZero()
+    {
+        $this->assertSame(
+            '0',
+            EasyRdf_Namespace::expand('0')
+        );
+    }
+
+    public function testExpandA()
+    {
+        $this->assertSame(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
+            EasyRdf_Namespace::expand('a')
+        );
+    }
+
+    public function testExpandFoafDoapProgrammingLanguage()
+    {
+        $this->assertSame(
+            'http://usefulinc.com/ns/doap#programming-language',
+            EasyRdf_Namespace::expand('doap:programming-language')
+        );
+    }
+
+    public function testExpandWithDefaultUri()
+    {
+        EasyRdf_Namespace::setDefault('http://ogp.me/ns#');
+        $this->assertSame(
+            'http://ogp.me/ns#title',
+            EasyRdf_Namespace::expand('title')
+        );
+    }
+
+    public function testExpandWithDefaultPrefix()
+    {
+        EasyRdf_Namespace::setDefault('foaf');
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/name',
+            EasyRdf_Namespace::expand('name')
+        );
+    }
+
+    public function testExpandZeroWithDefaultPrefix()
+    {
+        EasyRdf_Namespace::setDefault('foaf');
+        $this->assertSame(
+            'http://xmlns.com/foaf/0.1/0',
+            EasyRdf_Namespace::expand('0')
+        );
+    }
+
+    public function testExpandWithoutDefault()
+    {
+        EasyRdf_Namespace::setDefault(null);
+        $this->assertSame(
+            'unknown',
+            EasyRdf_Namespace::expand('unknown')
+        );
+    }
+
+    public function testExpandExpanded()
+    {
+        $this->assertSame(
+            'http://www.aelius.com/njh/',
+            EasyRdf_Namespace::expand('http://www.aelius.com/njh/')
+        );
+    }
+
+    public function testExpandURN()
+    {
+        $this->assertSame(
+            'urn:isbn:0451450523',
+            EasyRdf_Namespace::expand('urn:isbn:0451450523')
+        );
+    }
+
+    public function testExpandNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$shortUri should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::expand(null);
+    }
+
+    public function testExpandEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$shortUri should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::expand('');
+    }
+
+    public function testExpandNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$shortUri should be a string and cannot be null or empty'
+        );
+        EasyRdf_Namespace::expand($this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/ParsedUriTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,680 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_ParsedUriTest extends EasyRdf_TestCase
+{
+    public function setup()
+    {
+        $this->baseUri = new EasyRdf_ParsedUri(
+            'http://a/b/c/d;p?q'
+        );
+    }
+
+    public function testConstruct()
+    {
+        $uri = new EasyRdf_ParsedUri(
+            array(
+                'scheme' => 'http',
+                'authority' => 'example.com',
+                'path' => '/foo/bar',
+                'query' => 'k=v',
+                'fragment' => 'frag'
+            )
+        );
+        $this->assertStringEquals('http://example.com/foo/bar?k=v#frag', $uri);
+    }
+
+    public function testParseHttp()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $this->assertSame('http', $uri->getScheme());
+        $this->assertSame('www.ietf.org', $uri->getAuthority());
+        $this->assertSame('/rfc/rfc2396.txt', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseFile()
+    {
+        $uri = new EasyRdf_ParsedUri('file:///etc/hosts');
+        $this->assertSame('file', $uri->getScheme());
+        $this->assertSame('', $uri->getAuthority());
+        $this->assertSame('/etc/hosts', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('file:///etc/hosts', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseFtp()
+    {
+        $uri = new EasyRdf_ParsedUri('ftp://ftp.is.co.za/rfc/rfc1808.txt');
+        $this->assertSame('ftp', $uri->getScheme());
+        $this->assertSame('ftp.is.co.za', $uri->getAuthority());
+        $this->assertSame('/rfc/rfc1808.txt', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('ftp://ftp.is.co.za/rfc/rfc1808.txt', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseLdap()
+    {
+        $uri = new EasyRdf_ParsedUri('ldap://[2001:db8::7]/c=GB?objectClass?one');
+        $this->assertSame('ldap', $uri->getScheme());
+        $this->assertSame('[2001:db8::7]', $uri->getAuthority());
+        $this->assertSame('/c=GB', $uri->getPath());
+        $this->assertSame('objectClass?one', $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('ldap://[2001:db8::7]/c=GB?objectClass?one', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseMailto()
+    {
+        $uri = new EasyRdf_ParsedUri('mailto:John.Doe@example.com');
+        $this->assertSame('mailto', $uri->getScheme());
+        $this->assertSame(null, $uri->getAuthority());
+        $this->assertSame('John.Doe@example.com', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('mailto:John.Doe@example.com', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseNews()
+    {
+        $uri = new EasyRdf_ParsedUri('news:comp.infosystems.www.servers.unix');
+        $this->assertSame('news', $uri->getScheme());
+        $this->assertSame(null, $uri->getAuthority());
+        $this->assertSame('comp.infosystems.www.servers.unix', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('news:comp.infosystems.www.servers.unix', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseTel()
+    {
+        $uri = new EasyRdf_ParsedUri('tel:+1-816-555-1212');
+        $this->assertSame('tel', $uri->getScheme());
+        $this->assertSame(null, $uri->getAuthority());
+        $this->assertSame('+1-816-555-1212', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('tel:+1-816-555-1212', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseTelnet()
+    {
+        $uri = new EasyRdf_ParsedUri('telnet://192.0.2.16:80/');
+        $this->assertSame('telnet', $uri->getScheme());
+        $this->assertSame('192.0.2.16:80', $uri->getAuthority());
+        $this->assertSame('/', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('telnet://192.0.2.16:80/', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseUrn()
+    {
+        $uri = new EasyRdf_ParsedUri('urn:oasis:names:specification:docbook:dtd:xml:4.1.2');
+        $this->assertSame('urn', $uri->getScheme());
+        $this->assertSame(null, $uri->getAuthority());
+        $this->assertSame('oasis:names:specification:docbook:dtd:xml:4.1.2', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('urn:oasis:names:specification:docbook:dtd:xml:4.1.2', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseRelative()
+    {
+        $uri = new EasyRdf_ParsedUri('/foo/bar');
+        $this->assertSame(null, $uri->getScheme());
+        $this->assertSame(null, $uri->getAuthority());
+        $this->assertSame('/foo/bar', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('/foo/bar', $uri);
+        $this->assertTrue($uri->isRelative());
+    }
+
+    public function testParseEmptyFragment()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo#');
+        $this->assertSame('http', $uri->getScheme());
+        $this->assertSame('www.example.com', $uri->getAuthority());
+        $this->assertSame('/foo', $uri->getPath());
+        $this->assertSame(null, $uri->getQuery());
+        $this->assertSame('', $uri->getFragment());
+        $this->assertStringEquals('http://www.example.com/foo#', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testParseEmptyQuery()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo?');
+        $this->assertSame('http', $uri->getScheme());
+        $this->assertSame('www.example.com', $uri->getAuthority());
+        $this->assertSame('/foo', $uri->getPath());
+        $this->assertSame('', $uri->getQuery());
+        $this->assertSame(null, $uri->getFragment());
+        $this->assertStringEquals('http://www.example.com/foo?', $uri);
+        $this->assertTrue($uri->isAbsolute());
+    }
+
+    public function testNormaliseDotSegments()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo/././bar/.');
+        $uri->normalise();
+        $this->assertSame('/foo/bar/', $uri->getPath());
+    }
+
+    public function testNormaliseInitalDot()
+    {
+        $uri = new EasyRdf_ParsedUri('./foo/bar');
+        $uri->normalise();
+        $this->assertSame('foo/bar', $uri->getPath());
+    }
+
+    public function testNormaliseOneParent()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo/bar/../file');
+        $uri->normalise();
+        $this->assertSame('/foo/file', $uri->getPath());
+    }
+
+    public function testNormaliseTwoParents()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo/bar/../../file');
+        $uri->normalise();
+        $this->assertSame('/file', $uri->getPath());
+    }
+
+    public function testNormaliseThreeParents()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.example.com/foo/bar/../../../file');
+        $uri->normalise();
+        $this->assertSame('/file', $uri->getPath());
+    }
+
+    public function testNormaliseMixed()
+    {
+        $uri = new EasyRdf_ParsedUri('http://example.com/a/b/../c/./d/.');
+        $uri->normalise();
+        $this->assertStringEquals('http://example.com/a/c/d/', $uri);
+    }
+
+    public function testResolve()
+    {
+        $base = new EasyRdf_ParsedUri('http://example.com');
+        $this->assertStringEquals(
+            "http://example.com/filename",
+            $base->resolve("filename")
+        );
+    }
+
+    public function testToString()
+    {
+        $uri = new EasyRdf_ParsedUri('http://example.com/foo/bar?q#f');
+        $this->assertSame(
+            "http://example.com/foo/bar?q#f",
+            $uri->toString()
+        );
+    }
+
+    public function testSetScheme()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $uri->setScheme('https');
+        $this->assertStringEquals('https://www.ietf.org/rfc/rfc2396.txt', $uri);
+    }
+
+    public function testSetAuthority()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $uri->setAuthority('example.com');
+        $this->assertStringEquals('http://example.com/rfc/rfc2396.txt', $uri);
+    }
+
+    public function testSetPath()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $uri->setPath('/foobar');
+        $this->assertStringEquals('http://www.ietf.org/foobar', $uri);
+    }
+
+    public function testSetQuery()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $uri->setQuery('foo=bar');
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt?foo=bar', $uri);
+    }
+
+    public function testSetQueryEmpty()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt?foo=bar');
+        $uri->setQuery('');
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt?', $uri);
+    }
+
+    public function testSetQueryNull()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt?foo=bar');
+        $uri->setQuery(null);
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt', $uri);
+    }
+
+    public function testSetFragment()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt');
+        $uri->setFragment('foobar');
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt#foobar', $uri);
+    }
+
+    public function testSetFragmentEmpty()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt#foobar');
+        $uri->setFragment('');
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt#', $uri);
+    }
+
+    public function testSetFragmentNull()
+    {
+        $uri = new EasyRdf_ParsedUri('http://www.ietf.org/rfc/rfc2396.txt#foobar');
+        $uri->setFragment(null);
+        $this->assertStringEquals('http://www.ietf.org/rfc/rfc2396.txt', $uri);
+    }
+
+    /**
+     * Tests from RFC3986 Section 5
+     */
+
+    /*  RFC3986 5.4.1 Normal Examples */
+    public function testResolveReferenceUriNormal1()
+    {
+        $this->assertStringEquals(
+            "g:h",
+            $this->baseUri->resolve("g:h")
+        );
+    }
+
+    public function testResolveReferenceUriNormal2()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g",
+            $this->baseUri->resolve("g")
+        );
+    }
+
+    public function testResolveReferenceUriNormal3()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g",
+            $this->baseUri->resolve("./g")
+        );
+    }
+
+    public function testResolveReferenceUriNormal4()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g/",
+            $this->baseUri->resolve("g/")
+        );
+    }
+
+    public function testResolveReferenceUriNormal5()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("/g")
+        );
+    }
+
+    public function testResolveReferenceUriNormal6()
+    {
+        $this->assertStringEquals(
+            "http://g",
+            $this->baseUri->resolve("//g")
+        );
+    }
+
+    public function testResolveReferenceUriNormal7()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/d;p?y",
+            $this->baseUri->resolve("?y")
+        );
+    }
+
+    public function testResolveReferenceUriNormal8()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g?y",
+            $this->baseUri->resolve("g?y")
+        );
+    }
+
+    public function testResolveReferenceUriNormal9()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/d;p?q#s",
+            $this->baseUri->resolve("#s")
+        );
+    }
+
+    public function testResolveReferenceUriNormal10()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g#s",
+            $this->baseUri->resolve("g#s")
+        );
+    }
+
+    public function testResolveReferenceUriNormal11()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g?y#s",
+            $this->baseUri->resolve("g?y#s")
+        );
+    }
+
+    public function testResolveReferenceUriNormal12()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g;x",
+            $this->baseUri->resolve("g;x")
+        );
+    }
+
+    public function testResolveReferenceUriNormal13()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g;x",
+            $this->baseUri->resolve("g;x")
+        );
+    }
+
+    public function testResolveReferenceUriNormal14()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g;x?y#s",
+            $this->baseUri->resolve("g;x?y#s")
+        );
+    }
+
+    public function testResolveReferenceUriNormal15()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/d;p?q",
+            $this->baseUri->resolve("")
+        );
+    }
+
+    public function testResolveReferenceUriNormal16()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/",
+            $this->baseUri->resolve(".")
+        );
+    }
+
+    public function testResolveReferenceUriNormal17()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/",
+            $this->baseUri->resolve("./")
+        );
+    }
+
+    public function testResolveReferenceUriNormal18()
+    {
+        $this->assertStringEquals(
+            "http://a/b/",
+            $this->baseUri->resolve("..")
+        );
+    }
+
+    public function testResolveReferenceUriNormal19()
+    {
+        $this->assertStringEquals(
+            "http://a/b/",
+            $this->baseUri->resolve("../")
+        );
+    }
+
+    public function testResolveReferenceUriNormal20()
+    {
+        $this->assertStringEquals(
+            "http://a/b/g",
+            $this->baseUri->resolve("../g")
+        );
+    }
+
+    public function testResolveReferenceUriNormal21()
+    {
+        $this->assertStringEquals(
+            "http://a/",
+            $this->baseUri->resolve("../..")
+        );
+    }
+
+    public function testResolveReferenceUriNormal22()
+    {
+        $this->assertStringEquals(
+            "http://a/",
+            $this->baseUri->resolve("../../")
+        );
+    }
+
+    public function testResolveReferenceUriNormal23()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("../../g")
+        );
+    }
+
+
+    /* RFC3986 5.4.2 Abnormal Examples */
+    public function testResolveReferenceUriAbnormal1()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("../../../g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal2()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("../../../../g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal3()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("/./g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal4()
+    {
+        $this->assertStringEquals(
+            "http://a/g",
+            $this->baseUri->resolve("/../g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal5()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g.",
+            $this->baseUri->resolve("g.")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal6()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/.g",
+            $this->baseUri->resolve(".g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal7()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g..",
+            $this->baseUri->resolve("g..")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal8()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/..g",
+            $this->baseUri->resolve("..g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal9()
+    {
+        $this->assertStringEquals(
+            "http://a/b/g",
+            $this->baseUri->resolve("./../g")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal10()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g/",
+            $this->baseUri->resolve("./g/.")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal11()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g/h",
+            $this->baseUri->resolve("g/./h")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal12()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/h",
+            $this->baseUri->resolve("g/../h")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal13()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g;x=1/y",
+            $this->baseUri->resolve("g;x=1/./y")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal14()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/y",
+            $this->baseUri->resolve("g;x=1/../y")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal15()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/y",
+            $this->baseUri->resolve("g;x=1/../y")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal16()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g?y/./x",
+            $this->baseUri->resolve("g?y/./x")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal17()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g?y/../x",
+            $this->baseUri->resolve("g?y/../x")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal18()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g#s/./x",
+            $this->baseUri->resolve("g#s/./x")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal19()
+    {
+        $this->assertStringEquals(
+            "http://a/b/c/g#s/../x",
+            $this->baseUri->resolve("g#s/../x")
+        );
+    }
+
+    public function testResolveReferenceUriAbnormal20()
+    {
+        $this->assertStringEquals(
+            "http:g",
+            $this->baseUri->resolve("http:g")
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/ArcTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/Arc.php';
+
+class EasyRdf_Parser_ArcTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        if (requireExists('arc/ARC2.php')) {
+            $this->parser = new EasyRdf_Parser_Arc();
+            $this->graph = new EasyRdf_Graph();
+            $this->data = readFixture('foaf.rdf');
+        } else {
+            $this->markTestSkipped(
+                "ARC2 library is not available."
+            );
+        }
+    }
+
+    public function testParseRdfXml()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'rdfxml',
+            'http://www.example.com/joe/foaf.rdf'
+        );
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertStringEquals('Joe Bloggs', $name);
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $foaf = $this->graph->resource('http://www.example.com/joe/foaf.rdf');
+        $this->assertNotNull($foaf);
+        $this->assertStringEquals("Joe Bloggs' FOAF File", $foaf->label());
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_Arc does not support: unsupportedformat'
+        );
+        $rdf = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/ExceptionTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Parser_ExceptionTest extends EasyRdf_TestCase
+{
+    public function testThrowException()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Test'
+        );
+        throw new EasyRdf_Parser_Exception('Test');
+    }
+
+    public function testThrowExceptionWithLine()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Test on line 10'
+        );
+        throw new EasyRdf_Parser_Exception('Test', 10);
+    }
+
+    public function testThrowExceptionWithLineAndColumn()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Test on line 10, column 22'
+        );
+        throw new EasyRdf_Parser_Exception('Test', 10, 22);
+    }
+
+    public function testGetParserLine()
+    {
+        $exp = new EasyRdf_Parser_Exception('Test', 10);
+        $this->assertSame(
+            10,
+            $exp->getParserLine()
+        );
+    }
+
+    public function testGetParserColumn()
+    {
+        $exp = new EasyRdf_Parser_Exception('Test', 10, 22);
+        $this->assertSame(
+            22,
+            $exp->getParserColumn()
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/JsonTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Parser_JsonTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->parser = new EasyRdf_Parser_Json();
+    }
+
+    public function testParse()
+    {
+        $data = readFixture('foaf.json');
+        $count = $this->parser->parse($this->graph, $data, 'json', null);
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $project = $joe->get('foaf:currentProject');
+        $this->assertNotNull($project);
+        $this->assertClass('EasyRdf_Resource', $project);
+        $this->assertSame('_:genid1', $project->getUri());
+    }
+
+    public function testParseJsonTriples()
+    {
+        $data = readFixture('foaf.json-triples');
+        $count = $this->parser->parse($this->graph, $data, 'json', null);
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $project = $joe->get('foaf:currentProject');
+        $this->assertNotNull($project);
+        $this->assertClass('EasyRdf_Resource', $project);
+        $this->assertSame('_:genid1', $project->getUri());
+    }
+
+    public function testParseWithFormatObject()
+    {
+        $data = readFixture('foaf.json');
+        $format = EasyRdf_Format::getFormat('json');
+        $count = $this->parser->parse($this->graph, $data, $format, null);
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertStringEquals('Joe Bloggs', $joe->get('foaf:name'));
+    }
+
+    public function testParseBadJson()
+    {
+        # Test parsing JSON with 'bad' bnode identifiers
+        $data = readFixture('foaf.bad-json');
+        $count = $this->parser->parse($this->graph, $data, 'json', 'http://www.bbc.co.uk/');
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertStringEquals('Joe Bloggs', $joe->get('foaf:name'));
+
+        $project = $joe->get('foaf:currentProject');
+        $this->assertNotNull($project);
+        $this->assertTrue($project->isBNode());
+        $this->assertStringEquals("Joe's Current Project", $project->label());
+
+        # Test going the other way
+        $project2 = $this->graph->resource('foaf:Project')->get('^rdf:type');
+        $this->assertNotNull($project2);
+        $this->assertTrue($project2->isBNode());
+        $this->assertStringEquals("Joe's Current Project", $project2->label());
+
+        $joe2 = $project2->get('^foaf:currentProject');
+        $this->assertNotNull($joe2);
+        $this->assertStringEquals('Joe Bloggs', $joe2->get('foaf:name'));
+    }
+
+    public function testParseJsonSyntaxError()
+    {
+        if (version_compare(PHP_VERSION, "5.3.0") >= 0) {
+            $this->setExpectedException(
+                'EasyRdf_Parser_Exception',
+                'JSON Parse syntax error'
+            );
+        } else {
+            $this->setExpectedException(
+                'EasyRdf_Parser_Exception',
+                'JSON Parse error'
+            );
+        }
+        $this->parser->parse(
+            $this->graph,
+            '{ "foo":"bar"',
+            'json',
+            'http://www.example.com/'
+        );
+    }
+
+    public function testParseEmpty()
+    {
+        $count = $this->parser->parse($this->graph, '{}', 'json', null);
+        $this->assertSame(0, $count);
+
+        // Should be empty but no exception thrown
+        $this->assertSame(0, $this->graph->countTriples());
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_Json does not support: unsupportedformat'
+        );
+        $rdf = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/NtriplesTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,368 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Parser_NtriplesTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->parser = new EasyRdf_Parser_Ntriples();
+        $this->data = readFixture('foaf.nt');
+    }
+
+    public function testParse()
+    {
+        $count = $this->parser->parse($this->graph, $this->data, 'ntriples', null);
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joe Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+    }
+
+    public function testParseBnode()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            "_:a <http://example.com/b> \"c\" . \n".
+            "_:d <http://example.com/e> _:a . \n",
+            'ntriples',
+            null
+        );
+        $this->assertSame(2, $count);
+
+        $bnode1 = $this->graph->resource('_:genid1');
+        $this->assertNotNull($bnode1);
+        $this->assertSame(true, $bnode1->isBNode());
+        $this->assertStringEquals('c', $bnode1->get('<http://example.com/b>'));
+
+        $bnode2 = $this->graph->resource('_:genid2');
+        $this->assertNotNull($bnode2);
+        $this->assertSame(true, $bnode2->isBNode());
+        $this->assertSame($bnode1, $bnode2->get('<http://example.com/e>'));
+    }
+
+    public function testParseAnonymousBnode()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            "_: <http://example.com/a> _: . \n".
+            "_: <http://example.com/b> _: . \n",
+            'ntriples',
+            null
+        );
+        $this->assertSame(2, $count);
+
+        $bnode1 = $this->graph->resource('_:genid1');
+        $this->assertSame(true, $bnode1->isBNode());
+        $this->assertStringEquals('_:genid2', $bnode1->get('<http://example.com/a>'));
+
+        $bnode2 = $this->graph->resource('_:genid3');
+        $this->assertSame(true, $bnode2->isBNode());
+        $this->assertStringEquals('_:genid4', $bnode2->get('<http://example.com/b>'));
+    }
+
+    public function testParseLang()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "English"@en-gb .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $int = $this->graph->get('http://example.com/a', '<http://example.com/b>');
+        $this->assertNotNull($int);
+        $this->assertSame('English', $int->getValue());
+        $this->assertSame('en-gb', $int->getLang());
+        $this->assertSame(null, $int->getDatatype());
+    }
+
+    public function testParseDatatype()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "1"^^<http://www.w3.org/2001/XMLSchema#integer> .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $int = $this->graph->get('http://example.com/a', '<http://example.com/b>');
+        $this->assertNotNull($int);
+        $this->assertSame(1, $int->getValue());
+        $this->assertSame(null, $int->getLang());
+        $this->assertSame('xsd:integer', $int->getDatatype());
+    }
+
+    public function testParseEscapedTab()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\t" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $this->assertNotNull($a);
+
+        $b = $a->get('<http://example.com/b>');
+        $this->assertNotNull($b);
+        $this->assertSame("\t", $b->getValue());
+    }
+
+    public function testParseUnicode1()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\u000A" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("\x0A", $b->getValue());
+    }
+
+    public function testParseUnicode2()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "Iv\u00E1n" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("Iván", $b->getValue());
+    }
+
+    public function testParseUnicode3()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\u0394" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("Δ", $b->getValue());
+    }
+
+    public function testParseUnicode4()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\u2603" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("☃", $b->getValue());
+    }
+
+    public function testParseUnicode5()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\U0001F600" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("😀", $b->getValue());
+    }
+
+    public function testParseUnicode6()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '<http://example.com/a> <http://example.com/b> "\UFFFFFFFF" .',
+            'ntriples',
+            null
+        );
+        $this->assertSame(1, $count);
+
+        $a = $this->graph->resource('http://example.com/a');
+        $b = $a->get('<http://example.com/b>');
+        $this->assertSame("", $b->getValue());
+    }
+
+    public function testParseComment()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            "<http://example.com/a> <http://example.com/a> \"Test 1\" .\n".
+            "# <http://example.com/b> <http://example.com/b> \"a comment\" .\n".
+            "  # another comment .\n".
+            "<http://example.com/c> <http://example.com/c> \"Test 2\" .\n",
+            'ntriples',
+            null
+        );
+        $this->assertSame(2, $count);
+        $this->assertCount(2, $this->graph->resources());
+    }
+
+    public function testParseBlankLines()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            "\n".
+            "<http://example.com/a> <http://example.com/a> \"Test 1\" .\n".
+            "  \r\n".
+            "\r\n".
+            "<http://example.com/c> <http://example.com/c> \"Test 2\" .\n".
+            "    ",
+            'ntriples',
+            null
+        );
+        $this->assertSame(2, $count);
+        $this->assertCount(2, $this->graph->resources());
+    }
+
+    public function testParseEmpty()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            '',
+            'ntriples',
+            null
+        );
+        $this->assertSame(0, $count);
+    }
+
+    public function testParseInvalidSubject()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Failed to parse subject: foobar on line 1'
+        );
+        $this->parser->parse(
+            $this->graph,
+            "foobar <http://example.com/a> \"Test 1\" .\n",
+            'ntriples',
+            null
+        );
+    }
+
+    public function testParseInvalidPredicate()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Failed to parse statement on line 2'
+        );
+        $this->parser->parse(
+            $this->graph,
+            "\n<b> rdf:type <http://example.com/type> .\n",
+            'ntriples',
+            null
+        );
+    }
+
+    public function testParseInvalidObject()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Failed to parse object: foobar on line 1'
+        );
+        $this->parser->parse(
+            $this->graph,
+            "<http://example.com/b> <http://example.com/a> foobar .\n",
+            'ntriples',
+            null
+        );
+    }
+
+    public function testParseInvalidStatement()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Failed to parse statement on line 3'
+        );
+        $this->parser->parse(
+            $this->graph,
+            "# line 1\n\nFoo .\n",
+            'ntriples',
+            null
+        );
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_Ntriples does not support: unsupportedformat'
+        );
+        $rdf = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/RapperTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/Rapper.php';
+
+class EasyRdf_Parser_RapperTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        exec('rapper --version 2>/dev/null', $output, $retval);
+        if ($retval == 0) {
+            $this->parser = new EasyRdf_Parser_Rapper();
+            $this->graph = new EasyRdf_Graph();
+            $this->data = readFixture('foaf.rdf');
+        } else {
+            $this->markTestSkipped(
+                "The rapper command is not available on this system."
+            );
+        }
+    }
+
+    public function testRapperNotFound()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            "Failed to execute the command 'random_command_that_doesnt_exist'"
+        );
+        new EasyRdf_Parser_Rapper('random_command_that_doesnt_exist');
+    }
+
+    public function testRapperTooOld()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            "Version 1.4.17 or higher of rapper is required."
+        );
+        new EasyRdf_Parser_Rapper('echo 1.0.0');
+    }
+
+    public function testParseRdfXml()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'rdfxml',
+            'http://www.example.com/joe/foaf.rdf'
+        );
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertStringEquals('Joe Bloggs', $name);
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $foaf = $this->graph->resource('http://www.example.com/joe/foaf.rdf');
+        $this->assertNotNull($foaf);
+        $this->assertStringEquals("Joe Bloggs' FOAF File", $foaf->label());
+    }
+
+    public function testParseEmpty()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            readFixture('empty.rdf'),
+            'rdfxml',
+            'http://www.example.com/empty.rdf'
+        );
+
+        // Should be empty but no exception thrown
+        $this->assertSame(0, $count);
+        $this->assertSame(0, $this->graph->countTriples());
+    }
+
+    public function testParseXMLLiteral()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            readFixture('xml_literal.rdf'),
+            'rdfxml',
+            'http://www.example.com/'
+        );
+        $this->assertSame(2, $count);
+
+        $doc = $this->graph->resource('http://www.example.com/');
+        $this->assertSame('foaf:Document', $doc->type());
+        $description = $doc->get('dc:description');
+        $this->assertSame('rdf:XMLLiteral', $description->getDataType());
+        $this->assertSame(
+            "\n      <p>Here is a block of <em>HTML text</em></p>\n    ",
+            $description->getValue()
+        );
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Error while executing command rapper'
+        );
+        $rdf = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/RdfPhpTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Parser_RdfPhpTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->parser = new EasyRdf_Parser_RdfPhp();
+        $this->data = array(
+            'http://example.com/joe' => array(
+                'http://xmlns.com/foaf/0.1/name' => array(
+                    array(
+                        'type' => 'literal',
+                        'value' => 'Joseph Bloggs',
+                        'lang' => 'en'
+                    )
+                )
+            )
+        );
+    }
+
+    public function testParse()
+    {
+        $count = $this->parser->parse($this->graph, $this->data, 'php', null);
+        $this->assertSame(1, $count);
+
+        $joe = $this->graph->resource('http://example.com/joe');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://example.com/joe', $joe->getUri());
+        $this->assertNull($joe->type());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertSame('Joseph Bloggs', $name->getValue());
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+    }
+
+    public function testParseTwice()
+    {
+        $count = $this->parser->parse($this->graph, $this->data, 'php', null);
+        $this->assertSame(1, $count);
+        $count = $this->parser->parse($this->graph, $this->data, 'php', null);
+        $this->assertSame(0, $count);
+    }
+
+    public function testParseDuplicateBNodes()
+    {
+        $foafName = 'http://xmlns.com/foaf/0.1/name';
+        $bnodeA = array( '_:genid1' => array(
+            $foafName => array(array( 'type' => 'literal', 'value' => 'A' ))
+        ));
+        $bnodeB = array( '_:genid1' => array(
+            $foafName => array(array( 'type' => 'literal', 'value' => 'B' ))
+        ));
+
+        $this->parser->parse($this->graph, $bnodeA, 'php', null);
+        $this->parser->parse($this->graph, $bnodeB, 'php', null);
+
+        $this->assertStringEquals(
+            'A',
+            $this->graph->get('_:genid1', 'foaf:name')
+        );
+        $this->assertStringEquals(
+            'B',
+            $this->graph->get('_:genid2', 'foaf:name')
+        );
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_RdfPhp does not support: unsupportedformat'
+        );
+        $rdf = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/RdfXmlTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/RdfXml.php';
+
+class EasyRdf_Parser_RdfXmlTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->parser = new EasyRdf_Parser_RdfXml();
+        $this->data = readFixture('foaf.rdf');
+    }
+
+    public function testParseRdfXml()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'rdfxml',
+            'http://www.example.com/joe/foaf.rdf'
+        );
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertStringEquals('Joe Bloggs', $name);
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $foaf = $this->graph->resource('http://www.example.com/joe/foaf.rdf');
+        $this->assertNotNull($foaf);
+        $this->assertStringEquals("Joe Bloggs' FOAF File", $foaf->label());
+    }
+
+    public function testParseSeq()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            readFixture('rdf-seq.rdf'),
+            'rdfxml',
+            'http://www.w3.org/TR/REC-rdf-syntax/'
+        );
+        $this->assertSame(5, $count);
+
+        $favourites = $this->graph->resource('http://example.org/favourite-fruit');
+        $this->assertSame('rdf:Seq', $favourites->type());
+        $this->assertStringEquals('http://example.org/banana', $favourites->get('rdf:_1'));
+        $this->assertStringEquals('http://example.org/apple', $favourites->get('rdf:_2'));
+        $this->assertStringEquals('http://example.org/pear', $favourites->get('rdf:_3'));
+        $this->assertStringEquals('http://example.org/pear', $favourites->get('rdf:_4'));
+    }
+
+    public function testXMLParseError()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'XML error: "Mismatched tag" on line 4, column 21'
+        );
+        $this->parser->parse(
+            $this->graph,
+            "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n".
+            "  <rdf:Description rdf:about='http://example.org/foo'>\n".
+            "    <rdf:foo>Hello World\n".
+            "  </rdf:Description>\n".
+            "</rdf:RDF>",
+            'rdfxml',
+            'http://example.org/'
+        );
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_RdfXml does not support: unsupportedformat'
+        );
+        $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/RdfaTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1066 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2012-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2012-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/Rdfa.php';
+require_once 'EasyRdf/Serialiser/NtriplesArray.php';
+
+class EasyRdf_Parser_RdfaTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+    protected $graph = null;
+    protected $data = null;
+
+    public function setUp()
+    {
+        $this->rdfaParser = new EasyRdf_Parser_Rdfa();
+        $this->ntriplesParser = new EasyRdf_Parser_Ntriples();
+        $this->baseUri = 'http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/';
+    }
+
+
+    protected function parseRdfa($filename)
+    {
+        $graph = new EasyRdf_Graph();
+        $this->rdfaParser->parse(
+            $graph,
+            readFixture($filename),
+            'rdfa',
+            $this->baseUri . basename($filename)
+        );
+        return $graph->serialise('ntriples-array');
+    }
+
+    protected function parseNtriples($filename)
+    {
+        $graph = new EasyRdf_Graph();
+        $this->ntriplesParser->parse(
+            $graph,
+            readFixture($filename),
+            'ntriples',
+            $this->baseUri . basename($filename)
+        );
+        return $graph->serialise('ntriples-array');
+    }
+
+    protected function rdfaTestCase($name, $message)
+    {
+        $this->assertEquals(
+            $this->parseNtriples("rdfa/$name.nt"),
+            $this->parseRdfa("rdfa/$name.xhtml"),
+            $message
+        );
+    }
+
+    public function testCase0001()
+    {
+        $this->rdfaTestCase('0001', 'Predicate establishment with @property');
+    }
+
+    public function testCase0006()
+    {
+        $this->rdfaTestCase('0006', '@rel and @rev');
+    }
+
+    public function testCase0007()
+    {
+        $this->rdfaTestCase('0007', '@rel, @rev, @property, @content');
+    }
+
+    public function testCase0008()
+    {
+        $this->rdfaTestCase('0008', 'empty string @about');
+    }
+
+    public function testCase0009()
+    {
+        $this->rdfaTestCase('0009', '@rev');
+    }
+
+    public function testCase0010()
+    {
+        $this->rdfaTestCase('0010', '@rel, @rev, @href');
+    }
+
+    public function testCase0014()
+    {
+        $this->rdfaTestCase('0014', '@datatype, xsd:integer');
+    }
+
+    public function testCase0015()
+    {
+        $this->rdfaTestCase('0015', 'meta and link');
+    }
+
+    public function testCase0017()
+    {
+        $this->rdfaTestCase('0017', 'Related blanknodes');
+    }
+
+    public function testCase0018()
+    {
+        $this->rdfaTestCase('0018', '@rel for predicate');
+    }
+
+    public function testCase0019()
+    {
+        $this->rdfaTestCase('0019', '@about for subject');
+    }
+
+    public function testCase0020()
+    {
+        $this->rdfaTestCase('0020', 'Inheriting @about for subject');
+    }
+
+    public function testCase0021()
+    {
+        $this->rdfaTestCase('0021', 'Subject inheritance with no @about');
+    }
+
+    public function testCase0023()
+    {
+        $this->rdfaTestCase('0023', '@id does not generate subjects');
+    }
+
+    public function testCase0025()
+    {
+        $this->rdfaTestCase('0025', 'simple chaining test');
+    }
+
+    public function testCase0026()
+    {
+        $this->rdfaTestCase('0026', '@content');
+    }
+
+    public function testCase0027()
+    {
+        $this->rdfaTestCase('0027', '@content, ignore element content');
+    }
+
+    public function testCase0029()
+    {
+        $this->rdfaTestCase('0029', 'markup stripping with @datatype');
+    }
+
+    public function testCase0030()
+    {
+        $this->rdfaTestCase('0030', 'omitted @about');
+    }
+
+    public function testCase0031()
+    {
+        $this->rdfaTestCase('0031', 'simple @resource');
+    }
+
+    public function testCase0032()
+    {
+        $this->rdfaTestCase('0032', '@resource overrides @href');
+    }
+
+    public function testCase0033()
+    {
+        $this->rdfaTestCase('0033', 'simple chaining test with bNode');
+    }
+
+    public function testCase0034()
+    {
+        $this->rdfaTestCase('0034', 'simple img[@src] test');
+    }
+
+    public function testCase0035()
+    {
+        $this->rdfaTestCase('0035', '@src/@href test');
+    }
+
+    public function testCase0036()
+    {
+        $this->rdfaTestCase('0036', '@src/@resource test');
+    }
+
+    public function testCase0037()
+    {
+        $this->rdfaTestCase('0037', '@src/@href/@resource test');
+    }
+
+    public function testCase0038()
+    {
+        $this->rdfaTestCase('0038', '@rev - img[@src] test');
+    }
+
+    public function testCase0039()
+    {
+        $this->rdfaTestCase('0039', '@rev - @src/@href test');
+    }
+
+    public function testCase0041()
+    {
+        $this->rdfaTestCase('0041', '@rev - @src/@href/@resource test');
+    }
+
+    public function testCase0048()
+    {
+        $this->rdfaTestCase('0048', '@typeof with @about and @rel present, no @resource');
+    }
+
+    public function testCase0049()
+    {
+        $this->rdfaTestCase('0049', '@typeof with @about, no @rel or @resource');
+    }
+
+    public function testCase0050()
+    {
+        $this->rdfaTestCase('0050', '@typeof without anything else');
+    }
+
+    public function testCase0051()
+    {
+        $this->rdfaTestCase('0051', '@typeof with a single @property');
+    }
+
+    public function testCase0052()
+    {
+        $this->rdfaTestCase('0052', '@typeof with @resource and nothing else');
+    }
+
+    public function testCase0053()
+    {
+        $this->rdfaTestCase('0053', '@typeof with @resource and nothing else, with a subelement');
+    }
+
+    public function testCase0054()
+    {
+        $this->rdfaTestCase('0054', 'multiple @property');
+    }
+
+    public function testCase0055()
+    {
+        $this->rdfaTestCase('0055', 'multiple @rel');
+    }
+
+    public function testCase0056()
+    {
+        $this->rdfaTestCase('0056', '@typeof applies to @about on same element with hanging rel');
+    }
+
+    public function testCase0057()
+    {
+        $this->rdfaTestCase('0057', 'hanging @rel creates multiple triples');
+    }
+
+    public function testCase0059()
+    {
+        $this->rdfaTestCase('0059', 'multiple hanging @rels with multiple children');
+    }
+
+    public function testCase0060()
+    {
+        $this->rdfaTestCase('0060', 'UTF-8 conformance');
+    }
+
+    public function testCase0063()
+    {
+        $this->rdfaTestCase('0063', '@rel in head using reserved XHTML value and empty-prefix CURIE syntax');
+    }
+
+    public function testCase0064()
+    {
+        $this->rdfaTestCase('0064', '@about with safe CURIE');
+    }
+
+    public function testCase0065()
+    {
+        $this->rdfaTestCase('0065', '@rel with safe CURIE');
+    }
+
+    public function testCase0066()
+    {
+        $this->rdfaTestCase('0066', '@about with @typeof in the head');
+    }
+
+    public function testCase0067()
+    {
+        $this->rdfaTestCase('0067', '@property in the head');
+    }
+
+    public function testCase0068()
+    {
+        $this->rdfaTestCase('0068', 'Relative URI in @about');
+    }
+
+    public function testCase0069()
+    {
+        $this->rdfaTestCase('0069', 'Relative URI in @href');
+    }
+
+    public function testCase0070()
+    {
+        $this->rdfaTestCase('0070', 'Relative URI in @resource');
+    }
+
+    public function testCase0071()
+    {
+        $this->rdfaTestCase('0071', 'No explicit @about');
+    }
+
+    public function testCase0072()
+    {
+        $this->rdfaTestCase('0072', 'Relative URI in @about (with XHTML base in head)');
+    }
+
+    public function testCase0073()
+    {
+        $this->rdfaTestCase('0073', 'Relative URI in @resource (with XHTML base in head)');
+    }
+
+    public function testCase0074()
+    {
+        $this->rdfaTestCase('0074', 'Relative URI in @href (with XHTML base in head)');
+    }
+
+    public function testCase0075()
+    {
+        $this->rdfaTestCase('0075', 'Reserved word \'license\' in @rel with no explicit @about');
+    }
+
+    public function testCase0079()
+    {
+        $this->rdfaTestCase('0079', '@resource and @href in completing incomplete triples');
+    }
+
+    public function testCase0080()
+    {
+        $this->rdfaTestCase('0080', '@about overrides @resource in incomplete triples');
+    }
+
+    public function testCase0083()
+    {
+        $this->rdfaTestCase('0083', 'multiple ways of handling incomplete triples (merged)');
+    }
+
+    public function testCase0084()
+    {
+        $this->rdfaTestCase('0084', 'multiple ways of handling incomplete triples, this time with both @rel and @rev');
+    }
+
+    public function testCase0085()
+    {
+        $this->rdfaTestCase('0085', '@resource and @href in completing incomplete triples');
+    }
+
+    public function testCase0087()
+    {
+        $this->rdfaTestCase('0087', 'All reserved XHTML @rel values (with :xxx)');
+    }
+
+    public function testCase0088()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0088', 'Interpretation of the CURIE "_:"');
+    }
+
+    public function testCase0089()
+    {
+        $this->rdfaTestCase('0089', '@src sets a new subject (@typeof)');
+    }
+
+    public function testCase0091()
+    {
+        $this->rdfaTestCase('0091', 'Non-reserved, un-prefixed CURIE in @property');
+    }
+
+    public function testCase0093()
+    {
+        $this->rdfaTestCase('0093', 'Tests XMLLiteral content with explicit @datatype (user-data-typed literal)');
+    }
+
+    public function testCase0099()
+    {
+        $this->rdfaTestCase('0099', 'Preservation of white space in literals');
+    }
+
+    public function testCase0104()
+    {
+        $this->rdfaTestCase('0104', 'rdf:value');
+    }
+
+    public function testCase0106()
+    {
+        $this->rdfaTestCase('0106', 'chaining with empty value in inner @rel');
+    }
+
+    public function testCase0107()
+    {
+        $this->rdfaTestCase('0107', 'no garbage collecting bnodes');
+    }
+
+    public function testCase0110()
+    {
+        $this->rdfaTestCase('0110', 'bNode generated even though no nested @about exists');
+    }
+
+    public function testCase0111()
+    {
+        $this->rdfaTestCase('0111', 'two bNodes generated after three levels of nesting');
+    }
+
+    public function testCase0112()
+    {
+        $this->rdfaTestCase('0112', 'plain literal with datatype=""');
+    }
+
+    public function testCase0114()
+    {
+        $this->rdfaTestCase('0114', 'Relative URI dot-segment removal');
+    }
+
+    public function testCase0115()
+    {
+        $this->rdfaTestCase('0115', 'XML Entities must be supported by RDFa parser');
+    }
+
+    public function testCase0117()
+    {
+        $this->rdfaTestCase('0117', 'Fragment identifiers stripped from BASE');
+    }
+
+    public function testCase0118()
+    {
+        $this->rdfaTestCase('0118', 'empty string "" is not equivalent to NULL - @about');
+    }
+
+    public function testCase0119()
+    {
+        $this->rdfaTestCase('0119', '"[prefix:]" CURIE format is valid');
+    }
+
+    public function testCase0120()
+    {
+        $this->rdfaTestCase('0120', '"[:]" CURIE format is valid');
+    }
+
+    public function testCase0121()
+    {
+        $this->rdfaTestCase('0121', '"[]" is a valid safe CURIE');
+    }
+
+    public function testCase0122()
+    {
+        $this->rdfaTestCase('0122', 'resource="[]" does not set the object');
+    }
+
+    public function testCase0126()
+    {
+        $this->rdfaTestCase('0126', 'Multiple @typeof values');
+    }
+
+    public function testCase0131()
+    {
+        $this->rdfaTestCase('0131', 'Whitespace alternatives in attributes');
+    }
+
+    public function testCase0134()
+    {
+        $this->rdfaTestCase('0134', 'Uppercase reserved words');
+    }
+
+    public function testCase0140()
+    {
+        $this->rdfaTestCase('0140', 'Blank nodes identifiers are not allowed as predicates');
+    }
+
+    public function testCase0147()
+    {
+        $this->rdfaTestCase('0147', 'xmlns prefix \'xmlzzz\' (reserved)');
+    }
+
+    public function testCase0174()
+    {
+        $this->rdfaTestCase('0174', 'Support single character prefix in CURIEs');
+    }
+
+    public function testCase0175()
+    {
+        $this->rdfaTestCase('0175', 'IRI for @property is allowed');
+    }
+
+    public function testCase0176()
+    {
+        $this->rdfaTestCase('0176', 'IRI for @rel and @rev is allowed');
+    }
+
+    public function testCase0177()
+    {
+        $this->rdfaTestCase('0177', 'Test @prefix');
+    }
+
+    public function testCase0178()
+    {
+        $this->rdfaTestCase('0178', 'Test @prefix with multiple mappings');
+    }
+
+    public function testCase0179()
+    {
+        $this->rdfaTestCase('0179', 'Test @prefix vs @xmlns priority');
+    }
+
+    public function testCase0180()
+    {
+        $this->rdfaTestCase('0180', 'Test @prefix with empty mapping');
+    }
+
+    public function testCase0181()
+    {
+        $this->rdfaTestCase('0181', 'Test default XHTML vocabulary');
+    }
+
+    public function testCase0182()
+    {
+        $this->rdfaTestCase('0182', 'Test prefix locality');
+    }
+
+    public function testCase0183()
+    {
+        $this->rdfaTestCase('0183', 'Test @xmlns redefines @prefix');
+    }
+
+    public function testCase0186()
+    {
+        $this->rdfaTestCase('0186', '@vocab after subject declaration');
+    }
+
+    public function testCase0187()
+    {
+        $this->rdfaTestCase('0187', '@vocab redefinition');
+    }
+
+    public function testCase0188()
+    {
+        $this->rdfaTestCase('0188', '@vocab only affects predicates');
+    }
+
+    public function testCase0189()
+    {
+        $this->rdfaTestCase('0189', '@vocab overrides default term');
+    }
+
+    public function testCase0190()
+    {
+        $this->rdfaTestCase('0190', 'Test term case insensitivity');
+    }
+
+    public function testCase0196()
+    {
+        $this->rdfaTestCase('0196', 'Test process explicit XMLLiteral');
+    }
+
+    public function testCase0197()
+    {
+        $this->rdfaTestCase('0197', 'Test TERMorCURIEorAbsURI requires an absolute URI');
+    }
+
+    public function testCase0198()
+    {
+        $this->rdfaTestCase('0198', 'datatype XMLLiteral with other embedded RDFa');
+    }
+
+    public function testCase0206()
+    {
+        $this->rdfaTestCase('0206', 'Usage of Initial Context');
+    }
+
+    public function testCase0207()
+    {
+        $this->rdfaTestCase('0207', 'Vevent using @typeof');
+    }
+
+    public function testCase0213()
+    {
+        $this->rdfaTestCase('0213', 'Datatype generation for a literal with XML content, version 1.1');
+    }
+
+    public function testCase0214()
+    {
+        $this->rdfaTestCase('0214', 'Root element has implicit @about=""');
+    }
+
+    public function testCase0216()
+    {
+        $this->rdfaTestCase('0216', 'Proper character encoding detection in spite of large headers');
+    }
+
+    public function testCase0217()
+    {
+        $this->rdfaTestCase('0217', '@vocab causes rdfa:usesVocabulary triple to be added');
+    }
+
+    public function testCase0218()
+    {
+        $this->rdfaTestCase('0218', '@inlist to create empty list');
+    }
+
+    public function testCase0219()
+    {
+        $this->rdfaTestCase('0219', '@inlist with literal');
+    }
+
+    public function testCase0220()
+    {
+        $this->rdfaTestCase('0220', '@inlist with IRI');
+    }
+
+    public function testCase0221()
+    {
+        $this->rdfaTestCase('0221', '@inlist with hetrogenious membership');
+    }
+
+    public function testCase0222()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0222', '@inlist with multi-level elements');
+    }
+
+    public function testCase0223()
+    {
+        $this->rdfaTestCase('0223', '@inlist with non-list property');
+    }
+
+    public function testCase0224()
+    {
+        $this->markTestSkipped("FIXME: need to implement @inlist");
+        $this->rdfaTestCase('0224', '@inlist hanging @rel');
+    }
+
+    public function testCase0225()
+    {
+        $this->rdfaTestCase('0225', '@inlist on different elements with same subject');
+    }
+
+    public function testCase0226()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0226', 'confusion between multiple implicit collections (resource)');
+    }
+
+    public function testCase0227()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0227', 'confusion between multiple implicit collections (about)');
+    }
+
+    public function testCase0228()
+    {
+        $this->rdfaTestCase('0228', '1.1 alternate for test 0040: @rev - @src/@resource test');
+    }
+
+    public function testCase0229()
+    {
+        $this->rdfaTestCase('0229', 'img[@src] test with omitted @about');
+    }
+
+    public function testCase0230()
+    {
+        $this->rdfaTestCase('0230', '@src does not set a new subject (@rel/@href)');
+    }
+
+    public function testCase0231()
+    {
+        $this->rdfaTestCase('0231', 'Set image license information');
+    }
+
+    public function testCase0232()
+    {
+        $this->rdfaTestCase(
+            '0232',
+            '@typeof with @rel present, no @href, @resource, or @about (1.1 behavior of 0046);'
+        );
+    }
+
+    public function testCase0233()
+    {
+        $this->rdfaTestCase('0233', '@typeof with @rel and @resource present, no @about (1.1 behavior of 0047)');
+    }
+
+    public function testCase0234()
+    {
+        $this->rdfaTestCase('0234', 'All defined HTML link relation values');
+    }
+
+    public function testCase0246()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0246', 'hanging @rel creates multiple triples, @typeof permutation; RDFa 1.1 version');
+    }
+
+    public function testCase0247()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0247', 'Multiple incomplete triples, RDFa 1.1version');
+    }
+
+    public function testCase0248()
+    {
+        $this->rdfaTestCase('0248', 'multiple ways of handling incomplete triples (with @rev); RDFa 1.1 version');
+    }
+
+    public function testCase0249()
+    {
+        $this->rdfaTestCase(
+            '0249',
+            'multiple ways of handling incomplete triples (with @rel and @rev); RDFa 1.1 version'
+        );
+    }
+
+    public function testCase0250()
+    {
+        $this->rdfaTestCase('0250', 'Checking the right behaviour of @typeof with @about, in presence of @property');
+    }
+
+    public function testCase0251()
+    {
+        $this->rdfaTestCase('0251', 'lang');
+    }
+
+    public function testCase0252()
+    {
+        $this->rdfaTestCase('0252', 'lang inheritance');
+    }
+
+    public function testCase0253()
+    {
+        $this->rdfaTestCase('0253', 'plain literal with datatype="" and lang preservation');
+    }
+
+    public function testCase0254()
+    {
+        $this->rdfaTestCase('0254', '@datatype="" generates plain literal in presence of child nodes');
+    }
+
+    public function testCase0255()
+    {
+        $this->rdfaTestCase('0255', 'lang="" clears language setting');
+    }
+
+    public function testCase0256()
+    {
+        $this->rdfaTestCase('0256', 'lang and xml:lang on the same element');
+    }
+
+    public function testCase0257()
+    {
+        $this->rdfaTestCase(
+            '0257',
+            'element with @property and no child nodes generates  empty plain literal (HTML5 version of 0113)'
+        );
+    }
+
+    public function testCase0258()
+    {
+        $this->rdfaTestCase('0258', 'The underscore character is not allowed as a prefix or in xmlns');
+    }
+
+    public function testCase0259()
+    {
+        $this->rdfaTestCase('0259', 'XML+RDFa Initial Context');
+    }
+
+    public function testCase0261()
+    {
+        $this->rdfaTestCase('0261', 'White space preservation in XMLLiteral');
+    }
+
+    public function testCase0262()
+    {
+        $this->rdfaTestCase(
+            '0262',
+            'Predicate establishment with @property, with white spaces before and after the attribute value'
+        );
+    }
+
+    public function testCase0263()
+    {
+        $this->rdfaTestCase('0263', '@property appearing on the html element yields the base as the subject');
+    }
+
+    public function testCase0264()
+    {
+        $this->rdfaTestCase(
+            '0264',
+            '@property appearing on the head element gets the subject from <html>, ie, parent'
+        );
+    }
+
+    public function testCase0265()
+    {
+        $this->rdfaTestCase(
+            '0265',
+            '@property appearing on the head element gets the subject from <html>, ie, parent'
+        );
+    }
+
+    public function testCase0266()
+    {
+        $this->rdfaTestCase('0266', '@property without @content or @datatype, typed object set by @href and @typeof');
+    }
+
+    public function testCase0267()
+    {
+        $this->rdfaTestCase(
+            '0267',
+            '@property without @content or @datatype, typed object set by @resource and @typeof'
+        );
+    }
+
+    public function testCase0268()
+    {
+        $this->rdfaTestCase('0268', '@property without @content or @datatype, typed object set by @src and @typeof');
+    }
+
+    public function testCase0269()
+    {
+        $this->rdfaTestCase(
+            '0269',
+            '@property appearing on the html element yields the base as the subject, also with @content'
+        );
+    }
+
+    public function testCase0271()
+    {
+        $this->rdfaTestCase('0271', 'Use of @property in HEAD with explicit parent subject via @about');
+    }
+
+    public function testCase0272()
+    {
+        $this->rdfaTestCase('0272', 'time element with @datetime an xsd:date');
+    }
+
+    public function testCase0273()
+    {
+        $this->rdfaTestCase('0273', 'time element with @datetime an xsd:time');
+    }
+
+    public function testCase0274()
+    {
+        $this->rdfaTestCase('0274', 'time element with @datetime an xsd:dateTime');
+    }
+
+    public function testCase0275()
+    {
+        $this->rdfaTestCase('0275', 'time element with value an xsd:date');
+    }
+
+    public function testCase0276()
+    {
+        $this->rdfaTestCase('0276', 'time element with value an xsd:time');
+    }
+
+    public function testCase0277()
+    {
+        $this->rdfaTestCase('0277', 'time element with value an xsd:dateTime');
+    }
+
+    public function testCase0278()
+    {
+        $this->rdfaTestCase('0278', '@datetime overrides @content');
+    }
+
+    public function testCase0279()
+    {
+        $this->rdfaTestCase('0279', '@datatype used with @datetime overrides default datatype');
+    }
+
+    public function testCase0280()
+    {
+        $this->rdfaTestCase('0280', 'time element with @datetime an xsd:duration');
+    }
+
+    public function testCase0281()
+    {
+        $this->rdfaTestCase('0281', 'time element with @datetime an xsd:gYear');
+    }
+
+    public function testCase0282()
+    {
+        $this->rdfaTestCase('0282', 'time element with @datetime an xsd:gYearMonth');
+    }
+
+    public function testCase0283()
+    {
+        $this->rdfaTestCase('0283', 'time element with @datetime an invalid datatype generates plain literal');
+    }
+
+    public function testCase0284()
+    {
+        $this->rdfaTestCase('0284', 'time element not matching datatype but with explicit @datatype');
+    }
+
+    public function testCase0285()
+    {
+        $this->rdfaTestCase(
+            '0285',
+            'time element with @datetime an invalid datatype and in scope @lang generates plain literal '.
+            'with language'
+        );
+    }
+
+    public function testCase0286()
+    {
+        $this->rdfaTestCase('0286', '@value attribute overrides @content');
+    }
+
+    public function testCase0287()
+    {
+        $this->rdfaTestCase('0287', 'time element with @datetime an xsd:dateTime with TZ offset');
+    }
+
+    public function testCase0289()
+    {
+        $this->rdfaTestCase('0289', '@href becomes subject when @property and @content are present');
+    }
+
+    public function testCase0290()
+    {
+        $this->rdfaTestCase('0290', '@href becomes subject when @property and @datatype are present');
+    }
+
+    public function testCase0291()
+    {
+        $this->rdfaTestCase('0291', '@href as subject overridden by @about');
+    }
+
+    public function testCase0292()
+    {
+        $this->rdfaTestCase('0292', '@about overriding @href as subject is used as parent resource');
+    }
+
+    public function testCase0293()
+    {
+        $this->rdfaTestCase('0293', 'Testing the \':\' character usage in a CURIE');
+    }
+
+    public function testCase0295()
+    {
+        $this->markTestSkipped("FIXME: Graph comparison isn't working");
+        $this->rdfaTestCase('0295', 'Benchmark test');
+    }
+
+    public function testCase0296()
+    {
+        $this->rdfaTestCase('0296', '@property does set parent object without @typeof');
+    }
+
+    public function testCase0297()
+    {
+        $this->rdfaTestCase('0297', '@about=[] with @typeof does not create a new subject');
+    }
+
+    public function testCase0298()
+    {
+        $this->rdfaTestCase('0298', '@about=[] with @typeof does not create a new object');
+    }
+
+    public function testCase0299()
+    {
+        $this->rdfaTestCase('0299', '@resource=[] with @href or @src uses @href or @src (@rel)');
+    }
+
+    public function testCase0300()
+    {
+        $this->rdfaTestCase('0300', '@resource=[] with @href or @src uses @href or @src (@property)');
+    }
+
+    public function testCase0301()
+    {
+        $this->rdfaTestCase('0301', '@property with @typeof creates a typed_resource for chaining');
+    }
+
+    public function testCase0302()
+    {
+        $this->rdfaTestCase('0302', '@typeof with different content types');
+    }
+
+    public function testCase0303()
+    {
+        $this->markTestSkipped("FIXME");
+        $this->rdfaTestCase(
+            '0303',
+            'For HTML+RDFa 1.1, remove term elements of @rel/@rev when on same element as @property'
+        );
+    }
+
+    public function testCase0311()
+    {
+        $this->rdfaTestCase('0311', 'Ensure no triples are generated when @property is empty');
+    }
+
+    public function testCase0312()
+    {
+        $this->markTestSkipped("FIXME");
+        $this->rdfaTestCase('0312', 'Mute plain @rel if @property is present');
+    }
+
+    public function testCase0315()
+    {
+        $this->rdfaTestCase('0315', '@property and @typeof with incomplete triples');
+    }
+
+    public function testCase0316()
+    {
+        $this->rdfaTestCase('0316', '@property and @typeof with incomplete triples (@href variant)');
+    }
+
+    public function testCase0317()
+    {
+        $this->rdfaTestCase('0317', '@datatype inhibits new @property behavior');
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_Rdfa does not support: unsupportedformat'
+        );
+        $graph = new EasyRdf_Graph();
+        $this->rdfaParser->parse(
+            $graph,
+            'data',
+            'unsupportedformat',
+            null
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/RedlandTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/Redland.php';
+
+class EasyRdf_Parser_RedlandTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        if (extension_loaded('redland')) {
+            $this->parser = new EasyRdf_Parser_Redland();
+            $this->graph = new EasyRdf_Graph();
+            $this->data = readFixture('foaf.rdf');
+        } else {
+            $this->markTestSkipped("Redland PHP extension is not available.");
+        }
+    }
+
+    public function testParseRdfXml()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            $this->data,
+            'rdfxml',
+            'http://www.example.com/joe/foaf.rdf'
+        );
+        $this->assertSame(14, $count);
+
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertStringEquals('Joe Bloggs', $name);
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $foaf = $this->graph->resource('http://www.example.com/joe/foaf.rdf');
+        $this->assertNotNull($foaf);
+        $this->assertStringEquals("Joe Bloggs' FOAF File", $foaf->label());
+    }
+
+    public function testParseRdfXmlBnodeRemap()
+    {
+        $count = $this->parser->parse(
+            $this->graph,
+            "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' ".
+            "         xmlns:foaf='http://xmlns.com/foaf/0.1/' >".
+            "  <rdf:Description rdf:nodeID='bob'>".
+            "    <foaf:name>Bob</foaf:name>".
+            "  </rdf:Description>".
+            "</rdf:RDF>",
+            'rdfxml',
+            'http://www.example.com/bob/foaf.rdf'
+        );
+        $this->assertSame(1, $count);
+
+        $this->assertStringEquals(
+            'Bob',
+            $this->graph->get('_:genid1', 'foaf:name')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Parser/TurtleTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,489 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Parser/Turtle.php';
+require_once 'EasyRdf/Serialiser/NtriplesArray.php';
+
+class EasyRdf_Parser_TurtleTest extends EasyRdf_TestCase
+{
+    protected $parser = null;
+
+    public function setUp()
+    {
+        $this->turtleParser = new EasyRdf_Parser_Turtle();
+        $this->ntriplesParser = new EasyRdf_Parser_Ntriples();
+        $this->baseUri = 'http://www.w3.org/2001/sw/DataAccess/df1/tests/';
+    }
+
+    public function testParseFoaf()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $this->turtleParser->parse(
+            $graph,
+            readFixture('foaf.ttl'),
+            'turtle',
+            $this->baseUri
+        );
+        $this->assertSame(14, $count);
+
+        $joe = $graph->resource('http://www.example.com/joe#me');
+        $this->assertNotNull($joe);
+        $this->assertClass('EasyRdf_Resource', $joe);
+        $this->assertSame('http://www.example.com/joe#me', $joe->getUri());
+
+        $name = $joe->get('foaf:name');
+        $this->assertNotNull($name);
+        $this->assertClass('EasyRdf_Literal', $name);
+        $this->assertStringEquals('Joe Bloggs', $name);
+        $this->assertSame('en', $name->getLang());
+        $this->assertSame(null, $name->getDatatype());
+
+        $foaf = $graph->resource('http://www.example.com/joe/foaf.rdf');
+        $this->assertNotNull($foaf);
+        $this->assertStringEquals("Joe Bloggs' FOAF File", $foaf->label());
+    }
+
+    public function testParseCollection()
+    {
+        $graph = new EasyRdf_Graph();
+        $count = $this->turtleParser->parse(
+            $graph,
+            "<http://example.com/s> <http://example.com/p> ('A' 'B' 'C' 'D') .",
+            'turtle',
+            $this->baseUri
+        );
+        $this->assertSame(9, $count);
+
+        $array = array();
+        $collection = $graph->resource('http://example.com/s')->get('<http://example.com/p>');
+        foreach ($collection as $item) {
+            $array[] = strval($item);
+        }
+
+        $this->assertEquals(
+            array('A', 'B', 'C', 'D'),
+            $array
+        );
+    }
+
+    public function testParseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Parser_Turtle does not support: unsupportedformat'
+        );
+        $this->turtleParser->parse(
+            new EasyRdf_Graph(),
+            'data',
+            'unsupportedformat',
+            null
+        );
+    }
+
+    /* The rest of this script is runs the Turtle Test Suite
+       from the files here:
+       http://www.w3.org/TeamSubmission/turtle/tests/
+     */
+
+    protected function parseTurtle($filename)
+    {
+        $graph = new EasyRdf_Graph();
+        $this->turtleParser->parse(
+            $graph,
+            readFixture($filename),
+            'turtle',
+            $this->baseUri . basename($filename)
+        );
+        return $graph->serialise('ntriples-array');
+    }
+
+    protected function parseNtriples($filename)
+    {
+        $graph = new EasyRdf_Graph();
+        $this->ntriplesParser->parse(
+            $graph,
+            readFixture($filename),
+            'ntriples',
+            $this->baseUri . basename($filename)
+        );
+        return $graph->serialise('ntriples-array');
+    }
+
+    protected function turtleTestCase($name)
+    {
+        $this->assertSame(
+            $this->parseNtriples("turtle/$name.out"),
+            $this->parseTurtle("turtle/$name.ttl")
+        );
+    }
+
+    public function testCase00()
+    {
+        # Blank subject
+        $this->turtleTestCase('test-00');
+    }
+
+    public function testCase01()
+    {
+        # @prefix and qnames
+        $this->turtleTestCase('test-01');
+    }
+
+    public function testCase02()
+    {
+        # , operator
+        $this->turtleTestCase('test-02');
+    }
+
+    public function testCase03()
+    {
+        # ; operator
+        $this->turtleTestCase('test-03');
+    }
+
+    public function testCase04()
+    {
+        # empty [] as subject and object
+        $this->turtleTestCase('test-04');
+    }
+
+    public function testCase05()
+    {
+        # non-empty [] as subject and object
+        $this->turtleTestCase('test-05');
+    }
+
+    public function testCase06()
+    {
+        # 'a' as predicate
+        $this->turtleTestCase('test-06');
+    }
+
+    public function testCase07()
+    {
+        # simple collection
+        $this->turtleTestCase('test-07');
+    }
+
+    public function testCase08()
+    {
+        # empty collection
+        $this->turtleTestCase('test-08');
+    }
+
+    public function testCase09()
+    {
+        # integer datatyped literal
+        $this->turtleTestCase('test-09');
+    }
+
+    public function testCase10()
+    {
+        # decimal integer canonicalization
+        $this->turtleTestCase('test-10');
+    }
+
+    public function testCase11()
+    {
+        # - and _ in names and qnames
+        $this->turtleTestCase('test-11');
+    }
+
+    public function testCase12()
+    {
+        # tests for rdf:_<numbers> and other qnames starting with _
+        $this->turtleTestCase('test-12');
+    }
+
+    public function testCase13()
+    {
+        # bare : allowed
+        $this->turtleTestCase('test-13');
+    }
+
+    // Removed tests 14-16 because they take a long time to run
+
+    public function testCase17()
+    {
+        # simple long literal
+        $this->turtleTestCase('test-17');
+    }
+
+    public function testCase18()
+    {
+        # long literals with escapes
+        $this->turtleTestCase('test-18');
+    }
+
+    public function testCase19()
+    {
+        # floating point number
+        $this->turtleTestCase('test-19');
+    }
+
+    public function testCase20()
+    {
+        # empty literals, normal and long variant
+        $this->turtleTestCase('test-20');
+    }
+
+    public function testCase21()
+    {
+        # positive integer, decimal and doubles
+        $this->turtleTestCase('test-21');
+    }
+
+    public function testCase22()
+    {
+        # negative integer, decimal and doubles
+        $this->turtleTestCase('test-22');
+    }
+
+    public function testCase23()
+    {
+        # long literal ending in double quote
+        $this->turtleTestCase('test-23');
+    }
+
+    public function testCase24()
+    {
+        # boolean literals
+        $this->turtleTestCase('test-24');
+    }
+
+    public function testCase25()
+    {
+        # comments
+        $this->turtleTestCase('test-25');
+    }
+
+    public function testCase26()
+    {
+        # no final newline
+        $this->turtleTestCase('test-26');
+    }
+
+    public function testCase27()
+    {
+        # duplicate prefix
+        $this->turtleTestCase('test-27');
+    }
+
+    public function testTurtleSyntaxPnameEsc01()
+    {
+        $this->turtleTestCase('turtle-syntax-pname-esc-01');
+    }
+
+    public function testTurtleSyntaxPnameEsc02()
+    {
+        $this->turtleTestCase('turtle-syntax-pname-esc-02');
+    }
+
+    public function testTurtleSyntaxPnameEsc03()
+    {
+        $this->turtleTestCase('turtle-syntax-pname-esc-03');
+    }
+
+    public function testBase1()
+    {
+        # Resolution of a relative URI against an absolute base.
+        $this->turtleTestCase('base1');
+    }
+
+    public function testRdfSchema()
+    {
+        $this->turtleTestCase('rdf-schema');
+    }
+
+    public function testQuotes1()
+    {
+        $this->turtleTestCase('quotes1');
+    }
+
+    public function testBad00()
+    {
+        # prefix name must end in a :
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected ':', found '<' on line 2, column 12"
+        );
+        $this->parseTurtle("turtle/bad-00.ttl");
+    }
+
+    public function testBad01()
+    {
+        # Forbidden by RDF - predicate cannot be blank
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found '[' on line 3, column 4"
+        );
+        $this->parseTurtle("turtle/bad-01.ttl");
+    }
+
+    public function testBad02()
+    {
+        # Forbidden by RDF - predicate cannot be blank
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found '[' on line 3, column 4"
+        );
+        $this->parseTurtle("turtle/bad-02.ttl");
+    }
+
+    public function testBad03()
+    {
+        # 'a' only allowed as a predicate
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected ':', found ' ' on line 3, column 3"
+        );
+        $this->parseTurtle("turtle/bad-03.ttl");
+    }
+
+    public function testBad04()
+    {
+        # No comma is allowed in collections
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found ',' on line 3, column 16"
+        );
+        $this->parseTurtle("turtle/bad-04.ttl");
+    }
+
+    public function testBad05()
+    {
+        # N3 {}s are not in Turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found '{' on line 3, column 1"
+        );
+        $this->parseTurtle("turtle/bad-05.ttl");
+    }
+
+    public function testBad06()
+    {
+        # is and of are not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected ':', found ' ' on line 3, column 7"
+        );
+        $this->parseTurtle("turtle/bad-06.ttl");
+    }
+
+    public function testBad07()
+    {
+        # paths are not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: object for statement missing on line 3, column 5"
+        );
+        $this->parseTurtle("turtle/bad-07.ttl");
+    }
+
+    public function testBad08()
+    {
+        # @keywords is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            'Turtle Parse Error: unknown directive "@keywords" on line 1, column 10'
+        );
+        $this->parseTurtle("turtle/bad-08.ttl");
+    }
+
+    public function testBad09()
+    {
+        # implies is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found '=' on line 3, column 4"
+        );
+        $this->parseTurtle("turtle/bad-09.ttl");
+    }
+
+    public function testBad10()
+    {
+        # equivalence is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: expected an RDF value here, found '=' on line 3, column 4"
+        );
+        $this->parseTurtle("turtle/bad-10.ttl");
+    }
+
+    public function testBad11()
+    {
+        # @forAll is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: unknown directive \"@forall\" on line 3, column 8"
+        );
+        $this->parseTurtle("turtle/bad-11.ttl");
+    }
+
+    public function testBad12()
+    {
+        # @forSome is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: unknown directive \"@forsome\" on line 3, column 9"
+        );
+        $this->parseTurtle("turtle/bad-12.ttl");
+    }
+
+    public function testBad13()
+    {
+        # <= is not in turtle
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: unexpected end of file while reading URI on line 4, column 1"
+        );
+        $this->parseTurtle("turtle/bad-13.ttl");
+    }
+
+    public function testBad14()
+    {
+        # Test long literals with missing end
+        $this->setExpectedException(
+            'EasyRdf_Parser_Exception',
+            "Turtle Parse Error: unexpected end of file while reading long string on line 7, column 1"
+        );
+        $this->parseTurtle("turtle/bad-14.ttl");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/ParserTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,183 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class MockParser extends EasyRdf_Parser
+{
+    public function parse($graph, $data, $format, $baseUri)
+    {
+        parent::checkParseParams($graph, $data, $format, $baseUri);
+        // Parsing goes here
+        return true;
+    }
+}
+
+class EasyRdf_ParserTest extends EasyRdf_TestCase
+{
+    /**
+     * Set up the test suite before each test
+     */
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->resource = $this->graph->resource('http://www.example.com/');
+        $this->parser = new MockParser();
+        $this->data = readFixture('foaf.json');
+    }
+
+    public function testParse()
+    {
+        $this->assertTrue(
+            $this->parser->parse(
+                $this->graph,
+                $this->data,
+                'json',
+                null
+            )
+        );
+    }
+
+    public function testParseFormatObject()
+    {
+        $format = EasyRdf_Format::getFormat('json');
+        $this->assertTrue(
+            $this->parser->parse(
+                $this->graph,
+                $this->data,
+                $format,
+                null
+            )
+        );
+    }
+
+    public function testParseNullGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->parser->parse(null, $this->data, 'json', null);
+    }
+
+    public function testParseNonObjectGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->parser->parse('string', $this->data, 'json', null);
+    }
+
+    public function testParseNonGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->parser->parse($this->resource, $this->data, 'json', null);
+    }
+
+    public function testParseNullData()
+    {
+        $this->assertTrue(
+            $this->parser->parse($this->graph, null, 'json', null)
+        );
+    }
+
+    public function testParseEmptyData()
+    {
+        $this->assertTrue(
+            $this->parser->parse($this->graph, '', 'json', null)
+        );
+    }
+
+    public function testParseNullFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format cannot be null or empty'
+        );
+        $this->parser->parse($this->graph, $this->data, null, null);
+    }
+
+    public function testParseEmptyFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format cannot be null or empty'
+        );
+        $this->parser->parse($this->graph, $this->data, '', null);
+    }
+
+    public function testParseBadObjectFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format should be a string or an EasyRdf_Format object'
+        );
+        $this->parser->parse($this->graph, $this->data, $this, null);
+    }
+
+    public function testParseIntegerFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format should be a string or an EasyRdf_Format object'
+        );
+        $this->parser->parse($this->graph, $this->data, 1, null);
+    }
+
+    public function testParseNonStringBaseUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$baseUri should be a string'
+        );
+        $this->parser->parse($this->graph, $this->data, 'json', 1);
+    }
+
+    public function testParseUndefined()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'This method should be overridden by sub-classes.'
+        );
+        $parser = new EasyRdf_Parser();
+        $parser->parse($this->graph, 'data', 'format', 'baseUri');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/ResourceTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1268 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_ResourceTest extends EasyRdf_TestCase
+{
+    /**
+     * Set up the test suite before each test
+     */
+    public function setUp()
+    {
+        // Reset default namespace
+        EasyRdf_Namespace::setDefault(null);
+    }
+
+    public function testConstructNullUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string and cannot be null or empty'
+        );
+        $res = new EasyRdf_Resource(null);
+    }
+
+    public function testConstructEmptyUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string and cannot be null or empty'
+        );
+        $res = new EasyRdf_Resource('');
+    }
+
+    public function testConstructNonStringUri()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$uri should be a string and cannot be null or empty'
+        );
+        $res = new EasyRdf_Resource(array());
+    }
+
+    public function testConstructBadGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object'
+        );
+        $res = new EasyRdf_Resource('http://www.example.com/', $this);
+    }
+
+    public function testGetUri()
+    {
+        $res = new EasyRdf_Resource('http://example.com/testGetUri');
+        $this->assertSame(
+            'http://example.com/testGetUri',
+            $res->getUri()
+        );
+    }
+
+    public function testIsBNode()
+    {
+        $bnode = new EasyRdf_Resource('_:foobar');
+        $this->assertSame(true, $bnode->isBNode());
+    }
+
+    public function testIsNotBnode()
+    {
+        $nonbnode = new EasyRdf_Resource('http://www.exaple.com/');
+        $this->assertSame(false, $nonbnode->isBNode());
+    }
+
+    public function testGetBNodeId()
+    {
+        $bnode = new EasyRdf_Resource('_:foobar');
+        $this->assertSame('foobar', $bnode->getBNodeId());
+    }
+
+    public function testGetBNodeIdForUri()
+    {
+        $nonbnode = new EasyRdf_Resource('http://www.exaple.com/');
+        $this->assertSame(null, $nonbnode->getBNodeId());
+    }
+
+    public function testPrefix()
+    {
+        $foafName = new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name');
+        $this->assertStringEquals('foaf', $foafName->prefix());
+    }
+
+    public function testUnknownPrefix()
+    {
+        $unknown = new EasyRdf_Resource('http://example.com/foo');
+        $this->assertNull($unknown->prefix());
+    }
+
+    public function testShorten()
+    {
+        $foafName = new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name');
+        $this->assertSame('foaf:name', $foafName->shorten());
+    }
+
+    public function testShortenUnknown()
+    {
+        $unknown = new EasyRdf_Resource('http://example.com/foo');
+        $this->assertSame(null, $unknown->shorten());
+    }
+
+    public function testLocalnameWithSlash()
+    {
+        $res = new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name');
+        $this->assertSame('name', $res->localName());
+    }
+
+    public function testLocalnameWithHash()
+    {
+        $res = new EasyRdf_Resource('http://purl.org/vocab/aiiso/schema#College');
+        $this->assertSame('College', $res->localName());
+    }
+
+    public function testLocalnameWithUrn()
+    {
+        $res = new EasyRdf_Resource('urn:isbn:978-0300067156');
+        $this->assertSame('978-0300067156', $res->localName());
+    }
+
+    public function testLocalnameWithNoPath()
+    {
+        $res = new EasyRdf_Resource('http://example.com/');
+        $this->assertSame(null, $res->localName());
+    }
+
+    public function testParseUri()
+    {
+        $res = new EasyRdf_Resource('http://example.com/foo/bar');
+        $uri = $res->parseUri();
+        $this->assertClass('EasyRdf_ParsedUri', $uri);
+        $this->assertSame('/foo/bar', $uri->getPath());
+    }
+
+    public function testHtmlLinkNoText()
+    {
+        $res = new EasyRdf_Resource('http://example.com/');
+        $this->assertSame('<a href="http://example.com/">http://example.com/</a>', $res->htmlLink());
+    }
+
+    public function testHtmlLinkWithText()
+    {
+        $res = new EasyRdf_Resource('http://example.com/');
+        $this->assertSame(
+            '<a href="http://example.com/">Click Here</a>',
+            $res->htmlLink('Click Here')
+        );
+    }
+
+    public function testHtmlLinkWithOptions()
+    {
+        $res = new EasyRdf_Resource('http://example.com/');
+        $this->assertSame(
+            '<a href="http://example.com/" style="font-weight: bold">Click Here</a>',
+            $res->htmlLink('Click Here', array('style' => 'font-weight: bold'))
+        );
+    }
+
+    public function testHtmlLinkWithEscaping()
+    {
+        $res = new EasyRdf_Resource('http://example.com/');
+        $this->assertSame(
+            '<a href="http://example.com/">=&gt; Click Here &lt;=</a>',
+            $res->htmlLink('=> Click Here <=')
+        );
+    }
+
+    public function testHtmlLinkInjectJavascript()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$options should use valid attribute names as keys'
+        );
+
+        $res = new EasyRdf_Resource('http://example.com/');
+        $html = $res->htmlLink(null, array('onclick=alert(1) a' => 'b"'));
+    }
+
+    public function testToRdfPhpForUri()
+    {
+        $uri = new EasyRdf_Resource('http://www.example.com/');
+        $this->assertSame(
+            array('type' => 'uri', 'value' => 'http://www.example.com/'),
+            $uri->toRdfPhp()
+        );
+    }
+
+    public function testToRdfPhpForBnode()
+    {
+        $bnode = new EasyRdf_Resource('_:foobar');
+        $this->assertSame(
+            array('type' => 'bnode', 'value' => '_:foobar'),
+            $bnode->toRdfPhp()
+        );
+    }
+
+    public function testDumpValue()
+    {
+        $res = new EasyRdf_Resource('http://www.example.com/');
+        $this->assertSame(
+            "http://www.example.com/",
+            $res->dumpValue('text')
+        );
+        $this->assertSame(
+            "<a href='http://www.example.com/' ".
+            "style='text-decoration:none;color:blue'>".
+            "http://www.example.com/</a>",
+            $res->dumpValue('html')
+        );
+    }
+
+    public function testDumpValueWithColor()
+    {
+        $res = new EasyRdf_Resource('http://www.example.com/');
+        $this->assertSame(
+            "<a href='http://www.example.com/' ".
+            "style='text-decoration:none;color:red'>".
+            "http://www.example.com/</a>",
+            $res->dumpValue('html', 'red')
+        );
+    }
+
+    public function testToString()
+    {
+        $res = new EasyRdf_Resource('http://example.com/testToString');
+        $this->assertStringEquals('http://example.com/testToString', $res);
+    }
+
+
+
+
+    /*
+     *
+     * The following tests require a graph of test data
+     *
+     */
+
+    protected function setupTestGraph()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->type = $this->graph->resource('foaf:Person');
+        $this->resource = $this->graph->resource('http://example.com/#me');
+        $this->graph->set($this->resource, 'rdf:type', $this->type);
+        $this->graph->add($this->resource, 'rdf:test', 'Test A');
+        $this->graph->add($this->resource, 'rdf:test', new EasyRdf_Literal('Test B', 'en'));
+    }
+
+    public function testLoad()
+    {
+        EasyRdf_Http::setDefaultHttpClient(
+            $client = new EasyRdf_Http_MockClient()
+        );
+        $client->addMock('GET', 'http://example.com/foaf.json', readFixture('foaf.json'));
+        $graph = new EasyRdf_Graph('http://example.com/');
+        $resource = $graph->resource('http://example.com/foaf.json');
+        $resource->load();
+        $this->assertStringEquals(
+            'Joe Bloggs',
+            $graph->get('http://www.example.com/joe#me', 'foaf:name')
+        );
+    }
+
+    public function testGetUriWithGraph()
+    {
+        $graph = new EasyRdf_Graph();
+        $res = new EasyRdf_Resource('http://example.com/testGetUriWithGraph', $graph);
+        $this->assertSame(
+            'http://example.com/testGetUriWithGraph',
+            $res->getUri()
+        );
+    }
+
+    public function testGetGraph()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            $this->graph,
+            $this->resource->getGraph()
+        );
+    }
+
+    public function testGet()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->get('rdf:test')
+        );
+    }
+
+    public function testGetWithoutGraph()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Resource is not part of a graph.'
+        );
+        $res = new EasyRdf_Resource('http://example.com/');
+        $res->get('rdf:test');
+    }
+
+    public function testGetAResource()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'http://xmlns.com/foaf/0.1/Person',
+            $this->resource->get('rdf:type')
+        );
+    }
+
+    public function testGetWithUri()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->get(
+                '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+            )
+        );
+    }
+
+    public function testGetWithPropertyResource()
+    {
+        $this->setupTestGraph();
+        $test = new EasyRdf_Resource(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#test',
+            $this->graph
+        );
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->get($test)
+        );
+    }
+
+    public function testGetWithLanguage()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test B',
+            $this->resource->get('rdf:test', 'literal', 'en')
+        );
+    }
+
+    public function testGetInverse()
+    {
+        $this->setupTestGraph();
+        $homepage = new EasyRdf_Resource('http://example.com/', $this->graph);
+        $this->resource->add('foaf:homepage', $homepage);
+        $this->assertSame($this->resource, $homepage->get('^foaf:homepage'));
+    }
+
+    public function testGetMultipleProperties()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->get('rdf:test|rdf:foobar')
+        );
+    }
+
+    public function testGetMultipleProperties2()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->get('rdf:foobar|rdf:test')
+        );
+    }
+
+    public function testGetNonExistantProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertNull($this->resource->get('foo:bar'));
+    }
+
+    public function testGetNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->get(null);
+    }
+
+    public function testGetEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->resource->get('');
+    }
+
+    public function testGetNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->get($this);
+    }
+
+    public function testGetLiteral()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->getLiteral('rdf:test')
+        );
+    }
+
+    public function testGetLiteralForResource()
+    {
+        $this->setupTestGraph();
+        $this->assertNull(
+            $this->resource->getLiteral('rdf:type')
+        );
+    }
+
+    public function testGetResource()
+    {
+        $this->setupTestGraph();
+        $this->resource->addLiteral('foaf:homepage', 'Joe');
+        $this->resource->addResource('foaf:homepage', 'http://example.com/');
+        $this->assertStringEquals(
+            'http://example.com/',
+            $this->resource->getResource('foaf:homepage')
+        );
+    }
+
+    public function testAll()
+    {
+        $this->setupTestGraph();
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithUri()
+    {
+        $this->setupTestGraph();
+        $all = $this->resource->all(
+            '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+        );
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithResource()
+    {
+        $this->setupTestGraph();
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $all = $this->resource->all($prop);
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllWithLang()
+    {
+        $this->setupTestGraph();
+        $all = $this->resource->all('rdf:test', 'literal', 'en');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('Test B', $all[0]);
+    }
+
+    public function testAllInverse()
+    {
+        $this->setupTestGraph();
+        $all = $this->type->all('^rdf:type');
+        $this->assertCount(1, $all);
+        $this->assertSame($this->resource, $all[0]);
+    }
+
+    public function testAllNonExistantProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            array(),
+            $this->resource->all('foo:bar')
+        );
+    }
+
+    public function testAllNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->all(null);
+    }
+
+    public function testAllEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->resource->all('');
+    }
+
+    public function testAllNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->all(array());
+    }
+
+    public function testAllLiterals()
+    {
+        $this->setupTestGraph();
+        $all = $this->resource->allLiterals('rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAllLiteralsForResource()
+    {
+        $this->setupTestGraph();
+        $all = $this->resource->allLiterals('rdf:type');
+        $this->assertTrue(is_array($all));
+        $this->assertCount(0, $all);
+    }
+
+    public function testAllResources()
+    {
+        $this->setupTestGraph();
+        $this->resource->addResource('rdf:test', 'http://example.com/thing');
+        $this->resource->addResource('rdf:test', '_:bnode1');
+        $all = $this->resource->allResources('rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('http://example.com/thing', $all[0]);
+        $this->assertFalse($all[0]->isBNode());
+        $this->assertStringEquals('_:bnode1', $all[1]);
+        $this->assertTrue($all[1]->isBNode());
+    }
+
+    public function testAdd()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->add('rdf:test', 'Test C');
+        $this->assertSame(1, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(3, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+    }
+
+    public function testAddWithUri()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->add(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#test',
+            'Test C'
+        );
+        $this->assertSame(1, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(3, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+    }
+
+    public function testAddLiteral()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->addLiteral('rdf:foobar', 'testAddLiteral');
+        $this->assertSame(1, $count);
+        $this->assertClass('EasyRdf_Literal', $this->resource->get('rdf:foobar'));
+        $this->assertStringEquals('testAddLiteral', $this->resource->get('rdf:foobar'));
+    }
+
+    public function testAddLiteralWithLanguage()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->addLiteral('dc:title', 'English Title', 'en');
+        $this->assertSame(1, $count);
+        $title = $this->resource->get('dc:title');
+        $this->assertSame('English Title', $title->getValue());
+        $this->assertSame('en', $title->getLang());
+        $this->assertSame(null, $title->getDataType());
+    }
+
+    public function testAddResource()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->addResource('rdf:foobar', 'http://testAddResource/');
+        $this->assertSame(1, $count);
+        $this->assertClass('EasyRdf_Resource', $this->resource->get('rdf:foobar'));
+        $this->assertStringEquals('http://testAddResource/', $this->resource->get('rdf:foobar'));
+    }
+
+    public function testAddMultipleLiterals()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->addLiteral('rdf:test', array('Test C', 'Test D'));
+        $this->assertSame(2, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(4, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+        $this->assertStringEquals('Test C', $all[2]);
+        $this->assertStringEquals('Test D', $all[3]);
+    }
+
+    public function testAddLiteralMultipleTimes()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->add('rdf:test2', 'foobar');
+        $this->assertSame(1, $count);
+        $count = $this->resource->add('rdf:test2', 'foobar');
+        $this->assertSame(0, $count);
+        $all = $this->resource->all('rdf:test2');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('foobar', $all[0]);
+    }
+
+    public function testAddLiteralDifferentLanguages()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->set('rdf:test', new EasyRdf_Literal('foobar', 'en'));
+        $this->assertSame(1, $count);
+        $count = $this->resource->add('rdf:test', new EasyRdf_Literal('foobar', 'fr'));
+        $this->assertSame(1, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('foobar', $all[0]);
+        $this->assertStringEquals('foobar', $all[1]);
+    }
+
+    public function testAddNull()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->add('rdf:test', null);
+        $this->assertSame(0, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(2, $all);
+        $this->assertStringEquals('Test A', $all[0]);
+        $this->assertStringEquals('Test B', $all[1]);
+    }
+
+    public function testAddNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->add(null, 'Test C');
+    }
+
+    public function testAddEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be an empty string'
+        );
+        $this->resource->add('', 'Test C');
+    }
+
+    public function testAddNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->add(array(), 'Test C');
+    }
+
+    public function testAddInvalidObject()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'PHPUnit_Framework_Error',
+            'Object of class EasyRdf_ResourceTest could not be converted to string'
+        );
+        $this->resource->add('rdf:foo', $this);
+    }
+
+    public function testDelete()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals('Test A', $this->resource->get('rdf:test'));
+        $this->resource->delete('rdf:test');
+        $this->assertSame(array(), $this->resource->all('rdf:test'));
+    }
+
+    public function testDeleteWithUri()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals('Test A', $this->resource->get('rdf:test'));
+        $this->resource->delete(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#test'
+        );
+        $this->assertSame(array(), $this->resource->all('rdf:test'));
+    }
+
+    public function testDeleteNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->delete(null);
+    }
+
+    public function testDeleteEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be an empty string'
+        );
+        $this->resource->delete('');
+    }
+
+    public function testDeleteNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->delete(array());
+    }
+
+    public function testDeleteValue()
+    {
+        $this->setupTestGraph();
+        $testa = $this->resource->get('rdf:test');
+        $this->resource->delete('rdf:test', $testa);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(1, $all);
+    }
+
+    public function testSet()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->set('rdf:test', 'Test C');
+        $this->assertSame(1, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('Test C', $all[0]);
+    }
+
+    public function testSetWithUri()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->set(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#test',
+            'Test C'
+        );
+        $this->assertSame(1, $count);
+        $all = $this->resource->all('rdf:test');
+        $this->assertCount(1, $all);
+        $this->assertStringEquals('Test C', $all[0]);
+    }
+
+    public function testSetInverse()
+    {
+        $this->setupTestGraph();
+        $homepage1 = new EasyRdf_Resource('http://example.com/1', $this->graph);
+        $homepage2 = new EasyRdf_Resource('http://example.com/2', $this->graph);
+        $count = $this->resource->set('foaf:homepage', $homepage1);
+        $this->assertSame(1, $count);
+        $this->assertSame(
+            $this->resource,
+            $homepage1->get('^foaf:homepage')
+        );
+        $this->assertSame(
+            null,
+            $homepage2->get('^foaf:homepage')
+        );
+
+        $count = $this->resource->set('foaf:homepage', $homepage2);
+        $this->assertSame(1, $count);
+        $this->assertSame(
+            null,
+            $homepage1->get('^foaf:homepage')
+        );
+        $this->assertSame(
+            $this->resource,
+            $homepage2->get('^foaf:homepage')
+        );
+    }
+
+    public function testSetNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->set(null, 'Test C');
+    }
+
+    public function testSetEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property cannot be an empty string'
+        );
+        $this->resource->set('', 'Test C');
+    }
+
+    public function testSetNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$property should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->set(array(), 'Test C');
+    }
+
+    public function testSetNull()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->set('rdf:test', null);
+        $this->assertSame(0, $count);
+        $this->assertSame(
+            array(),
+            $this->resource->all('rdf:test')
+        );
+    }
+
+    public function testCountValues()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(2, $this->resource->countValues('rdf:test'));
+    }
+
+    public function countValuesNonExistantProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(0, $this->resource->countValues('foo:bar'));
+    }
+
+    public function testJoinDefaultGlue()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            'Test A Test B',
+            $this->resource->join('rdf:test')
+        );
+    }
+
+    public function testJoinWithUri()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            'Test A Test B',
+            $this->resource->join(
+                '<http://www.w3.org/1999/02/22-rdf-syntax-ns#test>'
+            )
+        );
+    }
+
+    public function testJoinWithResource()
+    {
+        $this->setupTestGraph();
+        $prop = $this->graph->resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#test');
+        $this->assertSame(
+            'Test A Test B',
+            $this->resource->join($prop)
+        );
+    }
+
+    public function testJoinWithLang()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            'Test B',
+            $this->resource->join('rdf:test', ' ', 'en')
+        );
+    }
+
+    public function testJoinNonExistantProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertSame('', $this->resource->join('foo:bar'));
+    }
+
+    public function testJoinCustomGlue()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            'Test A:Test B',
+            $this->resource->join('rdf:test', ':')
+        );
+    }
+
+    public function testJoinNullKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->join(null, 'Test C');
+    }
+
+    public function testJoinEmptyKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath cannot be an empty string'
+        );
+        $this->resource->join('', 'Test C');
+    }
+
+    public function testJoinNonStringKey()
+    {
+        $this->setupTestGraph();
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$propertyPath should be a string or EasyRdf_Resource and cannot be null'
+        );
+        $this->resource->join(array(), 'Test C');
+    }
+
+    public function testProperties()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            array('rdf:type', 'rdf:test'),
+            $this->resource->properties()
+        );
+    }
+
+    public function testPropertyUris()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            array(
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#test'
+            ),
+            $this->resource->propertyUris()
+        );
+    }
+
+    public function testReversePropertyUris()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            array(
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'
+            ),
+            $this->type->reversePropertyUris()
+        );
+    }
+
+    public function testHasProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertTrue(
+            $this->resource->hasProperty('rdf:type')
+        );
+    }
+
+    public function testHasPropertyWithValue()
+    {
+        $this->setupTestGraph();
+        $this->assertTrue(
+            $this->resource->hasProperty('rdf:type', $this->type)
+        );
+    }
+
+    public function testDoesntHaveProperty()
+    {
+        $this->setupTestGraph();
+        $this->assertFalse(
+            $this->resource->hasProperty('rdf:doesntexist')
+        );
+    }
+
+    public function testTypes()
+    {
+        $this->setupTestGraph();
+        $types = $this->resource->types();
+        $this->assertCount(1, $types);
+        $this->assertStringEquals('foaf:Person', $types[0]);
+    }
+
+    public function testType()
+    {
+        $this->setupTestGraph();
+        $this->assertStringEquals('foaf:Person', $this->resource->type());
+    }
+
+    public function testTypeAsResource()
+    {
+        $this->setupTestGraph();
+        $this->assertSame(
+            $this->type,
+            $this->resource->typeAsResource()
+        );
+    }
+
+    public function testIsA()
+    {
+        $this->setupTestGraph();
+        $this->assertTrue($this->resource->isA('foaf:Person'));
+    }
+
+    public function testIsAFullUri()
+    {
+        $this->setupTestGraph();
+        $this->assertTrue(
+            $this->resource->isA('http://xmlns.com/foaf/0.1/Person')
+        );
+    }
+
+    public function testIsntA()
+    {
+        $this->setupTestGraph();
+        $this->assertFalse($this->resource->isA('foaf:Rat'));
+    }
+
+    public function testAddType()
+    {
+        $this->setupTestGraph();
+        $count = $this->resource->addType('rdf:newType');
+        $this->assertSame(1, $count);
+        $this->assertTrue(
+            $this->resource->isA('rdf:newType')
+        );
+    }
+
+    public function testSetType()
+    {
+        $this->setupTestGraph();
+        $this->assertTrue(
+            $this->resource->isA('foaf:Person')
+        );
+        $count = $this->resource->setType('foaf:Rat');
+        $this->assertSame(1, $count);
+        $this->assertTrue(
+            $this->resource->isA('foaf:Rat')
+        );
+        $this->assertFalse(
+            $this->resource->isA('foaf:Person')
+        );
+    }
+
+    public function testPrimaryTopic()
+    {
+        $this->setupTestGraph();
+        $doc = $this->graph->resource('http://example.com/foaf.rdf');
+        $person = $this->graph->resource('http://example.com/foaf.rdf#me');
+        $doc->add('foaf:primaryTopic', $person);
+        $this->assertSame(
+            'http://example.com/foaf.rdf#me',
+            $doc->primaryTopic()->getUri()
+        );
+    }
+
+    public function testIsPrimaryTopicOf()
+    {
+        $this->setupTestGraph();
+        $doc = $this->graph->resource('http://example.com/foaf.rdf');
+        $person = $this->graph->resource('http://example.com/foaf.rdf#me');
+        $person->add('foaf:isPrimaryTopicOf', $doc);
+        $this->assertSame(
+            'http://example.com/foaf.rdf#me',
+            $doc->primaryTopic()->getUri()
+        );
+    }
+
+    public function testLabelWithRdfsLabel()
+    {
+        $this->setupTestGraph();
+        $this->resource->set('rdfs:label', 'Label Text');
+        $this->resource->set('foaf:name', 'Foaf Name');
+        $this->resource->set('dc:title', 'Dc Title');
+        $this->assertStringEquals('Label Text', $this->resource->label());
+    }
+
+    public function testLabelWithFoafName()
+    {
+        $this->setupTestGraph();
+        $this->resource->set('foaf:name', 'Foaf Name');
+        $this->resource->set('dc:title', 'Dc Title');
+        $this->assertStringEquals('Foaf Name', $this->resource->label());
+    }
+
+    public function testLabelWithDc11Title()
+    {
+        $this->setupTestGraph();
+        $this->resource->set('dc11:title', 'Dc11 Title');
+        $this->assertStringEquals('Dc11 Title', $this->resource->label());
+    }
+
+    public function testLabelNoRdfsLabel()
+    {
+        $this->setupTestGraph();
+        $this->assertNull($this->resource->label());
+    }
+
+    public function testLabelWithLang()
+    {
+        $this->setupTestGraph();
+        $this->resource->set('rdfs:label', 'Label Text');
+        $this->resource->set(
+            'dc:title',
+            new EasyRdf_Literal('Dc Title', 'en')
+        );
+        $this->assertStringEquals('Dc Title', $this->resource->label('en'));
+    }
+
+    public function testDump()
+    {
+        $this->setupTestGraph();
+        $text = $this->resource->dump('text');
+        $this->assertContains(
+            "http://example.com/#me (EasyRdf_Resource)",
+            $text
+        );
+        $this->assertContains(
+            '-> rdf:type -> foaf:Person',
+            $text
+        );
+        $this->assertContains(
+            '-> rdf:test -> "Test A", "Test B"@en',
+            $text
+        );
+
+        $html = $this->resource->dump();
+        $this->assertContains("<div id='http://example.com/#me'", $html);
+        $this->assertContains(
+            "<a href='http://example.com/#me' ".
+            "style='text-decoration:none;color:blue'>".
+            "http://example.com/#me</a>",
+            $html
+        );
+        $this->assertContains(
+            "<span style='text-decoration:none;color:green'>rdf:type</span>",
+            $html
+        );
+        $this->assertContains(
+            "<a href='http://xmlns.com/foaf/0.1/Person' ".
+            "style='text-decoration:none;color:blue'>foaf:Person</a>",
+            $html
+        );
+        $this->assertContains(
+            "<span style='text-decoration:none;color:green'>rdf:test</span>",
+            $html
+        );
+        $this->assertContains(
+            "<span style='color:black'>&quot;Test A&quot;</span>",
+            $html
+        );
+        $this->assertContains(
+            "<span style='color:black'>&quot;Test B&quot;@en</span>",
+            $html
+        );
+    }
+
+    public function testMagicGet()
+    {
+        $this->setupTestGraph();
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->assertStringEquals(
+            'Test A',
+            $this->resource->test
+        );
+    }
+
+    public function testMagicGetNonExistent()
+    {
+        $this->setupTestGraph();
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->assertStringEquals(
+            null,
+            $this->resource->foobar
+        );
+    }
+
+    public function testMagicSet()
+    {
+        $this->setupTestGraph();
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->resource->test = 'testMagicSet';
+        $this->assertStringEquals(
+            'testMagicSet',
+            $this->resource->get('rdf:test')
+        );
+    }
+
+    public function testMagicIsSet()
+    {
+        $this->setupTestGraph();
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->assertFalse(isset($this->resource->testMagicIsSet));
+        $this->resource->add('rdf:testMagicIsSet', 'testMagicIsSet');
+        $this->assertTrue(isset($this->resource->testMagicIsSet));
+    }
+
+    public function testMagicUnset()
+    {
+        $this->setupTestGraph();
+        EasyRdf_Namespace::setDefault('rdf');
+        $this->resource->add('rdf:testMagicUnset', 'testMagicUnset');
+        unset($this->resource->testMagicUnset);
+        $this->assertStringEquals(
+            null,
+            $this->resource->get('rdf:testMagicUnset')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/ArcTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Serialiser/Arc.php';
+
+class EasyRdf_Serialiser_ArcTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        if (requireExists('arc/ARC2.php')) {
+            $this->graph = new EasyRdf_Graph();
+            $this->serialiser = new EasyRdf_Serialiser_Arc();
+            parent::setUp();
+        } else {
+            $this->markTestSkipped(
+                "ARC2 library is not available."
+            );
+        }
+    }
+
+    public function testSerialiseRdfXml()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+        $joe->add('foaf:project', $project);
+
+        $rdfxml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertNotNull($rdfxml);
+        $this->assertContains(
+            '<rdf:Description rdf:about="http://www.example.com/joe#me">',
+            $rdfxml
+        );
+        $this->assertContains(':name>Project Name<', $rdfxml);
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_Arc does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/GraphVizTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,283 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_GraphVizTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        exec('which dot', $output, $retval);
+        if ($retval == 0) {
+            $this->graph = new EasyRdf_Graph();
+            $this->serialiser = new EasyRdf_Serialiser_GraphViz();
+
+            // Put some data in the graph
+            $joe = $this->graph->resource('http://www.example.com/joe#me');
+            $joe->set('foaf:name', 'Joe Bloggs');
+            $project = $this->graph->newBNode();
+            $project->add('foaf:name', 'Project Name');
+            $joe->add('foaf:project', $project);
+
+            parent::setUp();
+        } else {
+            $this->markTestSkipped(
+                "The 'dot' command is not available on this system."
+            );
+        }
+    }
+
+    public function testSetDotCommand()
+    {
+        $this->serialiser->setDotCommand('/usr/bin/dot');
+        $this->assertSame('/usr/bin/dot', $this->serialiser->getDotCommand());
+    }
+
+    public function testSetUseLabelsTrue()
+    {
+        $this->serialiser->setUseLabels(true);
+        $this->assertTrue($this->serialiser->getUseLabels());
+    }
+
+    public function testSetUseLabelsFalse()
+    {
+        $this->serialiser->setUseLabels(false);
+        $this->assertFalse($this->serialiser->getUseLabels());
+    }
+
+    public function testSetOnlyLabelledTrue()
+    {
+        $this->serialiser->setOnlyLabelled(true);
+        $this->assertTrue($this->serialiser->getOnlyLabelled());
+    }
+
+    public function testSetOnlyLabelledFalse()
+    {
+        $this->serialiser->setOnlyLabelled(false);
+        $this->assertFalse($this->serialiser->getOnlyLabelled());
+    }
+
+    public function testGetAtrributeCharset()
+    {
+        $this->assertSame(
+            'utf-8',
+            $this->serialiser->getAttribute('charset')
+        );
+    }
+
+    public function testSetAtrribute()
+    {
+        $this->serialiser->setAttribute('rankdir', 'LR');
+        $this->assertSame('LR', $this->serialiser->getAttribute('rankdir'));
+        $this->serialiser->setAttribute('rankdir', 'RL');
+        $this->assertSame('RL', $this->serialiser->getAttribute('rankdir'));
+    }
+
+    public function testSerialiseDot()
+    {
+        $this->serialiser->setUseLabels(false);
+        $this->serialiser->setOnlyLabelled(false);
+        $dot = $this->serialiser->serialise($this->graph, 'dot');
+        $this->assertSame(
+            array(
+                'digraph {',
+                '  charset="utf-8";',
+                '',
+                '  // Edges',
+                '  "Rhttp://www.example.com/joe#me" -> "LJoe Bloggs" [label="foaf:name"];',
+                '  "Rhttp://www.example.com/joe#me" -> "B_:genid1" [label="foaf:project"];',
+                '  "B_:genid1" -> "LProject Name" [label="foaf:name"];',
+                '',
+                '  // Nodes',
+                '  "B_:genid1" [label="",shape=circle,color=green];',
+                '  "LJoe Bloggs" [label="Joe Bloggs",shape=record];',
+                '  "LProject Name" [label="Project Name",shape=record];',
+                '  "Rhttp://www.example.com/joe#me" [URL="http://www.example.com/joe#me",'.
+                'label="http://www.example.com/joe#me",shape=ellipse,color=blue];',
+                '}',
+                ''
+            ),
+            explode("\n", $dot)
+        );
+    }
+
+    public function testSerialiseDotUseLabels()
+    {
+        $this->serialiser->setUseLabels(true);
+        $this->serialiser->setOnlyLabelled(false);
+        $dot = $this->serialiser->serialise($this->graph, 'dot');
+
+        $this->assertSame(
+            array(
+                'digraph {',
+                '  charset="utf-8";',
+                '',
+                '  // Edges',
+                '  "Rhttp://www.example.com/joe#me" -> "LJoe Bloggs" [label="foaf:name"];',
+                '  "Rhttp://www.example.com/joe#me" -> "B_:genid1" [label="foaf:project"];',
+                '  "B_:genid1" -> "LProject Name" [label="foaf:name"];',
+                '',
+                '  // Nodes',
+                '  "B_:genid1" [label="Project Name",shape=circle,color=green];',
+                '  "LJoe Bloggs" [label="Joe Bloggs",shape=record];',
+                '  "LProject Name" [label="Project Name",shape=record];',
+                '  "Rhttp://www.example.com/joe#me" [URL="http://www.example.com/joe#me",'.
+                'label="Joe Bloggs",shape=ellipse,color=blue];',
+                '}',
+                ''
+            ),
+            explode("\n", $dot)
+        );
+    }
+
+    public function testSerialiseDotOnlyLabelled()
+    {
+        $this->graph->set('foaf:project', 'rdfs:label', 'project');
+        $this->serialiser->setUseLabels(true);
+        $this->serialiser->setOnlyLabelled(true);
+        $dot = $this->serialiser->serialise($this->graph, 'dot');
+
+        $this->assertSame(
+            array(
+                'digraph {',
+                '  charset="utf-8";',
+                '',
+                '  // Edges',
+                '  "Rhttp://www.example.com/joe#me" -> "B_:genid1" [label=project];',
+                '',
+                '  // Nodes',
+                '  "B_:genid1" [label="Project Name",shape=circle,color=green];',
+                '  "Rhttp://www.example.com/joe#me" [URL="http://www.example.com/joe#me",'.
+                'label="Joe Bloggs",shape=ellipse,color=blue];',
+                '}',
+                ''
+            ),
+            explode("\n", $dot)
+        );
+    }
+
+    public function testSerialisePng()
+    {
+        $this->serialiser->setUseLabels(false);
+        $this->serialiser->setOnlyLabelled(false);
+        $img = $this->serialiser->serialise($this->graph, 'png');
+        $info = getimagesize(
+            'data:application/octet-stream;base64,'.base64_encode($img)
+        );
+
+        $this->assertSame('image/png', $info['mime']);
+        $this->assertTrue(500 > $info[0], 'Image width is less than 500');  # width=469
+        $this->assertTrue(350 < $info[0], 'Image width is greater than 350');
+        $this->assertTrue(350 > $info[1], 'Image height is less than 350');  # height=299
+        $this->assertTrue(250 < $info[1], 'Image height is greater than 250');
+    }
+
+    public function testSerialiseGif()
+    {
+        $this->serialiser->setUseLabels(false);
+        $this->serialiser->setOnlyLabelled(false);
+        $img = $this->serialiser->serialise($this->graph, 'gif');
+        $info = getimagesize(
+            'data:application/octet-stream;base64,'.base64_encode($img)
+        );
+
+        $this->assertSame('image/gif', $info['mime']);
+        $this->assertTrue(500 > $info[0], 'Image width is less than 500');  # width=469
+        $this->assertTrue(350 < $info[0], 'Image width is greater than 350');
+        $this->assertTrue(350 > $info[1], 'Image height is less than 350');  # height=304
+        $this->assertTrue(250 < $info[1], 'Image height is greater than 250');
+    }
+
+    public function testSerialiseSvg()
+    {
+        $this->serialiser->setUseLabels(false);
+        $this->serialiser->setOnlyLabelled(false);
+        $svg = $this->serialiser->serialise($this->graph, 'svg');
+
+        $this->assertContains(
+            'class="node"><title>Rhttp://www.example.com/joe#me</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="node"><title>LJoe Bloggs</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="edge"><title>Rhttp://www.example.com/joe#me&#45;&gt;LJoe Bloggs</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="node"><title>B_:genid1</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="edge"><title>Rhttp://www.example.com/joe#me&#45;&gt;B_:genid1</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="node"><title>LProject Name</title>',
+            $svg
+        );
+        $this->assertContains(
+            'class="edge"><title>B_:genid1&#45;&gt;LProject Name</title>',
+            $svg
+        );
+    }
+
+    public function testDotNotFound()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Error while executing command does/not/exist'
+        );
+        $this->serialiser->setDotCommand('does/not/exist');
+        $this->serialiser->renderImage($this->graph);
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_GraphViz does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/JsonLdTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,98 @@
+<?php
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+    DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class JsonLdTest extends EasyRdf_TestCase
+{
+    /** @var EasyRdf_Serialiser_JsonLd */
+    protected $serialiser = null;
+
+    /** @var EasyRdf_Graph */
+    protected $graph = null;
+
+    public function setUp()
+    {
+        if (PHP_MAJOR_VERSION < 5 or (PHP_MAJOR_VERSION >= 5 and PHP_MINOR_VERSION < 3)) {
+            $this->markTestSkipped("JSON-LD support requires PHP 5.3+");
+        }
+
+        if (!class_exists('\ML\JsonLD\JsonLD')) {
+            $this->markTestSkipped('"ml/json-ld" dependency is not installed');
+        }
+
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_JsonLd();
+    }
+
+    public function testSerialiseJsonLd()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', new EasyRdf_Literal('Joe Bloggs', 'en'));
+        $joe->set('foaf:age', 59);
+
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+
+        $joe->add('foaf:project', $project);
+
+
+        $serialised = $this->serialiser->serialise($this->graph, 'jsonld');
+
+
+        $doc = \ML\JsonLD\JsonLD::getDocument($serialised);
+        $graph = $doc->getGraph();
+        $node = $graph->getNode('http://www.example.com/joe#me');
+
+        $this->assertEquals(
+            'http://xmlns.com/foaf/0.1/Person',
+            $node->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')->getId()
+        );
+        $this->assertEquals(
+            59,
+            $node->getProperty('http://xmlns.com/foaf/0.1/age')
+        );
+        $this->assertEquals(
+            'Joe Bloggs',
+            $node->getProperty('http://xmlns.com/foaf/0.1/name')->getValue()
+        );
+        $this->assertEquals(
+            'Project Name',
+            $node->getProperty('http://xmlns.com/foaf/0.1/project')->getProperty('http://xmlns.com/foaf/0.1/name')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/JsonTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_JsonTest extends EasyRdf_TestCase
+{
+    protected $serialiser = null;
+    protected $graph = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_Json();
+    }
+
+    public function testSerialiseJson()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', new EasyRdf_Literal('Joe Bloggs', 'en'));
+        $joe->set('foaf:age', 59);
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+        $joe->add('foaf:project', $project);
+
+        $this->assertSame(
+            '{"http:\/\/www.example.com\/joe#me":{'.
+            '"http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#type":['.
+            '{"type":"uri","value":"http:\/\/xmlns.com\/foaf\/0.1\/Person"}],'.
+            '"http:\/\/xmlns.com\/foaf\/0.1\/name":['.
+            '{"type":"literal","value":"Joe Bloggs","lang":"en"}],'.
+            '"http:\/\/xmlns.com\/foaf\/0.1\/age":['.
+            '{"type":"literal","value":"59","datatype":'.
+            '"http:\/\/www.w3.org\/2001\/XMLSchema#integer"}],'.
+            '"http:\/\/xmlns.com\/foaf\/0.1\/project":['.
+            '{"type":"bnode","value":"_:genid1"}]},"_:genid1":{'.
+            '"http:\/\/xmlns.com\/foaf\/0.1\/name":['.
+            '{"type":"literal","value":"Project Name"}]}}',
+            $this->serialiser->serialise($this->graph, 'json')
+        );
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_Json does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/NtriplesArray.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * Class to serialise an EasyRdf_Graph to an array of triples.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+class EasyRdf_Serialiser_NtriplesArray extends EasyRdf_Serialiser_Ntriples
+{
+
+    /**
+     * Sort an array of triples into a consistent order
+     *
+     * @ignore
+     */
+    protected function compareTriples($a, $b)
+    {
+        if ($a['s'] != $b['s']) {
+            return strcmp($a['s'], $b['s']);
+        } elseif ($a['p'] != $b['p']) {
+            return strcmp($a['p'], $b['p']);
+        } elseif ($a['o'] != $b['o']) {
+            return strcmp($a['o'], $b['o']);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Serialise an EasyRdf_Graph into an array of N-Triples objects
+     *
+     * @param object EasyRdf_Graph $graph   An EasyRdf_Graph object.
+     * @param string  $format               The name of the format to convert to.
+     * @return string                       The RDF in the new desired format.
+     */
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+
+        $triples = array();
+        foreach ($graph->toRdfPhp() as $resource => $properties) {
+            foreach ($properties as $property => $values) {
+                foreach ($values as $value) {
+                    array_push(
+                        $triples,
+                        array(
+                            's' => $this->ntriplesResource($resource),
+                            'p' => "<" . $this->escapeString($property) . ">",
+                            'o' => $this->ntriplesValue($value)
+                        )
+                    );
+                }
+            }
+        }
+
+        // Sort the triples into a consistent order
+        usort($triples, array($this, 'compareTriples'));
+
+        return $triples;
+    }
+}
+
+EasyRdf_Format::register('ntriples-array', 'PHP Array of Triples');
+EasyRdf_Format::registerSerialiser('ntriples-array', 'EasyRdf_Serialiser_NtriplesArray');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/NtriplesTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_NtriplesTest extends EasyRdf_TestCase
+{
+    protected $serialiser = null;
+    protected $graph = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_Ntriples();
+    }
+
+    public function testSerialise()
+    {
+        $joe = $this->graph->resource(
+            'http://www.example.com/joe#me',
+            'foaf:Person'
+        );
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $joe->set(
+            'foaf:homepage',
+            $this->graph->resource('http://www.example.com/joe/')
+        );
+        $this->assertSame(
+            "<http://www.example.com/joe#me> ".
+            "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ".
+            "<http://xmlns.com/foaf/0.1/Person> .\n".
+            "<http://www.example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/name> ".
+            "\"Joe Bloggs\" .\n".
+            "<http://www.example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/homepage> ".
+            "<http://www.example.com/joe/> .\n",
+            $this->serialiser->serialise($this->graph, 'ntriples')
+        );
+    }
+
+    public function testSerialiseQuotes()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $joe->set('foaf:nick', '"Joey"');
+        $this->assertSame(
+            "<http://www.example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/nick> ".
+            '"\"Joey\"" .'."\n",
+            $this->serialiser->serialise($this->graph, 'ntriples')
+        );
+    }
+
+    public function testSerialiseBNode()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+        $joe->add('foaf:project', $project);
+
+        $this->assertSame(
+            "_:genid1 <http://xmlns.com/foaf/0.1/name> \"Project Name\" .\n".
+            "<http://www.example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/project> _:genid1 .\n",
+            $this->serialiser->serialise($this->graph, 'ntriples')
+        );
+    }
+    public function testSerialiseLang()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', new EasyRdf_Literal('Joe', 'en'));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'ntriples');
+        $this->assertStringEquals(
+            "<http://example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/name> ".
+            "\"Joe\"@en .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:foo', EasyRdf_Literal::create(1, null, 'xsd:integer'));
+
+        $ntriples = $this->serialiser->serialise($this->graph, 'ntriples');
+        $this->assertStringEquals(
+            "<http://example.com/joe#me> ".
+            "<http://xmlns.com/foaf/0.1/foo> ".
+            "\"1\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n",
+            $ntriples
+        );
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_Ntriples does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/RapperTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+require_once 'EasyRdf/Serialiser/Rapper.php';
+
+class EasyRdf_Serialiser_RapperTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        exec('which rapper', $output, $retval);
+        if ($retval == 0) {
+            $this->graph = new EasyRdf_Graph();
+            $this->serialiser = new EasyRdf_Serialiser_Rapper();
+            parent::setUp();
+        } else {
+            $this->markTestSkipped(
+                "The rapper command is not available on this system."
+            );
+        }
+    }
+
+    public function testRapperNotFound()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            "Failed to execute the command 'random_command_that_doesnt_exist'"
+        );
+        new EasyRdf_Serialiser_Rapper('random_command_that_doesnt_exist');
+    }
+
+    public function testSerialiseRdfXml()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+        $joe->add('foaf:project', $project);
+
+        $rdfxml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertNotNull($rdfxml);
+        $this->assertContains(
+            '<rdf:Description rdf:about="http://www.example.com/joe#me">',
+            $rdfxml
+        );
+        $this->assertContains(':name>Project Name<', $rdfxml);
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Error while executing command rapper'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/RdfPhpTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_RdfPhpTest extends EasyRdf_TestCase
+{
+    protected $serialiser = null;
+    protected $graph = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_RdfPhp();
+    }
+
+    public function testSerialisePhp()
+    {
+        $joe = $this->graph->resource(
+            'http://www.example.com/joe#me',
+            'foaf:Person'
+        );
+        $joe->set('foaf:name', new EasyRdf_Literal('Joe Bloggs', 'en'));
+        $joe->set('foaf:age', 59);
+        $project = $this->graph->newBNode();
+        $project->add('foaf:name', 'Project Name');
+        $joe->add('foaf:project', $project);
+
+        $php = $this->serialiser->serialise($this->graph, 'php');
+        $this->assertInternalType('array', $php);
+        $subject = $php['http://www.example.com/joe#me'];
+        $this->assertInternalType('array', $subject);
+        $type = $subject['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'][0];
+        $this->assertSame('uri', $type['type']);
+        $this->assertSame('http://xmlns.com/foaf/0.1/Person', $type['value']);
+        $name = $subject['http://xmlns.com/foaf/0.1/name'][0];
+        $this->assertInternalType('array', $name);
+        $this->assertSame('literal', $name['type']);
+        $this->assertSame('Joe Bloggs', $name['value']);
+        $this->assertFalse(isset($name['datatype']));
+        $this->assertSame('en', $name['lang']);
+        $age = $subject['http://xmlns.com/foaf/0.1/age'][0];
+        $this->assertInternalType('array', $age);
+        $this->assertSame('literal', $age['type']);
+        $this->assertSame('59', $age['value']);
+        $this->assertSame(
+            'http://www.w3.org/2001/XMLSchema#integer',
+            $age['datatype']
+        );
+        $this->assertFalse(isset($age['lang']));
+
+        $nodeid = $subject['http://xmlns.com/foaf/0.1/project'][0]['value'];
+        $this->assertInternalType('array', $php[$nodeid]);
+        $projectName = $php[$nodeid]['http://xmlns.com/foaf/0.1/name'][0];
+        $this->assertSame('Project Name', $projectName['value']);
+        $this->assertFalse(isset($projectName['lang']));
+        $this->assertFalse(isset($projectName['datatype']));
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_RdfPhp does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/RdfXmlTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,407 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_RdfXmlTest extends EasyRdf_TestCase
+{
+    protected $serialiser = null;
+    protected $graph = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_RdfXml();
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Namespace::reset();
+    }
+
+    public function testSerialiseRdfXml()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $joe->addResource('foaf:homepage', 'http://www.example.com/joe/');
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <foaf:name>Joe Bloggs</foaf:name>\n".
+            "    <foaf:homepage rdf:resource=\"http://www.example.com/joe/\"/>\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlWithInline()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $homepage = $this->graph->resource('http://www.example.com/joe/');
+        $homepage->add('foaf:name', "Joe's Homepage");
+        $joe->set('foaf:homepage', $homepage);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <foaf:name>Joe Bloggs</foaf:name>\n".
+            "    <foaf:homepage>\n".
+            "      <rdf:Description rdf:about=\"http://www.example.com/joe/\">\n".
+            "        <foaf:name>Joe's Homepage</foaf:name>\n".
+            "      </rdf:Description>\n".
+            "    </foaf:homepage>\n\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlDoubleRefernce()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $homepage = $this->graph->resource('http://www.example.com/joe/');
+        $homepage->add('foaf:name', "Joe's Homepage");
+        $joe->set('foaf:homepage', $homepage);
+        $joe->set('foaf:made', $homepage);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <foaf:name>Joe Bloggs</foaf:name>\n".
+            "    <foaf:homepage rdf:resource=\"http://www.example.com/joe/\"/>\n".
+            "    <foaf:made rdf:resource=\"http://www.example.com/joe/\"/>\n".
+            "  </foaf:Person>\n\n".
+            "  <rdf:Description rdf:about=\"http://www.example.com/joe/\">\n".
+            "    <foaf:name>Joe's Homepage</foaf:name>\n".
+            "  </rdf:Description>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlWithInlineBnode()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $project = $this->graph->newBNode('foaf:Project');
+        $project->set('foaf:name', "Joe's Project");
+        $joe->set('foaf:currentProject', $project);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <foaf:name>Joe Bloggs</foaf:name>\n".
+            "    <foaf:currentProject>\n".
+            "      <foaf:Project>\n".
+            "        <foaf:name>Joe's Project</foaf:name>\n".
+            "      </foaf:Project>\n".
+            "    </foaf:currentProject>\n\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlBnodeMentionedTwice()
+    {
+        $bob = $this->graph->newBnode('foaf:Person');
+        $alice = $this->graph->newBnode('foaf:Person');
+        $carol = $this->graph->newBnode('foaf:Person');
+
+        $bob->add('foaf:knows', $alice);
+        $bob->add('foaf:knows', $carol);
+        $alice->add('foaf:knows', $bob);
+        $alice->add('foaf:knows', $carol);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:nodeID=\"genid1\">\n".
+            "    <foaf:knows>\n".
+            "      <foaf:Person>\n".
+            "        <foaf:knows rdf:nodeID=\"genid1\"/>\n".
+            "        <foaf:knows rdf:nodeID=\"genid3\"/>\n".
+            "      </foaf:Person>\n".
+            "    </foaf:knows>\n\n".
+            "    <foaf:knows rdf:nodeID=\"genid3\"/>\n".
+            "  </foaf:Person>\n\n".
+            "  <foaf:Person rdf:nodeID=\"genid3\">\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlTwoTypes()
+    {
+        $joe = $this->graph->resource(
+            'http://www.example.com/joe#me',
+            array('foaf:Person', 'foaf:Mammal')
+        );
+        $joe->set('foaf:name', 'Joe Bloggs');
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <rdf:type rdf:resource=\"http://xmlns.com/foaf/0.1/Mammal\"/>\n".
+            "    <foaf:name>Joe Bloggs</foaf:name>\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlWithTwoBNodes()
+    {
+        $nodeA = $this->graph->newBNode();
+        $nodeB = $this->graph->newBNode();
+        $this->graph->add($nodeA, 'rdf:foobar', $nodeB);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n\n".
+            "  <rdf:Description rdf:nodeID=\"genid1\">\n".
+            "    <rdf:foobar rdf:nodeID=\"genid2\"/>\n".
+            "  </rdf:Description>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseBNodesLast()
+    {
+        $bnode = $this->graph->newBNode();
+        $bnode->add('rdf:label', 'This is a bnode');
+        $res1 = $this->graph->resource('http://example.com/1');
+        $res1->add('rdf:test', $bnode);
+        $res2 = $this->graph->resource('http://example.com/2');
+        $res2->add('rdf:test', $bnode);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n\n".
+            "  <rdf:Description rdf:about=\"http://example.com/1\">\n".
+            "    <rdf:test rdf:nodeID=\"genid1\"/>\n".
+            "  </rdf:Description>\n\n".
+            "  <rdf:Description rdf:about=\"http://example.com/2\">\n".
+            "    <rdf:test rdf:nodeID=\"genid1\"/>\n".
+            "  </rdf:Description>\n\n".
+            "  <rdf:Description rdf:nodeID=\"genid1\">\n".
+            "    <rdf:label>This is a bnode</rdf:label>\n".
+            "  </rdf:Description>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseRdfXmlWithLang()
+    {
+        $this->graph->add(
+            'http://www.example.com/joe#me',
+            'foaf:name',
+            new EasyRdf_Literal('Joe', 'en')
+        );
+
+        $xml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertContains(
+            '<foaf:name xml:lang="en">Joe</foaf:name>',
+            $xml
+        );
+    }
+
+    public function testSerialiseRdfXmlWithDatatype()
+    {
+        $this->graph->add(
+            'http://www.example.com/joe#me',
+            'foaf:age',
+            EasyRdf_Literal::create(59, null, 'xsd:int')
+        );
+
+        $xml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertContains(
+            "<foaf:age rdf:datatype=\"http://www.w3.org/2001/XMLSchema#int\">59</foaf:age>",
+            $xml
+        );
+
+    }
+
+    public function testSerialiseRdfXmlWithUnknownProperty()
+    {
+        $this->graph->add(
+            'http://www.example.com/joe#me',
+            'http://www.example.com/ns/foo',
+            'bar'
+        );
+
+        $xml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertContains("<ns0:foo>bar</ns0:foo>", $xml);
+        $this->assertContains("xmlns:ns0=\"http://www.example.com/ns/\"", $xml);
+    }
+
+    public function testSerialiseRdfXmlWithUnshortenableProperty()
+    {
+        $this->graph->add(
+            'http://www.example.com/joe#me',
+            'http://www.example.com/foo/',
+            'bar'
+        );
+
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'foo'
+        );
+        $this->serialiser->serialise($this->graph, 'rdfxml');
+    }
+
+    public function testSerialiseRdfXmlWithXMLLiteral()
+    {
+        $this->graph->add(
+            'http://www.example.com/joe#me',
+            'foaf:bio',
+            EasyRdf_Literal::create("<b>html</b>", null, 'rdf:XMLLiteral')
+        );
+
+        $xml = $this->serialiser->serialise($this->graph, 'rdfxml');
+        $this->assertContains(
+            "<foaf:bio rdf:parseType=\"Literal\"><b>html</b></foaf:bio>",
+            $xml
+        );
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_RdfXml does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise($this->graph, 'unsupportedformat');
+    }
+
+    /**
+     * testSerialiseRdfTypeAddsPrefix
+     *
+     * A test to assert that serialising a resource with a certain rdf:type
+     * adds the correct namespace prefix, even if there are no properties tied
+     * to that particular namespace.
+     */
+    public function testSerialiseRdfTypeAddsPrefix()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me', 'foaf:Person');
+        $joe->set('dc:creator', 'Max Bloggs');
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\"\n".
+            "         xmlns:dc=\"http://purl.org/dc/terms/\">\n\n" .
+            "  <foaf:Person rdf:about=\"http://www.example.com/joe#me\">\n".
+            "    <dc:creator>Max Bloggs</dc:creator>\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    /**
+     * testSerialiseReferenceAlreadyOutput
+     *
+     * Test referencing a resource with a single property that
+     * has already been output.
+     */
+    public function testSerialiseReferenceAlreadyOutput()
+    {
+        $this->graph->addLiteral('http://example.com/2', 'rdf:label', 'label');
+        $this->graph->addResource('http://example.com/1', 'foaf:homepage', 'http://example.com/2');
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <rdf:Description rdf:about=\"http://example.com/2\">\n".
+            "    <rdf:label>label</rdf:label>\n".
+            "  </rdf:Description>\n\n".
+            "  <rdf:Description rdf:about=\"http://example.com/1\">\n".
+            "    <foaf:homepage rdf:resource=\"http://example.com/2\"/>\n".
+            "  </rdf:Description>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+
+    public function testSerialiseContainer()
+    {
+        $joe =  $this->graph->resource('http://example.com/joe', 'foaf:Person');
+        $pets =  $this->graph->newBnode('rdf:Seq');
+        $pets->append('Rat');
+        $pets->append('Cat');
+        $pets->append('Goat');
+        $joe->add('foaf:pets', $pets);
+
+        $this->assertSame(
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
+            "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n".
+            "         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\">\n\n".
+            "  <foaf:Person rdf:about=\"http://example.com/joe\">\n".
+            "    <foaf:pets>\n".
+            "      <rdf:Seq>\n".
+            "        <rdf:li>Rat</rdf:li>\n".
+            "        <rdf:li>Cat</rdf:li>\n".
+            "        <rdf:li>Goat</rdf:li>\n".
+            "      </rdf:Seq>\n".
+            "    </foaf:pets>\n\n".
+            "  </foaf:Person>\n\n".
+            "</rdf:RDF>\n",
+            $this->serialiser->serialise($this->graph, 'rdfxml')
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Serialiser/TurtleTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,683 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(dirname(__FILE__))).
+             DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_Serialiser_TurtleTest extends EasyRdf_TestCase
+{
+    protected $serialiser = null;
+    protected $graph = null;
+
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->serialiser = new EasyRdf_Serialiser_Turtle();
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_Namespace::reset();
+        EasyRdf_Namespace::delete('example');
+    }
+
+    public function testEscapeIri()
+    {
+        $this->assertSame(
+            '<http://example.com/>',
+            EasyRdf_Serialiser_Turtle::escapeIri('http://example.com/')
+        );
+    }
+
+    public function testEscapeIriAngleBracket()
+    {
+        $this->assertSame(
+            '<http://google.com/search?q=<\>>',
+            EasyRdf_Serialiser_Turtle::escapeIri('http://google.com/search?q=<>')
+        );
+    }
+
+    public function testQuotedString()
+    {
+        $this->assertSame(
+            '"The man said \\"Hello\\""',
+            EasyRdf_Serialiser_Turtle::quotedString('The man said "Hello"')
+        );
+    }
+
+    public function testMultilineQuotedString()
+    {
+        $this->assertSame(
+            '"""Hello	World"""',
+            EasyRdf_Serialiser_Turtle::quotedString('Hello	World')
+        );
+    }
+
+    public function testSerialiseResource()
+    {
+        $res = $this->graph->resource('http://example.com/');
+        $this->assertSame(
+            '<http://example.com/>',
+            $this->serialiser->serialiseResource($res)
+        );
+    }
+
+    public function testSerialiseResourceShortenable()
+    {
+        $res = $this->graph->resource('http://xmlns.com/foaf/0.1/name');
+        $this->assertSame(
+            'foaf:name',
+            $this->serialiser->serialiseResource($res)
+        );
+    }
+
+    public function testSerialiseResourceBnode()
+    {
+        $res = $this->graph->newBnode();
+        $this->assertSame(
+            '_:genid1',
+            $this->serialiser->serialiseResource($res)
+        );
+    }
+
+    public function testSerialiseResourceAngleBracket()
+    {
+        $res = $this->graph->resource('http://google.com/search?q=<>');
+        $this->assertSame(
+            '<http://google.com/search?q=<\>>',
+            $this->serialiser->serialiseResource($res)
+        );
+    }
+
+    public function testSerialiseLiteral()
+    {
+        $literal = new EasyRdf_Literal('Hello World');
+        $this->assertSame(
+            '"Hello World"',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralMultiline()
+    {
+        $literal = new EasyRdf_Literal("Hello\nWorld");
+        $this->assertSame(
+            "\"\"\"Hello\nWorld\"\"\"",
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralInteger()
+    {
+        $literal = new EasyRdf_Literal_Integer(1);
+        $this->assertSame(
+            '1',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralDecimal()
+    {
+        $literal = new EasyRdf_Literal_Decimal(1.01);
+        $this->assertSame(
+            '1.01',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralDouble()
+    {
+        $literal = EasyRdf_Literal::create(1, null, 'xsd:double');
+        $this->assertSame(
+            '1.000000e+0',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralBoolean()
+    {
+        $literal = EasyRdf_Literal::create(true);
+        $this->assertSame(
+            'true',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralOtherXsd()
+    {
+        $literal = EasyRdf_Literal::create('value', null, 'xsd:other');
+        $this->assertSame(
+            '"value"^^xsd:other',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralOtherDatatype()
+    {
+        $literal = EasyRdf_Literal::create('value', null, 'http://example.com/dt');
+        $this->assertSame(
+            '"value"^^ns0:dt',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseLiteralWithLang()
+    {
+        $literal = EasyRdf_Literal::create('valeur', 'fr');
+        $this->assertSame(
+            '"valeur"@fr',
+            $this->serialiser->serialiseLiteral($literal)
+        );
+    }
+
+    public function testSerialiseObjectLiteral()
+    {
+        $literal = new EasyRdf_Literal('Hello World');
+        $this->assertSame(
+            '"Hello World"',
+            $this->serialiser->serialiseObject($literal)
+        );
+    }
+
+    public function testSerialiseObjectResource()
+    {
+        $res = $this->graph->resource('http://example.com/');
+        $this->assertSame(
+            '<http://example.com/>',
+            $this->serialiser->serialiseObject($res)
+        );
+    }
+
+    public function testSerialiseObjectUnknown()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            'serialiseObject() requires $object to be of type EasyRdf_Resource or EasyRdf_Literal'
+        );
+        $turtle = $this->serialiser->serialiseObject($this);
+    }
+
+    public function testSerialise()
+    {
+        $joe = $this->graph->resource(
+            'http://example.com/joe#me',
+            'foaf:Person'
+        );
+        $joe->set('foaf:name', 'Joe Bloggs');
+        $joe->set(
+            'foaf:homepage',
+            $this->graph->resource('http://example.com/joe/')
+        );
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "\n".
+            "<http://example.com/joe#me>\n".
+            "  a foaf:Person ;\n".
+            "  foaf:name \"Joe Bloggs\" ;\n".
+            "  foaf:homepage <http://example.com/joe/> .\n\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseMultipleValues()
+    {
+        $joe = $this->graph->resource(
+            'http://example.com/joe#me',
+            'foaf:Person'
+        );
+        $joe->add('foaf:name', 'Joseph');
+        $joe->add('foaf:name', 'Joe');
+        $joe->add('foaf:name', 'Josh');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "\n".
+            "<http://example.com/joe#me>\n".
+            "  a foaf:Person ;\n".
+            "  foaf:name \"Joseph\", \"Joe\", \"Josh\" .\n\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseAnonymousSubject()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $anon =  $this->graph->newBnode();
+        $anon->addLiteral('foaf:name', 'Anon');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "\n".
+            "[] foaf:name \"Anon\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseBnode()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $alice = $this->graph->resource('http://example.com/alice#me');
+        $project =  $this->graph->newBnode();
+        $project->add('foaf:name', 'Amazing Project');
+        $joe->add('foaf:currentProject', $project);
+        $alice->add('foaf:currentProject', $project);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:currentProject _:genid1 .\n".
+            "<http://example.com/alice#me> foaf:currentProject _:genid1 .\n".
+            "_:genid1 foaf:name \"Amazing Project\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseNestedBnode1()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $amy =  $this->graph->newBnode();
+        $amy->addLiteral('foaf:name', 'Amy');
+        $joe->add('foaf:knows', $amy);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "\n".
+            "<http://example.com/joe#me> foaf:knows [ foaf:name \"Amy\" ] .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseNestedBnode2()
+    {
+        $doc = $this->graph->resource('http://example.com/doc');
+        $joe = $this->graph->newBnode();
+        $doc->set('dc:creator', $joe);
+        $joe->set('foaf:name', 'Joe');
+        $joe->addResource('foaf:homepage', 'http://example.com/joe');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix dc: <http://purl.org/dc/terms/> .\n".
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/doc> dc:creator [\n".
+            "    foaf:name \"Joe\" ;\n".
+            "    foaf:homepage <http://example.com/joe>\n".
+            "  ] .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseNestedBnode3()
+    {
+        $alice = $this->graph->newBnode();
+        $alice->add('foaf:name', 'Alice');
+        $bob = $this->graph->newBnode();
+        $bob->add('foaf:name', 'Bob');
+        $bob->addResource('foaf:mbox', 'mailto:bob@example.com');
+        $eve = $this->graph->newBnode();
+        $eve->add('foaf:name', 'Eve');
+        $alice->add('foaf:knows', $bob);
+        $bob->add('foaf:knows', $eve);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "[]\n".
+            "  foaf:name \"Alice\" ;\n".
+            "  foaf:knows [\n".
+            "    foaf:name \"Bob\" ;\n".
+            "    foaf:mbox <mailto:bob@example.com> ;\n".
+            "    foaf:knows [ foaf:name \"Eve\" ]\n".
+            "  ] .\n\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseNestedBnode4()
+    {
+        $joe =  $this->graph->newBnode();
+        $alice =  $this->graph->newBnode();
+        $joe->add('foaf:name', 'Joe');
+        $alice->add('foaf:name', 'Alice');
+        $joe->add('foaf:knows', $alice);
+        $alice->add('foaf:knows', $joe);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "_:genid1\n".
+            "  foaf:name \"Joe\" ;\n".
+            "  foaf:knows [\n".
+            "    foaf:name \"Alice\" ;\n".
+            "    foaf:knows _:genid1\n".
+            "  ] .\n\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseCollection()
+    {
+        $joe =  $this->graph->resource('http://example.com/joe');
+        $pets =  $this->graph->newBnode('rdf:List');
+        $pets->append('Rat');
+        $pets->append('Cat');
+        $pets->append('Goat');
+        $joe->add('foaf:pets', $pets);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe> foaf:pets (\n".
+            "   \"Rat\"\n".
+            "   \"Cat\"\n".
+            "   \"Goat\"\n".
+            " ) .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseCollectionSingle()
+    {
+        $joe =  $this->graph->resource('http://example.com/joe');
+        $pets =  $this->graph->newBnode('rdf:List');
+        $pets->append('Rat');
+        $joe->add('foaf:pets', $pets);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe> foaf:pets ( \"Rat\" ) .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseCollectionEmpty()
+    {
+        $joe =  $this->graph->resource('http://example.com/joe');
+        $pets =  $this->graph->newBnode('rdf:List');
+        $joe->add('foaf:pets', $pets);
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe> foaf:pets ( ) .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseLang()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', new EasyRdf_Literal('Joe', 'en'));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:name \"Joe\"@en .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseEscaped()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', '\n');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:name \"\\\\n\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseEscaped2()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', '"Joe"');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:name \"\\\"Joe\\\"\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseMultiLineEscaped()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', "Line 1\nLine 2");
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:name \"\"\"Line 1\nLine 2\"\"\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseMultiLineEscaped2()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:name', "\t".'"""'."\t");
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:name \"\"\"\t\\\"\"\"\t\"\"\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseBooleanDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:truth', EasyRdf_Literal::create(true));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/joe#me> foaf:truth true .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseDecimalDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:age', new EasyRdf_Literal_Decimal(1.5));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/joe#me> foaf:age 1.5 .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseDoubleDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:age', EasyRdf_Literal::create(1.5, null, 'xsd:double'));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/joe#me> foaf:age 1.500000e+0 .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseIntegerDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:age', new EasyRdf_Literal_Integer(49));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/joe#me> foaf:age 49 .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseDateTimeDatatype()
+    {
+        $doc = $this->graph->resource('http://example.com/');
+        $doc->set('dc:date', new EasyRdf_Literal_DateTime('2012-11-04T13:01:26+01:00'));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix dc: <http://purl.org/dc/terms/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/> dc:date \"2012-11-04T13:01:26+01:00\"^^xsd:dateTime .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseOtherDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set('foaf:foo', EasyRdf_Literal::create('foobar', null, 'xsd:other'));
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\n".
+            "<http://example.com/joe#me> foaf:foo \"foobar\"^^xsd:other .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseUnknownDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set(
+            'foaf:foo',
+            EasyRdf_Literal::create('foobar', null, 'http://example.com/ns/type')
+        );
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n".
+            "@prefix ns0: <http://example.com/ns/> .\n\n".
+            "<http://example.com/joe#me> foaf:foo \"foobar\"^^ns0:type .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseShortenableResource()
+    {
+        EasyRdf_Namespace::set("example", 'http://example.com/');
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->add('rdf:type', 'foaf:Person');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix example: <http://example.com/> .\n\n".
+            "example:joe#me a \"foaf:Person\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseUnshortenableDatatype()
+    {
+        $joe = $this->graph->resource('http://example.com/joe#me');
+        $joe->set(
+            'foaf:foo',
+            EasyRdf_Literal::create('foobar', null, 'http://example.com/datatype/')
+        );
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\n".
+            "<http://example.com/joe#me> foaf:foo \"foobar\"^^<http://example.com/datatype/> .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialisePropertyWithUnknownNamespace()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $joe->set('http://example.com/ns/prop', 'bar');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertContains(
+            "@prefix ns0: <http://example.com/ns/> .",
+            $turtle
+        );
+        $this->assertSame(
+            "@prefix ns0: <http://example.com/ns/> .\n\n".
+            "<http://www.example.com/joe#me> ns0:prop \"bar\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseUnshortenableProperty()
+    {
+        $joe = $this->graph->resource('http://www.example.com/joe#me');
+        $joe->set('http://example.com/property/', 'bar');
+
+        $turtle = $this->serialiser->serialise($this->graph, 'turtle');
+        $this->assertSame(
+            "<http://www.example.com/joe#me> <http://example.com/property/> \"bar\" .\n",
+            $turtle
+        );
+    }
+
+    public function testSerialiseUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'EasyRdf_Serialiser_Turtle does not support: unsupportedformat'
+        );
+        $rdf = $this->serialiser->serialise(
+            $this->graph,
+            'unsupportedformat'
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/SerialiserTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class MockSerialiser extends EasyRdf_Serialiser
+{
+    public function serialise($graph, $format)
+    {
+        parent::checkSerialiseParams($graph, $format);
+        // Serialising goes here
+        return true;
+    }
+}
+
+class EasyRdf_SerialiserTest extends EasyRdf_TestCase
+{
+    /**
+     * Set up the test suite before each test
+     */
+    public function setUp()
+    {
+        $this->graph = new EasyRdf_Graph();
+        $this->resource = $this->graph->resource('http://www.example.com/');
+        $this->serialiser = new MockSerialiser();
+    }
+
+    public function testSerialise()
+    {
+        $this->assertTrue(
+            $this->serialiser->serialise($this->graph, 'php')
+        );
+    }
+
+    public function testSerialiseFormatObject()
+    {
+        $format = EasyRdf_Format::getFormat('json');
+        $this->assertTrue(
+            $this->serialiser->serialise($this->graph, $format)
+        );
+    }
+
+    public function testSerialiseNullGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->serialiser->serialise(null, 'php');
+    }
+
+    public function testSerialiseNonObjectGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->serialiser->serialise('string', 'php');
+    }
+
+    public function testSerialiseNonGraph()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$graph should be an EasyRdf_Graph object and cannot be null'
+        );
+        $this->serialiser->serialise($this->resource, 'php');
+    }
+
+    public function testSerialiseNullFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format cannot be null or empty'
+        );
+        $this->serialiser->serialise($this->graph, null);
+    }
+
+    public function testSerialiseEmptyFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format cannot be null or empty'
+        );
+        $this->serialiser->serialise($this->graph, '');
+    }
+
+    public function testSerialiseBadObjectFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format should be a string or an EasyRdf_Format object'
+        );
+        $this->serialiser->serialise($this->graph, $this);
+    }
+
+    public function testSerialiseIntegerFormat()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$format should be a string or an EasyRdf_Format object'
+        );
+        $this->serialiser->serialise($this->graph, 1);
+    }
+
+    public function testSerialiseUndefined()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'This method should be overridden by sub-classes.'
+        );
+        $serialiser = new EasyRdf_Serialiser();
+        $serialiser->serialise($this->graph, 'format');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Sparql/ClientTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,371 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Sparql_ClientTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        EasyRdf_Http::setDefaultHttpClient(
+            $this->client = new EasyRdf_Http_MockClient()
+        );
+        $this->sparql = new EasyRdf_Sparql_Client('http://localhost:8080/sparql');
+    }
+
+    # FIXME: this is deprecated
+    public function testGetUri()
+    {
+        $this->assertSame(
+            'http://localhost:8080/sparql',
+            $this->sparql->getUri()
+        );
+    }
+
+    public function testGetQueryUri()
+    {
+        $this->assertSame(
+            'http://localhost:8080/sparql',
+            $this->sparql->getQueryUri()
+        );
+    }
+    
+    public function testGetUpdateUri()
+    {
+        $this->assertSame(
+            'http://localhost:8080/sparql',
+            $this->sparql->getUpdateUri()
+        );
+    }
+
+    public function testGetDifferentUpdateUri()
+    {
+        $sparql = new EasyRdf_Sparql_Client(
+            'http://localhost/query',
+            'http://localhost/update'
+        );
+        $this->assertSame(
+            'http://localhost/query',
+            $sparql->getQueryUri()
+        );
+        $this->assertSame(
+            'http://localhost/update',
+            $sparql->getUpdateUri()
+        );
+    }
+
+    public function testQuerySelectAll()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+%2A+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('sparql_select_all.xml'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+xml')
+            )
+        );
+        $result = $this->sparql->query("SELECT * WHERE {?s ?p ?o}");
+        $this->assertCount(14, $result);
+        $this->assertEquals(
+            new EasyRdf_Resource('_:genid1'),
+            $result[0]->s
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name'),
+            $result[0]->p
+        );
+        $this->assertEquals(
+            new EasyRdf_Literal("Joe's Current Project"),
+            $result[0]->o
+        );
+    }
+
+    public function testQuerySelectAllJsonWithCharset()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+%2A+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('sparql_select_all.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json; charset=utf-8')
+            )
+        );
+        $result = $this->sparql->query("SELECT * WHERE {?s ?p ?o}");
+        $this->assertCount(14, $result);
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+        $this->assertEquals(
+            new EasyRdf_Literal("Joe's Current Project"),
+            $result[0]->o
+        );
+    }
+
+    public function testQuerySelectAllUnsupportedFormat()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+%2A+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('sparql_select_all.json'),
+            array(
+                'headers' => array('Content-Type' => 'unsupported/format')
+            )
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Format is not recognised: unsupported/format'
+        );
+        $result = $this->sparql->query("SELECT * WHERE {?s ?p ?o}");
+    }
+
+    public function checkHugeQuerySelect($client)
+    {
+        $this->assertRegExp('/^query=/', $client->getRawData());
+        $this->assertSame("application/x-www-form-urlencoded", $client->getHeader('Content-Type'));
+        return true;
+    }
+
+    public function testHugeQuerySelect()
+    {
+        $this->client->addMock(
+            'POST',
+            '/sparql',
+            readFixture('sparql_select_all.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json'),
+                'callback' => array($this, 'checkHugeQuerySelect')
+            )
+        );
+
+        // Add extra 2k+ of comment to start of query
+        $padding = str_repeat("# comment 012345678901234567890123456789\n", 50);
+        $result = $this->sparql->query("$padding SELECT * WHERE {?s ?p ?o}");
+        $this->assertCount(14, $result);
+    }
+
+    public function testQueryAddPrefix()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=PREFIX+rdf%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F'.
+            '1999%2F02%2F22-rdf-syntax-ns%23%3E%0ASELECT+%3Ft+WHERE+'.
+            '%7B%3Fs+rdf%3Atype+%3Ft%7D',
+            readFixture('sparql_select_all_types.xml'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+xml')
+            )
+        );
+        $result = $this->sparql->query("SELECT ?t WHERE {?s rdf:type ?t}");
+        $this->assertCount(3, $result);
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/Project'),
+            $result[0]->t
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/PersonalProfileDocument'),
+            $result[1]->t
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/Person'),
+            $result[2]->t
+        );
+    }
+
+    public function testQueryAskTrue()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=ASK+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('sparql_ask_true.xml'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+xml')
+            )
+        );
+        $result = $this->sparql->query("ASK WHERE {?s ?p ?o}");
+        $this->assertSame(true, $result->getBoolean());
+    }
+
+    public function testQueryAskFalse()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=ASK+WHERE+%7B%3Fs+%3Fp+%3Cfalse%3E%7D',
+            readFixture('sparql_ask_false.xml'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+xml')
+            )
+        );
+        $result = $this->sparql->query("ASK WHERE {?s ?p <false>}");
+        $this->assertSame(false, $result->getBoolean());
+    }
+
+    public function testQueryConstructJson()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=CONSTRUCT+%7B%3Fs+%3Fp+%3Fo%7D+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('foaf.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/json')
+            )
+        );
+        $graph = $this->sparql->query("CONSTRUCT {?s ?p ?o} WHERE {?s ?p ?o}");
+        $this->assertClass('EasyRdf_Graph', $graph);
+        $name = $graph->get('http://www.example.com/joe#me', 'foaf:name');
+        $this->assertStringEquals('Joe Bloggs', $name);
+    }
+
+    public function testQueryConstructJsonWithCharset()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=CONSTRUCT+%7B%3Fs+%3Fp+%3Fo%7D+WHERE+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('foaf.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/json; charset=utf-8')
+            )
+        );
+        $graph = $this->sparql->query("CONSTRUCT {?s ?p ?o} WHERE {?s ?p ?o}");
+        $this->assertClass('EasyRdf_Graph', $graph);
+        $name = $graph->get('http://www.example.com/joe#me', 'foaf:name');
+        $this->assertStringEquals('Joe Bloggs', $name);
+    }
+
+    public function testQueryInvalid()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=FOOBAR',
+            "There was an error while executing the query.\nSPARQL syntax error at 'F', line 1",
+            array(
+                'status' => 500,
+                'headers' => array('Content-Type' => 'text/plain')
+            )
+        );
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'HTTP request for SPARQL query failed: There was an error while executing the query.'
+        );
+        $response = $this->sparql->query("FOOBAR");
+    }
+
+    public function testCountTriples()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+%28COUNT%28%2A%29+AS+%3Fcount%29+%7B%3Fs+%3Fp+%3Fo%7D',
+            readFixture('sparql_select_count.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json; charset=utf-8')
+            )
+        );
+        $count = $this->sparql->countTriples();
+        $this->assertSame(143, $count);
+    }
+
+    public function testCountTriplesWithCondition()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=PREFIX+foaf%3A+%3Chttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2F%3E%0A'.
+            'SELECT+%28COUNT%28%2A%29+AS+%3Fcount%29+%7B%3Fs+a+foaf%3APerson%7D',
+            readFixture('sparql_select_count_zero.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json; charset=utf-8')
+            )
+        );
+        $count = $this->sparql->countTriples('?s a foaf:Person');
+        $this->assertSame(0, $count);
+    }
+
+    public function testListNamedGraphs()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+DISTINCT+%3Fg+WHERE+%7BGRAPH+%3Fg+%7B%3Fs+%3Fp+%3Fo%7D%7D',
+            readFixture('sparql_select_named_graphs.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json; charset=utf-8')
+            )
+        );
+        $list = $this->sparql->listNamedGraphs();
+        $this->assertCount(3, $list);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/0'), $list[0]);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/1'), $list[1]);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/2'), $list[2]);
+    }
+
+    public function testListNamedGraphsWithLimit()
+    {
+        $this->client->addMock(
+            'GET',
+            '/sparql?query=SELECT+DISTINCT+%3Fg+WHERE+%7BGRAPH+%3Fg+%7B%3Fs+%3Fp+%3Fo%7D%7D+LIMIT+10',
+            readFixture('sparql_select_named_graphs.json'),
+            array(
+                'headers' => array('Content-Type' => 'application/sparql-results+json; charset=utf-8')
+            )
+        );
+        $list = $this->sparql->listNamedGraphs(10);
+        $this->assertCount(3, $list);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/0'), $list[0]);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/1'), $list[1]);
+        $this->assertEquals(new EasyRdf_Resource('http://example.org/2'), $list[2]);
+    }
+
+    public function checkUpdate($client)
+    {
+        $this->assertSame('INSERT DATA { <a> <p> <b> }', $client->getRawData());
+        $this->assertSame("application/sparql-update", $client->getHeader('Content-Type'));
+        return true;
+    }
+    
+    public function testUpdate()
+    {
+        $this->client->addMock(
+            'POST',
+            '/sparql',
+            '',
+            array(
+                'status' => 204,
+                'callback' => array($this, 'checkUpdate')
+            )
+        );
+
+        $result = $this->sparql->update('INSERT DATA { <a> <p> <b> }');
+        $this->assertSame(204, $result->getStatus());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/Sparql/ResultTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,485 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../') . '/TestHelper.php';
+
+
+class EasyRdf_Sparql_ResultTest extends EasyRdf_TestCase
+{
+    public function testSelectAllXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+
+        $this->assertCount(14, $result);
+        $this->assertSame(14, $result->numRows());
+        $this->assertSame(14, count($result));
+        $this->assertEquals(
+            new EasyRdf_Resource('_:genid1'),
+            $result[0]->s
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name'),
+            $result[0]->p
+        );
+        $this->assertEquals(
+            new EasyRdf_Literal("Joe's Current Project"),
+            $result[0]->o
+        );
+    }
+
+    public function testSelectAllXmlWithWhitespace()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all_ws.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+
+        $this->assertCount(14, $result);
+        $this->assertSame(14, $result->numRows());
+        $this->assertSame(14, count($result));
+        $this->assertEquals(
+            new EasyRdf_Resource('_:genid1'),
+            $result[0]->s
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name'),
+            $result[0]->p
+        );
+        $this->assertEquals(
+            new EasyRdf_Literal("Joe's Current Project"),
+            $result[0]->o
+        );
+    }
+
+    public function testSelectAllJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all.json'),
+            'application/sparql-results+json'
+        );
+
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+
+        $this->assertCount(14, $result);
+        $this->assertSame(14, $result->numRows());
+        $this->assertSame(14, count($result));
+        $this->assertEquals(
+            new EasyRdf_Resource('_:genid1'),
+            $result[0]->s
+        );
+        $this->assertEquals(
+            new EasyRdf_Resource('http://xmlns.com/foaf/0.1/name'),
+            $result[0]->p
+        );
+        $this->assertEquals(
+            new EasyRdf_Literal("Joe's Current Project"),
+            $result[0]->o
+        );
+    }
+
+    public function testSelectEmptyXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_empty.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+        $this->assertCount(0, $result);
+    }
+
+    public function testSelectEmptyJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_empty.json'),
+            'application/sparql-results+json'
+        );
+
+        $this->assertSame(3, $result->numFields());
+        $this->assertSame(array('s','p','o'), $result->getFields());
+        $this->assertCount(0, $result);
+    }
+
+    public function testSelectLangLiteralXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_lang.xml'),
+            'application/sparql-results+xml'
+        );
+
+        # 1st: Example using xml:lang="en"
+        $first = $result[0];
+        $this->assertSame('London', $first->label->getValue());
+        $this->assertSame('en', $first->label->getLang());
+        $this->assertSame(null, $first->label->getDatatype());
+
+        # 2nd: Example using xml:lang="es"
+        $second = $result[1];
+        $this->assertSame('Londres', $second->label->getValue());
+        $this->assertSame('es', $second->label->getLang());
+        $this->assertSame(null, $second->label->getDatatype());
+
+        # 3rd: no lang
+        $third = $result[2];
+        $this->assertSame('London', $third->label->getValue());
+        $this->assertSame(null, $third->label->getLang());
+        $this->assertSame(null, $third->label->getDatatype());
+    }
+
+    public function testSelectLangLiteralJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_lang.json'),
+            'application/sparql-results+json'
+        );
+
+        # 1st: Example using xml:lang="en"
+        $first = $result[0];
+        $this->assertSame('London', $first->label->getValue());
+        $this->assertSame('en', $first->label->getLang());
+        $this->assertSame(null, $first->label->getDatatype());
+
+        # 2nd: Example using lang="es"
+        $second = $result[1];
+        $this->assertSame('Londres', $second->label->getValue());
+        $this->assertSame('es', $second->label->getLang());
+        $this->assertSame(null, $second->label->getDatatype());
+
+        # 3rd: no lang
+        $third = $result[2];
+        $this->assertSame('London', $third->label->getValue());
+        $this->assertSame(null, $third->label->getLang());
+        $this->assertSame(null, $third->label->getDatatype());
+    }
+
+    public function testSelectTypedLiteralJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_typed_literal.json'),
+            'application/sparql-results+json'
+        );
+
+        $first = $result[0];
+        $this->assertStringEquals('http://www.bbc.co.uk/programmes/b0074dlv#programme', $first->episode);
+        $this->assertStringEquals(1, $first->pos);
+        $this->assertStringEquals('Rose', $first->label);
+    }
+
+    public function testSelectTypedLiteralXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_typed_literal.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $first = $result[0];
+        $this->assertStringEquals('http://www.bbc.co.uk/programmes/b0074dlv#programme', $first->episode);
+        $this->assertStringEquals(1, $first->pos);
+        $this->assertStringEquals('Rose', $first->label);
+    }
+
+    public function testAskTrueJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_true.json'),
+            'application/sparql-results+json'
+        );
+
+        $this->assertSame('boolean', $result->getType());
+        $this->assertFalse($result->isFalse());
+        $this->assertTrue($result->isTrue());
+        $this->assertSame(true, $result->getBoolean());
+        $this->assertStringEquals('true', $result);
+
+        $this->assertSame(0, $result->numFields());
+        $this->assertSame(0, $result->numRows());
+        $this->assertSame(0, count($result));
+    }
+
+    public function testAskFalseJson()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.json'),
+            'application/sparql-results+json'
+        );
+
+        $this->assertSame('boolean', $result->getType());
+        $this->assertTrue($result->isFalse());
+        $this->assertFalse($result->isTrue());
+        $this->assertSame(false, $result->getBoolean());
+        $this->assertStringEquals('false', $result);
+
+        $this->assertSame(0, $result->numFields());
+        $this->assertSame(0, $result->numRows());
+        $this->assertSame(0, count($result));
+    }
+
+    public function testAskTrueXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_true.xml'),
+            'application/sparql-results+xml'
+        );
+        $this->assertSame('boolean', $result->getType());
+        $this->assertFalse($result->isFalse());
+        $this->assertTrue($result->isTrue());
+        $this->assertSame(true, $result->getBoolean());
+        $this->assertStringEquals('true', $result);
+
+        $this->assertSame(0, $result->numFields());
+        $this->assertSame(0, $result->numRows());
+        $this->assertSame(0, count($result));
+    }
+
+    public function testAskFalseXml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.xml'),
+            'application/sparql-results+xml'
+        );
+        $this->assertSame('boolean', $result->getType());
+        $this->assertTrue($result->isFalse());
+        $this->assertFalse($result->isTrue());
+        $this->assertSame(false, $result->getBoolean());
+        $this->assertStringEquals('false', $result);
+
+        $this->assertSame(0, $result->numFields());
+        $this->assertSame(0, $result->numRows());
+        $this->assertSame(0, count($result));
+    }
+
+    public function testInvalidXml()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to parse SPARQL XML Query Results format'
+        );
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_invalid.xml'),
+            'application/sparql-results+xml'
+        );
+    }
+
+    public function testNotSparqlXml()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Incorrect root node in SPARQL XML Query Results format'
+        );
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('not_sparql_result.xml'),
+            'application/sparql-results+xml'
+        );
+    }
+
+    public function testInvalidJson()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to parse SPARQL JSON Query Results format'
+        );
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_invalid.json'),
+            'application/sparql-results+json'
+        );
+    }
+
+    public function testInvalidJsonTerm()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to parse SPARQL Query Results format, unknown term type: newtype'
+        );
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_invalid_term.json'),
+            'application/sparql-results+json'
+        );
+    }
+
+    public function testDumpSelectAllHtml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $html = $result->dump('html');
+        $this->assertContains("<table class='sparql-results'", $html);
+        $this->assertContains(">?s</th>", $html);
+        $this->assertContains(">?p</th>", $html);
+        $this->assertContains(">?o</th></tr>", $html);
+
+        $this->assertContains(">http://www.example.com/joe#me</a></td>", $html);
+        $this->assertContains(">foaf:name</a></td>", $html);
+        $this->assertContains(">&quot;Joe Bloggs&quot;@en</span></td>", $html);
+        $this->assertContains("</table>", $html);
+    }
+
+    public function testDumpSelectAllText()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $text = $result->dump('text');
+        $this->assertContains('+-------------------------------------+', $text);
+        $this->assertContains('| ?s                                  |', $text);
+        $this->assertContains('| http://www.example.com/joe#me       |', $text);
+        $this->assertContains('+---------------------+', $text);
+        $this->assertContains('| ?p                  |', $text);
+        $this->assertContains('| foaf:name           |', $text);
+        $this->assertContains('+--------------------------------+', $text);
+        $this->assertContains('| ?o                             |', $text);
+        $this->assertContains('| "Joe Bloggs"@en                |', $text);
+    }
+
+    public function testDumpSelectUnbound()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_unbound.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $html = $result->dump('html');
+        $this->assertContains(">?person</th>", $html);
+        $this->assertContains(">?name</th>", $html);
+        $this->assertContains(">?foo</th>", $html);
+
+        $this->assertContains('>http://dbpedia.org/resource/Tim_Berners-Lee</a>', $html);
+        $this->assertContains('>&quot;Tim Berners-Lee&quot;@en</span>', $html);
+        $this->assertContains('<td>&nbsp;</td>', $html);
+    }
+
+    public function testDumpAskFalseHtml()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $html = $result->dump('html');
+        $this->assertContains(">false</span>", $html);
+    }
+
+    public function testDumpAskFalseText()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $text = $result->dump('text');
+        $this->assertSame("Result: false", $text);
+    }
+
+    public function testDumpUnknownType()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $reflector = new ReflectionProperty('EasyRdf_Sparql_Result', 'type');
+        if (!method_exists($reflector, 'setAccessible')) {
+            $this->markTestSkipped(
+                'ReflectionProperty::setAccessible() is not available.'
+            );
+        } else {
+            $reflector->setAccessible(true);
+        }
+        $reflector->setValue($result, 'foobar');
+
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Failed to dump SPARQL Query Results format, unknown type: foobar'
+        );
+        $str = $result->dump();
+    }
+
+    public function testToStringBooleanTrue()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_true.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $this->assertSame("true", strval($result));
+    }
+
+    public function testToStringBooleanFalse()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_ask_false.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $this->assertSame("false", strval($result));
+    }
+
+    public function testToStringSelectAll()
+    {
+        $result = new EasyRdf_Sparql_Result(
+            readFixture('sparql_select_all.xml'),
+            'application/sparql-results+xml'
+        );
+
+        $string = strval($result);
+        $this->assertContains('+-------------------------------------+', $string);
+        $this->assertContains('| http://www.example.com/joe#me       |', $string);
+    }
+
+    public function testUnsupportedFormat()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Unsupported SPARQL Query Results format: foo/bar'
+        );
+        $result = new EasyRdf_Sparql_Result('foobar', 'foo/bar');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/TestCase.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+
+class EasyRdf_TestCase extends PHPUnit_Framework_TestCase
+{
+
+    public static function assertStringEquals($str1, $str2, $message = null)
+    {
+        self::assertSame(strval($str1), strval($str2), $message);
+    }
+
+    // Note: this differs from assertInstanceOf because it disallows subclasses
+    public static function assertClass($class, $object)
+    {
+        self::assertSame($class, get_class($object));
+    }
+
+    // PHPUnit 3.5 doesn't have assertCount()
+    public static function assertCount($expectedCount, $haystack, $message = '')
+    {
+        if (method_exists(get_parent_class(__CLASS__), 'assertCount')) {
+            parent::assertCount($expectedCount, $haystack, $message);
+        } else {
+            self::assertSame($expectedCount, count($haystack));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/TypeMapperTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,227 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class MyType_Class extends EasyRdf_Resource
+{
+    public function myMethod()
+    {
+        return true;
+    }
+}
+
+
+class EasyRdf_TypeMapperTest extends EasyRdf_TestCase
+{
+    public function setUp()
+    {
+        EasyRdf_TypeMapper::set('rdf:mytype', 'MyType_Class');
+    }
+
+    public function tearDown()
+    {
+        EasyRdf_TypeMapper::delete('rdf:mytype');
+        EasyRdf_TypeMapper::delete('foaf:Person');
+    }
+
+
+    public function testGet()
+    {
+        $this->assertSame(
+            'MyType_Class',
+            EasyRdf_TypeMapper::get('rdf:mytype')
+        );
+    }
+
+    public function testGetUri()
+    {
+        $this->assertSame(
+            'MyType_Class',
+            EasyRdf_TypeMapper::get(
+                'http://www.w3.org/1999/02/22-rdf-syntax-ns#mytype'
+            )
+        );
+    }
+
+    public function testGetNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::get(null);
+    }
+
+    public function testGetEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::get('');
+    }
+
+    public function testGetNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::get(array());
+    }
+
+    public function testGetUnknown()
+    {
+        $this->assertSame(null, EasyRdf_TypeMapper::get('unknown:type'));
+    }
+
+    public function testSetUri()
+    {
+        EasyRdf_TypeMapper::set(
+            'http://xmlns.com/foaf/0.1/Person',
+            'MyType_Class'
+        );
+
+        $this->assertSame(
+            'MyType_Class',
+            EasyRdf_TypeMapper::get('foaf:Person')
+        );
+    }
+
+    public function testSetTypeNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set(null, 'MyType_Class');
+    }
+
+    public function testSetTypeEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set('', 'MyType_Class');
+    }
+
+    public function testSetTypeNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set(array(), 'MyType_Class');
+    }
+
+    public function testSetClassNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set('rdf:mytype', null);
+    }
+
+    public function testSetClassEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set('rdf:mytype', '');
+    }
+
+    public function testSetClassNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$class should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::set('rdf:mytype', array());
+    }
+
+    public function testDelete()
+    {
+        $this->assertSame('MyType_Class', EasyRdf_TypeMapper::get('rdf:mytype'));
+        EasyRdf_TypeMapper::delete('rdf:mytype');
+        $this->assertSame(null, EasyRdf_TypeMapper::get('rdf:mytype'));
+    }
+
+    public function testDeleteTypeNull()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::delete(null);
+    }
+
+    public function testDeleteTypeEmpty()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::delete('');
+    }
+
+    public function testDeleteTypeNonString()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$type should be a string and cannot be null or empty'
+        );
+        EasyRdf_TypeMapper::delete(array());
+    }
+
+    public function testInstantiate()
+    {
+        EasyRdf_TypeMapper::set('foaf:Person', 'MyType_Class');
+        $data = readFixture('foaf.json');
+        $graph = new EasyRdf_Graph(
+            'http://www.example.com/joe/foaf.rdf',
+            $data,
+            'json'
+        );
+        $joe = $graph->resource('http://www.example.com/joe#me');
+        $this->assertClass('MyType_Class', $joe);
+        $this->assertTrue($joe->myMethod());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/EasyRdf/UtilsTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,392 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class EasyRdf_UtilsTest extends EasyRdf_TestCase
+{
+    public function testCameliseSimple()
+    {
+        $this->assertSame(
+            'Hello',
+            EasyRdf_Utils::camelise('hEllO')
+        );
+    }
+
+    public function testCameliseUnderscore()
+    {
+        $this->assertSame(
+            'HelloWorld',
+            EasyRdf_Utils::camelise('hello_world')
+        );
+    }
+
+    public function testCameliseDHyphen()
+    {
+        $this->assertSame(
+            'HelloWorld',
+            EasyRdf_Utils::camelise('hello-world')
+        );
+    }
+
+    public function testCameliseDoubleHyphen()
+    {
+        $this->assertSame(
+            'HelloWorld',
+            EasyRdf_Utils::camelise('hello--world')
+        );
+    }
+
+    public function testCameliseSpace()
+    {
+        $this->assertSame(
+            'HelloWorld',
+            EasyRdf_Utils::camelise('hello  world')
+        );
+    }
+
+    public function testCameliseFilePath()
+    {
+        $this->assertSame(
+            'IAmEvilPhp',
+            EasyRdf_Utils::camelise('../../I/am/Evil.php')
+        );
+    }
+
+    public function testCameliseEmpty()
+    {
+        $this->assertSame(
+            '',
+            EasyRdf_Utils::camelise('')
+        );
+    }
+
+    public function testIsAssoc()
+    {
+        $arr = array('foo' => 'bar');
+        $this->assertTrue(EasyRdf_Utils::isAssociativeArray($arr));
+
+    }
+
+    public function testIsAssocNonArray()
+    {
+         $this->assertFalse(EasyRdf_Utils::isAssociativeArray('foo'));
+    }
+
+    public function testIsAssocArray()
+    {
+        $arr = array('foo', 'bar');
+        $this->assertFalse(EasyRdf_Utils::isAssociativeArray($arr));
+    }
+
+    public function testIsAssocIntAppend()
+    {
+        $arr = array('foo' => 'bar');
+        array_push($arr, 'rat');
+        $this->assertTrue(EasyRdf_Utils::isAssociativeArray($arr));
+    }
+
+    public function testIsAssocIntPreppend()
+    {
+        $arr = array('foo' => 'bar');
+        array_unshift($arr, 'rat');
+        $this->assertFalse(EasyRdf_Utils::isAssociativeArray($arr));
+    }
+
+    public function testRemoveFragment()
+    {
+        $this->assertSame(
+            'http://example.com/',
+            EasyRdf_Utils::removeFragmentFromUri('http://example.com/#foo')
+        );
+    }
+
+    public function testRemoveFragmentNoFragment()
+    {
+        $this->assertSame(
+            'http://example.com/',
+            EasyRdf_Utils::removeFragmentFromUri('http://example.com/')
+        );
+    }
+
+    public function testRemoveFragmentExtraHash()
+    {
+        $this->assertSame(
+            'http://example.com/',
+            EasyRdf_Utils::removeFragmentFromUri('http://example.com/#foo#bar')
+        );
+    }
+
+    public function testDumpResourceValue()
+    {
+        $res = new EasyRdf_Resource('http://www.example.com/');
+        $this->assertSame(
+            "http://www.example.com/",
+            EasyRdf_Utils::dumpResourceValue($res, 'text')
+        );
+        $this->assertSame(
+            "<a href='http://www.example.com/' ".
+            "style='text-decoration:none;color:blue'>".
+            "http://www.example.com/</a>",
+            EasyRdf_Utils::dumpResourceValue($res, 'html')
+        );
+    }
+
+    public function testDumpResourceValueFromArray()
+    {
+        $res = array('type' => 'uri', 'value' => 'http://www.example.com/');
+        $this->assertSame(
+            "http://www.example.com/",
+            EasyRdf_Utils::dumpResourceValue($res, 'text')
+        );
+        $this->assertSame(
+            "<a href='http://www.example.com/' ".
+            "style='text-decoration:none;color:blue'>".
+            "http://www.example.com/</a>",
+            EasyRdf_Utils::dumpResourceValue($res, 'html')
+        );
+    }
+
+    public function testDumpResourceValueWithQuotes()
+    {
+        $this->assertSame(
+            "<a href='a&#039; onclick=&#039;alert(1)' ".
+            "style='text-decoration:none;color:blue'>a&#039; onclick=&#039;alert(1)</a>",
+            EasyRdf_Utils::dumpResourceValue("a' onclick='alert(1)")
+        );
+    }
+
+    public function testDumpResourceValueWithIllegalColor()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$color must be a legal color code or name'
+        );
+        EasyRdf_Utils::dumpResourceValue(
+            'http://example.com/',
+            'html',
+            "blue'><script>alert(1);</script><!--"
+        );
+    }
+
+    public function testDumpLiteralValue()
+    {
+        $literal = new EasyRdf_Literal("hello & world");
+        $this->assertSame(
+            '"hello & world"',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;hello &amp; world&quot;</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueFromArray()
+    {
+        $literal = array('type' => 'literal', 'value' => 'Hot Sauce');
+        $this->assertSame(
+            '"Hot Sauce"',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;Hot Sauce&quot;</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueFromString()
+    {
+        $literal = 'a string';
+        $this->assertSame(
+            '"a string"',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;a string&quot;</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueWithLanguage()
+    {
+        $literal = array('type' => 'literal', 'value' => 'Nick', 'lang' => 'en');
+        $this->assertSame(
+            '"Nick"@en',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;Nick&quot;@en</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueWithDatatype()
+    {
+        $literal = array(
+            'type' => 'literal',
+            'value' => '1',
+            'datatype' => 'http://www.w3.org/2001/XMLSchema#integer'
+        );
+        $this->assertSame(
+            '"1"^^xsd:integer',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;1&quot;^^xsd:integer</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueWithUriDatatype()
+    {
+        $literal = array(
+            'type' => 'literal',
+            'value' => '1',
+            'datatype' => 'http://example.com/datatypes/int'
+        );
+        $this->assertSame(
+            '"1"^^<http://example.com/datatypes/int>',
+            EasyRdf_Utils::dumpLiteralValue($literal, 'text')
+        );
+        $this->assertSame(
+            "<span style='color:black'>&quot;1&quot;^^".
+            "&lt;http://example.com/datatypes/int&gt;</span>",
+            EasyRdf_Utils::dumpLiteralValue($literal, 'html')
+        );
+    }
+
+    public function testDumpLiteralValueWithIllegalColor()
+    {
+        $this->setExpectedException(
+            'InvalidArgumentException',
+            '$color must be a legal color code or name'
+        );
+        EasyRdf_Utils::dumpLiteralValue(
+            'literal',
+            'html',
+            "blue'><script>alert(1);</script><!--"
+        );
+    }
+
+    public function testParseMimeTypeBasic()
+    {
+        list($type) = EasyRdf_Utils::parseMimeType('text/plain');
+        $this->assertSame('text/plain', $type);
+    }
+
+    public function testParseMimeTypeMixedCase()
+    {
+        list($type) = EasyRdf_Utils::parseMimeType('TEXT/Plain');
+        $this->assertSame('text/plain', $type);
+    }
+
+    public function testParseMimeTypeBasicWithWhitespace()
+    {
+        list($type) = EasyRdf_Utils::parseMimeType(' text/plain  ');
+        $this->assertSame('text/plain', $type);
+    }
+
+    public function testParseMimeTypeBasicWithCharset()
+    {
+        list($type, $params) = EasyRdf_Utils::parseMimeType('text/plain;charset=utf8');
+        $this->assertSame('text/plain', $type);
+        $this->assertSame('utf8', $params['charset']);
+    }
+
+    public function testParseMimeTypeBasicWithMixedcaseCharset()
+    {
+        list($type, $params) = EasyRdf_Utils::parseMimeType('text/plain;charset=UTF8');
+        $this->assertSame('text/plain', $type);
+        $this->assertSame('utf8', $params['charset']);
+    }
+
+    public function testParseMimeTypeBasicWithCharsetAndWhitespace()
+    {
+        list($type, $params) = EasyRdf_Utils::parseMimeType(' text/plain ; charset = utf8 ');
+        $this->assertSame('text/plain', $type);
+        $this->assertSame('utf8', $params['charset']);
+    }
+
+    public function testExecCommandPipeTrue()
+    {
+        $output = EasyRdf_Utils::execCommandPipe('true');
+        $this->assertSame('', $output);
+    }
+
+    public function testExecCommandPipeLs()
+    {
+        $output = EasyRdf_Utils::execCommandPipe('ls', array('/bin/'));
+        $this->assertContains('cat', explode("\n", $output));
+    }
+
+    public function testExecCommandPipeLsWithDir()
+    {
+        $output = EasyRdf_Utils::execCommandPipe('ls', null, null, '/bin');
+        $this->assertContains('rm', explode("\n", $output));
+    }
+
+    public function testExecCommandPipeEcho()
+    {
+        $output = EasyRdf_Utils::execCommandPipe('echo', 'Test Message');
+        $this->assertSame("Test Message\n", $output);
+    }
+
+    public function testExecCommandPipeCat()
+    {
+        $output = EasyRdf_Utils::execCommandPipe('cat', null, 'Test Message 2');
+        $this->assertSame("Test Message 2", $output);
+    }
+
+    public function testExecCommandPipeFalse()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Error while executing command false'
+        );
+        $output = EasyRdf_Utils::execCommandPipe('false');
+    }
+
+    public function testExecCommandPipeNotFound()
+    {
+        $this->setExpectedException(
+            'EasyRdf_Exception',
+            'Error while executing command no_such_command'
+        );
+        $output = EasyRdf_Utils::execCommandPipe('no_such_command');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/FusekiTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class FusekiTest extends EasyRdf_TestCase
+{
+    private static $port = null;
+    private static $proc = null;
+    
+    // Starting up Fuseki is slow - we re-use the same instance for every test
+    public static function setUpBeforeClass()
+    {
+        $descriptorspec = array(
+            0 => array('pipe', 'r'),
+            1 => array('pipe', 'w'),
+            2 => array('pipe', 'w')
+        );
+    
+        # Start fuseki on a random port number
+        self::$port = rand(10000, 60000);
+        $cmd = "fuseki-server --port=".self::$port." --update --mem /ds";
+        $dir = sys_get_temp_dir();
+        self::$proc = proc_open($cmd, $descriptorspec, $pipes, $dir);
+    
+        # FIXME: timeout
+        while ($line = fgets($pipes[1])) {
+            if (preg_match('/Started (.+) on port (\d+)/', $line, $matches)) {
+                break;
+            }
+        }
+
+        // Fuseki needs a little bit of extra time before it can acctually recieve requests
+        sleep(3);
+    }
+
+    public static function tearDownAfterClass()
+    {
+        if (self::$proc) {
+            // Cause the fuseki server process to terminate
+            proc_terminate(self::$proc);
+    
+            // Close the process resource
+            proc_close(self::$proc);
+        }
+    }
+    
+    public function setUp()
+    {
+        $this->gs = new EasyRdf_GraphStore("http://localhost:".self::$port."/ds/data");
+    }
+    
+    public function testGraphStoreReplace()
+    {
+        $graph1 = new EasyRdf_Graph();
+        $graph1->set('http://example.com/test', 'rdfs:label', 'Test 0');
+        $result = $this->gs->replace($graph1, 'easyrdf-graphstore-test.rdf');
+        $this->assertSame(201, $result->getStatus());
+
+        $graph1->set('http://example.com/test', 'rdfs:label', 'Test 1');
+        $result = $this->gs->replace($graph1, 'easyrdf-graphstore-test.rdf');
+        $this->assertSame(204, $result->getStatus());
+
+        $graph2 = $this->gs->get('easyrdf-graphstore-test.rdf');
+        $this->assertEquals(
+            array(new EasyRdf_Literal('Test 1')),
+            $graph2->all('http://example.com/test', 'rdfs:label')
+        );
+    }
+    
+    public function testGraphStoreInsert()
+    {
+        $graph1 = new EasyRdf_Graph();
+        $graph1->set('http://example.com/test', 'rdfs:label', 'Test 2');
+        $result = $this->gs->insert($graph1, 'easyrdf-graphstore-test2.rdf');
+        $this->assertSame(201, $result->getStatus());
+
+        $graph1->set('http://example.com/test', 'rdfs:label', 'Test 3');
+        $result = $this->gs->insert($graph1, 'easyrdf-graphstore-test2.rdf');
+        $this->assertSame(204, $result->getStatus());
+
+        $graph2 = $this->gs->get('easyrdf-graphstore-test2.rdf');
+        $labels = $graph2->all('http://example.com/test', 'rdfs:label');
+        sort($labels);
+        $this->assertEquals(
+            array(
+                new EasyRdf_Literal('Test 2'),
+                new EasyRdf_Literal('Test 3')
+            ),
+            $labels
+        );
+    }
+    
+    public function testGraphStoreDelete()
+    {
+        $graph1 = new EasyRdf_Graph();
+        $graph1->set('http://example.com/test', 'rdfs:label', 'Test 4');
+        $result = $this->gs->insert($graph1, 'easyrdf-graphstore-test3.rdf');
+        $this->assertSame(201, $result->getStatus());
+
+        $graph2 = $this->gs->get('easyrdf-graphstore-test3.rdf');
+        $this->assertEquals(1, $graph2->countTriples());
+
+        $result = $this->gs->delete('easyrdf-graphstore-test3.rdf');
+        $this->assertSame(204, $result->getStatus());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/ParserPerformance.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+
+set_include_path(
+    get_include_path() . PATH_SEPARATOR .
+    dirname(__FILE__) . '/../lib/'
+);
+require_once "EasyRdf.php";
+
+$parsers = array(
+    'Arc',
+    'Json',
+    'Ntriples',
+    'RdfXml',
+    'Rapper',
+    'Redland',
+    'Turtle',
+);
+
+$documents = array(
+    'foaf.rdf' => 'rdfxml',
+    'foaf.ttl' => 'turtle',
+    'foaf.nt' => 'ntriples',
+    'foaf.json' => 'json',
+    'dundee.rdf' => 'rdfxml',
+    'dundee.ttl' => 'turtle',
+    'dundee.nt' => 'ntriples',
+    'dundee.json' => 'json',
+    'london.rdf' => 'rdfxml',
+    'london.ttl' => 'turtle',
+    'london.nt' => 'ntriples',
+    'london.json' => 'json',
+);
+
+foreach ($documents as $filename => $type) {
+
+    print "Input file: $filename\n";
+    $filepath = dirname(__FILE__) . "/performance/$filename";
+    if (!file_exists($filepath)) {
+        print "Error: File does not exist.\n";
+        continue;
+    }
+
+    $url = "http://www.example.com/$filename";
+    $data = file_get_contents($filepath);
+    print "File size: ".strlen($data)." bytes\n";
+
+    foreach ($parsers as $parser_name) {
+        $class = "EasyRdf_Parser_$parser_name";
+        print "  Parsing using: $class\n";
+
+        try {
+            require_once "EasyRdf/Parser/$parser_name.php";
+            $parser = new $class();
+            $graph = new EasyRdf_Graph();
+
+            $start = microtime(true);
+            $parser->parse($graph, $data, $type, $url);
+            $duration = microtime(true) - $start;
+            print "  Parse time: $duration seconds\n";
+            print "  Triple count: ".$graph->countTriples()."\n";
+        } catch (Exception $e) {
+            print 'Parsing failed: '.$e->getMessage()."\n";
+        }
+        print "\n";
+
+        unset($graph);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/TestHelper.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+/*
+ * Include PHPUnit dependencies
+ */
+require_once 'PHPUnit/Framework/IncompleteTestError.php';
+require_once 'PHPUnit/Framework/TestCase.php';
+require_once 'PHPUnit/Framework/TestSuite.php';
+require_once 'PHPUnit/Runner/Version.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+require_once 'PHPUnit/Util/Filter.php';
+
+/*
+ * Set error reporting to the level to be stricter.
+ */
+error_reporting(E_ALL | E_STRICT);
+
+/*
+ * Check the version number of PHP Unit.
+ */
+if (version_compare(PHPUnit_Runner_Version::id(), '3.5.15', '<')) {
+    error_log("PHPUnit version 3.5.15 or higher is required.");
+    exit();
+}
+
+// Set time zone to UTC for running tests
+date_default_timezone_set('UTC');
+
+/*
+ * Determine the root, lib, and test directories
+ */
+$easyrdfRoot      = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..');
+$easyrdfLibDir    = $easyrdfRoot . DIRECTORY_SEPARATOR . 'lib';
+$easyrdfTestDir   = $easyrdfRoot . DIRECTORY_SEPARATOR . 'test';
+
+/*
+ * Prepend the lib and test directories to the  include_path.
+ */
+$path = array(
+    $easyrdfLibDir,
+    $easyrdfTestDir,
+    get_include_path()
+);
+set_include_path(implode(PATH_SEPARATOR, $path));
+
+/*
+ * Unset global variables that are no longer needed.
+ */
+unset($easyrdfRoot, $easyrdfLibDir, $easyrdfTestDir, $path);
+
+/*
+ * Load the core EasyRdf classes.
+ */
+require_once 'EasyRdf.php';
+
+require_once 'EasyRdf/TestCase.php';
+require_once 'EasyRdf/Http/MockClient.php';
+
+
+/**
+ * Helper function: get path to a fixture file
+ *
+ * @param string $name fixture file name
+ * @return string Path to the fixture file
+ */
+function fixturePath($name)
+{
+    return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . $name;
+}
+
+/**
+ * Helper function: read fixture data from file
+ *
+ * @param string $name fixture file name
+ * @return string Fixture data
+ */
+function readFixture($name)
+{
+    return file_get_contents(
+        fixturePath($name)
+    );
+}
+
+/**
+ * Helper function: check to see if a required file exists
+ *
+ * @param string $filename the filename to check
+ * @return boolean Returns true if the file exists
+ */
+function requireExists($filename)
+{
+    $paths = explode(PATH_SEPARATOR, get_include_path());
+    foreach ($paths as $path) {
+        if (substr($path, -1) == DIRECTORY_SEPARATOR) {
+            $fullpath = $path.$filename;
+        } else {
+            $fullpath = $path.DIRECTORY_SEPARATOR.$filename;
+        }
+        if (file_exists($fullpath)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * Helper function: execute an example script in a new process
+ *
+ * Process isolation helps ensure that one script isn't tainting
+ * the environment for another script, making it a fairer test.
+ *
+ * If you want to use a non-default PHP CLI executable, then set
+ * the PHP environment variable to the path of executable.
+ *
+ * @param string $name   the name of the example to run
+ * @param string $params query string parameters to pass to the script
+ * @return string The resulting webpage (everything printed to STDOUT)
+ */
+function executeExample($name, $params = array())
+{
+    $phpBin = getenv('PHP');
+    if (!$phpBin) {
+        $phpBin = 'php';
+    }
+
+    // We use a wrapper to setup the environment
+    $wrapper = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'cli_example_wrapper.php';
+
+    // Open a pipe to the new PHP process
+    $descriptorspec = array(
+        0 => array("pipe", "r"),
+        1 => array("pipe", "w"),
+        2 => array("pipe", "w")
+    );
+
+    $process = proc_open(
+        escapeshellcmd($phpBin)." ".
+        escapeshellcmd($wrapper)." ".
+        escapeshellcmd($name)." ".
+        escapeshellcmd(http_build_query($params)),
+        $descriptorspec,
+        $pipes
+    );
+    if (is_resource($process)) {
+        // $pipes now looks like this:
+        // 0 => writeable handle connected to child stdin
+        // 1 => readable handle connected to child stdout
+        // 2 => readable handle connected to child stderr
+
+        fclose($pipes[0]);
+        $stdout = stream_get_contents($pipes[1]);
+        fclose($pipes[1]);
+        $stderr = stream_get_contents($pipes[2]);
+        fclose($pipes[2]);
+
+        // It is important that you close any pipes before calling
+        // proc_close in order to avoid a deadlock
+        $returnValue = proc_close($process);
+        if ($returnValue or $stderr) {
+            throw new Exception(
+                "Failed to run script ($returnValue): ".$stderr.$stdout
+            );
+        }
+    } else {
+        throw new Exception(
+            "Failed to execute new php process: $phpBin"
+        );
+    }
+
+    return $stdout;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/cli_example_wrapper.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,43 @@
+#!/usr/bin/env php
+<?php
+
+//
+// This wrapper prepares an environment, similar to running
+// the example on a real web server.
+//
+
+$EXAMPLES_DIR = realpath(dirname(__FILE__) . '/../examples');
+if (count($argv) <= 1) {
+    print "Error: Missing name of the example to run.\n";
+    exit(-1);
+} else {
+    $THIS_SCRIPT = array_shift($argv);
+    $EXAMPLE_FILE = array_shift($argv);
+}
+
+// Catch more errors
+error_reporting(E_ALL | E_STRICT);
+
+// Set time zone to UTC for running tests
+date_default_timezone_set('UTC');
+
+// Change to the examples directory
+chdir($EXAMPLES_DIR);
+
+// Check that the example exists
+if (!file_exists($EXAMPLE_FILE)) {
+    print "Error: example does not exist: $EXAMPLE_FILE\n";
+    exit(-1);
+}
+
+// Setup the $_GET variable based on command-line arguments
+parse_str(
+    implode('&', $argv),
+    $_GET
+);
+
+// Copy the GET parameters into the REQUEST variable
+$_REQUEST = $_GET;
+
+// Run the example
+require $EXAMPLE_FILE;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/ArtistinfoTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_ArtistinfoTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('artistinfo.php');
+        $this->assertContains('<title>EasyRdf Artist Info Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf Artist Info Example</h1>', $output);
+    }
+
+    public function testBruce()
+    {
+        $output = executeExample(
+            'artistinfo.php',
+            array(
+                'uri' => 'http://www.bbc.co.uk/music/artists/70248960-cb53-4ea4-943a-edb18f7d336f.rdf',
+            )
+        );
+
+        $this->assertContains('<title>EasyRdf Artist Info Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf Artist Info Example</h1>', $output);
+        $this->assertContains('<dt>Artist Name:</dt><dd>Bruce Springsteen</dd>', $output);
+        $this->assertContains("<dt>Type:</dt><dd>mo:MusicArtist, mo:SoloMusicArtist</dd>", $output);
+        $this->assertContains(
+            '<dt>Homepage:</dt><dd><a href="http://www.brucespringsteen.net/">'.
+            'http://www.brucespringsteen.net/</a></dd>',
+            $output
+        );
+        $this->assertContains(
+            '<dt>Wikipedia page:</dt><dd><a href="http://en.wikipedia.org/wiki/Bruce_Springsteen">'.
+            'http://en.wikipedia.org/wiki/Bruce_Springsteen</a></dd>',
+            $output
+        );
+        $this->assertContains("<dt>Age:</dt>  <dd>".(date('Y') - 1949)."</dd>", $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/BasicSparqlTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_BasicSparqlTest extends EasyRdf_TestCase
+{
+    public function testCountries()
+    {
+        $output = executeExample('basic_sparql.php');
+        $this->assertContains('<title>EasyRdf Basic Sparql Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf Basic Sparql Example</h1>', $output);
+        $this->assertContains('<h2>List of countries</h2>', $output);
+        $this->assertContains(
+            '<li><a href="http://dbpedia.org/resource/China">China</a></li>',
+            $output
+        );
+        $this->assertContains(
+            '<li><a href="http://dbpedia.org/resource/India">India</a></li>',
+            $output
+        );
+        $this->assertContains(
+            '<li><a href="http://dbpedia.org/resource/United_States">United States</a></li>',
+            $output
+        );
+        $this->assertContains(
+            '<li><a href="http://dbpedia.org/resource/United_Kingdom">United Kingdom</a></li>',
+            $output
+        );
+        $this->assertContains(
+            '<li><a href="http://dbpedia.org/resource/Zimbabwe">Zimbabwe</a></li>',
+            $output
+        );
+        $this->assertRegExp('|Total number of countries: (\d+)|', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/BasicTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_BasicTest extends EasyRdf_TestCase
+{
+    public function testPageRendersCorrectly()
+    {
+        $output = executeExample('basic.php');
+        $this->assertContains('<title>Basic FOAF example</title>', $output);
+        $this->assertContains('My name is: Nicholas J Humfrey', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/ConverterTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_ConverterTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('converter.php');
+        $this->assertContains('<title>EasyRdf Converter</title>', $output);
+        $this->assertContains('<h1>EasyRdf Converter</h1>', $output);
+        $this->assertContains('<option value="ntriples">N-Triples</option>', $output);
+        $this->assertContains('<option value="turtle">Turtle Terse RDF Triple Language</option>', $output);
+        $this->assertContains('<option value="rdfxml">RDF/XML</option>', $output);
+    }
+
+    public function testConvertRdfXmlToNtriples()
+    {
+        $output = executeExample(
+            'converter.php',
+            array(
+                'data' =>
+                    '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'.
+                    '         xmlns:dc="http://purl.org/dc/elements/1.1/">'.
+                    ' <rdf:Description rdf:about="http://www.w3.org/">'.
+                    '  <dc:title>World Wide Web Consortium</dc:title>'.
+                    ' </rdf:Description>'.
+                    '</rdf:RDF>',
+                'uri' => 'http://example.com/',
+                'input_format' => 'guess',
+                'output_format' => 'ntriples'
+            )
+        );
+
+        $this->assertContains('<title>EasyRdf Converter</title>', $output);
+        $this->assertContains('<h1>EasyRdf Converter</h1>', $output);
+        $this->assertContains(
+            '&lt;http://www.w3.org/&gt; '.
+            '&lt;http://purl.org/dc/elements/1.1/title&gt; '.
+            '&quot;World Wide Web Consortium&quot; .',
+            $output
+        );
+    }
+
+    public function testConvertTurtle()
+    {
+        $output = executeExample(
+            'converter.php',
+            array(
+                'uri' => 'http://www.w3.org/TR/turtle/examples/example1.ttl',
+                'input_format' => 'guess',
+                'output_format' => 'ntriples'
+            )
+        );
+
+        $this->assertContains('<title>EasyRdf Converter</title>', $output);
+        $this->assertContains('<h1>EasyRdf Converter</h1>', $output);
+        $this->assertContains(
+            '&lt;http://www.w3.org/TR/rdf-syntax-grammar&gt; '.
+            '&lt;http://purl.org/dc/elements/1.1/title&gt; '.
+            '&quot;RDF/XML Syntax Specification (Revised)&quot; .',
+            $output
+        );
+        $this->assertContains(
+            '&lt;http://www.w3.org/TR/rdf-syntax-grammar&gt; '.
+            '&lt;http://example.org/stuff/1.0/editor&gt; _:genid1 .',
+            $output
+        );
+        $this->assertContains(
+            '_:genid1 &lt;http://example.org/stuff/1.0/fullname&gt; '.
+            '&quot;Dave Beckett&quot; .',
+            $output
+        );
+        $this->assertContains(
+            '_:genid1 &lt;http://example.org/stuff/1.0/homePage&gt; '.
+            '&lt;http://purl.org/net/dajobe/&gt; .',
+            $output
+        );
+    }
+
+    public function testConvertTurtleRaw()
+    {
+        $output = executeExample(
+            'converter.php',
+            array(
+                'uri' => 'http://www.w3.org/TR/turtle/examples/example1.ttl',
+                'input_format' => 'guess',
+                'output_format' => 'ntriples',
+                'raw' => 1
+            )
+        );
+
+        $this->assertSame(
+            "<http://www.w3.org/TR/rdf-syntax-grammar> <http://purl.org/dc/elements/1.1/title> ".
+            "\"RDF/XML Syntax Specification (Revised)\" .\n".
+            "<http://www.w3.org/TR/rdf-syntax-grammar> <http://example.org/stuff/1.0/editor> _:genid1 .\n".
+            "_:genid1 <http://example.org/stuff/1.0/fullname> \"Dave Beckett\" .\n".
+            "_:genid1 <http://example.org/stuff/1.0/homePage> <http://purl.org/net/dajobe/> .\n",
+            $output
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/DumpTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_DumpTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('dump.php');
+        $this->assertContains('<title>EasyRdf Graph Dumper</title>', $output);
+        $this->assertContains('<h1>EasyRdf Graph Dumper</h1>', $output);
+    }
+
+    public function testDumpHTML()
+    {
+        $output = executeExample(
+            'dump.php',
+            array(
+                'uri' => 'http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/test001.rdf',
+                'format' => 'html'
+            )
+        );
+
+        $this->assertContains('<title>EasyRdf Graph Dumper</title>', $output);
+        $this->assertContains('<h1>EasyRdf Graph Dumper</h1>', $output);
+        $this->assertContains('Graph: http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/test001.rdf', $output);
+        $this->assertContains("color:blue'>http://example/q?abc=1&amp;def=2</a>", $output);
+        $this->assertContains("color:green'>rdf:value</span>", $output);
+        $this->assertContains("color:black'>&quot;xxx&quot;</span>", $output);
+    }
+
+    public function testDumpText()
+    {
+        $output = executeExample(
+            'dump.php',
+            array(
+                'uri' => 'http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/test001.rdf',
+                'format' => 'text'
+            )
+        );
+        $this->assertContains('<title>EasyRdf Graph Dumper</title>', $output);
+        $this->assertContains('<h1>EasyRdf Graph Dumper</h1>', $output);
+        $this->assertContains('Graph: http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/test001.rdf', $output);
+        $this->assertContains('http://example/q?abc=1&def=2 (EasyRdf_Resource)', $output);
+        $this->assertContains('-> rdf:value -> "xxx"', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/FoafinfoTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_FoafinfoTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('foafinfo.php');
+        $this->assertContains('<title>EasyRdf FOAF Info Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf FOAF Info Example</h1>', $output);
+        $this->assertContains(
+            '<input type="text" name="uri" id="uri" value="http://njh.me/foaf.rdf" size="50" />',
+            $output
+        );
+    }
+
+    public function testNjh()
+    {
+        $output = executeExample(
+            'foafinfo.php',
+            array('uri' => 'http://njh.me/foaf.rdf')
+        );
+
+        $this->assertContains('<title>EasyRdf FOAF Info Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf FOAF Info Example</h1>', $output);
+        $this->assertContains("<dt>Name:</dt><dd>Nicholas J Humfrey</dd>", $output);
+        $this->assertContains(
+            "<dt>Homepage:</dt><dd><a href=\"http://www.aelius.com/njh/\">http://www.aelius.com/njh/</a></dd>",
+            $output
+        );
+
+        $this->assertContains("<h2>Known Persons</h2>", $output);
+        $this->assertContains(">Patrick Sinclair</a></li>", $output);
+        $this->assertContains(">Yves Raimond</a></li>", $output);
+
+        $this->assertContains("<h2>Interests</h2>", $output);
+        $this->assertContains(">RDF</a></li>", $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/FoafmakerTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_FoafmakerTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('foafmaker.php');
+        $this->assertContains('<title>EasyRdf FOAF Maker Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf FOAF Maker Example</h1>', $output);
+    }
+
+    public function testJoeBloggs()
+    {
+        $output = executeExample(
+            'foafmaker.php',
+            array(
+                'uri' => 'http://www.example.com/joe#me',
+                'title' => 'Mr',
+                'given_name' => 'Joe',
+                'family_name' => 'Bloggs',
+                'email' => 'joe@example.com',
+                'nickname' => 'Joe',
+                'homepage' => 'http://www.example.com/joe/',
+                'person_1' => 'http://www.example.com/fred#me',
+                'person_2' => 'http://www.example.com/alice#me',
+                'person_3' => '',
+                'person_4' => '',
+                'format' => 'turtle'
+            )
+        );
+
+        $this->assertContains('<title>EasyRdf FOAF Maker Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf FOAF Maker Example</h1>', $output);
+        $this->assertContains(
+            "@prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt; .\n\n".
+            "&lt;http://www.example.com/joe#me&gt;\n".
+            "  a foaf:Person ;\n".
+            "  foaf:name &quot;Mr Joe Bloggs&quot; ;\n".
+            "  foaf:mbox &lt;mailto:joe@example.com&gt; ;\n".
+            "  foaf:homepage &lt;http://www.example.com/joe/&gt; ;\n".
+            "  foaf:title &quot;Mr&quot; ;\n".
+            "  foaf:givenname &quot;Joe&quot; ;\n".
+            "  foaf:family_name &quot;Bloggs&quot; ;\n".
+            "  foaf:nick &quot;Joe&quot; ;\n".
+            "  foaf:knows &lt;http://www.example.com/fred#me&gt;,".
+            " &lt;http://www.example.com/alice#me&gt; .\n",
+            $output
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/GraphdirectTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_GraphdirectTest extends EasyRdf_TestCase
+{
+    public function test()
+    {
+        $output = executeExample('graph_direct.php');
+        $this->assertContains('<title>Example of using EasyRdf_Graph directly</title>', $output);
+
+        $this->assertContains('<b>Name:</b> Joe Bloggs <br />', $output);
+        $this->assertContains('<b>Names:</b> Joe Bloggs Joseph Bloggs <br />', $output);
+
+        $this->assertContains('<b>Label:</b> Nick <br />', $output);
+        $this->assertContains(
+            '<b>Properties:</b> rdf:type, foaf:name, rdfs:label <br />',
+            $output
+        );
+        $this->assertContains(
+            '<b>PropertyUris:</b> http://www.w3.org/1999/02/22-rdf-syntax-ns#type, '.
+            'http://xmlns.com/foaf/0.1/name, http://www.w3.org/2000/01/rdf-schema#label <br />',
+            $output
+        );
+        $this->assertContains(
+            '<b>People:</b> http://example.com/joe, http://njh.me/ <br />',
+            $output
+        );
+        $this->assertContains('<b>Unknown:</b>  <br />', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/HttpgetTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_HttpgetTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('httpget.php');
+        $this->assertContains('<title>Test EasyRdf_HTTP_Client Get</title>', $output);
+        $this->assertContains('<h1>Test EasyRdf_HTTP_Client Get</h1>', $output);
+        $this->assertContains(
+            '<input type="text" name="uri" id="uri" value="http://tomheath.com/id/me" size="50" />',
+            $output
+        );
+        $this->assertContains(
+            '<option value="application/rdf+xml">application/rdf+xml</option>',
+            $output
+        );
+        $this->assertContains(
+            '<option value="text/html">text/html</option>',
+            $output
+        );
+    }
+
+    public function testHtml()
+    {
+        $output = executeExample(
+            'httpget.php',
+            array(
+                'uri' => 'http://tomheath.com/id/me',
+                'accept' => 'text/html'
+            )
+        );
+        $this->assertContains('<title>Test EasyRdf_HTTP_Client Get</title>', $output);
+        $this->assertContains('<h1>Test EasyRdf_HTTP_Client Get</h1>', $output);
+        $this->assertContains('<b>Content-type</b>: text/html<br />', $output);
+        $this->assertContains('&lt;h1&gt;Home - Tom Heath&lt;/h1&gt;', $output);
+    }
+
+    public function testRdfXml()
+    {
+        $output = executeExample(
+            'httpget.php',
+            array(
+                'uri' => 'http://tomheath.com/id/me',
+                'accept' => 'application/rdf+xml'
+            )
+        );
+        $this->assertContains('<title>Test EasyRdf_HTTP_Client Get</title>', $output);
+        $this->assertContains('<h1>Test EasyRdf_HTTP_Client Get</h1>', $output);
+        $this->assertContains('<b>Content-type</b>: application/rdf+xml<br />', $output);
+        $this->assertContains(
+            '&lt;foaf:Person rdf:about=&quot;http://tomheath.com/id/me&quot;&gt;<br />',
+            $output
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/ParseRssTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_ParseRssTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('parse_rss.php');
+        $this->assertContains('<title>EasyRdf RSS 1.0 Parsing example</title>', $output);
+        $this->assertContains('<h1>EasyRdf RSS 1.0 Parsing example</h1>', $output);
+    }
+
+    public function testCeres()
+    {
+        $output = executeExample(
+            'parse_rss.php',
+            array('uri' => 'http://planetrdf.com/index.rdf')
+        );
+        $this->assertContains(
+            '<p>Channel: <a href="http://planetrdf.com/">Planet RDF</a></p>',
+            $output
+        );
+        $this->assertContains(
+            "<p>Description: It's triples all the way down</p>",
+            $output
+        );
+        $this->assertContains('<li><a href="http://', $output);
+        $this->assertContains('</a></li>', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/SerialiseTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_SerialiseTest extends EasyRdf_TestCase
+{
+    public function testNtriples()
+    {
+        $output = executeExample(
+            'serialise.php',
+            array('format' => 'ntriples')
+        );
+        $this->assertContains('<title>EasyRdf Serialiser Example</title>', $output);
+        $this->assertContains(
+            '&lt;http://www.example.com/joe#me&gt; '.
+            '&lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#type&gt; '.
+            '&lt;http://xmlns.com/foaf/0.1/Person&gt; .',
+            $output
+        );
+    }
+
+    public function testRdfXml()
+    {
+        $output = executeExample(
+            'serialise.php',
+            array('format' => 'rdfxml')
+        );
+        $this->assertContains('<title>EasyRdf Serialiser Example</title>', $output);
+        $this->assertContains(
+            '&lt;foaf:Person rdf:about=&quot;http://www.example.com/joe#me&quot;&gt;',
+            $output
+        );
+    }
+
+    public function testPhp()
+    {
+        $output = executeExample(
+            'serialise.php',
+            array('format' => 'php')
+        );
+        $this->assertContains('<title>EasyRdf Serialiser Example</title>', $output);
+        $this->assertContains("'value' =&gt; 'http://xmlns.com/foaf/0.1/Person',", $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/SparqlqueryformTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_SparqlqueryformTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('sparql_queryform.php');
+        $this->assertContains('<title>EasyRdf SPARQL Query Form</title>', $output);
+        $this->assertContains('<h1>EasyRdf SPARQL Query Form</h1>', $output);
+        $this->assertContains('PREFIX foaf: &lt;http://xmlns.com/foaf/0.1/&gt;', $output);
+    }
+
+    public function testDbpediaCountries()
+    {
+        $output = executeExample(
+            'sparql_queryform.php',
+            array(
+                'endpoint' => 'http://dbpedia.org/sparql',
+                'query' =>
+                    'PREFIX dbo: <http://dbpedia.org/ontology/> '.
+                    'SELECT * WHERE {'.
+                    '  ?country rdf:type dbo:Country . '.
+                    '  ?country rdfs:label ?label .'.
+                    '  ?country dc:subject category:Member_states_of_the_United_Nations .'.
+                    '  FILTER ( lang(?label) = "en" ) '.
+                    '} ORDER BY ?label LIMIT 100'
+            )
+        );
+        $this->assertContains('>http://dbpedia.org/resource/China</a>', $output);
+        $this->assertContains('>&quot;China&quot;@en</span>', $output);
+    }
+
+    public function testDbpediaCountriesText()
+    {
+        $output = executeExample(
+            'sparql_queryform.php',
+            array(
+                'endpoint' => 'http://dbpedia.org/sparql',
+                'query' =>
+                    'PREFIX dbo: <http://dbpedia.org/ontology/> '.
+                    'SELECT * WHERE {'.
+                    '  ?country rdf:type dbo:Country . '.
+                    '  ?country rdfs:label ?label .'.
+                    '  ?country dc:subject category:Member_states_of_the_United_Nations .'.
+                    '  FILTER ( lang(?label) = "en" ) '.
+                    '} ORDER BY ?label LIMIT 100',
+                'text' => 1
+            )
+        );
+
+        $this->assertContains('| http://dbpedia.org/resource/China', $output);
+        $this->assertContains('| &quot;China&quot;@en', $output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/UkpostcodeTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_UkpostcodeTest extends EasyRdf_TestCase
+{
+    public function testNoParams()
+    {
+        $output = executeExample('uk_postcode.php');
+        $this->assertContains('<title>EasyRdf UK Postcode Resolver</title>', $output);
+        $this->assertContains('<h1>EasyRdf UK Postcode Resolver</h1>', $output);
+    }
+
+    public function testW1A1AA()
+    {
+        $output = executeExample(
+            'uk_postcode.php',
+            array('postcode' => 'W1A 1AA')
+        );
+        $this->assertContains('<tr><th>Easting:</th><td>528887</td></tr>', $output);
+        $this->assertContains('<tr><th>Northing:</th><td>181593</td></tr>', $output);
+        $this->assertContains('<tr><th>Longitude:</th><td>-0.143785</td></tr>', $output);
+        $this->assertContains('<tr><th>Latitude:</th><td>51.518562</td></tr>', $output);
+        $this->assertContains('<tr><th>Electoral Ward:</th><td>West End</td></tr>', $output);
+        $this->assertContains(
+            "src='http://maps.google.com/maps?f=q&amp;ll=51.518562,-0.143785&amp;output=embed'",
+            $output
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/examples/VillagesTest.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * EasyRdf
+ *
+ * LICENSE
+ *
+ * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+require_once dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'TestHelper.php';
+
+class Examples_VillagesTest extends EasyRdf_TestCase
+{
+    public function testIndex()
+    {
+        $output = executeExample('villages.php');
+        $this->assertContains('<title>EasyRdf Village Info Example</title>', $output);
+        $this->assertContains('<h1>EasyRdf Village Info Example</h1>', $output);
+        $this->assertContains('?id=934787">Ceres, Fife</a></li>', $output);
+        $this->assertContains('?id=13953312">Strathkinness</a></li>', $output);
+    }
+
+    public function testCeres()
+    {
+        $output = executeExample(
+            'villages.php',
+            array('id' => '934787')
+        );
+        $this->assertContains('<h2>Ceres, Fife</h2>', $output);
+        $this->assertContains('<p>Ceres is a village in Fife, Scotland', $output);
+        $this->assertContains(
+            "src='http://maps.google.com/maps?f=q&amp;ll=56.29205,-2.971445&amp;output=embed'>",
+            $output
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/empty.rdf	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+</rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.bad-json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,96 @@
+
+{
+  "node16d2rluonx90" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/Project",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/homepage" : [ {
+        "value" : "http://www.example.com/project",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/name" : [ {
+        "value" : "Joe's Current Project",
+        "type" : "literal"
+        }
+
+      ]
+    }
+  ,
+  "http://www.example.com/joe#me" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/Person",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/currentProject" : [ {
+        "value" : "node16d2rluonx90",
+        "type" : "bnode"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/family_name" : [ {
+        "value" : "Bloggs",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/firstName" : [ {
+        "value" : "Joe",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/homepage" : [ {
+        "value" : "http://www.example.com/joe/",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/name" : [ {
+        "value" : "Joe Bloggs",
+        "lang" : "en",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/title" : [ {
+        "value" : "Mr",
+        "type" : "literal"
+        }
+
+      ]
+    }
+  ,
+  "http://www.example.com/joe/foaf.rdf" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/PersonalProfileDocument",
+        "type" : "uri"
+        }
+
+      ],
+    "http://www.w3.org/2000/01/rdf-schema#label" : [ {
+        "value" : "Joe Bloggs' FOAF File",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/maker" : [ {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/primaryTopic" : [ {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+
+      ]
+    }
+  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.html	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
+    "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+	    xmlns:foaf="http://xmlns.com/foaf/0.1/"
+	    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+	    version="XHTML+RDFa 1.0" xml:lang="en"
+>
+<head>
+	<title>Profile for Joe Bloggs</title>
+</head>
+<body>
+
+<div about="http://www.example.com/joe#me">
+  <h1>Profile for <span property="foaf:name">Joe Bloggs</span></h1>
+
+  <h2>Interests</h2>
+  <ul rel="foaf:interest">
+    <li class="interest" about="http://dbpedia.org/resource/Cat">
+      <a href="http://en.wikipedia.org/wiki/Cat" property="rdfs:label">Cats</a>
+    </li>
+    <li class="interest" about="http://dbpedia.org/resource/Dog">
+      <a href="http://en.wikipedia.org/wiki/Dog" property="rdfs:label">Dogs</a>
+    </li>
+  </ul>
+</div>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,96 @@
+
+{
+  "http://www.example.com/joe#me" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/Person",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/currentProject" : [ {
+        "value" : "_:genid1",
+        "type" : "bnode"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/family_name" : [ {
+        "value" : "Bloggs",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/firstName" : [ {
+        "value" : "Joe",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/homepage" : [ {
+        "value" : "http://www.example.com/joe/",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/name" : [ {
+        "value" : "Joe Bloggs",
+        "lang" : "en",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/title" : [ {
+        "value" : "Mr",
+        "type" : "literal"
+        }
+
+      ]
+    }
+  ,
+  "http://www.example.com/joe/foaf.rdf" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/PersonalProfileDocument",
+        "type" : "uri"
+        }
+
+      ],
+    "http://www.w3.org/2000/01/rdf-schema#label" : [ {
+        "value" : "Joe Bloggs' FOAF File",
+        "type" : "literal"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/maker" : [ {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/primaryTopic" : [ {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+
+      ]
+    }
+  ,
+  "_:genid1" : {
+    "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" : [ {
+        "value" : "http://xmlns.com/foaf/0.1/Project",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/homepage" : [ {
+        "value" : "http://www.example.com/project",
+        "type" : "uri"
+        }
+
+      ],
+    "http://xmlns.com/foaf/0.1/name" : [ {
+        "value" : "Joe's Current Project",
+        "type" : "literal"
+        }
+
+      ]
+    }
+  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.json-triples	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,207 @@
+{
+  "triples" : [
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://xmlns.com/foaf/0.1/Person",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/currentProject",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "_:genid1",
+        "type" : "bnode"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/family_name",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Bloggs",
+        "type" : "literal"
+        }
+
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/firstName",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Joe",
+        "type" : "literal"
+        }
+
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/homepage",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://www.example.com/joe/",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/name",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Joe Bloggs",
+        "lang" : "en",
+        "type" : "literal"
+        }
+
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/title",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Mr",
+        "type" : "literal"
+        }
+
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe/foaf.rdf",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://xmlns.com/foaf/0.1/PersonalProfileDocument",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe/foaf.rdf",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://www.w3.org/2000/01/rdf-schema#label",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Joe Bloggs' FOAF File",
+        "type" : "literal"
+        }
+
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe/foaf.rdf",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/maker",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "http://www.example.com/joe/foaf.rdf",
+        "type" : "uri"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/primaryTopic",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://www.example.com/joe#me",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "_:genid1",
+        "type" : "bnode"
+        },
+      "predicate" : {
+        "value" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://xmlns.com/foaf/0.1/Project",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "_:genid1",
+        "type" : "bnode"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/homepage",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "http://www.example.com/project",
+        "type" : "uri"
+        }
+      },
+    {
+      "subject" : {
+        "value" : "_:genid1",
+        "type" : "bnode"
+        },
+      "predicate" : {
+        "value" : "http://xmlns.com/foaf/0.1/name",
+        "type" : "uri"
+        },
+      "object" : {
+        "value" : "Joe's Current Project",
+        "type" : "literal"
+        }
+
+      }
+    ]
+  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<http://www.example.com/joe/foaf.rdf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/PersonalProfileDocument> .
+<http://www.example.com/joe/foaf.rdf> <http://www.w3.org/2000/01/rdf-schema#label> "Joe Bloggs' FOAF File" .
+<http://www.example.com/joe/foaf.rdf> <http://xmlns.com/foaf/0.1/maker> <http://www.example.com/joe#me> .
+<http://www.example.com/joe/foaf.rdf> <http://xmlns.com/foaf/0.1/primaryTopic> <http://www.example.com/joe#me> .
+<http://www.example.com/joe#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/title> "Mr" .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/name> "Joe Bloggs"@en .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/firstName> "Joe" .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/family_name> "Bloggs" .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/homepage> <http://www.example.com/joe/> .
+_:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Project> .
+_:genid1 <http://xmlns.com/foaf/0.1/name> "Joe's Current Project" .
+_:genid1 <http://xmlns.com/foaf/0.1/homepage> <http://www.example.com/project> .
+<http://www.example.com/joe#me> <http://xmlns.com/foaf/0.1/currentProject> _:genid1 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.rdf	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,34 @@
+<!-- This is the FOAF formal vocabulary description, expressed using W3C RDFS and OWL markup. foaf/spec version -->
+<!-- For more information about FOAF:                                            -->
+<!--   see the FOAF project homepage, http://www.foaf-project.org/               -->
+<!--   FOAF specification, http://xmlns.com/foaf/spec/                             -->
+<!--                                                                             -->
+<!-- first we introduce a number of RDF namespaces we will be using... -->
+<rdf:RDF 
+	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
+	xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" 
+	xmlns:owl="http://www.w3.org/2002/07/owl#" 
+	xmlns:vs="http://www.w3.org/2003/06/sw-vocab-status/ns#" 
+	xmlns:foaf="http://xmlns.com/foaf/0.1/" 
+	xmlns:wot="http://xmlns.com/wot/0.1/" 
+	xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <foaf:PersonalProfileDocument rdf:about="">
+    <rdfs:label>Joe Bloggs' FOAF File</rdfs:label>
+    <foaf:maker rdf:resource="http://www.example.com/joe#me" />
+    <foaf:primaryTopic rdf:resource="http://www.example.com/joe#me" />
+  </foaf:PersonalProfileDocument>
+
+  <foaf:Person rdf:about="http://www.example.com/joe#me">
+    <foaf:title>Mr</foaf:title>
+    <foaf:name xml:lang="en">Joe Bloggs</foaf:name>
+    <foaf:firstName>Joe</foaf:firstName>
+    <foaf:family_name>Bloggs</foaf:family_name>
+    <foaf:homepage rdf:resource="http://www.example.com/joe/" />
+    <foaf:currentProject>
+      <foaf:Project>
+        <foaf:name>Joe's Current Project</foaf:name>
+        <foaf:homepage rdf:resource="http://www.example.com/project" />
+      </foaf:Project>
+    </foaf:currentProject>
+  </foaf:Person>
+</rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/foaf.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,23 @@
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<http://www.example.com/joe/foaf.rdf>
+    a foaf:PersonalProfileDocument ;
+    rdfs:label "Joe Bloggs' FOAF File" ;
+    foaf:maker <http://www.example.com/joe#me> ;
+    foaf:primaryTopic <http://www.example.com/joe#me> .
+
+<http://www.example.com/joe#me>
+    a foaf:Person ;
+    foaf:currentProject [
+        a foaf:Project ;
+        foaf:homepage <http://www.example.com/project> ;
+        foaf:name "Joe's Current Project"
+    ] ;
+    foaf:family_name "Bloggs" ;
+    foaf:firstName "Joe" ;
+    foaf:homepage <http://www.example.com/joe/> ;
+    foaf:name "Joe Bloggs"@en ;
+    foaf:title "Mr" .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/http_response_200	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+HTTP/1.1 200 OK
+Date: Sun, 09 Aug 2009 19:28:19 GMT
+Server: Apache/2.2.9 (Unix) PHP/5.2.6
+Last-Modified: Sun, 09 Aug 2009 19:28:16 GMT
+ETag: "96b26d-c-470ba78937400"
+Accept-Ranges: bytes
+X-Multiple: foo
+X-Multiple: bar
+Content-Length: 12
+Content-Type: text/plain
+
+Hello World
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/http_response_200_chunked	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,9 @@
+HTTP/1.1 200 OK
+Server: Apache
+Connection: close
+Transfer-encoding: chunked
+Content-type: text/plain
+
+0b
+Hello World
+0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/http_response_302	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,9 @@
+HTTP/1.1 302 Found
+Date: Sun, 09 Aug 2009 19:55:07 GMT
+Server: Apache/2.2.3 (Red Hat)
+Location: http://localhost/new/location
+Content-Type: text/plain; charset=UTF-8
+Vary: Accept
+Content-Length: 1
+
+_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/http_response_404	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+HTTP/1.1 404 Not Found
+Date: Sun, 09 Aug 2009 19:33:54 GMT
+Server: Apache/2.2.9 (Unix) PHP/5.2.6
+Content-Length: 289
+Content-Type: text/html; charset=iso-8859-1
+
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<html><head>
+<title>404 Not Found</title>
+</head><body>
+<h1>Not Found</h1>
+<p>The requested URL /not/found was not found on this server.</p>
+<hr>
+<address>Apache/2.2.9 (Unix) PHP/5.2.6 Server at localhost Port 80</address>
+</body></html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/http_response_500	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,24 @@
+HTTP/1.1 500 Internal Server Error
+Date: Sun, 09 Aug 2009 19:30:43 GMT
+Server: Apache
+Content-Length: 593
+Connection: close
+Content-Type: text/html; charset=iso-8859-1
+
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<html><head>
+<title>500 Internal Server Error</title>
+</head><body>
+<h1>Internal Server Error</h1>
+<p>The server encountered an internal error or
+misconfiguration and was unable to complete
+your request.</p>
+<p>Please contact the server administrator,
+ root@localhost and inform them of the time the error occurred,
+and anything you might have done that may have
+caused the error.</p>
+<p>More information about this error may be available
+in the server error log.</p>
+<hr>
+<address>Apache Server at localhost Port 80</address>
+</body></html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/not_sparql_result.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<notsparql xmlns="http://www.example.com/notsparql">
+  <head>
+  </head>
+  <boolean>true</boolean>
+</notsparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdf-collection.rdf	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<rdf:RDF xmlns:ex="http://example.org/"
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <rdf:Description rdf:about="http://example.org/owner">
+     <ex:pets rdf:parseType="Collection">
+       <rdf:Description rdf:about='http://example.org/rat' />
+       <rdf:Description rdf:about='http://example.org/cat' />
+       <rdf:Description rdf:about='http://example.org/goat' />
+     </ex:pets>
+  </rdf:Description>
+</rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdf-seq.rdf	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,8 @@
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+  <rdf:Seq rdf:about='http://example.org/favourite-fruit'>
+    <rdf:li rdf:resource='http://example.org/banana'/>
+    <rdf:li rdf:resource='http://example.org/apple'/>
+    <rdf:li rdf:resource='http://example.org/pear'/>
+    <rdf:li rdf:resource='http://example.org/pear'/>
+  </rdf:Seq>
+</rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0001.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0001.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<head>
+   <title>Test 0001</title>
+</head>
+<body>
+   <p>This photo was taken by <span class="author" about="photo1.jpg" property="dc:creator">Mark Birbeck</span>.</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0006.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.blogger.com/profile/1109404> <http://xmlns.com/foaf/0.1/img> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> <http://www.blogger.com/profile/1109404> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0006.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+	<head>
+		<title>Test 0006</title>
+	</head>
+	<body>
+		<p>
+			This photo was taken by
+			<a 	about="photo1.jpg" rel="dc:creator" rev="foaf:img"
+   				href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+		</p>	
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0007.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://www.blogger.com/profile/1109404> <http://xmlns.com/foaf/0.1/img> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/title> "Portrait of Mark" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> <http://www.blogger.com/profile/1109404> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0007.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+	<head>
+		<title>Test 0007</title>
+	</head>
+	<body>
+		<p>This photo was taken by
+			<a 	about="photo1.jpg" property="dc:title"
+   				content="Portrait of Mark" rel="dc:creator"
+      			rev="foaf:img" href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+		</p>	
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0008.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0008.xhtml> <http://creativecommons.org/ns#license> <http://creativecommons.org/licenses/by-nc-nd/2.5/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0008.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cc="http://creativecommons.org/ns#">
+	<head>
+		<title>Test 0008</title>
+	</head>
+  <body>
+  	<p>This document is licensed under a
+  		<a 	about="" rel="cc:license"
+    		href="http://creativecommons.org/licenses/by-nc-nd/2.5/">
+       		Creative Commons
+  		</a>.
+  	</p>	
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0009.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/people#Person2> <http://xmlns.com/foaf/0.1/knows> <http://example.org/people#Person1> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0009.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+	<head>
+		<title>Test 0009</title>
+    	<link about="http://example.org/people#Person1"
+          	  rev="foaf:knows" href="http://example.org/people#Person2" />
+
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0010.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/people#Person2> <http://xmlns.com/foaf/0.1/knows> <http://example.org/people#Person1> .
+<http://example.org/people#Person1> <http://xmlns.com/foaf/0.1/knows> <http://example.org/people#Person2> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0010.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0010</title>
+	  	<link about="http://example.org/people#Person1"
+          rel="foaf:knows" rev="foaf:knows" href="http://example.org/people#Person2" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0012.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "chat"@fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0012.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" version="XHTML+RDFa 1.1" xmlns:ex="http://example.org/">
+  <head about="">
+	<title>Test 0012</title>
+  	<meta about="http://example.org/node" property="ex:property" xml:lang="fr" content="chat" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0013.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "chat"@fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0013.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" version="XHTML+RDFa 1.1" xmlns:ex="http://example.org/">
+  <head about="" xml:lang="fr">
+  	<title xml:lang="en">Test 0013</title>
+  	<meta about="http://example.org/node" property="ex:property" content="chat" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0014.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/foo> <http://example.org/bar> "10"^^<http://www.w3.org/2001/XMLSchema#integer> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0014.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://example.org/"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
+	<head>
+		<title>Test 0014</title>
+	</head>
+  <body>
+  	<p>
+  		<span	about="http://example.org/foo"
+        		property="ex:bar" content="10" datatype="xsd:integer">ten</span>
+	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0015.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0015.xhtml> <http://purl.org/dc/elements/1.1/creator> "Fyodor Dostoevsky" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0015.xhtml> <http://purl.org/dc/elements/1.1/source> <urn:isbn:0140449132> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0015.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0015</title>
+	<link rel="dc:source" href="urn:isbn:0140449132" />
+    <meta property="dc:creator" content="Fyodor Dostoevsky" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0017.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:a <http://xmlns.com/foaf/0.1/name> "Manu Sporny" .
+_:a <http://xmlns.com/foaf/0.1/knows> _:b .
+_:b <http://xmlns.com/foaf/0.1/name> "Ralph Swick" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0017.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+	<title>Test 0017</title>   
+  </head>
+  <body>
+  	 <p>
+          <span about="[_:a]" property="foaf:name">Manu Sporny</span>
+           <span about="[_:a]" rel="foaf:knows"
+resource="[_:b]">knows</span>
+           <span about="[_:b]" property="foaf:name">Ralph Swick</span>.
+        </p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0018.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> <http://www.blogger.com/profile/1109404> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0018.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0018</title>
+  </head>
+  <body>
+  	<p>
+	  This photo was taken by
+	  <a about="photo1.jpg" rel="dc:creator"
+		 href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+	</p>	 
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0019.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<mailto:manu.sporny@digitalbazaar.com> <http://xmlns.com/foaf/0.1/knows> <mailto:michael.hausenblas@joanneum.at> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0019.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+	<title>Test 0019</title>
+  </head>
+  <body>
+    <div about="mailto:manu.sporny@digitalbazaar.com"
+      rel="foaf:knows" href="mailto:michael.hausenblas@joanneum.at"></div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0020.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0020.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0020</title>
+  </head>
+  <body>
+    <div about="photo1.jpg">
+      <span class="attribution-line">this photo was taken by
+        <span property="dc:creator">Mark Birbeck</span>
+      </span>
+    </div>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0021.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0021.xhtml> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0021.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<head>
+	<title>Test 0021</title>
+</head>
+<body>
+    <div>
+      <span class="attribution-line">this photo was taken by
+        <span property="dc:creator">Mark Birbeck</span>
+      </span>
+    </div>
+</body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0023.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0023.xhtml> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0023.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0023</title>
+  </head>
+  <body>
+    <div id="photo1">
+      	This photo was taken by
+        <span property="dc:creator">Mark Birbeck</span> 
+    </div>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0025.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0025.xhtml#me> <http://xmlns.com/foaf/0.1/name> "Ben Adida" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0025.xhtml> <http://purl.org/dc/elements/1.1/creator> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0025.xhtml#me> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0025.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+	<title>Test 0025</title>
+  </head>
+  <body>
+  	<p>
+    	This paper was written by
+    	<span rel="dc:creator" resource="#me">
+      		<span property="foaf:name">Ben Adida</span>.
+    	</span>
+	</p>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0026.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://internet-apps.blogspot.com/> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0026.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0026</title>
+  </head>
+  <body>
+  	<p>
+		<span 	about="http://internet-apps.blogspot.com/"
+	      		property="dc:creator" content="Mark Birbeck" />
+	</p>	
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0027.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://internet-apps.blogspot.com/> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0027.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+   <title>Test 0027</title>
+  </head>
+  <body>
+  	<p>
+    	<span 	about="http://internet-apps.blogspot.com/"
+       			property="dc:creator" content="Mark Birbeck">Mark B.
+		</span>
+	</p>	
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0029.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/foo> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck"^^<http://www.w3.org/2001/XMLSchema#string> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0029.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
+  <head>
+   <title>Test 0029</title>
+  </head>
+  <body>
+  	<p>
+    	<span 	about="http://example.org/foo"
+	      		property="dc:creator" datatype="xsd:string"><b>M</b>ark <b>B</b>irbeck</span>.
+	</p>	  
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0030.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0030.xhtml> <http://creativecommons.org/ns#license> <http://creativecommons.org/licenses/by-nc-nd/2.5/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0030.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cc="http://creativecommons.org/ns#">
+	<head>
+		<title>Test 0030</title>
+	</head>
+  <body>
+  	<p>This document is licensed under a
+  		<a 	rel="cc:license"
+    		href="http://creativecommons.org/licenses/by-nc-nd/2.5/">
+       		Creative Commons License
+  		</a>.
+  	</p>	
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0031.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0031.xhtml#wtw> <http://purl.org/dc/elements/1.1/identifier> <urn:ISBN:0752820907> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0031.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0031</title>
+  </head>
+  <body>
+  	<p about="#wtw">
+  	  The book <b>Weaving the Web</b> (hardcover) has the ISBN
+  	  <span rel="dc:identifier" resource="urn:ISBN:0752820907">0752820907</span>.
+  	</p>	
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0032.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0032.xhtml#wtw> <http://purl.org/dc/elements/1.1/identifier> <urn:ISBN:0752820907> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0032.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+	<head>
+		<title>Test 0032</title>
+	</head>
+  <body>
+  	<p about="#wtw">
+  	  The book <b>Weaving the Web</b> (hardcover) has the ISBN
+  	  <a rel="dc:identifier" resource="urn:ISBN:0752820907" 
+  	  href="http://www.amazon.com/Weaving-Web-Tim-Berners-Lee/dp/0752820907">0752820907</a>.
+  	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0033.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:g78975260 <http://xmlns.com/foaf/0.1/name> "Ben Adida" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0033.xhtml> <http://purl.org/dc/elements/1.1/creator> _:g78975260 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0033.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+	<title>Test 0033</title>
+  </head>
+  <body>
+  	<p>
+    	This paper was written by
+    	<span rel="dc:creator">
+      		<span property="foaf:name">Ben Adida</span>.
+    	</span>
+	</p>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0034.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2007_01.jpg> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0034.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0034</title>    
+  </head>
+  <body>
+  	<div about="http://sw-app.org/mic.xhtml#i" rel="foaf:img">
+  	  <img 	src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0035.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2006_03.jpg> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0035.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0035</title>    
+  </head>
+  <body>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0036.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2006_03.jpg> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0036.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0036</title>    
+  </head>
+  <body>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		resource="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0037.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/mic.xhtml#photo> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0037.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0037</title>    
+  </head>
+  <body>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg"
+  	   		resource="http://sw-app.org/mic.xhtml#photo" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0038.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/img/mic_2007_01.jpg> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0038.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0038</title>    
+  </head>
+  <body>
+  	<div about="http://sw-app.org/mic.xhtml#i" rev="foaf:depicts">
+  	  <img 	src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0039.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/img/mic_2006_03.jpg> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0039.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0039</title>    
+  </head>
+  <body>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rev="foaf:depicts"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0041.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/mic.xhtml#photo> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0041.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0041</title>    
+  </head>
+  <body>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rev="foaf:depicts"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg"
+  	   		resource="http://sw-app.org/mic.xhtml#photo" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0048.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/knows> _:g78112880 .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g78112880 <http://xmlns.com/foaf/0.1/name> "John Doe" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0048.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0048</title>    
+  </head>
+  <body>
+  	<div about="http://www.example.org/#me" rel="foaf:knows" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0049.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/name> "John Doe" .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0049.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0049</title>    
+  </head>
+  <body>
+  	<div about="http://www.example.org/#me" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0050.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:g78954530 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+_:g78954530 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0050.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0050</title>    
+  </head>
+  <body>
+  	<div typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0051.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0051.xhtml> <http://xmlns.com/foaf/0.1/topic> "John Doe" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0051.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0051.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0051</title>    
+  </head>
+  <body>
+  	<p about="" typeof="foaf:Document" property="foaf:topic">John Doe</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0052.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0052.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0052</title>    
+  </head>
+  <body>
+  	<p typeof="foaf:Person" resource="http://www.example.org/#me">
+	    John Doe
+   	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0053.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/name> "John Doe" .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0053.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0053</title>    
+  </head>
+  <body>
+  	<p typeof="foaf:Person" resource="http://www.example.org/#me">
+	    <span property="foaf:name">John Doe</span>
+   	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0054.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0054.xhtml> <http://purl.org/dc/elements/1.1/creator> "Fabien Gandon" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0054.xhtml> <http://purl.org/dc/elements/1.1/publisher> "Fabien Gandon" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0054.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+		<title>Test 0054</title>    
+  </head>
+  <body>
+  	<p>
+		This document was authored and published by  		
+		<span about="" property="dc:creator dc:publisher">Fabien Gandon</span>.
+  	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0055.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0055.xhtml> <http://purl.org/dc/elements/1.1/creator> <http://www-sop.inria.fr/acacia/fabien/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0055.xhtml> <http://purl.org/dc/elements/1.1/publisher> <http://www-sop.inria.fr/acacia/fabien/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0055.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+		<title>Test 0055</title>    
+  </head>
+  <body>
+  	<p>
+		This document was authored and published by
+		<a about="" rel="dc:creator dc:publisher" href="http://www-sop.inria.fr/acacia/fabien/">Fabien Gandon</a>.
+	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0056.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#mark> .
+<http://www.example.org/#ben> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#mark> <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0056.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0056</title>
+  </head>
+  <body>
+    <div about="http://www.example.org/#ben" typeof="foaf:Person" rel="foaf:knows">
+      <p about="http://www.example.org/#mark" property="foaf:name">Mark Birbeck</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0057.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://www.example.org/#mark> <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#mark> .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#ivan> .
+<http://www.example.org/#ivan> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0057.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0057</title>
+  </head>
+  <body>
+    <div about="http://www.example.org/#ben" rel="foaf:knows">
+      <p about="http://www.example.org/#mark" property="foaf:name">Mark Birbeck</p>
+      <p about="http://www.example.org/#ivan" property="foaf:name">Ivan Herman</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0059.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://www.example.org/#fabien> <http://xmlns.com/foaf/0.1/name> "Fabien Gandon" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0059.xhtml> <http://purl.org/dc/elements/1.1/creator> <http://www.example.org/#manu> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0059.xhtml> <http://purl.org/dc/elements/1.1/creator> <http://www.example.org/#fabien> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0059.xhtml> <http://purl.org/dc/elements/1.1/publisher> <http://www.example.org/#manu> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0059.xhtml> <http://purl.org/dc/elements/1.1/publisher> <http://www.example.org/#fabien> .
+<http://www.example.org/#manu> <http://xmlns.com/foaf/0.1/name> "Manu Sporny" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0059.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0059</title>
+  </head>
+  <body>
+    <p>This document was authored and published by:</p>
+    <ul rel="dc:creator dc:publisher">
+      <li about="http://www.example.org/#manu" property="foaf:name">Manu Sporny</li>
+      <li about="http://www.example.org/#fabien" property="foaf:name">Fabien Gandon</li>
+    </ul>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0060.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.example.org/#matsumoto-kimiko> <http://xmlns.com/foaf/0.1/name> "\u677E\u672C \u540E\u5B50" .
+<http://www.example.org/#matsumoto-kimiko> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0060.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0060</title>
+  </head>
+  <body>
+    <div about="http://www.example.org/#matsumoto-kimiko"
+         typeof="foaf:Person">
+      <p property="foaf:name">松本 后子</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0063.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0063.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0064.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0063.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+   <head>
+      <title>Test 0063</title>
+      <link rel=":next" href="http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0064.xhtml" />
+   </head>
+   <body>
+      <p>This is the 63<sup>rd</sup> test. The next test is #64.</p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0064.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+_:michael <http://xmlns.com/foaf/0.1/knows> <http://digitalbazaar.com/people/manu> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0064.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0064</title>
+  </head>
+  <body>
+    <p about="[_:michael]">Michael knows
+      <a rel="foaf:knows" href="http://digitalbazaar.com/people/manu">Manu</a>.
+    </p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0065.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:manu <http://xmlns.com/foaf/0.1/mbox> <mailto:manu.sporny@digitalbazaar.com> .
+_:manu <http://xmlns.com/foaf/0.1/knows> _:michael .
+_:michael <http://xmlns.com/foaf/0.1/mbox> <mailto:michael.hausenblas@joanneum.at> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0065.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0065</title>
+  </head>
+    <body>
+    <div about="[_:manu]">
+      Manu Sporny can be reached via
+      <a rel="foaf:mbox" href="mailto:manu.sporny@digitalbazaar.com">email</a>.
+      <span rel="foaf:knows" resource="[_:michael]">He knows Michael.</span>
+    </div>
+
+    <div about="[_:michael]">
+      Michael can be reached via
+      <a rel="foaf:mbox" href="mailto:michael.hausenblas@joanneum.at">email</a>.
+    </div>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0066.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0066.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0066.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+   <head typeof="foaf:Document">
+      <title>Test 0066</title>
+   </head>
+   <body>
+      <p>This is test #66.</p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0067.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0067.xhtml> <http://xmlns.com/foaf/0.1/topic> "Test 0067" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0067.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+   <head>
+      <title property="foaf:topic">Test 0067</title>
+   </head>
+   <body>
+      <p>This is test #67.</p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0068.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0067.xhtml> <http://purl.org/dc/elements/1.1/title> "Test 0067" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0068.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <title>Test 0068</title>
+   </head>
+   <body>
+      <p about="0067.xhtml">
+         The previous test was
+         <span property="dc:title">Test 0067</span>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0069.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0069.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0070.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0069.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
+   <head>
+      <title>Test 0069</title>
+   </head>
+   <body>
+      <p>The next test will be
+         <a about="" rel="xhv:next" href="0070.xhtml">Test 0070</a>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0070.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0070.xhtml> <http://www.w3.org/1999/xhtml/vocab#prev> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0069.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0070.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
+   <head>
+      <title>Test 0070</title>
+   </head>
+   <body>
+      <p>The previous test was
+         <span about="" rel="xhv:prev" resource="0069.xhtml">Test 0069</span>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0071.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0071.xhtml> <http://creativecommons.org/ns#license> <http://creativecommons.org/licenses/by-nd/3.0/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0071.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cc="http://creativecommons.org/ns#">
+   <head>
+      <title>Test 0071</title>
+   </head>
+   <body>
+      <p>This page is under a Creative Commons
+         <a rel="cc:license"
+            href="http://creativecommons.org/licenses/by-nd/3.0/">
+          Attribution-No Derivatives 3.0 license</a>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0072.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/faq> <http://purl.org/dc/elements/1.1/title> "Example FAQ" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0072.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <base href="http://www.example.org/"></base>
+      <title>Test 0072</title>
+   </head>
+   <body>
+      <p about="faq">
+         Learn more by reading the example.org
+         <span property="dc:title">Example FAQ</span>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0073.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://purl.org/dc/elements/1.1/creator> <http://www.example.org/jane> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0073.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <base href="http://www.example.org/"></base>
+      <title>Test 0073</title>
+   </head>
+   <body>
+      <p>
+        This article was written by
+      	<span rel="dc:creator" resource="jane">Jane</span>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0074.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://purl.org/dc/elements/1.1/creator> <http://www.example.org/jane> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0074.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <base href="http://www.example.org/"></base>
+      <title>Test 0074</title>
+   </head>
+   <body>
+     <p>
+     	This article was written by
+      	<a rel="dc:creator" href="jane">Jane</a>.
+	 </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0075.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nd/3.0/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0075.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <base href="http://www.example.org/"></base>
+      <title>Test 0075</title>
+   </head>
+   <body>
+   	<p>
+    	This page is under a Creative Commons
+        <a rel="license" href="http://creativecommons.org/licenses/by-nd/3.0/">Attribution-No Derivatives 3.0 license</a>.
+    </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0079.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.org/Ivan_Herman> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/People/Berners-Lee/card#i> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0079.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0079</title>    
+  </head>
+  <body>    
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p resource="http://www.ivan-herman.org/Ivan_Herman">Ivan Herman</p>
+	    <p href="http://www.w3.org/People/Berners-Lee/card#i">Tim Berners Lee</p>
+	    <p resource="http://danbri.org/foaf.rdf#danbri" href="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0080.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0080.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0080</title>    
+  </head>
+  <body>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p about="http://danbri.org/foaf.rdf#danbri" resource="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0083.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+_:g78109870 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g78109870 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+<http://danbri.org/foaf.rdf#danbri> <http://xmlns.com/foaf/0.1/name> "Dan Brickley" .
+<http://danbri.org/foaf.rdf#danbri> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g78109870 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0083.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0083</title>    
+  </head>
+  <body>
+	<div about="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p about="http://danbri.org/foaf.rdf#danbri" typeof="foaf:Person" property="foaf:name">Dan Brickley</p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0084.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,8 @@
+_:g79433050 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g79433050 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g79433050 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+<http://danbri.org/foaf.rdf#danbri> <http://xmlns.com/foaf/0.1/name> "Dan Brickley" .
+<http://danbri.org/foaf.rdf#danbri> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+<http://danbri.org/foaf.rdf#danbri> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g79433050 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0084.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0084</title>    
+  </head>
+  <body>
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows" rel="foaf:knows">
+	    <div>
+		    <p property="foaf:name">Ivan Herman</p>
+			<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+			<p about="http://danbri.org/foaf.rdf#danbri" typeof="foaf:Person" property="foaf:name">Dan Brickley</p>
+			
+		</div>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0085.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g78779030 .
+_:g78779030 <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.org/Ivan_Herman> .
+_:g78779030 <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/People/Berners-Lee/card#i> .
+_:g78779030 <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0085.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0085</title>    
+  </head>
+  <body>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	   <div rel="foaf:knows">
+		    <p resource="http://www.ivan-herman.org/Ivan_Herman">Ivan Herman</p>
+		    <p href="http://www.w3.org/People/Berners-Lee/card#i">Tim Berners Lee</p>
+		    <p resource="http://danbri.org/foaf.rdf#danbri" href="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	   </div>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0087.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,24 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#bookmark> <http://example.org/bookmark> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#last> <http://example.org/last> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> <http://example.org/role> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://example.org/next> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#appendix> <http://example.org/appendix> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#start> <http://example.org/start> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#glossary> <http://example.org/glossary> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://example.org/license> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#prev> <http://example.org/prev> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#chapter> <http://example.org/chapter> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#p3pv1> <http://example.org/p3pv1> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#subsection> <http://example.org/subsection> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#section> <http://example.org/section> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#meta> <http://example.org/meta> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#cite> <http://example.org/cite> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#copyright> <http://example.org/copyright> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#index> <http://example.org/index> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#first> <http://example.org/first> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#up> <http://example.org/up> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#contents> <http://example.org/contents> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#help> <http://example.org/help> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#alternate> <http://example.org/alternate> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#icon> <http://example.org/icon> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0087.xhtml> <http://www.w3.org/1999/xhtml/vocab#stylesheet> <http://example.org/stylesheet> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0087.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+   <head>
+      <title>Test 0087</title>
+   </head>
+   <body>
+      <p>
+         <a rel=":alternate" href="http://example.org/alternate">alternate</a>
+         <a rel=":appendix" href="http://example.org/appendix">appendix</a>
+         <a rel=":bookmark" href="http://example.org/bookmark">bookmark</a>
+         <a rel=":cite" href="http://example.org/cite">cite</a>
+         <a rel=":chapter" href="http://example.org/chapter">chapter</a>
+         <a rel=":contents" href="http://example.org/contents">contents</a>
+         <a rel=":copyright" href="http://example.org/copyright">copyright</a>
+         <a rel=":glossary" href="http://example.org/glossary">glossary</a>
+         <a rel=":help" href="http://example.org/help">help</a>
+         <a rel=":icon" href="http://example.org/icon">icon</a>
+         <a rel=":index" href="http://example.org/index">index</a>
+         <a rel=":first" href="http://example.org/first">first</a>
+         <a rel=":last" href="http://example.org/last">last</a>
+         <a rel=":license" href="http://example.org/license">license</a>
+         <a rel=":meta" href="http://example.org/meta">meta</a>
+         <a rel=":next" href="http://example.org/next">next</a>
+         <a rel=":p3pv1" href="http://example.org/p3pv1">p3pv1</a>
+         <a rel=":prev" href="http://example.org/prev">prev</a>
+         <a rel=":role" href="http://example.org/role">role</a>
+         <a rel=":section" href="http://example.org/section">section</a>
+         <a rel=":subsection" href="http://example.org/subsection">subsection</a>
+         <a rel=":start" href="http://example.org/start">start</a>
+         <a rel=":stylesheet" href="http://example.org/stylesheet">stylesheet</a>
+         <a rel=":up" href="http://example.org/up">up</a>
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0088.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_: <http://xmlns.com/foaf/0.1/name> "Dan Brickley" .
+_: <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _: .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0088.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0088</title>    
+  </head>
+  <body>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p about="[_:]" property="foaf:name">Dan Brickley</p>
+	    <p about="[_:]" typeof="foaf:Person">Dan Brickley again:-)</p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0089.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/example.png> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Image> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0089.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+ <head profile="http://www.w3.org/1999/xhtml/vocab">
+      <title>Test 0089</title>
+   </head>
+   <body>
+      <div>
+      	<img src="http://example.org/example.png" typeof="foaf:Image" alt="example image" />
+      </div>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0091.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:human <http://www.w3.org/1999/xhtml/vocab#definition> "a bi-pedal primate" .
+_:human <http://www.w3.org/1999/xhtml/vocab#note> "confused animal" .
+_:human <http://www.w3.org/1999/xhtml/vocab#foo> "Milky Way" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0091.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head profile="http://www.w3.org/1999/xhtml/vocab">
+      <title>Test 0091</title>
+   </head>
+   <body>
+      <p about="[_:human]">
+         A human is
+         <span property=":definition">a bi-pedal primate</span>.
+         They are quite possibly one of the most
+         <span property=":note">confused animal</span>s residing in the 
+		 <span property=":foo">Milky Way</span>.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0093.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0093.xhtml> <http://purl.org/dc/elements/1.1/title> "E = mc2: The Most Urgent Problem of Our Time"^^<http://www.example.org/XMLLiteral> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0093.xhtml> <http://purl.org/dc/elements/1.1/creator> "Albert Einstein" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0093.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:ex="http://www.example.org/">
+  <head profile="http://www.w3.org/1999/xhtml/vocab">
+	<title>Test 0093</title>
+  </head>
+  <body>
+  	<div about="">
+      Author: <span property="dc:creator">Albert Einstein</span>
+      <h2 property="dc:title" datatype="ex:XMLLiteral">E = mc<sup>2</sup>: The Most Urgent Problem of Our Time</h2>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0099.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.cwi.nl/~steven/> <http://www.example.org/likes> "\n    We put thirty spokes together and call it a wheel;\n    But it is on the space where there is nothing that the usefulness of the wheel depends.\n    We turn clay to make a vessel;\n    But it is on the space where there is nothing that the usefulness of the vessel depends.\n    We pierce doors and windows to make a house;\n    And it is on these spaces where there is nothing that the usefulness of the house depends.\n    Therefore just as we take advantage of what is, we should recognize the usefulness of what is not.\n\n    Lao Tzu: Tao Te Ching" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0099.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:example="http://www.example.org/">
+   <head profile="http://www.w3.org/1999/xhtml/vocab">
+      <title>Test 0099</title>
+   </head>
+   <body>
+		<p about="http://www.cwi.nl/~steven/" property="example:likes">
+    We put thirty spokes together and call it a wheel;
+    But it is on the space where there is nothing that the usefulness of the wheel depends.
+    We turn clay to make a vessel;
+    But it is on the space where there is nothing that the usefulness of the vessel depends.
+    We pierce doors and windows to make a house;
+    And it is on these spaces where there is nothing that the usefulness of the house depends.
+    Therefore just as we take advantage of what is, we should recognize the usefulness of what is not.
+
+    Lao Tzu: Tao Te Ching</p>
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0104.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:g78294430 <http://www.example.org/unit> "character" .
+_:g78294430 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "17" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0104.xhtml#interfenestration> <http://www.example.org/size> _:g78294430 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0104.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:example="http://www.example.org/">
+  <head profile="http://www.w3.org/1999/xhtml/vocab">
+	<title>Test 0104</title>
+  </head>
+  <body>
+  	<p>
+    	The word "interfenestration" has 
+    	<span about="#interfenestration" rel="example:size">
+            <span property="rdf:value">17</span>
+            <span property="example:unit">character</span>s.
+    	</span>
+	</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0106.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0106.xhtml> <http://purl.org/dc/elements/1.1/creator> _:g78051450 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0106.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0106</title>
+  </head>
+  <body>
+  	  <div about="" rel="dc:creator">
+         <a rel="" href="manu.html">Manu</a> created this page.
+      </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0107.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://example.org/">
+  <head>
+	<title>Test 0107</title>
+  </head>
+  <body>
+  	  <div rel="next"></div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0110.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0110.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> _:g78832160 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0110.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
+  <head>
+        <title>Test 0110</title>
+  </head>
+  <body>
+    <div rel="xhv:next">
+      <div rel="xhv:next" />
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0111.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:g78554010 <http://www.w3.org/1999/xhtml/vocab#next> _:g78530800 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0111.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> _:g78554010 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0111.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
+  <head>
+    <title>Test 0111</title>
+  </head>
+  <body>
+    <div rel="xhv:next">
+      <div rel="xhv:next">
+        <div rel="xhv:next" />
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0112.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "not an XML Literal,\nwhitespace     preserved\n" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0112.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://example.org/">
+  <head>
+	<title>Test 0112</title>
+  </head>
+  <body>
+  	  <p>
+      <span about="http://example.org/node" property="ex:property"
+            datatype="">not an XML Literal,
+whitespace     preserved
+</span>
+    </p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0114.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,8 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase5> <http://rdfa.info/test-suite/test-cases/.../.htaccess> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase4> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml?foo=bar../baz> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase3> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/...> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase1> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://creativecommons.org/ns#attributionURL> <http://rdfa.info/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://www.w3.org/1999/xhtml/vocab#index> <http://rdfa.info/test-suite/#> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0114.xhtml> <http://www.w3.org/1999/xhtml/vocab#up> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0114.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cc="http://creativecommons.org/ns#"
+xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#"
+xmlns:rdfatest="http://rdfa.info/vocabs/rdfa-test#">
+  <head>
+    <title>Test 0114</title>
+  </head>
+  <body>
+    <div>
+      <a rel="xhv:index" href="../../.././#">Test Suite</a>
+      <a rel="xhv:next" href="0115.xhtml">Test Case 0115</a>
+      <a rel="xhv:up" href="./">Test Case 0114</a>
+      <a rel="cc:attributionURL" href="../../../../">RDFa Website</a>
+      <a rel="rdfatest:cornerCase1" href=".">Corner Case #1</a>
+      <a rel="rdfatest:cornerCase3" href="...">Corner Case #3</a>
+      <a rel="rdfatest:cornerCase4" href="?foo=bar../baz">Corner Case #4</a>
+      <a rel="rdfatest:cornerCase5" href="../..../../../.../.htaccess">Corner Case #5</a>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0115.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> <http://www.example.com/entity4> "@" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> <http://www.example.com/entity3> "@" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> <http://www.example.com/entity2> "Ben & Co." .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> <http://www.example.com/entity1> ">" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0115.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://www.example.com/">
+   <head>
+     <title>Test 0115</title>
+   </head>
+   <body>
+      <p>Description: XML entities in the RDFa content</p>
+      <p>
+        <span property="ex:entity1">&gt;</span>
+        <span property="ex:entity2">Ben &amp; Co.</span>
+        <span property="ex:entity3">&#x40;</span>
+        <span property="ex:entity4">&#64;</span>
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0117.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.example.org/tc117.xhtml> <http://purl.org/dc/elements/1.1/title> "Test 0117" .
+<http://www.example.org/tc117.xhtml> <http://purl.org/dc/elements/1.1/contributor> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0117.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <base href="http://www.example.org/tc117.xhtml#fragment"></base>
+      <title property="dc:title">Test 0117</title>
+   </head>
+   <body>
+      <p>
+		<span property="dc:contributor">Mark Birbeck</span>
+         added this triple test.
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0118.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0118.xhtml> <http://purl.org/dc/elements/1.1/creator> "Ben" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0118.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <title>Test 0118</title>
+   </head>
+   <body>
+      <p>
+         Check to see if parsers get confused when "" is
+         interpreted as NULL in some chaining cases.
+         <a href="http://example.org/ben.html"><span
+            about="" property="dc:creator">Ben</span></a>
+      </p>
+   </body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0119.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/> <http://purl.org/dc/elements/1.1/title> "Example Website" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0119.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:example="http://example.org/">
+   <head>
+      <title>Test 0119</title>
+   </head>
+   <body>
+      <div>
+         <p about="[example:]">
+            The
+            <span property="dc:title">Example Website</span>
+            is used in many W3C tutorials.
+         </p>
+      </div>
+   </body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0120.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/1999/xhtml/vocab#> <http://purl.org/dc/elements/1.1/title> "The XHTML Vocabulary Document" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0120.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:example="http://example.org/">
+   <head>
+      <title>Test 0120</title>
+   </head>
+   <body>
+      <p about="[:]">
+	         The
+	         <span property="dc:title">The XHTML Vocabulary Document</span>
+	         is the default prefix for XHTML+RDFa 1.0.
+	      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0121.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/> <http://purl.org/dc/elements/1.1/title> "Test Case 0121" .
+<http://example.org/> <http://purl.org/dc/elements/1.1/contributor> "Shane McCarron" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0121.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+   <head>
+      <title>Test 0121</title>
+   </head>
+   <body>
+    <div>
+	<p about="http://example.org/">
+		<span about="[]" property="dc:title">Test Case 0121</span>
+		checks to make sure RDFa processors resolve the empty CURIE correctly.
+		<p resource="[]">
+			<span property="dc:contributor">Shane McCarron</span>
+			contributed to this test.
+		</p>
+	</p>
+	</div>
+   </body>
+
+
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0122.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+   <head>
+      <title>Test 0122</title>
+   </head>
+   <body>
+    <p about="http://example.org/section1.html">
+         This section is contained below <span rel="up" resource="[]">the main site</span>.
+      </p>
+   </body>
+
+
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0126.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://www.example.org/#article> <http://purl.org/dc/terms/title> "My article" .
+<http://www.example.org/#article> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
+<http://www.example.org/#article> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#Post> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0126.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dct="http://purl.org/dc/terms/"
+xmlns:sioc="http://rdfs.org/sioc/ns#"
+xmlns:foaf="http://xmlns.com/foaf/0.1/">
+    <head>
+      <title>Test 0126</title>
+    </head>
+    <body>
+      <div about="http://www.example.org/#article" typeof="foaf:Document sioc:Post">
+        <h1 property="dct:title">My article</h1>
+      </div>
+    </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0131.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0131.xhtml> <http://www.w3.org/1999/xhtml/vocab#last> <http://example.org/test.css> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0131.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://example.org/test.css> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0131.xhtml> <http://www.w3.org/1999/xhtml/vocab#prev> <http://example.org/test.css> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0131.xhtml> <http://www.w3.org/1999/xhtml/vocab#subsection> <http://example.org/test.css> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0131.xhtml> <http://www.w3.org/1999/xhtml/vocab#first> <http://example.org/test.css> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0131.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
+<head>
+  <title>Test</title>
+  <link rel="xhv:next&#x20;xhv:prev&#x09;xhv:first&#x0a;xhv:last&#x0d;xhv:subsection" href="http://example.org/test.css" />
+</head>
+<body>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0134.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0134.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://example.org/test.css> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0134.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test</title>
+  <link rel="LICENSE" href="http://example.org/test.css" />
+</head>
+<body>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0140.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Blank-node as Predicate Test</title>
+</head>
+<body>
+<p>Blank Nodes are not allowed to be predicate identifiers in RDF:</p>
+<p property="_:invalid">Test</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0147.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0147.xhtml> <http://example.org/test> "Test" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0147.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test</title>
+</head>
+<body>
+<p xmlns:xmlzzz="http://example.org/" property="xmlzzz:test">Test</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0174.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/jd> <http://www.w3.org/2006/vcard/ns#fn> "John Doe" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0174.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="http://www.w3.org/2006/vcard/ns#">
+<head> 
+   <title>Test 0174</title> 
+</head> 
+<body> 
+   <p>
+      This test ensures that single-character prefixes are allowed. 
+      My name is:
+      <span about="http://example.org/jd" property="v:fn">John Doe</span> 
+   </p>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0175.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+_:gregg <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0175.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0175</title>
+  </head>
+  <body>
+    <p about="_:gregg">My name is
+      <em property="http://xmlns.com/foaf/0.1/name">Gregg Kellogg</em>.
+    </p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0176.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+_:manu <http://xmlns.com/foaf/0.1/mbox> <mailto:manu.sporny@digitalbazaar.com> .
+_:manu <http://xmlns.com/foaf/0.1/knows> _:gregg .
+_:gregg <http://xmlns.com/foaf/0.1/knows> _:manu .
+_:gregg <http://xmlns.com/foaf/0.1/mbox> <mailto:gregg@kellogg-assoc.com> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0176.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+    <title>Test 0176</title>
+  </head>
+    <body>
+    <div about="_:manu">
+      Manu can be reached via
+      <a rel="http://xmlns.com/foaf/0.1/mbox" href="mailto:manu.sporny@digitalbazaar.com">email</a>.
+      <span rel="http://xmlns.com/foaf/0.1/knows" resource="_:gregg">He knows Gregg.</span>
+      <span rev="http://xmlns.com/foaf/0.1/knows" resource="_:gregg">Who knows Manu.</span>
+    </div>
+
+    <div about="_:gregg">
+      Gregg can be reached via
+      <a rel="http://xmlns.com/foaf/0.1/mbox" href="mailto:gregg@kellogg-assoc.com">email</a>.
+    </div>
+  </body>
+
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0177.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0177.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0177</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <div about ="#me" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+        <p property="foaf:name">Ivan Herman</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0178.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/#this> <http://xmlns.com/foaf/0.1/name> "A particular agent" .
+<http://example.org/#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/dc/terms/Agent> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0178.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0178</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <div about ="#this" prefix="foaf: http://xmlns.com/foaf/0.1/ dc: http://purl.org/dc/terms/" typeof="dc:Agent">
+        <p property="foaf:name">A particular agent</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0179.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0179.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0179</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <!-- prefix has a higher priority than xmlns -->
+  <div about ="#me" xmlns:foaf="http://www.example.com/wrong/foaf/uri" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">Ivan Herman</p>
+  </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0180.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/#me> <http://www.w3.org/1999/xhtml/vocab#name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0180.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0180</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+  <div about ="#me" prefix=": http://xmlns.com/foaf/0.1/" >
+      <p property=":name">Ivan Herman</p>
+  </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0181.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/software> <http://www.w3.org/1999/xhtml/vocab#license> <http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0181.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0181</title>
+  </head>
+  <body>
+  <div about ="http://www.example.org/software">
+      <p rel=":license" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+  </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0182.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/#this> <http://xmlns.com/foaf/0.1/name> "A particular agent" .
+<http://example.org/#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/dc/terms/Agent> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0182.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0182</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <div prefix="foaf: http://example.org/wrong/foaf/uri/ dc: http://purl.org/dc/terms/" >
+      <div about ="#this" typeof="dc:Agent" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+        <p property="foaf:name">A particular agent</p>
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0183.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/#this> <http://xmlns.com/foaf/0.1/name> "A particular agent" .
+<http://example.org/#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/dc/terms/Agent> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0183.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0183</title>
+  <base href="http://example.org/"/>
+</head>
+<body>
+  <div prefix="foaf: http://example.org/wrong/foaf/uri/ dc: http://purl.org/dc/terms/" >
+    <div about ="#this" typeof="dc:Agent" xmlns:foaf="http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">A particular agent</p>
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0186.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0186.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0186</title>
+  <base href="http://example.org/"/>
+</head>
+<body>
+  <div about ="#me" vocab="http://xmlns.com/foaf/0.1/" >
+    <p property="name">Ivan Herman</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0187.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org/> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://example.org/wrong/foaf/uri/> .
+<http://example.org/> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0187.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0187</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <div vocab="http://example.org/wrong/foaf/uri/">
+      <div about ="#me" vocab="http://xmlns.com/foaf/0.1/" >
+        <p property="name">Ivan Herman</p>
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0188.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0188.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0188</title>
+    <base href="http://example.org/"/>
+  </head>
+  <body>
+    <div vocab="http://xmlns.com/foaf/0.1/">
+      <div about ="#me">
+        <p property="name">Ivan Herman</p>
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0189.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0189.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://www.example.org/vocab#> .
+<http://www.example.org/software> <http://www.example.org/vocab#license> <http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0189.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0189</title>
+  </head>
+  <body>
+    <div about ="http://www.example.org/software" vocab="http://www.example.org/vocab#">
+      <p rel="license" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0190.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/software> <http://www.w3.org/1999/xhtml/vocab#license> <http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0190.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0190</title>
+  </head>
+  <body>
+    <div about ="http://www.example.org/software">
+      <p rel="liCeNse" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0196.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.example.org> <http://example.org/rdf/plainlit> "This is a plain literal" .
+<http://www.example.org> <http://example.org/rdf/xmllit> "This is an XMLLiteral"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0196.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://example.org/rdf/"
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<head>
+	<title>Test 0196</title>
+</head>
+<body>
+	<div about="http://www.example.org">
+    <p property="ex:xmllit" datatype="rdf:XMLLiteral">This is an XMLLiteral</p>
+    <p property="ex:plainlit">This is a <em>plain</em> literal</p>
+</div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0197.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/me> <http://purl.org/dc/terms/language> "Ruby" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0197.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/terms/">
+<head>
+	<title>Test 0197</title>
+	<base href="http://www.example.org/me" />
+</head>
+<body>
+  <p about="" typeof="class/Person" property="pred/name">Gregg Kellogg</p>
+  <p property="dc:language" datatype="pred/lang">Ruby</p>
+  <p rel="pred/rel" resource="http://kellogg-assoc.com/">Kellogg Associates</p>
+  <p rev="pred/rev" resource="http://github.org/gkellogg/rdf_context">Ruby Gem</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0198.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://www.example.org/me#mark> <http://xmlns.com/foaf/0.1/name> "<span xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:foaf=\"http://xmlns.com/foaf/0.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" property=\"foaf:firstName\">Mark</span> <span xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:foaf=\"http://xmlns.com/foaf/0.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" property=\"foaf:surname\">Birbeck</span>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
+<http://www.example.org/me#mark> <http://xmlns.com/foaf/0.1/firstName> "Mark" .
+<http://www.example.org/me#mark> <http://xmlns.com/foaf/0.1/surname> "Birbeck" .
+<http://www.example.org/me#mark> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0198.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/"
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<head>
+	<title>Test 0198</title>
+	<base href="http://www.example.org/me" />
+</head>
+<body>
+      <div id="mark" about="#mark" typeof="foaf:Person">
+        <h2 property="foaf:name" datatype="rdf:XMLLiteral"><span 
+property="foaf:firstName">Mark</span> <span 
+property="foaf:surname">Birbeck</span></h2>
+      </div>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0206.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/2001/XMLSchema#maxExclusive> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0206.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+   <title>Default context test 0206</title>
+</head>
+<body>
+	<p about ="xsd:maxExclusive" rel="rdf:type" resource="owl:DatatypeProperty">
+	    An OWL Axiom: "xsd:maxExclusive" is a Datatype Property in OWL.
+	</p>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0207.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#summary> "Weekend off in Iona" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2006-10-21"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#dtend> "2006-10-23"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#url> <http://freetime.example.org/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0207.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#location> "Iona, UK" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0207.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cal="http://www.w3.org/2002/12/cal/icaltzd#"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
+<head>
+   <title>Test 0207</title>    
+</head>
+   <body>
+   <p about="#event1" typeof="cal:Vevent">
+       <b property="cal:summary">Weekend off in Iona</b>: 
+       <span property="cal:dtstart" content="2006-10-21" datatype="xsd:date">Oct 21st</span>
+       to <span property="cal:dtend" content="2006-10-23"  datatype="xsd:date">Oct 23rd</span>.
+       See <a rel="cal:url" href="http://freetime.example.org/">FreeTime.Example.org</a> for
+       info on <span property="cal:location">Iona, UK</span>.
+   </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0213.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://purl.org/dc/elements/1.1/title> "E = mc2: The Most Urgent Problem of Our Time" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0213.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="dc: http://purl.org/dc/elements/1.1/">
+  <head>
+	<title>Test 0213</title>
+  </head>
+  <body>
+    <!-- In RDFa 1.1, by default a plain literal is generated even if it contains XML elements -->
+  	<div about="http://www.example.org/">
+      <h2 property="dc:title">E = mc<sup>2</sup>: The Most Urgent Problem of Our Time</h2>
+	</div>
+  </body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0214.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0214.xhtml> <http://purl.org/dc/terms/title> "Test 0214" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0214.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0214.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" typeof="foaf:Document">
+<head>
+   <title property="dc:title">Test 0214</title>
+</head>
+<body>
+   <p>This document has a title.</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0216.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Iv\u00E1n" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0216.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix = "
+air: http://www.daml.org/2001/10/html/airport-ont#
+bio: http://vocab.org/bio/0.1/
+contact: http://www.w3.org/2000/10/swap/pim/contact#
+dc: http://purl.org/dc/terms/
+foaf: http://xmlns.com/foaf/0.1/
+ical: http://www.w3.org/2002/12/cal/icaltzd#
+owl: http://www.w3.org/2002/07/owl#
+rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
+rdfs: http://www.w3.org/2000/01/rdf-schema#
+rel: http://vocab.org/relationship/
+openid: http://xmlns.openid.net/auth#
+rss: http://web.resource.org/rss/1.0/
+sioc: http://rdfs.org/sioc/ns#
+xsd: http://www.w3.org/2001/XMLSchema#
+google: http://rdf.data-vocabulary.org/#
+rsa: http://www.w3.org/ns/auth/rsa#
+cert: http://www.w3.org/ns/auth/cert#
+wot: http://xmlns.com/wot/0.1/
+">
+<head>
+   <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
+</head>
+<body>
+      <!-- Tests whether the Unicode (UTF-8 encoded) characters are properly handled even with a large set of properties
+	  in the html element, ie, when the content sniffing to find out the character encoding may not work -->
+	  <p about="http://www.ivan-herman.net/foaf#me" property="foaf:name">Iván</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0217.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://example.org/#me> <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0217.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0217</title>
+  <base href="http://example.org/"/>
+</head>
+<body>
+  <div about="#me" vocab="http://xmlns.com/foaf/0.1/" >
+    <p property="name">Gregg Kellogg</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0218.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0218.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0218.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0218</title>
+</head>
+<body>
+  <div about ="">
+    <p rel="rdf:value" inlist=""/>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0219.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0219.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g77749300 .
+_:g77749300 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g77749300 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0219.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0219</title>
+</head>
+<body>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0220.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:g78842450 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78842450 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0220.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78842450 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0220.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0220</title>
+</head>
+<body>
+  <div about="">
+    <a rel="rdf:value" inlist="" href="foo">Foo</a>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0221.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0221.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78451470 .
+_:g78379550 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78379550 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
+_:g78451470 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g78379550 .
+_:g78451470 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0221.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0221</title>
+</head>
+<body>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <a rel="rdf:value" inlist="" href="foo">Foo</a>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0222.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+_:g78035150 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78035150 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+_:g78057660 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g78035150 .
+_:g78057660 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0222.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78057660 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0222.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0222</title>
+</head>
+<body>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <strong><p property="rdf:value" inlist="">Bar</p></strong>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0223.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+_:g77844170 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g77759660 .
+_:g77844170 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0223.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "Baz" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0223.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g77844170 .
+_:g77759660 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g77759660 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0223.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0223</title>
+</head>
+<body>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <strong><p property="rdf:value" inlist="">Bar</p></strong>
+    <p property="rdf:value">Baz</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0224.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+_:g79290600 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g79290600 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/bar> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0224.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g79463470 .
+_:g79463470 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g79290600 .
+_:g79463470 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0224.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0224</title>
+</head>
+<body>
+  <div about="">
+    <ol rel="rdf:value" inlist="">
+      <li><a href="foo">Foo</a></li>
+      <li><a href="bar">Bar</a></li>
+    </ol>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0225.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78613430 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78521650 .
+_:g78613430 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78613430 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+_:g78521650 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78521650 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0225.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0225</title>
+</head>
+<body>
+  <div about="foo">
+    <p property="rdf:value" inlist="">Foo</p>
+  </div>
+  <div about="foo">
+    <p property="rdf:value" inlist="">Bar</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0226.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0226.xhtml> <http://www.example.org/inlist> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0226.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78111740 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g78062780 .
+_:g78062780 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78062780 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+_:g78111740 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g78111740 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0226.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0226</title>
+</head>
+<body prefix="ex: http://www.example.org/">
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <span rel="ex:inlist" resource="res">
+      <p property="rdf:value" inlist="">Bar</p>
+    </span>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0227.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+_:g77829450 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g77829450 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0227.xhtml> <http://www.example.org/inlist> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0227.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g77869430 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g77829450 .
+_:g77869430 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g77869430 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0227.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0227</title>
+</head>
+<body prefix="ex: http://www.example.org/">
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <span rel="ex:inlist">
+      <p about="res" property="rdf:value" inlist="">Bar</p>
+    </span>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0228.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://sw-app.org/img/mic_2006_03.jpg> <http://www.w3.org/1999/xhtml/vocab#alternate> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0228.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0228.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+		<title>Test 0228</title>
+		<!-- Based on 1.1 semantics for 0040 -->
+  </head>
+  <body>
+  	<div>
+     <img src="http://sw-app.org/img/mic_2007_01.jpg"
+           rev="xhv:alternate"
+           resource="http://sw-app.org/img/mic_2006_03.jpg"
+           alt="A photo depicting Michael" />	
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0229.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0229.xhtml> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2007_01.jpg> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0229.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0042</title>    
+  </head>
+  <body>
+  	<div>
+  	  <img 	rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0230.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0230.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nc-sa/2.0/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0230.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0230</title>
+</head>
+<body>
+  <div>
+    <img
+      src="http://example.org/example.png"  
+      rel="license"
+      href="http://creativecommons.org/licenses/by-nc-sa/2.0/"
+      alt="example image" />
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0231.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/example.png> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nc-sa/2.0/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0231.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0231</title>
+</head>
+<body>
+  <div about="http://creativecommons.org/licenses/by-nc-sa/2.0/" rev="license">
+    <img src="http://example.org/example.png" alt="example image" />
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0232.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:g77900230 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+_:g77900230 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0232.xhtml> <http://xmlns.com/foaf/0.1/maker> _:g77900230 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0232.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0232</title>    
+  </head>
+  <body>
+  	<div rel="foaf:maker" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0233.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0233.xhtml> <http://xmlns.com/foaf/0.1/maker> <http://www.example.org/#me> .
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/name> "John Doe" .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0233.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foaf="http://xmlns.com/foaf/0.1/">
+  <head>
+		<title>Test 0233</title>    
+  </head>
+  <body>
+  	<div rel="foaf:maker" typeof="foaf:Person" resource="http://www.example.org/#me">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0234.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0234.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> <http://example.org/role> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0234.xhtml> <http://www.w3.org/2007/05/powder-s#describedby> <http://example.org/describedby> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0234.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://example.org/license> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0234.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+   <head>
+      <title>Test 0234</title>
+   </head>
+   <body>
+      <p>
+         <a rel="describedby" href="http://example.org/describedby">describedby</a>
+         <a rel="license" href="http://example.org/license">license</a>
+         <a rel="role" href="http://example.org/role">role</a>
+      </p>
+   </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0246.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> _:g78602720 .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> _:g78539140 .
+_:g78539140 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g78539140 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g78602720 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g78602720 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0246.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Test 0246</title>
+  </head>
+  <body prefix="foaf: http://xmlns.com/foaf/0.1/">
+    <div about="http://www.example.org/#ben" rel="foaf:knows">
+      <p typeof="foaf:Person"><span property="foaf:name">Mark Birbeck</span></p>
+      <p typeof="foaf:Person"><span property="foaf:name">Ivan Herman</span></p>
+    </div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0247.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+_:g78075450 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g78075450 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g78112540 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g78075450 .
+_:g78112540 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g78112540 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0247.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+		<title>Test 0247</title>    
+  </head>
+  <body prefix="foaf: http://xmlns.com/foaf/0.1/">    
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person"><span property="foaf:name">Mark Birbeck</span></p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0248.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+_:g77897430 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g77897430 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g77897430 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g77869710 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g77869710 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g77869710 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0248.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+		<title>Test 0248</title>    
+  </head>
+  <body prefix="foaf: http://xmlns.com/foaf/0.1/">
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person"><span property="foaf:name">Mark Birbeck</span></p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0249.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,8 @@
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g77612730 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g77559090 .
+_:g77612730 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g77612730 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g77612730 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g77559090 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g77559090 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g77559090 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0249.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+		<title>Test 0249</title>    
+  </head>
+  <body prefix="foaf: http://xmlns.com/foaf/0.1/">
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person"><span property="foaf:name">Mark Birbeck</span></p>
+	</div>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0250.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+<http://www.ivan-herman.net/foaf#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0250.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+		<title>Test 0250</title>    
+  </head>
+  <body prefix="foaf: http://xmlns.com/foaf/0.1/">
+	<p about ="http://www.ivan-herman.net/foaf#me" typeof="foaf:Person" property="foaf:name">Ivan Herman</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0251.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "chat"@fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0251.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/">
+  <head about="">
+	<title>Test 251</title>
+  	<meta about="http://example.org/node" property="ex:property" lang="fr" content="chat" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0252.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "chat"@fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0252.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/">
+  <head about="" lang="fr">
+  	<title lang="en">Test 0252</title>
+  	<meta about="http://example.org/node" property="ex:property" content="chat" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0253.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "\u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03CC\n\u03AC\u03C3\u03C0\u03C1\u03BF   \u03B4\u03B9\u03AC\u03C3\u03C4\u03B7\u03BC\u03B1\n"@el .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0253.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/">
+  <head>
+	<title>Test 0108</title>
+  </head>
+  <body>
+    <p about="http://example.org/node" property="ex:property"
+       datatype="" lang="el">ελληνικό
+άσπρο   διάστημα
+</p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0254.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/> <http://example.org/terms#prop> "A plain literal with a lang tag."@en .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0254.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/terms#">
+<head> 
+   <title>Test 0254</title> 
+   <base href="http://example.org/"/> 
+</head> 
+<body lang="en"> 
+   <p property="ex:prop" datatype="">A <strong>plain literal</strong> with a lang tag.</p> 
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0255.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/> <http://example.org/terms#prop> "Just a plain literal." .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0255.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/terms#">
+<head> 
+   <title>Test 0255</title> 
+   <base href="http://example.org/"/> 
+</head> 
+<body lang="en"> 
+   <p property="ex:prop" lang="">Just a plain literal.</p> 
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0256.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/node> <http://example.org/property> "chat"@fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0256.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="ex: http://example.org/">
+  <head about="">
+	<title>Test 0256</title>
+  	<meta about="http://example.org/node" property="ex:property" xml:lang="fr" lang="hu" content="chat" />
+  </head>
+  <body>
+  	<p></p>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0257.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0257.xhtml#a> <http://purl.org/dc/elements/1.1/title> "" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0257.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" prefix="dc: http://purl.org/dc/elements/1.1/">
+  <head>
+    <title>Test 0257</title>
+  </head>
+  <body>
+    <span about="#a" property="dc:title"></span>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0258.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0258.xhtml> <http://www.w3.org/ns/earl#testcase> _:test .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0258.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Undescore Prefix is Ignored Test</title>
+</head>
+<body>
+<p>Ensure that the "_" prefix is ignored.</p>
+<p xmlns:_="http://example.org/"
+   prefix="_: http://example.org/" 
+   xmlns:earl="http://www.w3.org/ns/earl#" 
+   rel="earl:testcase" resource="_:test">Test</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0259.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,31 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/ns/rdfa#> "RDFa" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://rdfs.org/ns/void#> "VOID" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://commontag.org/ns#> "CTAG" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> "Role" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2002/07/owl#> "OWL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/1999/xhtml/vocab#> "XHV" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://creativecommons.org/ns#> "CC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://rdfs.org/sioc/ns#> "SIOC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "RDF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2000/01/rdf-schema#> "RDFS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2007/05/powder#> "WDR" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://xmlns.com/foaf/0.1/> "FOAF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://purl.org/goodrelations/v1#> "GR" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2007/05/powder-s#describedby> "DescribedBy" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2007/rif#> "RIF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> "License" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/XML/1998/namespace> "XML" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2001/XMLSchema#> "XSD" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2006/vcard/ns#> "VCARD" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2003/g/data-view#> "GRDDL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://rdf.data-vocabulary.org/#> "V" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/ns/ma-ont#> "MA" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2008/05/skos-xl#> "SKOS-XL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2002/12/cal/icaltzd#> "ICAL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2004/02/skos/core#> "SKOS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://www.w3.org/2007/05/powder-s#> "WDRS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://purl.org/dc/terms/> "DC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://purl.org/dc/terms/> "DCTERMS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://ogp.me/ns#> "OG" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://schema.org/> "Schema" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0259.xhtml> <http://purl.org/stuff/rev#> "REV" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0259.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0259</title>
+</head>
+<body>
+  <div>
+    Vocabulary Prefixes
+    <span property="grddl:">GRDDL</span>
+    <span property="ma:">MA</span>
+    <span property="owl:">OWL</span>
+    <span property="rdf:">RDF</span>
+    <span property="rdfa:">RDFa</span>
+    <span property="rdfs:">RDFS</span>
+    <span property="rif:">RIF</span>
+    <span property="skos:">SKOS</span>
+    <span property="skosxl:">SKOS-XL</span>
+    <span property="wdr:">WDR</span>
+    <span property="void:">VOID</span>
+    <span property="wdrs:">WDRS</span>
+    <span property="xhv:">XHV</span>
+    <span property="xml:">XML</span>
+    <span property="xsd:">XSD</span>
+  </div>
+  <div>
+    Widely Used prefixes
+    <span property="cc:">CC</span>
+    <span property="ctag:">CTAG</span>
+    <span property="dc:">DC</span>
+    <span property="dcterms:">DCTERMS</span>
+    <span property="foaf:">FOAF</span>
+    <span property="gr:">GR</span>
+    <span property="ical:">ICAL</span>
+    <span property="og:">OG</span>
+    <span property="rev:">REV</span>
+    <span property="sioc:">SIOC</span>
+    <span property="v:">V</span>
+    <span property="vcard:">VCARD</span>
+    <span property="schema:">Schema</span>
+  </div>
+  <div>
+    Vocabulary Terms
+    <span property="describedby">DescribedBy</span>
+    <span property="license">License</span>
+    <span property="role">Role</span>
+  </div>
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0261.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org> <http://example.org/rdf/xmllit> "This is\nan XMLLiteral"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0261.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ex="http://example.org/rdf/"
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<head>
+	<title>Test 0261</title>
+</head>
+<body>
+	<div about="http://www.example.org">
+    <p property="ex:xmllit" datatype="rdf:XMLLiteral">This is
+an XMLLiteral</p>
+</div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0262.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/elements/1.1/creator> "Mark Birbeck" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0262.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<head>
+   <title>Test 0262</title>
+</head>
+<body>
+   <p>This photo was taken by <span class="author" about="photo1.jpg" property="    dc:creator
+">Mark Birbeck</span>.</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0263.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0263.xhtml> <http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.example.org> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0263.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" property="rdfs:seeAlso" resource="http://www.example.org">
+<head >
+	<title>Test 0263</title>
+</head>
+<body>
+  <p> </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0264.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0264.xhtml> <http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.example.org> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0264.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head  property="rdfs:seeAlso" resource="http://www.example.org">
+	<title>Test 0264</title>
+</head>
+<body>
+  <p> </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0265.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.com> <http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.example.org> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0265.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" about="http://www.example.com">
+<head  property="rdfs:seeAlso" resource="http://www.example.org">
+	<title>Test 0265</title>
+</head>
+<body>
+  <p> </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0266.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.ivan-herman.net/foaf#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.w3.org/Person/Ivan#me> <http://www.w3.org/2002/07/owl#sameAs> <http://www.ivan-herman.net/foaf#me> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0266.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Test 0266</title>
+</head>
+<body>
+  <div about="http://www.w3.org/Person/Ivan#me">
+     <a href="http://www.ivan-herman.net/foaf#me" typeof="foaf:Person" property="owl:sameAs">Ivan Herman</a>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0267.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.ivan-herman.net/foaf#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.w3.org/Person/Ivan#me> <http://www.w3.org/2002/07/owl#sameAs> <http://www.ivan-herman.net/foaf#me> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0267.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Test 0267</title>
+</head>
+<body>
+  <div about="http://www.w3.org/Person/Ivan#me">
+     <p resource="http://www.ivan-herman.net/foaf#me" typeof="foaf:Person" property="owl:sameAs">Ivan Herman</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0268.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://www.ivan-herman.net/Images/me2003-small.png> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Image> .
+<http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/depiction> <http://www.ivan-herman.net/Images/me2003-small.png> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0268.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Test 0268</title>
+</head>
+<body>
+  <div about="http://www.ivan-herman.net/foaf#me">
+     <img src="http://www.ivan-herman.net/Images/me2003-small.png" typeof="foaf:Image" property="foaf:depiction" />
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0269.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0269.xhtml> <http://www.w3.org/2000/01/rdf-schema#comment> "This is an RDFa test" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0269.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" property="rdfs:comment" content="This is an RDFa test">
+<head >
+	<title>Test 0269</title>
+</head>
+<body>
+  <p> </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0271.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://www.w3.org/2000/01/rdf-schema#comment> "This is an RDFa test" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0271.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" about="http://www.example.org/">
+<head property="rdfs:comment" content="This is an RDFa test">
+	<title>Test 0269</title>
+</head>
+<body>
+  <p> </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0272.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0272.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18Z"^^<http://www.w3.org/2001/XMLSchema#date> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0272.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0272</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03-18Z">18 March 2012</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0273.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0273.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#time> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0273.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0273</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="00:00:00Z">midnight</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0274.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0274.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0274.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0274</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00Z">18 March 2012 at midnight</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0275.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0275.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18Z"^^<http://www.w3.org/2001/XMLSchema#date> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0275.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0275</title>
+</head>
+<body>
+  <time property="rdf:value">2012-03-18Z</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0276.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0276.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#time> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0276.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0275</title>
+</head>
+<body>
+  <time property="rdf:value">00:00:00Z</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0277.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0277.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0277.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0277</title>
+</head>
+<body>
+  <time property="rdf:value">2012-03-18T00:00:00Z</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0278.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0278.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18"^^<http://www.w3.org/2001/XMLSchema#date> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0278.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0278</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03-18" content="not this">18 March 2012</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0279.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0279.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#date> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0279.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0279</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00Z" datatype="xsd:date">18 March 2012 at midnight</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0280.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0280.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "P2011Y06M28DT00H00M00S"^^<http://www.w3.org/2001/XMLSchema#duration> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0280.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0280</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="P2011Y06M28DT00H00M00S">2011 years 6 months 28 days</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0281.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0281.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012"^^<http://www.w3.org/2001/XMLSchema#gYear> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0281.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0281</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012">Two Thousand Twelve</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0282.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0282.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03"^^<http://www.w3.org/2001/XMLSchema#gYearMonth> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0282.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0282</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03">March, Two Thousand Twelve</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0283.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0283.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> " 2012-03-18Z" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0283.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0283</title>
+</head>
+<body>
+  <time property="rdf:value"> 2012-03-18Z</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0284.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0284.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> " 2012-03-18Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0284.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0284</title>
+</head>
+<body>
+  <time property="rdf:value" datatype="xsd:dateTime"> 2012-03-18Z</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0285.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0285.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "D-Day"@en .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0285.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0285</title>
+</head>
+<body>
+  <time property="rdf:value" lang="en" datetime="D-Day">
+    Non matching lexical value with language.
+  </time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0286.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0286.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "veni, vidi, vici"@lat .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0286.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0286</title>
+</head>
+<body>
+  <data property="rdf:value" lang="lat" value="veni, vidi, vici" content="I came, I saw, I conquered">
+    @value overrides @content in the 'data' element.
+  </data>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0287.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0287.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00-08:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0287.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0287</title>
+</head>
+<body>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00-08:00">18 March 2012 at midnight in San Francisco</time>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0289.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0289.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0289</title>
+</head>
+<body>
+  <h1>@href becomes subject when @property and @content are present</h1>
+  <a href="http://example.org/" property="rdf:value" content="value">ignored</a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0290.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0290.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0290</title>
+</head>
+<body>
+  <h1>@href becomes subject when @property and @datatype are present</h1>
+  <a href="http://example.org/" property="rdf:value" datatype="">value</a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0291.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0291.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<head>
+  <title>Test 0291</title>
+</head>
+<body>
+  <h1>@href as subject overridden by @about</h1>
+  <a about="http://example.net/" href="http://example.org/" property="rdf:value" content="value">ignored</a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0292.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value one" .
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value two" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0292.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<head>
+  <title>Test 0292</title>
+</head>
+<body>
+  <h1>@about overriding @href as subject is used as parent resource</h1>
+  <a about="http://example.net/" href="http://example.org/" property="rdf:value" content="value one">
+    <span property="rdf:value">value two</span>
+  </a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0293.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org> <http://www.example.org/column:test> "Test" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0293.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0293</title>
+</head>
+<body>
+  <h1>Testing the ':' character usage in a CURIE</h1>
+  <div prefix="ex: http://www.example.org/">
+     <p about="http://www.example.org" property="ex:column:test">Test</p>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0295.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,308 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0077.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> <http://example.org/role> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0077.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://example.org/license> .
+_:g91336410 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g91336410 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g91336410 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g90978840 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g90913350 .
+_:g90978840 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/bar> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#this> <http://xmlns.com/foaf/0.1/name> "A particular agent" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/dc/terms/Agent> .
+_:g91036640 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+_:g91036640 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_: <http://xmlns.com/foaf/0.1/name> "Dan Brickley" .
+_: <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:michael <http://xmlns.com/foaf/0.1/knows> <http://digitalbazaar.com/people/manu> .
+_:michael <http://xmlns.com/foaf/0.1/mbox> <mailto:michael.hausenblas@joanneum.at> .
+_:g90913350 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91379370 .
+_:g90913350 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+_:g90991410 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g90978840 .
+_:g90991410 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g90984140 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.org/Ivan_Herman> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/People/Berners-Lee/card#i> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g91393080 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g91366010 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g91336410 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _:g91305190 .
+<http://www.example.org/#somebody> <http://xmlns.com/foaf/0.1/knows> _: .
+<http://sw-app.org/img/mic_2007_01.jpg> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
+<http://www.example.org/#manu> <http://xmlns.com/foaf/0.1/name> "Manu Sporny" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/terms/title> "Portrait of Mark" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/terms/creator> "Mark Birbeck" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> <http://purl.org/dc/terms/creator> <http://www.blogger.com/profile/1109404> .
+<http://www.example.org/> <http://purl.org/dc/terms/title> "E = mc2: The Most Urgent Problem of Our Time" .
+<http://danbri.org/foaf.rdf#danbri> <http://xmlns.com/foaf/0.1/name> "Dan Brickley" .
+<http://danbri.org/foaf.rdf#danbri> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+<http://danbri.org/foaf.rdf#danbri> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g91181100 <http://xmlns.com/foaf/0.1/name> "Ben Adida" .
+<http://www.cwi.nl/~steven/> <http://example.org/likes> "\n    We put thirty spokes together and call it a wheel;\n    But it is on the space where there is nothing that the usefulness of the wheel depends.\n    We turn clay to make a vessel;\n    But it is on the space where there is nothing that the usefulness of the vessel depends.\n    We pierce doors and windows to make a house;\n    And it is on these spaces where there is nothing that the usefulness of the house depends.\n    Therefore just as we take advantage of what is, we should recognize the usefulness of what is not.\n\n    Lao Tzu: Tao Te Ching" .
+<http://www.example.org/software> <http://www.w3.org/1999/xhtml/vocab#license> <http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231> .
+<http://www.example.org/software> <http://www.example.org/vocab#license> <http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231> .
+_:g91088720 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91077100 .
+_:g91088720 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
+_:g91393080 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g91393080 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g91393080 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g91393080 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g91366540 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g91366540 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#summary> "Weekend off in Iona" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2006-10-21"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#dtend> "2006-10-23"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#url> <http://freetime.example.org/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#event1> <http://www.w3.org/2002/12/cal/icaltzd#location> "Iona, UK" .
+_:g91379370 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g91379370 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#mark> <http://xmlns.com/foaf/0.1/name> "<span xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"http://www.w3.org/2006/vcard/ns#\" xmlns:rsa=\"http://www.w3.org/ns/auth/rsa#\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:example=\"http://example.org/\" xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\" xmlns:earl=\"http://www.w3.org/ns/earl#\" xmlns:rel=\"http://vocab.org/relationship/\" xmlns:cal=\"http://www.w3.org/2002/12/cal/icaltzd#\" xmlns:owl=\"http://www.w3.org/2002/07/owl#\" xmlns:contact=\"http://www.w3.org/2000/10/swap/pim/contact#\" xmlns:cert=\"http://www.w3.org/ns/auth/cert#\" xmlns:google=\"http://rdf.data-vocabulary.org/#\" xmlns:foaf=\"http://xmlns.com/foaf/0.1/\" xmlns:xhv=\"http://www.w3.org/1999/xhtml/vocab#\" xmlns:wot=\"http://xmlns.com/wot/0.1/\" xmlns:rss=\"http://web.resource.org/rss/1.0/\" xmlns:ical=\"http://www.w3.org/2002/12/cal/icaltzd#\" xmlns:ex=\"http://example.org/\" xmlns:bio=\"http://vocab.org/bio/0.1/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:rdfatest=\"http://rdfa.info/vocabs/rdfa-test#\" xmlns:openid=\"http://xmlns.openid.net/auth#\" xmlns:dc=\"http://purl.org/dc/terms/\" xmlns:sioc=\"http://rdfs.org/sioc/ns#\" xmlns:dct=\"http://purl.org/dc/terms/\" xmlns:air=\"http://www.daml.org/2001/10/html/airport-ont#\" property=\"foaf:firstName\">Mark</span> <span xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"http://www.w3.org/2006/vcard/ns#\" xmlns:rsa=\"http://www.w3.org/ns/auth/rsa#\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:example=\"http://example.org/\" xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\" xmlns:earl=\"http://www.w3.org/ns/earl#\" xmlns:rel=\"http://vocab.org/relationship/\" xmlns:cal=\"http://www.w3.org/2002/12/cal/icaltzd#\" xmlns:owl=\"http://www.w3.org/2002/07/owl#\" xmlns:contact=\"http://www.w3.org/2000/10/swap/pim/contact#\" xmlns:cert=\"http://www.w3.org/ns/auth/cert#\" xmlns:google=\"http://rdf.data-vocabulary.org/#\" xmlns:foaf=\"http://xmlns.com/foaf/0.1/\" xmlns:xhv=\"http://www.w3.org/1999/xhtml/vocab#\" xmlns:wot=\"http://xmlns.com/wot/0.1/\" xmlns:rss=\"http://web.resource.org/rss/1.0/\" xmlns:ical=\"http://www.w3.org/2002/12/cal/icaltzd#\" xmlns:ex=\"http://example.org/\" xmlns:bio=\"http://vocab.org/bio/0.1/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:rdfatest=\"http://rdfa.info/vocabs/rdfa-test#\" xmlns:openid=\"http://xmlns.openid.net/auth#\" xmlns:dc=\"http://purl.org/dc/terms/\" xmlns:sioc=\"http://rdfs.org/sioc/ns#\" xmlns:dct=\"http://purl.org/dc/terms/\" xmlns:air=\"http://www.daml.org/2001/10/html/airport-ont#\" property=\"foaf:surname\">Birbeck</span>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#mark> <http://xmlns.com/foaf/0.1/firstName> "Mark" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#mark> <http://xmlns.com/foaf/0.1/surname> "Birbeck" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#mark> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/name> "John Doe" .
+<http://www.example.org/#me> <http://xmlns.com/foaf/0.1/knows> _:g91053130 .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
+<http://www.example.org/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://example.org/jd> <http://www.w3.org/2006/vcard/ns#fn> "John Doe" .
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value" .
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value one" .
+<http://example.net/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value two" .
+_:a <http://xmlns.com/foaf/0.1/name> "Manu Sporny" .
+_:a <http://xmlns.com/foaf/0.1/knows> _:b .
+_:g91404000 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org/#ivan> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+<http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Iv\u00E1n" .
+<http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/depiction> <http://www.ivan-herman.net/Images/me2003-small.png> .
+<http://www.ivan-herman.net/foaf#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g90970690 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g91108800 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91088720 .
+_:g91108800 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+_:b <http://xmlns.com/foaf/0.1/name> "Ralph Swick" .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#mark> .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#ivan> .
+<http://www.example.org/#ben> <http://xmlns.com/foaf/0.1/knows> _:g90954040 .
+<http://www.example.org/#ben> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://www.example.org> <http://example.org/plainlit> "This is a plain literal" .
+<http://www.example.org> <http://www.example.org/column:test> "Test" .
+<http://www.example.org> <http://example.org/xmllit> "This is an XMLLiteral"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
+<http://www.w3.org/2001/XMLSchema#maxExclusive> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
+_:g91027920 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91015140 .
+_:g91027920 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/faq> <http://purl.org/dc/terms/title> "Example FAQ" .
+<http://www.ivan-herman.net/Images/me2003-small.png> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Image> .
+<http://www.example.org/#article> <http://purl.org/dc/terms/title> "My article" .
+<http://www.example.org/#article> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
+<http://www.example.org/#article> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#Post> .
+<http://example.org/foo> <http://example.org/bar> "10"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org/foo> <http://purl.org/dc/terms/creator> "Mark Birbeck"^^<http://www.w3.org/2001/XMLSchema#string> .
+_:g91366010 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g91366010 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g90998370 <http://www.w3.org/1999/xhtml/vocab#next> _:g90995150 .
+<http://www.example.org/#fabien> <http://xmlns.com/foaf/0.1/name> "Fabien Gandon" .
+<http://example.org/node> <http://example.org/property> "\u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03CC\n\u03AC\u03C3\u03C0\u03C1\u03BF   \u03B4\u03B9\u03AC\u03C3\u03C4\u03B7\u03BC\u03B1\n"@el .
+<http://example.org/node> <http://example.org/property> "not an XML Literal,\nwhitespace     preserved\n" .
+_:g91077100 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91067150 .
+_:g91077100 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+_:g90954040 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g90954040 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g91376310 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://sw-app.org/img/mic_2006_03.jpg> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
+<http://sw-app.org/img/mic_2006_03.jpg> <http://www.w3.org/1999/xhtml/vocab#alternate> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> .
+_:g91051870 <http://example.org/unit> "character" .
+_:g91051870 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "17" .
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2007_01.jpg> .
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2006_03.jpg> .
+<http://sw-app.org/mic.xhtml#i> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/mic.xhtml#photo> .
+_:g91296760 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+_:g91296760 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g90943720 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g90943720 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+_:g90969080 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g90969080 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://internet-apps.blogspot.com/> <http://purl.org/dc/terms/creator> "Mark Birbeck" .
+_:human <http://www.w3.org/1999/xhtml/vocab#definition> "a bi-pedal primate" .
+_:human <http://www.w3.org/1999/xhtml/vocab#note> "confused animal" .
+_:human <http://www.w3.org/1999/xhtml/vocab#foo> "Milky Way" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#wtw> <http://purl.org/dc/terms/identifier> <urn:ISBN:0752820907> .
+_:g91054290 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91042730 .
+_:g91054290 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Foo" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#me> <http://xmlns.com/foaf/0.1/name> "Ben Adida" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#me> <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#me> <http://www.w3.org/1999/xhtml/vocab#name> "Ivan Herman" .
+_:g91042730 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91027920 .
+_:g91042730 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+<http://example.org/> <http://purl.org/dc/terms/contributor> "Shane McCarron" .
+<http://example.org/> <http://purl.org/dc/terms/title> "Example Website" .
+<http://example.org/> <http://purl.org/dc/terms/title> "Test Case 0121" .
+<http://example.org/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "value" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0067.xhtml> <http://purl.org/dc/terms/title> "Test 0067" .
+<mailto:manu.sporny@digitalbazaar.com> <http://xmlns.com/foaf/0.1/knows> <mailto:michael.hausenblas@joanneum.at> .
+_:g90984140 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g90984140 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g90984140 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+<http://sw-app.org/mic.xhtml#photo> <http://xmlns.com/foaf/0.1/depicts> <http://sw-app.org/mic.xhtml#i> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g91421340 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g91366540 .
+_:g90951000 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g91053130 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#b> <http://purl.org/dc/terms/title> "" .
+<http://www.example.org/#mark> <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+<http://www.blogger.com/profile/1109404> <http://xmlns.com/foaf/0.1/img> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/photo1.jpg> .
+_:manu <http://xmlns.com/foaf/0.1/mbox> <mailto:manu.sporny@digitalbazaar.com> .
+_:manu <http://xmlns.com/foaf/0.1/knows> _:michael .
+_:manu <http://xmlns.com/foaf/0.1/knows> _:gregg .
+<http://example.org/invalid/> <http://purl.org/dc/terms/title> "Test 0109" .
+_:g91420340 <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
+_:g91420340 <http://xmlns.com/foaf/0.1/name> "Mark Birbeck" .
+_:g91420340 <http://xmlns.com/foaf/0.1/knows> <http://www.example.org/#somebody> .
+_:g91420340 <http://xmlns.com/foaf/0.1/mailbox> <mailto:ivan@w3.org> .
+_:g91421340 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+_:g91421340 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
+_:g91076130 <http://xmlns.com/foaf/0.1/name> "John Doe" .
+_:g91076130 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
+_:gregg <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .
+_:gregg <http://xmlns.com/foaf/0.1/knows> _:manu .
+_:gregg <http://xmlns.com/foaf/0.1/mbox> <mailto:gregg@kellogg-assoc.com> .
+<http://www.example.org/#matsumoto-kimiko> <http://xmlns.com/foaf/0.1/name> "\u677E\u672C \u540E\u5B50" .
+<http://www.example.org/#matsumoto-kimiko> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/stuff/rev#> "REV" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#alternate> <http://example.org/alternate> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/goodrelations/v1#> "GR" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase4> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml?foo=bar../baz> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/earl#testcase> _:test .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2002/07/owl#> "OWL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#p3pv1> <http://example.org/p3pv1> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase3> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/...> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase2> <http://example.org/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://example.org/wrong/foaf/uri/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://www.example.org/vocab#> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#appendix> <http://example.org/appendix> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#inlist> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/res> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2004/02/skos/core#> "SKOS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/topic> "John Doe" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase1> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2007/05/powder-s#describedby> <http://example.org/describedby> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2007/05/powder-s#describedby> "DescribedBy" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0070.xhtml> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://example.org/next> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> _:g91005320 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> _:g90998370 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#next> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0115.xhtml> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#subsection> <http://example.org/subsection> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/title> "E = mc2: The Most Urgent Problem of Our Time"^^<http://example.org/XMLLiteral> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/title> "rdfagraph" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://creativecommons.org/ns#> "CC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://commontag.org/ns#> "CTAG" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/maker> _:g91076130 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/maker> <http://www.example.org/#me> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/maker> _:g91296760 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://example.org/entity4> "@" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> <http://example.org/role> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#role> "Role" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://example.org/entity3> "@" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#chapter> <http://example.org/chapter> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "Baz" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18Z"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#time> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "P2011Y06M28DT00H00M00S"^^<http://www.w3.org/2001/XMLSchema#duration> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03"^^<http://www.w3.org/2001/XMLSchema#gYearMonth> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> " 2012-03-18Z" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> " 2012-03-18Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "D-Day"@en .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "veni, vidi, vici"@lat .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2012-03-18T00:00:00-08:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g91108800 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#index> <http://example.org/index> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#index> <http://rdfa.info/test-suite/#> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://example.org/entity2> "Ben & Co." .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://example.org/test> "Test" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/> "FOAF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#start> <http://example.org/start> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "RDF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2000/01/rdf-schema#> "RDFS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/publisher> "Fabien Gandon" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/publisher> <http://www-sop.inria.fr/acacia/fabien/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/publisher> <http://www.example.org/#manu> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/publisher> <http://www.example.org/#fabien> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://example.org/entity1> ">" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#copyright> <http://example.org/copyright> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#icon> <http://example.org/icon> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nd/3.0/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://example.org/license> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nc-sa/2.0/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> "License" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#license> "license" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/language> "Ruby" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2007/05/powder#> "WDR" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfs.org/sioc/ns#> "SIOC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://creativecommons.org/ns#attributionURL> <http://rdfa.info/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2006/vcard/ns#> "V" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2006/vcard/ns#> "VCARD" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#last> <http://example.org/last> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/rdfa#> "RDFa" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#cite> <http://example.org/cite> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#meta> <http://example.org/meta> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#section> <http://example.org/section> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://ogp.me/ns#> "OG" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2007/05/powder-s#> "WDRS" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://xmlns.com/foaf/0.1/img> <http://sw-app.org/img/mic_2007_01.jpg> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfs.org/ns/void#> "VOID" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#help> <http://example.org/help> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#bookmark> <http://example.org/bookmark> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#contents> <http://example.org/contents> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#first> <http://example.org/first> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2002/12/cal/icaltzd#> "ICAL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/XML/1998/namespace> "XML" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/contributor> "Mark Birbeck" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#stylesheet> <http://example.org/stylesheet> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2008/05/skos-xl#> "SKOS-XL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#glossary> <http://example.org/glossary> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#prev> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0069.xhtml> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#prev> <http://example.org/prev> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://schema.org/> "Schema" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2003/g/data-view#> "GRDDL" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://creativecommons.org/ns#license> <http://creativecommons.org/licenses/by-nc-nd/2.5/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://creativecommons.org/ns#license> <http://creativecommons.org/licenses/by-nd/3.0/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#up> <http://example.org/up> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#up> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/1999/xhtml/vocab#> "XHV" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://rdfa.info/vocabs/rdfa-test#cornerCase5> <http://rdfa.info/test-suite/test-cases/.../.htaccess> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2007/rif#> "RIF" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/2001/XMLSchema#> "XSD" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://www.w3.org/ns/ma-ont#> "MA" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> "Mark Birbeck" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#me> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> _:g91181100 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> "Fabien Gandon" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> <http://www-sop.inria.fr/acacia/fabien/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> <http://www.example.org/#manu> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> <http://www.example.org/#fabien> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/jane> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> "Albert Einstein" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> _:g91036200 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/creator> "Ben" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/> "DC" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml> <http://purl.org/dc/terms/> "DCTERMS" .
+<http://example.org/example.png> <http://www.w3.org/1999/xhtml/vocab#license> <http://creativecommons.org/licenses/by-nc-sa/2.0/> .
+<http://example.org/example.png> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Image> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#a> <http://purl.org/dc/terms/title> "" .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0295.xhtml#interfenestration> <http://example.org/size> _:g91051870 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g90969080 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:g90943720 .
+<http://www.w3.org/Person/Ivan#me> <http://www.w3.org/2002/07/owl#sameAs> <http://www.ivan-herman.net/foaf#me> .
+_:g91067150 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g91054290 .
+_:g91067150 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/foo> .
+<http://www.w3.org/1999/xhtml/vocab#> <http://purl.org/dc/terms/title> "The XHTML Vocabulary Document" .
+_:g90944750 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+_:g91305190 <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.org/Ivan_Herman> .
+_:g91305190 <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/People/Berners-Lee/card#i> .
+_:g91305190 <http://xmlns.com/foaf/0.1/knows> <http://danbri.org/foaf.rdf#danbri> .
+_:g91015140 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g90991410 .
+_:g91015140 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Bar" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0295.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,930 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:air="http://www.daml.org/2001/10/html/airport-ont#"
+xmlns:bio="http://vocab.org/bio/0.1/"
+xmlns:cal="http://www.w3.org/2002/12/cal/icaltzd#"
+xmlns:cc="http://creativecommons.org/ns#"
+xmlns:cert="http://www.w3.org/ns/auth/cert#"
+xmlns:contact="http://www.w3.org/2000/10/swap/pim/contact#"
+xmlns:dc="http://purl.org/dc/terms/"
+xmlns:dct="http://purl.org/dc/terms/"
+xmlns:earl="http://www.w3.org/ns/earl#"
+xmlns:example="http://example.org/"
+xmlns:ex="http://example.org/"
+xmlns:foaf="http://xmlns.com/foaf/0.1/"
+xmlns:google="http://rdf.data-vocabulary.org/#"
+xmlns:ical="http://www.w3.org/2002/12/cal/icaltzd#"
+xmlns:openid="http://xmlns.openid.net/auth#"
+xmlns:owl="http://www.w3.org/2002/07/owl#"
+xmlns:rdfatest="http://rdfa.info/vocabs/rdfa-test#"
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+xmlns:rel="http://vocab.org/relationship/"
+xmlns:rsa="http://www.w3.org/ns/auth/rsa#"
+xmlns:rss="http://web.resource.org/rss/1.0/"
+xmlns:sioc="http://rdfs.org/sioc/ns#"
+xmlns:v="http://www.w3.org/2006/vcard/ns#"
+xmlns:wot="http://xmlns.com/wot/0.1/"
+xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
+<head>
+   <title>RDFa 1.1 Benchmark File #1</title>
+</head>
+<body>
+   <p>This photo was taken by <span class="author" about="photo1.jpg" property="dc:creator">Mark Birbeck</span>.</p>
+		<p>
+			This photo was taken by
+			<a 	about="photo1.jpg" rel="dc:creator" rev="foaf:img"
+   				href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+		</p>	
+		<p>This photo was taken by
+			<a 	about="photo1.jpg" property="dc:title"
+   				content="Portrait of Mark" rel="dc:creator"
+      			rev="foaf:img" href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+		</p>	
+  	<p>This document is licensed under a
+  		<a 	about="" rel="cc:license"
+    		href="http://creativecommons.org/licenses/by-nc-nd/2.5/">
+       		Creative Commons
+  		</a>.
+  	</p>	
+  	<p></p>
+  	<p></p>
+  	<p></p>
+  	<p></p>
+  	<p>
+  		<span	about="http://example.org/foo"
+        		property="ex:bar" content="10" datatype="xsd:integer">ten</span>
+	</p>
+  	<p></p>
+  	 <p>
+          <span about="[_:a]" property="foaf:name">Manu Sporny</span>
+           <span about="[_:a]" rel="foaf:knows"
+resource="[_:b]">knows</span>
+           <span about="[_:b]" property="foaf:name">Ralph Swick</span>.
+        </p>
+  	<p>
+	  This photo was taken by
+	  <a about="photo1.jpg" rel="dc:creator"
+		 href="http://www.blogger.com/profile/1109404">Mark Birbeck</a>.
+	</p>	 
+    <div about="mailto:manu.sporny@digitalbazaar.com"
+      rel="foaf:knows" href="mailto:michael.hausenblas@joanneum.at"></div>
+    <div about="photo1.jpg">
+      <span class="attribution-line">this photo was taken by
+        <span property="dc:creator">Mark Birbeck</span>
+      </span>
+    </div>
+    <div>
+      <span class="attribution-line">this photo was taken by
+        <span property="dc:creator">Mark Birbeck</span>
+      </span>
+    </div>
+    <div id="photo1">
+      	This photo was taken by
+        <span property="dc:creator">Mark Birbeck</span> 
+    </div>
+  	<p>
+    	This paper was written by
+    	<span rel="dc:creator" resource="#me">
+      		<span property="foaf:name">Ben Adida</span>.
+    	</span>
+	</p>
+  	<p>
+		<span 	about="http://internet-apps.blogspot.com/"
+	      		property="dc:creator" content="Mark Birbeck" />
+	</p>	
+  	<p>
+    	<span 	about="http://internet-apps.blogspot.com/"
+       			property="dc:creator" content="Mark Birbeck">Mark B.
+		</span>
+	</p>	
+  	<p>
+    	<span 	about="http://example.org/foo"
+	      		property="dc:creator" datatype="xsd:string"><b>M</b>ark <b>B</b>irbeck</span>.
+	</p>	  
+  	<p>This document is licensed under a
+  		<a 	rel="cc:license"
+    		href="http://creativecommons.org/licenses/by-nc-nd/2.5/">
+       		Creative Commons License
+  		</a>.
+  	</p>	
+  	<p about="#wtw">
+  	  The book <b>Weaving the Web</b> (hardcover) has the ISBN
+  	  <span rel="dc:identifier" resource="urn:ISBN:0752820907">0752820907</span>.
+  	</p>	
+  	<p about="#wtw">
+  	  The book <b>Weaving the Web</b> (hardcover) has the ISBN
+  	  <a rel="dc:identifier" resource="urn:ISBN:0752820907" 
+  	  href="http://www.amazon.com/Weaving-Web-Tim-Berners-Lee/dp/0752820907">0752820907</a>.
+  	</p>
+  	<p>
+    	This paper was written by
+    	<span rel="dc:creator">
+      		<span property="foaf:name">Ben Adida</span>.
+    	</span>
+	</p>
+  	<div about="http://sw-app.org/mic.xhtml#i" rel="foaf:img">
+  	  <img 	src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		resource="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg"
+  	   		resource="http://sw-app.org/mic.xhtml#photo" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  	<div about="http://sw-app.org/mic.xhtml#i" rev="foaf:depicts">
+  	  <img 	src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rev="foaf:depicts"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  	<div>
+     <img src="http://sw-app.org/img/mic_2007_01.jpg"
+           rev="alternate"
+           resource="http://sw-app.org/img/mic_2006_03.jpg"
+           alt="A photo depicting Michael" />	
+  	</div>
+  	<div>
+      <img 	about="http://sw-app.org/mic.xhtml#i"
+  	   		rev="foaf:depicts"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		href="http://sw-app.org/img/mic_2006_03.jpg"
+  	   		resource="http://sw-app.org/mic.xhtml#photo" 
+  	   		alt="A photo depicting Michael" />  	
+  	</div>
+  	<div>
+  	  <img 	rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  	<div rel="foaf:maker" typeof="foaf:Document">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<div rel="foaf:maker" typeof="foaf:Document" resource="http://www.example.org/#me">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<div about="http://www.example.org/#me" rel="foaf:knows" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<div about="http://www.example.org/#me" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<div typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<p about="" typeof="foaf:Document" property="foaf:topic">John Doe</p>
+  	<p typeof="foaf:Person" resource="http://www.example.org/#me">
+	    John Doe
+   	</p>
+  	<p typeof="foaf:Person" resource="http://www.example.org/#me">
+	    <span property="foaf:name">John Doe</span>
+   	</p>
+  	<p>
+		This document was authored and published by  		
+		<span about="" property="dc:creator dc:publisher">Fabien Gandon</span>.
+  	</p>
+  	<p>
+		This document was authored and published by
+		<a about="" rel="dc:creator dc:publisher" href="http://www-sop.inria.fr/acacia/fabien/">Fabien Gandon</a>.
+	</p>
+    <div about="http://www.example.org/#ben" typeof="foaf:Person" rel="foaf:knows">
+      <p about="http://www.example.org/#mark" property="foaf:name">Mark Birbeck</p>
+    </div>
+    <div about="http://www.example.org/#ben" rel="foaf:knows">
+      <p about="http://www.example.org/#mark" property="foaf:name">Mark Birbeck</p>
+      <p about="http://www.example.org/#ivan" property="foaf:name">Ivan Herman</p>
+    </div>
+    <div about="http://www.example.org/#ben" rel="foaf:knows">
+      <p typeof="foaf:Person" property="foaf:name">Mark Birbeck</p>
+      <p typeof="foaf:Person" property="foaf:name">Ivan Herman</p>
+    </div>
+    <p>This document was authored and published by:</p>
+    <ul rel="dc:creator dc:publisher">
+      <li about="http://www.example.org/#manu" property="foaf:name">Manu Sporny</li>
+      <li about="http://www.example.org/#fabien" property="foaf:name">Fabien Gandon</li>
+    </ul>
+    <div about="http://www.example.org/#matsumoto-kimiko"
+         typeof="foaf:Person">
+      <p property="foaf:name">松本 后子</p>
+    </div>
+      <p>This is the first chapter in a series of chapters.</p>
+      <p>This is unit test #62. The next unit test is #63.</p>
+      <p>This is the 63<sup>rd</sup> test. The next test is #64.</p>
+    <p about="[_:michael]">Michael knows
+      <a rel="foaf:knows" href="http://digitalbazaar.com/people/manu">Manu</a>.
+    </p>
+    <div about="[_:manu]">
+      Manu Sporny can be reached via
+      <a rel="foaf:mbox" href="mailto:manu.sporny@digitalbazaar.com">email</a>.
+      <span rel="foaf:knows" resource="[_:michael]">He knows Michael.</span>
+    </div>
+
+    <div about="[_:michael]">
+      Michael can be reached via
+      <a rel="foaf:mbox" href="mailto:michael.hausenblas@joanneum.at">email</a>.
+    </div>
+      <p>This is test #66.</p>
+      <p>This is test #67.</p>
+      <p about="0067.xhtml">
+         The previous test was
+         <span property="dc:title">Test 0067</span>.
+      </p>
+      <p>The next test will be
+         <a about="" rel="xhv:next" href="0070.xhtml">Test 0070</a>.
+      </p>
+      <p>The previous test was
+         <span about="" rel="xhv:prev" resource="0069.xhtml">Test 0069</span>.
+      </p>
+      <p>This page is under a Creative Commons
+         <a rel="cc:license"
+            href="http://creativecommons.org/licenses/by-nd/3.0/">
+          Attribution-No Derivatives 3.0 license</a>.
+      </p>
+      <p about="faq">
+         Learn more by reading the example.org
+         <span property="dc:title">Example FAQ</span>.
+      </p>
+      <p>
+        This article was written by
+      	<span rel="dc:creator" resource="jane">Jane</span>.
+      </p>
+     <p>
+     	This article was written by
+      	<a rel="dc:creator" href="jane">Jane</a>.
+	 </p>
+   	<p>
+    	This page is under a Creative Commons
+        <a rel="license" href="http://creativecommons.org/licenses/by-nd/3.0/">Attribution-No Derivatives 3.0 license</a>.
+    </p>
+      <p>
+         <a rel="alternate" href="http://example.org/alternate">alternate</a>
+         <a rel="appendix" href="http://example.org/appendix">appendix</a>
+         <a rel="bookmark" href="http://example.org/bookmark">bookmark</a>
+         <a rel="cite" href="http://example.org/cite">cite</a>
+         <a rel="chapter" href="http://example.org/chapter">chapter</a>
+         <a rel="contents" href="http://example.org/contents">contents</a>
+         <a rel="copyright" href="http://example.org/copyright">copyright</a>
+         <a rel="glossary" href="http://example.org/glossary">glossary</a>
+         <a rel="help" href="http://example.org/help">help</a>
+         <a rel="icon" href="http://example.org/icon">icon</a>
+         <a rel="index" href="http://example.org/index">index</a>
+         <a rel="last" href="http://example.org/last">last</a>
+         <a rel="license" href="http://example.org/license">license</a>
+         <a rel="meta" href="http://example.org/meta">meta</a>
+         <a rel="next" href="http://example.org/next">next</a>
+         <a rel="p3pv1" href="http://example.org/p3pv1">p3pv1</a>
+         <a rel="prev" href="http://example.org/prev">prev</a>
+         <a rel="role" href="http://example.org/role">role</a>
+         <a rel="section" href="http://example.org/section">section</a>
+         <a rel="subsection" href="http://example.org/subsection">subsection</a>
+         <a rel="start" href="http://example.org/start">start</a>
+		 <a rel="stylesheet" href="http://example.org/stylesheet">stylesheet</a>
+         <a rel="up" href="http://example.org/up">up</a>
+      </p>
+       <p>
+         <span about="http://example.org/alternate" rev="alternate"
+               href="0077.xhtml">alternate</span>
+         <span about="http://example.org/appendix" rev="appendix"
+               href="0077.xhtml">appendix</span>
+         <span about="http://example.org/bookmark" rev="bookmark"
+               href="0077.xhtml">bookmark</span>
+         <span about="http://example.org/cite" rev="cite"
+               href="0077.xhtml">cite</span>
+         <span about="http://example.org/chapter" rev="chapter"
+               href="0077.xhtml">chapter</span>
+         <span about="http://example.org/contents" rev="contents"
+               href="0077.xhtml">contents</span>
+         <span about="http://example.org/copyright" rev="copyright"
+               href="0077.xhtml">copyright</span>
+         <span about="http://example.org/glossary" rev="glossary"
+               href="0077.xhtml">glossary</span>
+         <span about="http://example.org/help" rev="help"
+               href="0077.xhtml">help</span>
+         <span about="http://example.org/icon" rev="icon"
+               href="0077.xhtml">icon</span>
+         <span about="http://example.org/index" rev="index"
+               href="0077.xhtml">index</span>
+         <span about="http://example.org/first" rev="first"
+               href="0077.xhtml">first</span>
+         <span about="http://example.org/last" rev="last"
+               href="0077.xhtml">last</span>
+         <span about="http://example.org/license" rev="license"
+               href="0077.xhtml">license</span>
+         <span about="http://example.org/meta" rev="meta"
+               href="0077.xhtml">meta</span>
+         <span about="http://example.org/next" rev="next"
+               href="0077.xhtml">next</span>
+         <span about="http://example.org/p3pv1" rev="p3pv1"
+               href="0077.xhtml">p3pv1</span>
+         <span about="http://example.org/prev" rev="prev"
+               href="0077.xhtml">prev</span>
+         <span about="http://example.org/role" rev="role"
+               href="0077.xhtml">role</span>
+         <span about="http://example.org/section" rev="section"
+               href="0077.xhtml">section</span>
+         <span about="http://example.org/subsection" rev="subsection"
+               href="0077.xhtml">subsection</span>
+         <span about="http://example.org/start" rev="start"
+               href="0077.xhtml">start</span>
+		<span about="http://example.org/stylesheet" rev="stylesheet"
+               href="0077.xhtml">stylesheet</span>			   
+         <span about="http://example.org/up" rev="up"
+               href="0077.xhtml">up</span>
+      </p>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person" property="foaf:name">Mark Birbeck</p>
+	</div>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p resource="http://www.ivan-herman.org/Ivan_Herman">Ivan Herman</p>
+	    <p href="http://www.w3.org/People/Berners-Lee/card#i">Tim Berners Lee</p>
+	    <p resource="http://danbri.org/foaf.rdf#danbri" href="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	</div>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p about="http://danbri.org/foaf.rdf#danbri" resource="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	</div>
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person" property="foaf:name">Mark Birbeck</p>
+	</div>
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p typeof="foaf:Person" property="foaf:name">Mark Birbeck</p>
+	</div>
+	<div about="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p property="foaf:name">Ivan Herman</p>
+		<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+		<p about="http://danbri.org/foaf.rdf#danbri" typeof="foaf:Person" property="foaf:name">Dan Brickley</p>
+	</div>
+	<div about ="http://www.example.org/#somebody" rev="foaf:knows" rel="foaf:knows">
+	    <div>
+		    <p property="foaf:name">Ivan Herman</p>
+			<p rel="foaf:mailbox" resource="mailto:ivan@w3.org">mailto:ivan@w3.org</p>
+			<p about="http://danbri.org/foaf.rdf#danbri" typeof="foaf:Person" property="foaf:name">Dan Brickley</p>
+			
+		</div>
+	</div>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	   <div rel="foaf:knows">
+		    <p resource="http://www.ivan-herman.org/Ivan_Herman">Ivan Herman</p>
+		    <p href="http://www.w3.org/People/Berners-Lee/card#i">Tim Berners Lee</p>
+		    <p resource="http://danbri.org/foaf.rdf#danbri" href="http://www.leobard.net/rdf/foaf.xml#me">Dan Brickley</p>
+	   </div>
+	</div>
+      <p>
+         <a rel=":alternate" href="http://example.org/alternate">alternate</a>
+         <a rel=":appendix" href="http://example.org/appendix">appendix</a>
+         <a rel=":bookmark" href="http://example.org/bookmark">bookmark</a>
+         <a rel=":cite" href="http://example.org/cite">cite</a>
+         <a rel=":chapter" href="http://example.org/chapter">chapter</a>
+         <a rel=":contents" href="http://example.org/contents">contents</a>
+         <a rel=":copyright" href="http://example.org/copyright">copyright</a>
+         <a rel=":glossary" href="http://example.org/glossary">glossary</a>
+         <a rel=":help" href="http://example.org/help">help</a>
+         <a rel=":icon" href="http://example.org/icon">icon</a>
+         <a rel=":index" href="http://example.org/index">index</a>
+         <a rel=":first" href="http://example.org/first">first</a>
+         <a rel=":last" href="http://example.org/last">last</a>
+         <a rel=":license" href="http://example.org/license">license</a>
+         <a rel=":meta" href="http://example.org/meta">meta</a>
+         <a rel=":next" href="http://example.org/next">next</a>
+         <a rel=":p3pv1" href="http://example.org/p3pv1">p3pv1</a>
+         <a rel=":prev" href="http://example.org/prev">prev</a>
+         <a rel=":role" href="http://example.org/role">role</a>
+         <a rel=":section" href="http://example.org/section">section</a>
+         <a rel=":subsection" href="http://example.org/subsection">subsection</a>
+         <a rel=":start" href="http://example.org/start">start</a>
+         <a rel=":stylesheet" href="http://example.org/stylesheet">stylesheet</a>
+         <a rel=":up" href="http://example.org/up">up</a>
+      </p>
+	<div about ="http://www.example.org/#somebody" rel="foaf:knows">
+	    <p about="[_:]" property="foaf:name">Dan Brickley</p>
+	    <p about="[_:]" typeof="foaf:Person">Dan Brickley again:-)</p>
+	</div>
+      <div>
+      	<img src="http://example.org/example.png" typeof="foaf:Image" alt="example image" />
+      </div>
+      <div>
+      	<img	src="http://example.org/example.png"  
+				rel="license"
+           		href="http://creativecommons.org/licenses/by-nc-sa/2.0/"
+				alt="example image" />
+      </div>
+      <p about="[_:human]">
+         A human is
+         <span property=":definition">a bi-pedal primate</span>.
+         They are quite possibly one of the most
+         <span property=":note">confused animal</span>s residing in the 
+		 <span property=":foo">Milky Way</span>.
+      </p>
+  	<div about="">
+      Author: <span property="dc:creator">Albert Einstein</span>
+      <h2 property="dc:title" datatype="ex:XMLLiteral">E = mc<sup>2</sup>: The Most Urgent Problem of Our Time</h2>
+	</div>
+		<p about="http://www.cwi.nl/~steven/" property="example:likes">
+    We put thirty spokes together and call it a wheel;
+    But it is on the space where there is nothing that the usefulness of the wheel depends.
+    We turn clay to make a vessel;
+    But it is on the space where there is nothing that the usefulness of the vessel depends.
+    We pierce doors and windows to make a house;
+    And it is on these spaces where there is nothing that the usefulness of the house depends.
+    Therefore just as we take advantage of what is, we should recognize the usefulness of what is not.
+
+    Lao Tzu: Tao Te Ching</p>
+  	<p>
+    	The word "interfenestration" has 
+    	<span about="#interfenestration" rel="example:size">
+            <span property="rdf:value">17</span>
+            <span property="example:unit">character</span>s.
+    	</span>
+	</p>
+  	  <div about="" rel="dc:creator">
+         <a rel="" href="manu.html">Manu</a> created this page.
+      </div>
+  	  <div rel="next"></div>
+    <p about="http://example.org/node" property="ex:property"
+       datatype="" xml:lang="el">ελληνικό
+άσπρο   διάστημα
+</p>
+   	  <!-- This a NOT a valid XHTML document (due to @xml:base) -->
+      <div xml:base="http://example.org/invalid/">
+         <p about="">This is <span property="dc:title">Test 0109</span>.</p>
+      </div>
+    <div rel="xhv:next">
+      <div rel="xhv:next" />
+    </div>
+    <div rel="xhv:next">
+      <div rel="xhv:next">
+        <div rel="xhv:next" />
+      </div>
+    </div>
+  	  <p>
+      <span about="http://example.org/node" property="ex:property"
+            datatype="">not an XML Literal,
+whitespace     preserved
+</span>
+    </p>
+    <span about="#a" property="dc:title"></span>
+    <span about="#b" property="dc:title" />
+    <div>
+      <a rel="xhv:index" href="../../.././#">Test Suite</a>
+      <a rel="xhv:next" href="0115.xhtml">Test Case 0115</a>
+      <a rel="xhv:up" href="./">Test Case 0114</a>
+      <a rel="cc:attributionURL" href="../../../../">RDFa Website</a>
+      <a rel="rdfatest:cornerCase1" href=".">Corner Case #1</a>
+      <a rel="rdfatest:cornerCase2" href="http://example.org/foo/..">Corner Case #2</a>
+      <a rel="rdfatest:cornerCase3" href="...">Corner Case #3</a>
+      <a rel="rdfatest:cornerCase4" href="?foo=bar../baz">Corner Case #4</a>
+      <a rel="rdfatest:cornerCase5" href="../..../../../.../.htaccess">Corner Case #5</a>
+    </div>
+      <p>Description: XML entities in the RDFa content</p>
+      <p>
+        <span property="ex:entity1">&gt;</span>
+        <span property="ex:entity2">Ben &amp; Co.</span>
+        <span property="ex:entity3">&#x40;</span>
+        <span property="ex:entity4">&#64;</span>
+      </p>
+      <p>
+		<span property="dc:contributor">Mark Birbeck</span>
+         added this triple test.
+      </p>
+      <p>
+         Check to see if parsers get confused when "" is
+         interpreted as NULL in some chaining cases.
+         <a href="http://example.org/ben.html"><span
+            about="" property="dc:creator">Ben</span></a>
+      </p>
+      <div>
+         <p about="[example:]">
+            The
+            <span property="dc:title">Example Website</span>
+            is used in many W3C tutorials.
+         </p>
+      </div>
+      <p about="[:]">
+	         The
+	         <span property="dc:title">The XHTML Vocabulary Document</span>
+	         is the default prefix for XHTML+RDFa 1.0.
+	      </p>
+    <div>
+	<p about="http://example.org/">
+		<span about="[]" property="dc:title">Test Case 0121</span>
+		checks to make sure RDFa processors resolve the empty CURIE correctly.
+		<p resource="[]">
+			<span property="dc:contributor">Shane McCarron</span>
+			contributed to this test.
+		</p>
+	</p>
+	</div>
+    <p about="http://example.org/section1.html">
+         This section is contained below <span rel="up" resource="[]">the main site</span>.
+      </p>
+      <div about="http://www.example.org/#article" typeof="foaf:Document sioc:Post">
+        <h1 property="dct:title">My article</h1>
+      </div>
+<p>Blank Nodes are not allowed to be predicate identifiers in RDF:</p>
+<p property="_:invalid">Test</p>
+<p xmlns:xmlzzz="http://example.org/" property="xmlzzz:test">Test</p>
+   <p>
+      This test ensures that single-character prefixes are allowed. 
+      My name is:
+      <span about="http://example.org/jd" property="v:fn">John Doe</span> 
+   </p>
+    <p about="_:gregg">My name is
+      <em property="http://xmlns.com/foaf/0.1/name">Gregg Kellogg</em>.
+    </p>
+    <div about="_:manu">
+      Manu can be reached via
+      <a rel="http://xmlns.com/foaf/0.1/mbox" href="mailto:manu.sporny@digitalbazaar.com">email</a>.
+      <span rel="http://xmlns.com/foaf/0.1/knows" resource="_:gregg">He knows Gregg.</span>
+      <span rev="http://xmlns.com/foaf/0.1/knows" resource="_:gregg">Who knows Manu.</span>
+    </div>
+
+    <div about="_:gregg">
+      Gregg can be reached via
+      <a rel="http://xmlns.com/foaf/0.1/mbox" href="mailto:gregg@kellogg-assoc.com">email</a>.
+    </div>
+    <div about ="#me" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+        <p property="foaf:name">Ivan Herman</p>
+    </div>
+    <div about ="#this" prefix="foaf: http://xmlns.com/foaf/0.1/ dc: http://purl.org/dc/terms/" typeof="dc:Agent">
+        <p property="foaf:name">A particular agent</p>
+    </div>
+    <!-- prefix has a higher priority than xmlns -->
+  <div about ="#me" xmlns:foaf="http://www.example.com/wrong/foaf/uri" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">Ivan Herman</p>
+  </div>
+  <div about ="#me" prefix=": http://xmlns.com/foaf/0.1/" >
+      <p property=":name">Ivan Herman</p>
+  </div>
+  <div about ="http://www.example.org/software">
+      <p rel=":license" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+  </div>
+    <div prefix="foaf: http://example.org/wrong/foaf/uri/ dc: http://purl.org/dc/terms/" >
+      <div about ="#this" typeof="dc:Agent" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+        <p property="foaf:name">A particular agent</p>
+      </div>
+    </div>
+  <div prefix="foaf: http://example.org/wrong/foaf/uri/ dc: http://purl.org/dc/terms/" >
+    <div about ="#this" typeof="dc:Agent" xmlns:foaf="http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">A particular agent</p>
+    </div>
+  </div>
+  <div about ="#me" vocab="http://xmlns.com/foaf/0.1/" >
+    <p property="name">Ivan Herman</p>
+  </div>
+    <div vocab="http://example.org/wrong/foaf/uri/">
+      <div about ="#me" vocab="http://xmlns.com/foaf/0.1/" >
+        <p property="name">Ivan Herman</p>
+      </div>
+    </div>
+    <div vocab="http://xmlns.com/foaf/0.1/">
+      <div about ="#me">
+        <p property="name">Ivan Herman</p>
+      </div>
+    </div>
+    <div about ="http://www.example.org/software" vocab="http://www.example.org/vocab#">
+      <p rel="license" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+    </div>
+    <div about ="http://www.example.org/software">
+      <p rel="liCeNse" resource="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">Ivan Herman</p>
+    </div>
+	<div about="http://www.example.org">
+    <p property="ex:xmllit" datatype="rdf:XMLLiteral">This is an XMLLiteral</p>
+    <p property="ex:plainlit">This is a <em>plain</em> literal</p>
+</div>
+  <p about="" typeof="class/Person" property="pred/name">Gregg Kellogg</p>
+  <p property="dc:language" datatype="pred/lang">Ruby</p>
+  <p rel="pred/rel" resource="http://kellogg-assoc.com/">Kellogg Associates</p>
+  <p rev="pred/rev" resource="http://github.org/gkellogg/rdf_context">Ruby Gem</p>
+      <div id="mark" about="#mark" typeof="foaf:Person">
+        <h2 property="foaf:name" datatype="rdf:XMLLiteral"><span 
+property="foaf:firstName">Mark</span> <span 
+property="foaf:surname">Birbeck</span></h2>
+      </div>
+	<p about ="xsd:maxExclusive" rel="rdf:type" resource="owl:DatatypeProperty">
+	    An OWL Axiom: "xsd:maxExclusive" is a Datatype Property in OWL.
+	</p>
+   <p about="#event1" typeof="cal:Vevent">
+       <b property="cal:summary">Weekend off in Iona</b>: 
+       <span property="cal:dtstart" content="2006-10-21" datatype="xsd:date">Oct 21st</span>
+       to <span property="cal:dtend" content="2006-10-23"  datatype="xsd:date">Oct 23rd</span>.
+       See <a rel="cal:url" href="http://freetime.example.org/">FreeTime.Example.org</a> for
+       info on <span property="cal:location">Iona, UK</span>.
+   </p>
+    <!-- @prefix should be ignored in the RDFa 1.0 case -->
+    <div about ="#me" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+        <p property="foaf:name">Ivan Herman</p>
+    </div>
+    <!-- prefix has a higher priority than xmlns, but should be ignored because version is explicitly set to 1.0 -->
+  <div about ="#me" xmlns:foaf="http://www.example.com/wrong/foaf/uri/" prefix="foaf: http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">Ivan Herman</p>
+  </div>
+    <!-- The version statement should be ignored with version set to 1.0 -->
+  <div about ="#me" vocab="http://xmlns.com/foaf/0.1/" >
+      <p property="foaf:name">Ivan Herman</p>
+  </div>
+	  <!-- In RDFa 1.0, if a literal contains XML elements, and no explicit datatype is set, the result is XMLLiteral -->
+  	<div about="http://www.example.org/">
+      <h2 property="dc:title">E = mc<sup>2</sup>: The Most Urgent Problem of Our Time</h2>
+	</div>
+    <!-- In RDFa 1.1, by default a plain literal is generated even if it contains XML elements -->
+  	<div about="http://www.example.org/">
+      <h2 property="dc:title">E = mc<sup>2</sup>: The Most Urgent Problem of Our Time</h2>
+	</div>
+   <p>This document has a title.</p>
+      <!-- Tests whether the Unicode (UTF-8 encoded) characters are properly handled even with a large set of properties
+	  in the html element, ie, when the content sniffing to find out the character encoding may not work -->
+	  <p about="http://www.ivan-herman.net/foaf#me" property="foaf:name">Iván</p>
+      <!-- Tests whether the Unicode (UTF-8 encoded) characters are properly handled even with a large set of properties
+	  in the html element, ie, when the content sniffing to find out the character encoding may not work -->
+	  <p about="http://www.ivan-herman.net/foaf#me" property="foaf:name">Iván</p>
+  <div about="#me" vocab="http://xmlns.com/foaf/0.1/" >
+    <p property="name">Gregg Kellogg</p>
+  </div>
+  <div about ="">
+    <p rel="rdf:value" inlist=""/>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+  </div>
+  <div about="">
+    <a rel="rdf:value" inlist="" href="foo">Foo</a>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <a rel="rdf:value" inlist="" href="foo">Foo</a>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <strong><p property="rdf:value" inlist="">Bar</p></strong>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <strong><p property="rdf:value" inlist="">Bar</p></strong>
+    <p property="rdf:value">Baz</p>
+  </div>
+  <div about="">
+    <ol rel="rdf:value" inlist="">
+      <li><a href="foo">Foo</a></li>
+      <li><a href="bar">Bar</a></li>
+    </ol>
+  </div>
+  <div about="foo">
+    <p property="rdf:value" inlist="">Foo</p>
+  </div>
+  <div about="foo">
+    <p property="rdf:value" inlist="">Bar</p>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <span rel="rdf:inlist" resource="res">
+      <p property="rdf:value" inlist="">Bar</p>
+    </span>
+  </div>
+  <div about="">
+    <p property="rdf:value" inlist="">Foo</p>
+    <span rel="rdf:inlist">
+      <p about="res" property="rdf:value" inlist="">Bar</p>
+    </span>
+  </div>
+  	<div>
+     <img src="http://sw-app.org/img/mic_2007_01.jpg"
+           rev="xhv:alternate"
+           resource="http://sw-app.org/img/mic_2006_03.jpg"
+           alt="A photo depicting Michael" />	
+  	</div>
+  	<div>
+  	  <img 	rel="foaf:img"
+  	   		src="http://sw-app.org/img/mic_2007_01.jpg" 
+  	   		alt="A photo depicting Michael" />
+  	</div>
+  <div>
+    <img
+      src="http://example.org/example.png"  
+      rel="license"
+      href="http://creativecommons.org/licenses/by-nc-sa/2.0/"
+      alt="example image" />
+  </div>
+  <div about="http://creativecommons.org/licenses/by-nc-sa/2.0/" rev="license">
+    <img src="http://example.org/example.png" alt="example image" />
+  </div>
+  	<div rel="foaf:maker" typeof="foaf:Person">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+  	<div rel="foaf:maker" typeof="foaf:Person" resource="http://www.example.org/#me">
+	    <p property="foaf:name">John Doe</p>
+   	</div>
+      <p>
+         <a rel="describedby" href="http://example.org/describedby">describedby</a>
+         <a rel="license" href="http://example.org/license">license</a>
+         <a rel="role" href="http://example.org/role">role</a>
+      </p>
+    <p>
+      The <span property="dc:title">rdfagraph</span> should not generate triples when
+      looking only at the processor graph.
+    </p>
+  	<p></p>
+  	<p></p>
+    <p about="http://example.org/node" property="ex:property"
+       datatype="" lang="el">ελληνικό
+άσπρο   διάστημα
+</p>
+  	<p></p>
+    <span about="#a" property="dc:title"></span>
+<p>Ensure that the "_" prefix is ignored.</p>
+<p xmlns:_="http://example.org/"
+   prefix="_: http://example.org/" 
+   xmlns:earl="http://www.w3.org/ns/earl#" 
+   rel="earl:testcase" resource="_:test">Test</p>
+  <div>
+    Vocabulary Prefixes
+    <span property="grddl:">GRDDL</span>
+    <span property="ma:">MA</span>
+    <span property="owl:">OWL</span>
+    <span property="rdf:">RDF</span>
+    <span property="rdfa:">RDFa</span>
+    <span property="rdfs:">RDFS</span>
+    <span property="rif:">RIF</span>
+    <span property="skos:">SKOS</span>
+    <span property="skosxl:">SKOS-XL</span>
+    <span property="wdr:">WDR</span>
+    <span property="void:">VOID</span>
+    <span property="wdrs:">WDRS</span>
+    <span property="xhv:">XHV</span>
+    <span property="xml:">XML</span>
+    <span property="xsd:">XSD</span>
+  </div>
+  <div>
+    Widely Used prefixes
+    <span property="cc:">CC</span>
+    <span property="ctag:">CTAG</span>
+    <span property="dc:">DC</span>
+    <span property="dcterms:">DCTERMS</span>
+    <span property="foaf:">FOAF</span>
+    <span property="gr:">GR</span>
+    <span property="ical:">ICAL</span>
+    <span property="og:">OG</span>
+    <span property="rev:">REV</span>
+    <span property="sioc:">SIOC</span>
+    <span property="v:">V</span>
+    <span property="vcard:">VCARD</span>
+    <span property="schema:">Schema</span>
+  </div>
+  <div>
+    Vocabulary Terms
+    <span property="describedby">DescribedBy</span>
+    <span property="license">License</span>
+    <span property="role">Role</span>
+  </div>
+  <div>
+    Vocabulary Terms
+    <span property="alternate">alternate</span>
+    <span property="appendix">appendix</span>
+    <span property="cite">cite</span>
+    <span property="bookmark">bookmark</span>
+    <span property="contents">contents</span>
+    <span property="chapter">chapter</span>
+    <span property="copyright">copyright</span>
+    <span property="first">first</span>
+    <span property="glossary">glossary</span>
+    <span property="help">help</span>
+    <span property="icon">icon</span>
+    <span property="index">index</span>
+    <span property="last">last</span>
+    <span property="license">license</span>
+    <span property="meta">meta</span>
+    <span property="next">next</span>
+    <span property="prev">prev</span>
+    <span property="previous">previous</span>
+    <span property="section">section</span>
+    <span property="start">start</span>
+    <span property="stylesheet">stylesheet</span>
+    <span property="subsection">subsection</span>
+    <span property="top">top</span>
+    <span property="up">up</span>
+    <span property="p3pv1">p3pv1</span>
+  </div>
+	<div about="http://www.example.org">
+    <p property="ex:xmllit" datatype="rdf:XMLLiteral">This is
+an XMLLiteral</p>
+</div>
+   <p>This photo was taken by <span class="author" about="photo1.jpg" property="    dc:creator
+">Mark Birbeck</span>.</p>
+  <p> </p>
+  <p> </p>
+  <p> </p>
+  <div about="http://www.w3.org/Person/Ivan#me">
+     <a href="http://www.ivan-herman.net/foaf#me" typeof="foaf:Person" property="owl:sameAs">Ivan Herman</a>
+  </div>
+  <div about="http://www.w3.org/Person/Ivan#me">
+     <p resource="http://www.ivan-herman.net/foaf#me" typeof="foaf:Person" property="owl:sameAs">Ivan Herman</p>
+  </div>
+  <div about="http://www.ivan-herman.net/foaf#me">
+     <img src="http://www.ivan-herman.net/Images/me2003-small.png" typeof="foaf:Image" property="foaf:depiction" />
+  </div>
+  <p> </p>
+  <p> </p>
+  <p> </p>
+  <time property="rdf:value" datetime="2012-03-18Z">18 March 2012</time>
+  <time property="rdf:value" datetime="00:00:00Z">midnight</time>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00Z">18 March 2012 at midnight</time>
+  <time property="rdf:value">2012-03-18Z</time>
+  <time property="rdf:value">00:00:00Z</time>
+  <time property="rdf:value">2012-03-18T00:00:00Z</time>
+  <time property="rdf:value" datetime="2012-03-18" content="not this">18 March 2012</time>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00Z" datatype="xsd:date">18 March 2012 at midnight</time>
+  <time property="rdf:value" datetime="P2011Y06M28DT00H00M00S">2011 years 6 months 28 days</time>
+  <time property="rdf:value" datetime="2012">Two Thousand Twelve</time>
+  <time property="rdf:value" datetime="2012-03">March, Two Thousand Twelve</time>
+  <time property="rdf:value"> 2012-03-18Z</time>
+  <time property="rdf:value" datatype="xsd:dateTime"> 2012-03-18Z</time>
+  <time property="rdf:value" lang="en" datetime="D-Day">
+    Non matching lexical value with language.
+  </time>
+  <data property="rdf:value" lang="lat" value="veni, vidi, vici" content="I came, I saw, I conquered">
+    @value overrides @content in the 'data' element.
+  </data>
+  <time property="rdf:value" datetime="2012-03-18T00:00:00-08:00">18 March 2012 at midnight in San Francisco</time>
+  <object property="rdf:value" data="http://example.com/"></object>
+  <h1>@href becomes subject when @property and @content are present</h1>
+  <a href="http://example.org/" property="rdf:value" content="value">ignored</a>
+  <h1>@href becomes subject when @property and @datatype are present</h1>
+  <a href="http://example.org/" property="rdf:value" datatype="">value</a>
+  <h1>@href as subject overridden by @about</h1>
+  <a about="http://example.net/" href="http://example.org/" property="rdf:value" content="value">ignored</a>
+  <h1>@about overriding @href as subject is used as parent resource</h1>
+  <a about="http://example.net/" href="http://example.org/" property="rdf:value" content="value one">
+    <span property="rdf:value">value two</span>
+  </a>
+  <h1>Testing the ':' character usage in a CURIE</h1>
+  <div prefix="ex: http://www.example.org/">
+     <p about="http://www.example.org" property="ex:column:test">Test</p>
+  </div>
+  <p>None of these triples should be generated in RDFa 1.0.</p>
+  <div>
+    Vocabulary Prefixes
+    <span property="grddl:">GRDDL</span>
+    <span property="ma:">MA</span>
+    <span property="owl:">OWL</span>
+    <span property="rdf:">RDF</span>
+    <span property="rdfa:">RDFa</span>
+    <span property="rdfs:">RDFS</span>
+    <span property="rif:">RIF</span>
+    <span property="skos:">SKOS</span>
+    <span property="skosxl:">SKOS-XL</span>
+    <span property="wdr:">WDR</span>
+    <span property="void:">VOID</span>
+    <span property="wdrs:">WDRS</span>
+    <span property="xhv:">XHV</span>
+    <span property="xml:">XML</span>
+    <span property="xsd:">XSD</span>
+  </div>
+  <div>
+    Widely Used prefixes
+    <span property="cc:">CC</span>
+    <span property="ctag:">CTAG</span>
+    <span property="dc:">DC</span>
+    <span property="dcterms:">DCTERMS</span>
+    <span property="foaf:">FOAF</span>
+    <span property="gr:">GR</span>
+    <span property="ical:">ICAL</span>
+    <span property="og:">OG</span>
+    <span property="rev:">REV</span>
+    <span property="sioc:">SIOC</span>
+    <span property="v:">V</span>
+    <span property="vcard:">VCARD</span>
+    <span property="schema:">Schema</span>
+  </div>
+  <div>
+    Vocabulary Terms
+    <span property="describedby">DescribedBy</span>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0296.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,20 @@
+<http://example.com/manu/#me> <http://xmlns.com/foaf/0.1/name> "Manu" .
+<http://example.com/manu/#me> <http://xmlns.com/foaf/0.1/homepage> <http://example.com/manu/> .
+<http://example.com/manu/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://example.com/ivan/#me> <http://xmlns.com/foaf/0.1/name> "Ivan" .
+<http://example.com/ivan/#me> <http://xmlns.com/foaf/0.1/homepage> <http://example.com/ivan/> .
+<http://example.com/ivan/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://example.com/niklas/#me> <http://xmlns.com/foaf/0.1/name> "Niklas" .
+<http://example.com/niklas/#me> <http://xmlns.com/foaf/0.1/homepage> <http://example.com/niklas/> .
+<http://example.com/niklas/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0296.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://xmlns.com/foaf/0.1/> .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/name> "Gregg" .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/knows> <http://example.com/niklas/#me> .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/knows> <http://example.com/st\u00E9phane/#me> .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/knows> <http://example.com/ivan/#me> .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/knows> <http://example.com/manu/#me> .
+<http://example.com/gregg/#me> <http://xmlns.com/foaf/0.1/homepage> <http://example.com/gregg/> .
+<http://example.com/gregg/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://example.com/st\u00E9phane/#me> <http://xmlns.com/foaf/0.1/name> "St\u00E9phane" .
+<http://example.com/st\u00E9phane/#me> <http://xmlns.com/foaf/0.1/homepage> <http://example.com/st\u00E9phane/> .
+<http://example.com/st\u00E9phane/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0296.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0296</title>
+</head>
+<body>
+  <div vocab="http://xmlns.com/foaf/0.1/" resource="http://example.com/gregg/#me" typeof="Person">
+    <a property="homepage" href="http://example.com/gregg/"><span property="name">Gregg</span></a>
+    Knows
+    <ul>
+      <li property="knows" resource="http://example.com/niklas/#me" typeof="Person">
+        <a property="homepage" href="http://example.com/niklas/"><span property="name">Niklas</span></a>
+      </li>
+      <li property="knows" resource="http://example.com/stéphane/#me" typeof="Person">
+        <a property="homepage" href="http://example.com/stéphane/"><span property="name">Stéphane</span></a>
+      </li>
+      <li property="knows" resource="http://example.com/ivan/#me" typeof="Person">
+        <a property="homepage" href="http://example.com/ivan/"><span property="name">Ivan</span></a>
+      </li>
+      <li property="knows" resource="http://example.com/manu/#me" typeof="Person">
+        <a property="homepage" href="http://example.com/manu/"><span property="name">Manu</span></a>
+      </li>
+    </ul>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0297.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:g91413060 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0297.xhtml> <http://xmlns.com/foaf/0.1/name> "Alex Milowski" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0297.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0297: Testing @typeof and @about=[]</title>
+</head>
+<body>
+  <div about="[]" typeof="foaf:Person" property="foaf:name">Alex Milowski</div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0298.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:g91354540 <http://xmlns.com/foaf/0.1/name> "Alex Milowski" .
+_:g91354540 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0298.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0298: Testing @typeof and @about=[]</title>
+</head>
+<body>
+  <div about="[]" typeof="foaf:Person">
+    <span property="foaf:name">Alex Milowski</span>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0299.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://www.w3.org/1999/xhtml/vocab#license> <http://www.example.org/license.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0299.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0299: Testing @resource=[]</title>
+</head>
+<body about="http://www.example.org/">
+  <a href="http://www.example.org/license.xhtml" rel="xhv:license" resource="[]">The Foo Document</a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0300.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.example.org/> <http://www.w3.org/1999/xhtml/vocab#license> <http://www.example.org/license.xhtml> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0300.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0300: Testing @resource=[]</title>
+</head>
+<body about="http://www.example.org/">
+  <a href="http://www.example.org/license.xhtml" property="xhv:license" resource="[]">The Foo Document</a>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0301.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+_:g91168940 <http://www.milowski.com/V/name> "Fizzbit" .
+_:g91168940 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.milowski.com/V/thing> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0301.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://www.milowski.com/V/> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0301.xhtml> <http://www.milowski.com/V/bit> _:g91168940 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0301.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0301: Typed Property</title>
+</head>
+<body>
+  <p vocab="http://www.milowski.com/V/" property="bit" typeof="thing">
+    <span property="name">Fizzbit</span>
+  </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0302.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0302.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://schema.org/> .
+<http://openspring.net/scor#me> <http://schema.org/homepage> <http://openspring.net/> .
+<http://openspring.net/scor#me> <http://schema.org/name> "St\u00E9phane Corlosquet" .
+<http://openspring.net/scor#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
+<http://openspring.net/scor#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
+<http://openspring.net/scor#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/dc/terms/Agent> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0302.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0302: various types of tokens in @typeof</title>
+</head>
+<body>
+  <div vocab="http://schema.org/" resource="http://openspring.net/scor#me" typeof="Person foaf:Person http://purl.org/dc/terms/Agent">
+    <a property="homepage" href="http://openspring.net/"><span property="name">Stéphane Corlosquet</span></a>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0303.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0303.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://schema.org/> .
+<http://example.org/base> <http://schema.org/name> "Gregg Kellogg" .
+<http://example.org/base> <http://xmlns.com/foaf/0.1/homepage> <http://greggkellogg.net/> .
+<http://example.org/base> <http://schema.org/uri> <http://example.orb/val1> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0303.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0303: @rel/@rev terms removed if @property exists</title>
+</head>
+<body>
+  <div vocab="http://schema.org/" resource="http://example.org/base">
+    <a property="uri" rel="license" href="http://example.orb/val1">Not This</a>
+    <a property="name" rel="homepage foaf:homepage" href="http://greggkellogg.net/">Gregg Kellogg</a>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0311.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Test 0311</title>
+</head>
+<body>
+    <div>
+      <span class="attribution-line">this photo was taken by
+        <span property="">Stéphane Corlosquet</span>
+      </span>
+    </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0312.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:g93543710 <http://schema.org/homepage> <http://example.org/> .
+_:g93543710 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0312.xhtml> <http://www.w3.org/ns/rdfa#usesVocabulary> <http://schema.org/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0312.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0312</title>
+</head>
+<body>
+  <p vocab="http://schema.org/" typeof="Person">
+    The homepage of <a href="http://example.org/" property="homepage" rel="nofollow">Some Body</a>.
+  </p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0315.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+_:g102669810 <http://www.w3.org/2000/01/rdf-schema#label> _:g102665920 .
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0315.xhtml> <http://example.org/role> _:g102669810 .
+_:g102665920 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Role> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0315.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0315</title>
+</head>
+<body prefix="po: http://example.org/">
+  <dl>
+    <dt rel="po:role" class="role">
+      <span typeof="po:Role" property="rdfs:label">Director</span>
+    </dt>
+  </dl>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0316.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0316.xhtml> <http://example.org/role> _:g102582410 .
+<http://example.org/profiles/director.html> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Role> .
+_:g102582410 <http://www.w3.org/2000/01/rdf-schema#label> <http://example.org/profiles/director.html> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0316.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0316</title>
+</head>
+<body prefix="po: http://example.org/">
+  <dl>
+    <dt rel="po:role" class="role">
+      <a typeof="po:Role" property="rdfs:label" href="http://example.org/profiles/director.html">Director</a>
+    </dt>
+  </dl>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0317.nt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://rdfa.info/test-suite/test-cases/rdfa1.1/xhtml5/0317.xhtml> <http://purl.org/ontology/po/role> <http://example.org/profiles/director.html> .
+<http://example.org/profiles/director.html> <http://www.w3.org/2000/01/rdf-schema#label> "Director" .
+<http://example.org/profiles/director.html> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Role> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/0317.xhtml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test 0316</title>
+</head>
+<body prefix="po: http://purl.org/ontology/po/">
+  <dl>
+    <dt rel="po:role" class="role">
+      <a typeof="po:Role" property="rdfs:label" datatype="" href="http://example.org/profiles/director.html">Director</a>
+    </dt>
+  </dl>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/rdfa/update.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * Script to update test cases from rdfa.info
+ *
+ * @package    EasyRdf
+ * @copyright  Copyright (c) 2012-2013 Nicholas J Humfrey
+ * @license    http://www.opensource.org/licenses/bsd-license.php
+ */
+
+set_include_path(get_include_path() . PATH_SEPARATOR . './lib/');
+require_once "EasyRdf.php";
+
+$RDFA_VERSION = 'rdfa1.1';
+$HOST_LANGUAGE = 'xhtml5';
+$REFERENCE_DISTILLER = 'http://rdf.greggkellogg.net/distiller?raw=true&fmt=ntriples&in_fmt=rdfa&uri=';
+$FIXTURE_DIR = dirname(__FILE__);
+
+EasyRdf_Namespace::set('test', 'http://www.w3.org/2006/03/test-description#');
+EasyRdf_Namespace::set('rdfatest', 'http://rdfa.info/vocabs/rdfa-test#');
+
+$client = new EasyRdf_Http_Client();
+
+$manifest = EasyRdf_Graph::newAndLoad('http://rdfa.info/test-suite/manifest.ttl');
+foreach ($manifest->allOfType('test:TestCase') as $test) {
+    if (!in_array($RDFA_VERSION, $test->all('rdfatest:rdfaVersion'))) {
+        continue;
+    }
+    if (!in_array($HOST_LANGUAGE, $test->all('rdfatest:hostLanguage'))) {
+        continue;
+    }
+    if ($test->get('test:classification')->shorten() != 'test:required') {
+        continue;
+    }
+
+    $id = $test->localName();
+    $title = $test->get('dc:title');
+    $escapedTitle = addcslashes($title, '\'');
+
+    # Download the test input
+    $inputUri = "http://rdfa.info/test-suite/test-cases/$RDFA_VERSION/$HOST_LANGUAGE/$id.xhtml";
+    $client->setUri("$inputUri");
+    $response = $client->request();
+    file_put_contents("$FIXTURE_DIR/$id.xhtml", $response->getBody());
+
+    # Download the expected output
+    $client->setUri($REFERENCE_DISTILLER . urlencode($inputUri));
+    $response = $client->request();
+    file_put_contents("$FIXTURE_DIR/$id.nt", $response->getBody());
+
+    # Output code for PHPUnit
+    print "    public function testCase$id()\n";
+    print "    {\n";
+    if (strlen($title) < 80) {
+        print "        \$this->rdfaTestCase('$id', '$escapedTitle');\n";
+    } else {
+        print "        \$this->rdfaTestCase(\n";
+        print "            '$id', '$escapedTitle'\n";
+        print "        );\n";
+    }
+    print "    }\n\n";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_ask_false.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+{
+  "head": {
+  },
+  "boolean" : false
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_ask_false.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+  </head>
+  <boolean>false</boolean>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_ask_true.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+{
+  "head": {
+  },
+  "boolean" : true
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_ask_true.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+  </head>
+  <boolean>true</boolean>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_invalid.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+{
+  "head": {
+  },
+  "unknown" : [
+    "stuff"
+  ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_invalid.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+  </head>
+  <unknown><stuff></stuff></unknown>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_invalid_term.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+{
+  "head": {
+    "vars": [ "foo" ]
+  },
+  "results": {
+    "ordered" : false,
+    "distinct" : false,
+    "bindings" : [
+      {
+        "foo" : { "type": "newtype", "value": "foobar" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_all.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,82 @@
+{
+  "head": {
+    "vars": [ "s", "p", "o" ]
+  },
+  "results": {
+    "ordered" : false,
+    "distinct" : false,
+    "bindings" : [
+      {
+        "s" : { "type": "bnode", "value": "genid1" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/name" },
+        "o" : { "type": "literal", "value": "Joe's Current Project" }
+      },
+      {
+        "s" : { "type": "bnode", "value": "genid1" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/homepage" },
+        "o" : { "type": "uri", "value": "http://www.example.com/project" }
+      },
+      {
+        "s" : { "type": "bnode", "value": "genid1" },
+        "p" : { "type": "uri", "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" },
+        "o" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/Project" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe/foaf.rdf" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/primaryTopic" },
+        "o" : { "type": "uri", "value": "http://www.example.com/joe#me" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe/foaf.rdf" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/maker" },
+        "o" : { "type": "uri", "value": "http://www.example.com/joe#me" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe/foaf.rdf" },
+        "p" : { "type": "uri", "value": "http://www.w3.org/2000/01/rdf-schema#label" },
+        "o" : { "type": "literal", "value": "Joe Bloggs' FOAF File" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe/foaf.rdf" },
+        "p" : { "type": "uri", "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" },
+        "o" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/PersonalProfileDocument" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/title" },
+        "o" : { "type": "literal", "value": "Mr" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/name" },
+        "o" : { "type": "literal", "value": "Joe Bloggs",
+      "xml:lang" : "en" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/homepage" },
+        "o" : { "type": "uri", "value": "http://www.example.com/joe/" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/firstName" },
+        "o" : { "type": "literal", "value": "Joe" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/family_name" },
+        "o" : { "type": "literal", "value": "Bloggs" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/currentProject" },
+        "o" : { "type": "bnode", "value": "genid1" }
+      },
+      {
+        "s" : { "type": "uri", "value": "http://www.example.com/joe#me" },
+        "p" : { "type": "uri", "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" },
+        "o" : { "type": "uri", "value": "http://xmlns.com/foaf/0.1/Person" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_all.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s"><bnode>genid1</bnode></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/name</uri></binding>
+      <binding name="o"><literal>Joe's Current Project</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><bnode>genid1</bnode></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/homepage</uri></binding>
+      <binding name="o"><uri>http://www.example.com/project</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><bnode>genid1</bnode></binding>
+      <binding name="p"><uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri></binding>
+      <binding name="o"><uri>http://xmlns.com/foaf/0.1/Project</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe/foaf.rdf</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/primaryTopic</uri></binding>
+      <binding name="o"><uri>http://www.example.com/joe#me</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe/foaf.rdf</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/maker</uri></binding>
+      <binding name="o"><uri>http://www.example.com/joe#me</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe/foaf.rdf</uri></binding>
+      <binding name="p"><uri>http://www.w3.org/2000/01/rdf-schema#label</uri></binding>
+      <binding name="o"><literal>Joe Bloggs' FOAF File</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe/foaf.rdf</uri></binding>
+      <binding name="p"><uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri></binding>
+      <binding name="o"><uri>http://xmlns.com/foaf/0.1/PersonalProfileDocument</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/title</uri></binding>
+      <binding name="o"><literal>Mr</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/name</uri></binding>
+      <binding name="o"><literal xml:lang="en">Joe Bloggs</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/homepage</uri></binding>
+      <binding name="o"><uri>http://www.example.com/joe/</uri></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/firstName</uri></binding>
+      <binding name="o"><literal>Joe</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/family_name</uri></binding>
+      <binding name="o"><literal>Bloggs</literal></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://xmlns.com/foaf/0.1/currentProject</uri></binding>
+      <binding name="o"><bnode>genid1</bnode></binding>
+    </result>
+    <result>
+      <binding name="s"><uri>http://www.example.com/joe#me</uri></binding>
+      <binding name="p"><uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri></binding>
+      <binding name="o"><uri>http://xmlns.com/foaf/0.1/Person</uri></binding>
+    </result>
+  </results>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_all_types.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="t"/>
+  </head>
+  <results>
+    <result>
+      <binding name="t"><uri>http://xmlns.com/foaf/0.1/Project</uri></binding>
+    </result>
+    <result>
+      <binding name="t"><uri>http://xmlns.com/foaf/0.1/PersonalProfileDocument</uri></binding>
+    </result>
+    <result>
+      <binding name="t"><uri>http://xmlns.com/foaf/0.1/Person</uri></binding>
+    </result>
+  </results>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_all_ws.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <bnode>genid1</bnode>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/name</uri>
+      </binding>
+      <binding name="o">
+        <literal>Joe's Current Project</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <bnode>genid1</bnode>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/homepage</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://www.example.com/project</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <bnode>genid1</bnode>
+      </binding>
+      <binding name="p">
+        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://xmlns.com/foaf/0.1/Project</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe/foaf.rdf</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/primaryTopic</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe/foaf.rdf</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/maker</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe/foaf.rdf</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://www.w3.org/2000/01/rdf-schema#label</uri>
+      </binding>
+      <binding name="o">
+        <literal>Joe Bloggs' FOAF File</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe/foaf.rdf</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://xmlns.com/foaf/0.1/PersonalProfileDocument</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/title</uri>
+      </binding>
+      <binding name="o">
+        <literal>Mr</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/name</uri>
+      </binding>
+      <binding name="o">
+        <literal xml:lang="en">Joe Bloggs</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/homepage</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://www.example.com/joe/</uri>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/firstName</uri>
+      </binding>
+      <binding name="o">
+        <literal>Joe</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/family_name</uri>
+      </binding>
+      <binding name="o">
+        <literal>Bloggs</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://xmlns.com/foaf/0.1/currentProject</uri>
+      </binding>
+      <binding name="o">
+        <bnode>genid1</bnode>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.com/joe#me</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri>
+      </binding>
+      <binding name="o">
+        <uri>http://xmlns.com/foaf/0.1/Person</uri>
+      </binding>
+    </result>
+  </results>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_count.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+{
+  "head": {
+    "vars": [ "count" ]
+  } ,
+  "results": {
+    "bindings": [
+      {
+        "count": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "143" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_count_zero.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,12 @@
+{
+  "head": {
+    "vars": [ "count" ]
+  } ,
+  "results": {
+    "bindings": [
+      {
+        "count": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "0" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_empty.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+{
+  "head": {
+    "vars": [ "s" , "p" , "o" ]
+  } ,
+  "results": {
+    "bindings": [
+
+    ]
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_empty.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+  </head>
+  <results>
+  </results>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_lang.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+
+{ "head": { "link": [], "vars": ["label"] },
+  "results": { "distinct": false, "ordered": true, "bindings": [
+    { "label": { "type": "literal", "xml:lang": "en", "value": "London" }},
+    { "label": { "type": "literal", "xml:lang": "es", "value": "Londres" }},
+    { "label": { "type": "literal", "value": "London" }} ] } }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_lang.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,16 @@
+<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
+ <head>
+  <variable name="label"/>
+ </head>
+ <results distinct="false" ordered="true">
+  <result>
+   <binding name="label"><literal xml:lang="en">London</literal></binding>
+  </result>
+  <result>
+   <binding name="label"><literal xml:lang="es">Londres</literal></binding>
+  </result>
+  <result>
+   <binding name="label"><literal>London</literal></binding>
+  </result>
+ </results>
+</sparql>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_named_graphs.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,18 @@
+{
+  "head": {
+    "vars": [ "g" ]
+  } ,
+  "results": {
+    "bindings": [
+      {
+        "g": { "type": "uri" , "value": "http://example.org/0" }
+      } ,
+      {
+        "g": { "type": "uri" , "value": "http://example.org/1" }
+      } ,
+      {
+        "g": { "type": "uri" , "value": "http://example.org/2" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_select_unbound.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+ <head>
+  <variable name="person"/>
+  <variable name="name"/>
+  <variable name="foo"/>
+ </head>
+ <results distinct="false" ordered="true">
+  <result>
+   <binding name="person"><uri>http://dbpedia.org/resource/Tim_Berners-Lee</uri></binding>
+   <binding name="name"><literal xml:lang="en">Tim Berners-Lee</literal></binding>
+  </result>
+  <result>
+   <binding name="person"><uri>http://dbpedia.org/resource/Sergey_Brin</uri></binding>
+   <binding name="name"><literal xml:lang="en">Sergey Brin</literal></binding>
+  </result>
+  <result>
+   <binding name="person"><uri>http://dbpedia.org/resource/Larry_Page</uri></binding>
+   <binding name="name"><literal xml:lang="en">Larry Page</literal></binding>
+  </result>
+ </results>
+</sparql>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_typed_literal.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,74 @@
+{
+  "head": {
+    "vars": [ "episode" , "pos" , "label" ]
+  } ,
+  "results": {
+    "bindings": [
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dlv#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "1" } ,
+        "label": { "type": "literal" , "value": "Rose" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dmp#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "2" } ,
+        "label": { "type": "literal" , "value": "The End of the World" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dng#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "3" } ,
+        "label": { "type": "literal" , "value": "The Unquiet Dead" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dp9#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "4" } ,
+        "label": { "type": "literal" , "value": "Aliens of London" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dpv#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "5" } ,
+        "label": { "type": "literal" , "value": "World War Three" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dq8#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "6" } ,
+        "label": { "type": "literal" , "value": "Dalek" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dr5#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "7" } ,
+        "label": { "type": "literal" , "value": "The Long Game" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074drw#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "8" } ,
+        "label": { "type": "literal" , "value": "Father's Day" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074ds9#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "9" } ,
+        "label": { "type": "literal" , "value": "The Empty Child" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dsp#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "10" } ,
+        "label": { "type": "literal" , "value": "The Doctor Dances" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dt5#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "11" } ,
+        "label": { "type": "literal" , "value": "Boom Town" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dth#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "12" } ,
+        "label": { "type": "literal" , "value": "Bad Wolf" }
+      } ,
+      {
+        "episode": { "type": "uri" , "value": "http://www.bbc.co.uk/programmes/b0074dv1#programme" } ,
+        "pos": { "datatype": "http://www.w3.org/2001/XMLSchema#integer" , "type": "typed-literal" , "value": "13" } ,
+        "label": { "type": "literal" , "value": "The Parting of the Ways" }
+      }
+    ]
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/sparql_typed_literal.xml	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,153 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="episode"/>
+    <variable name="pos"/>
+    <variable name="label"/>
+  </head>
+  <results>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dlv#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+      <binding name="label">
+        <literal>Rose</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dmp#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+      <binding name="label">
+        <literal>The End of the World</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dng#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+      <binding name="label">
+        <literal>The Unquiet Dead</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dp9#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">4</literal>
+      </binding>
+      <binding name="label">
+        <literal>Aliens of London</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dpv#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">5</literal>
+      </binding>
+      <binding name="label">
+        <literal>World War Three</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dq8#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">6</literal>
+      </binding>
+      <binding name="label">
+        <literal>Dalek</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dr5#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">7</literal>
+      </binding>
+      <binding name="label">
+        <literal>The Long Game</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074drw#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">8</literal>
+      </binding>
+      <binding name="label">
+        <literal>Father's Day</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074ds9#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">9</literal>
+      </binding>
+      <binding name="label">
+        <literal>The Empty Child</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dsp#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">10</literal>
+      </binding>
+      <binding name="label">
+        <literal>The Doctor Dances</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dt5#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">11</literal>
+      </binding>
+      <binding name="label">
+        <literal>Boom Town</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dth#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">12</literal>
+      </binding>
+      <binding name="label">
+        <literal>Bad Wolf</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="episode">
+        <uri>http://www.bbc.co.uk/programmes/b0074dv1#programme</uri>
+      </binding>
+      <binding name="pos">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">13</literal>
+      </binding>
+      <binding name="label">
+        <literal>The Parting of the Ways</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/README.txt	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,20 @@
+These are the tests for the Turtle Terse RDF Triple Language
+that must be passed by conformant systems.  See
+  http://www.w3.org/TeamSubmission/turtle/
+for the full conformance information.
+
+The format is a set of good tests and bad tests.
+
+Good tests are a pair of files:
+  abc.ttl abc.out
+which are the input Turtle file and the expected output RDF triples,
+written in N-Triples.
+
+bad tests are of the form
+  bad-XX.ttl
+which must fail.
+
+The tests should be performed with an assumed base URI
+of http://www.w3.org/2001/sw/DataAccess/df1/tests/
+
+Dave
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-00.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+# prefix name must end in a :
+@prefix a <#> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-01.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# Forbidden by RDF - predicate cannot be blank
+@prefix : <http://example.org/base#> .
+:a [ :b :c ] :d .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-02.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# Forbidden by RDF - predicate cannot be blank
+@prefix : <http://example.org/base#> .
+:a [] :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-03.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# 'a' only allowed as a predicate
+@prefix : <http://example.org/base#> .
+a :a :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-04.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# No comma is allowed in collections
+@prefix : <http://example.org/stuff/1.0/> .
+:a :b ( "apple", "banana" ) .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-05.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+# N3 {}s are not in Turtle
+@prefix : <http://example.org/stuff/1.0/> .
+{ :a :b :c . } :d :e .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-06.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# is and of are not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+:a is :b of :c .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-07.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+# paths are not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+:a.:b.:c .
+:a^:b^:c .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-08.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+@keywords something.
+# @keywords is not in turtle
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-09.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# implies is not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+:a => :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-10.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# equivalence is not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+:a = :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-11.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# @forAll is not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+@forAll :x .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-12.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# @forSome is not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+@forSome :x .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-13.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# <= is not in turtle
+@prefix : <http://example.org/stuff/1.0/> .
+:a <= :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/bad-14.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+# Test long literals with missing end
+@prefix :  <http://example.org/ex#> .
+:a :b """a long
+	literal
+with
+newlines
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/base1.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/2010/01/Turtle/tests/base1/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#PositiveSyntaxTest> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/base1.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# base1 - Resolution of a relative URI against an absolute base.
+@base <http://www.w3.org/2010/01/Turtle/tests/base1/> .
+<a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#PositiveSyntaxTest> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/quotes1.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+<http://example.com/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "'single'" .
+<http://example.com/b> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "\"double\"" .
+<http://example.com/c> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "'single'" .
+<http://example.com/d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "\"double\"" .
+<http://example.com/e> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "'single'" .
+<http://example.com/f> <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "\"double\"" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/quotes1.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,9 @@
+# quotes1 - Test different types of quotes
+@prefix ex: <http://example.com/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+ex:a rdf:value "'single'" .
+ex:b rdf:value '"double"' .
+ex:c rdf:value """'single'""" .
+ex:d rdf:value '''"double"''' .
+ex:e rdf:value '\'single\'' .
+ex:f rdf:value "\"double\"" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/rdf-schema.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,126 @@
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#comment> "Indicates membership of a class" .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#label> "type"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#label> "type"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Class> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Class> <http://www.w3.org/2000/01/rdf-schema#comment> "The concept of Class" .
+<http://www.w3.org/2000/01/rdf-schema#Class> <http://www.w3.org/2000/01/rdf-schema#label> "Class"@en .
+<http://www.w3.org/2000/01/rdf-schema#Class> <http://www.w3.org/2000/01/rdf-schema#label> "Classe"@fr .
+<http://www.w3.org/2000/01/rdf-schema#Class> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/2000/01/rdf-schema#comment> "Properties used to express RDF Schema constraints." .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/2000/01/rdf-schema#label> "ConstraintProperty"@en .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/2000/01/rdf-schema#label> "Propri\u00E9t\u00E9Contrainte"@fr .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#ConstraintResource> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/2000/01/rdf-schema#comment> "Resources used to express RDF Schema constraints." .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/2000/01/rdf-schema#label> "ConstraintResource"@en .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/2000/01/rdf-schema#label> "RessourceContrainte"@fr .
+<http://www.w3.org/2000/01/rdf-schema#ConstraintResource> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#Container> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Container> <http://www.w3.org/2000/01/rdf-schema#comment> "This represents the set Containers." .
+<http://www.w3.org/2000/01/rdf-schema#Container> <http://www.w3.org/2000/01/rdf-schema#label> "Container"@en .
+<http://www.w3.org/2000/01/rdf-schema#Container> <http://www.w3.org/2000/01/rdf-schema#label> "Enveloppe"@fr .
+<http://www.w3.org/2000/01/rdf-schema#Container> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#ContainerMembershipProperty> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#ContainerMembershipProperty> <http://www.w3.org/2000/01/rdf-schema#label> "ContainerMembershipProperty"@en .
+<http://www.w3.org/2000/01/rdf-schema#ContainerMembershipProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#Literal> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Literal> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Literal> <http://www.w3.org/2000/01/rdf-schema#comment> "This represents the set of atomic values, eg. textual strings." .
+<http://www.w3.org/2000/01/rdf-schema#Literal> <http://www.w3.org/2000/01/rdf-schema#label> "Literal"@en .
+<http://www.w3.org/2000/01/rdf-schema#Literal> <http://www.w3.org/2000/01/rdf-schema#label> "Litt\u00E9ral"@fr .
+<http://www.w3.org/2000/01/rdf-schema#Resource> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#Resource> <http://www.w3.org/2000/01/rdf-schema#comment> "The most general class" .
+<http://www.w3.org/2000/01/rdf-schema#Resource> <http://www.w3.org/2000/01/rdf-schema#label> "Resource"@en .
+<http://www.w3.org/2000/01/rdf-schema#Resource> <http://www.w3.org/2000/01/rdf-schema#label> "Ressource"@fr .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/2000/01/rdf-schema#comment> "Use this for descriptions" .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/2000/01/rdf-schema#label> "comment"@en .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/2000/01/rdf-schema#label> "commentaire"@fr .
+<http://www.w3.org/2000/01/rdf-schema#comment> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Literal> .
+<http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> .
+<http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#comment> "This is how we associate a class with properties that its instances can have" .
+<http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#label> "domain"@en .
+<http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#label> "domaine"@fr .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#comment> "Indicates a resource containing and defining the subject resource." .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#label> "esD\u00E9finiPar"@fr .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#label> "isDefinedBy"@en .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#seeAlso> .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/2000/01/rdf-schema#comment> "Provides a human-readable version of a resource name." .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/2000/01/rdf-schema#label> "label"@en .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/2000/01/rdf-schema#label> "label"@fr .
+<http://www.w3.org/2000/01/rdf-schema#label> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Literal> .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#ConstraintProperty> .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#comment> "Properties that can be used in a schema to provide constraints" .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#label> "range"@en .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#label> "\u00E9tendue"@fr .
+<http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema#comment> "Indicates a resource that provides information about the subject resource." .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema#label> "seeAlso"@en .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema#label> "voirAussi"@fr .
+<http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#comment> "Indicates membership of a class" .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#label> "sousClasseDe"@fr .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#label> "subClassOf"@en .
+<http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#comment> "Indicates specialization of properties" .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#label> "sousPropri\u00E9t\u00E9De"@fr .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#label> "subPropertyOf"@en .
+<http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt> <http://www.w3.org/2000/01/rdf-schema#label> "Alt"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt> <http://www.w3.org/2000/01/rdf-schema#label> "Choix"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Container> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag> <http://www.w3.org/2000/01/rdf-schema#label> "Bag"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag> <http://www.w3.org/2000/01/rdf-schema#label> "Ensemble"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Container> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> <http://www.w3.org/2000/01/rdf-schema#comment> "The concept of a property." .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> <http://www.w3.org/2000/01/rdf-schema#label> "Property"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> <http://www.w3.org/2000/01/rdf-schema#label> "Propri\u00E9t\u00E9"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq> <http://www.w3.org/2000/01/rdf-schema#label> "Sequence"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq> <http://www.w3.org/2000/01/rdf-schema#label> "S\u00E9quence"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Container> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> <http://www.w3.org/2000/01/rdf-schema#comment> "This represents the set of reified statements." .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> <http://www.w3.org/2000/01/rdf-schema#label> "D\u00E9claration"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> <http://www.w3.org/2000/01/rdf-schema#label> "Statement"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#object> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#object> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#object> <http://www.w3.org/2000/01/rdf-schema#label> "object"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#object> <http://www.w3.org/2000/01/rdf-schema#label> "objet"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> <http://www.w3.org/2000/01/rdf-schema#label> "predicate"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> <http://www.w3.org/2000/01/rdf-schema#label> "pr\u00E9dicat"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> <http://www.w3.org/2000/01/rdf-schema#domain> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> <http://www.w3.org/2000/01/rdf-schema#label> "subject"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> <http://www.w3.org/2000/01/rdf-schema#label> "sujet"@fr .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2000/01/rdf-schema#Resource> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/1999/02/22-rdf-syntax-ns#Property> .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://www.w3.org/2000/01/rdf-schema#label> "object"@en .
+<http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://www.w3.org/2000/01/rdf-schema#label> "value"@fr .
+<http://www.w3.org/2000/01/rdf-schema#> <http://www.w3.org/2000/01/rdf-schema#seeAlso> <http://www.w3.org/2000/01/rdf-schema-more> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/rdf-schema.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,156 @@
+# RDF Namespace document converted into Turtle
+
+@prefix : <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+
+rdf:type     a rdf:Property;
+     :comment "Indicates membership of a class";
+     :label "type"@en,
+            "type"@fr;
+     :range :Class .
+
+:Class     a :Class;
+     :comment "The concept of Class";
+     :label "Class"@en,
+            "Classe"@fr;
+     :subClassOf :Resource .
+
+:ConstraintProperty     a :Class;
+     :comment "Properties used to express RDF Schema constraints.";
+     :label "ConstraintProperty"@en,
+            "Propri\u00E9t\u00E9Contrainte"@fr;
+     :subClassOf :ConstraintResource,
+            rdf:Property .
+
+:ConstraintResource     a :Class,
+            :Class;
+     :comment "Resources used to express RDF Schema constraints.";
+     :label "ConstraintResource"@en,
+            "RessourceContrainte"@fr;
+     :subClassOf :Resource .
+
+:Container     a :Class;
+     :comment "This represents the set Containers.";
+     :label "Container"@en,
+            "Enveloppe"@fr;
+     :subClassOf :Resource .
+
+:ContainerMembershipProperty     a :Class;
+     :label "ContainerMembershipProperty"@en;
+     :subClassOf rdf:Property .
+
+:Literal     a :Class,
+            :Class;
+     :comment "This represents the set of atomic values, eg. textual strings.";
+     :label "Literal"@en,
+            "Litt\u00E9ral"@fr .
+
+:Resource     a :Class;
+     :comment "The most general class";
+     :label "Resource"@en,
+            "Ressource"@fr .
+
+:comment     a rdf:Property;
+     :comment "Use this for descriptions";
+     :domain :Resource;
+     :label "comment"@en,
+            "commentaire"@fr;
+     :range :Literal .
+
+:domain     a :ConstraintProperty;
+     :comment "This is how we associate a class with properties that its instances can have";
+     :label "domain"@en,
+            "domaine"@fr .
+
+:isDefinedBy     a rdf:Property;
+     :comment "Indicates a resource containing and defining the subject resource.";
+     :domain :Resource;
+     :label "esD\u00E9finiPar"@fr,
+            "isDefinedBy"@en;
+     :range :Resource;
+     :subPropertyOf :seeAlso .
+
+:label     a rdf:Property;
+     :comment "Provides a human-readable version of a resource name.";
+     :domain :Resource;
+     :label "label"@en,
+            "label"@fr;
+     :range :Literal .
+
+:range     a :ConstraintProperty;
+     :comment "Properties that can be used in a schema to provide constraints";
+     :domain rdf:Property;
+     :label "range"@en,
+            "\u00E9tendue"@fr;
+     :range :Class .
+
+:seeAlso     a rdf:Property;
+     :comment "Indicates a resource that provides information about the subject resource.";
+     :domain :Resource;
+     :label "seeAlso"@en,
+            "voirAussi"@fr;
+     :range :Resource .
+
+:subClassOf     a rdf:Property;
+     :comment "Indicates membership of a class";
+     :domain :Class;
+     :label "sousClasseDe"@fr,
+            "subClassOf"@en;
+     :range :Class .
+
+:subPropertyOf     a rdf:Property;
+     :comment "Indicates specialization of properties";
+     :domain rdf:Property;
+     :label "sousPropri\u00E9t\u00E9De"@fr,
+            "subPropertyOf"@en;
+     :range rdf:Property .
+
+rdf:Alt     a :Class;
+     :label "Alt"@en,
+            "Choix"@fr;
+     :subClassOf :Container .
+
+rdf:Bag     a :Class;
+     :label "Bag"@en,
+            "Ensemble"@fr;
+     :subClassOf :Container .
+
+rdf:Property     a :Class;
+     :comment "The concept of a property.";
+     :label "Property"@en,
+            "Propri\u00E9t\u00E9"@fr;
+     :subClassOf :Resource .
+
+rdf:Seq     a :Class;
+     :label "Sequence"@en,
+            "S\u00E9quence"@fr;
+     :subClassOf :Container .
+
+rdf:Statement     a :Class;
+     :comment "This represents the set of reified statements.";
+     :label "D\u00E9claration"@fr,
+            "Statement"@en;
+     :subClassOf :Resource .
+
+rdf:object     a rdf:Property;
+     :domain rdf:Statement;
+     :label "object"@en,
+            "objet"@fr .
+
+rdf:predicate     a rdf:Property;
+     :domain rdf:Statement;
+     :label "predicate"@en,
+            "pr\u00E9dicat"@fr;
+     :range rdf:Property .
+
+rdf:subject     a rdf:Property;
+     :domain rdf:Statement;
+     :label "subject"@en,
+            "sujet"@fr;
+     :range :Resource .
+
+rdf:value     a rdf:Property;
+     :label "object"@en,
+            "value"@fr .
+
+:     :seeAlso <http://www.w3.org/2000/01/rdf-schema-more> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-00.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+_:genid1 <http://www.w3.org/2001/sw/DataAccess/df1/tests/test-00.ttl#x> <http://www.w3.org/2001/sw/DataAccess/df1/tests/test-00.ttl#y> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-00.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+@prefix : <#> .
+[] :x :y .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-01.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org/base1#a> <http://example.org/base1#b> <http://example.org/base1#c> .
+<http://example.org/base2#a> <http://example.org/base2#b> <http://example.org/base2#c> .
+<http://example.org/base1#a> <http://example.org/base2#a> <http://example.org/base3#a> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-01.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+# Test @prefix and qnames
+@prefix :  <http://example.org/base1#> .
+@prefix a: <http://example.org/base2#> .
+@prefix b: <http://example.org/base3#> .
+:a :b :c .
+a:a a:b a:c .
+:a a:a b:a .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-02.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org/base#a> <http://example.org/base#b> <http://example.org/base#c> .
+<http://example.org/base#a> <http://example.org/base#b> <http://example.org/base#d> .
+<http://example.org/base#a> <http://example.org/base#b> <http://example.org/base#e> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-02.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+# Test , operator
+@prefix : <http://example.org/base#> .
+:a :b :c,
+      :d,
+      :e .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-03.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org/base#a> <http://example.org/base#b> <http://example.org/base#c> .
+<http://example.org/base#a> <http://example.org/base#d> <http://example.org/base#e> .
+<http://example.org/base#a> <http://example.org/base#f> <http://example.org/base#g> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-03.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+# Test ; operator
+@prefix : <http://example.org/base#> .
+:a :b :c ;
+   :d :e ;
+   :f :g .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-04.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:genid1 <http://example.org/base#a> <http://example.org/base#b> .
+<http://example.org/base#c> <http://example.org/base#d> _:genid2 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-04.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+# Test empty [] operator; not allowed as predicate
+@prefix : <http://example.org/base#> .
+[] :a :b .
+:c :d [] .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-05.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+_:genid1 <http://example.org/base#a> <http://example.org/base#b> .
+_:genid1 <http://example.org/base#c> <http://example.org/base#d> .
+_:genid2 <http://example.org/base#g> <http://example.org/base#h> .
+<http://example.org/base#e> <http://example.org/base#f> _:genid2 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-05.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+# Test non empty [] operator; not allowed as predicate
+@prefix : <http://example.org/base#> .
+[ :a :b ] :c :d .
+:e :f [ :g :h ] .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-06.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/base#a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/base#b> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-06.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# 'a' only allowed as a predicate
+@prefix : <http://example.org/base#> .
+:a a :b .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-07.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+_:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "apple" .
+_:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:genid2 .
+_:genid2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "banana" .
+_:genid2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
+<http://example.org/stuff/1.0/a> <http://example.org/stuff/1.0/b> _:genid1 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-07.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+@prefix : <http://example.org/stuff/1.0/> .
+:a :b ( "apple" "banana" ) .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-08.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/stuff/1.0/a> <http://example.org/stuff/1.0/b> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-08.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+@prefix : <http://example.org/stuff/1.0/> .
+:a :b ( ) .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-09.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+_:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
+_:genid2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
+_:genid2 <http://www.w3.org/2002/07/owl#onProperty> _:genid1 .
+_:genid2 <http://www.w3.org/2002/07/owl#maxCardinality> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-09.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+# Test integer datatyped literals using an OWL cardinality constraint
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+
+# based on examples in the OWL Reference
+
+_:hasParent a owl:ObjectProperty .
+
+[] a owl:Restriction ;
+  owl:onProperty _:hasParent ;
+  owl:maxCardinality 2 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-10.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+<http://example.org/res1> <http://example.org/prop1> "000000"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org/res2> <http://example.org/prop2> "0"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org/res3> <http://example.org/prop3> "000001"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org/res4> <http://example.org/prop4> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org/res5> <http://example.org/prop5> "4"^^<http://www.w3.org/2001/XMLSchema#integer> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-10.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+<http://example.org/res1> <http://example.org/prop1> 000000 .
+<http://example.org/res2> <http://example.org/prop2> 0 .
+<http://example.org/res3> <http://example.org/prop3> 000001 .
+<http://example.org/res4> <http://example.org/prop4> 2 .
+<http://example.org/res5> <http://example.org/prop5> 4 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-11.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://example.org/ex1#foo-bar> <http://example.org/ex1#foo_bar> "a" .
+<http://example.org/ex2#foo-bar> <http://example.org/ex2#foo_bar> "b" .
+<http://example.org/ex3#foo-bar> <http://example.org/ex3#foo_bar> "c" .
+<http://example.org/ex4#foo-bar> <http://example.org/ex4#foo_bar> "d" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-11.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,10 @@
+# Tests for - and _ in names, qnames
+@prefix ex1: <http://example.org/ex1#> .
+@prefix ex-2: <http://example.org/ex2#> .
+@prefix ex3_: <http://example.org/ex3#> .
+@prefix ex4-: <http://example.org/ex4#> .
+
+ex1:foo-bar ex1:foo_bar "a" .
+ex-2:foo-bar ex-2:foo_bar "b" .
+ex3_:foo-bar ex3_:foo_bar "c" .
+ex4-:foo-bar ex4-:foo_bar "d" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-12.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+<http://example.org/ex#foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#_1> "1" .
+<http://example.org/ex#foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#_2> "2" .
+<http://example.org/ex#foo> <http://example.org/myprop#_abc> "def" .
+<http://example.org/ex#foo> <http://example.org/myprop#_345> "678" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-12.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,9 @@
+# Tests for rdf:_<numbers> and other qnames starting with _
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix ex:  <http://example.org/ex#> .
+@prefix :    <http://example.org/myprop#> .
+
+ex:foo rdf:_1 "1" .
+ex:foo rdf:_2 "2" .
+ex:foo :_abc "def" .
+ex:foo :_345 "678" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-13.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+_:genid1 <http://example.org/ron> _:genid2 .
+<http://example.org/ron> <http://example.org/ron> <http://example.org/ron> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-13.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+# Test for : allowed
+@prefix :    <http://example.org/ron> .
+
+[] : [] .
+
+: : : .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-17.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/ex#a> <http://example.org/ex#b> "a long\n\tliteral\nwith\nnewlines" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-17.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+# Test long literal
+@prefix :  <http://example.org/ex#> .
+:a :b """a long
+	literal
+with
+newlines""" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-18.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/foo#a> <http://example.org/foo#b> "\nthis \ris a \U00015678long\t\nliteral\uABCD\n" .
+<http://example.org/foo#d> <http://example.org/foo#e> "\tThis \uABCDis\r \U00015678another\n\none\n" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-18.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,9 @@
+@prefix : <http://example.org/foo#> .
+
+:a :b """\nthis \ris a \U00015678long\t
+literal\uABCD
+""" .
+
+:d :e """\tThis \uABCDis\r \U00015678another\n
+one
+""" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-19.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/#a> <http://example.org/#b> "1.0"^^<http://www.w3.org/2001/XMLSchema#decimal> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-19.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+@prefix : <http://example.org/#> .
+
+:a :b  1.0 .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-20.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org/#a> <http://example.org/#b> "" .
+<http://example.org/#c> <http://example.org/#d> "" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-20.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,6 @@
+@prefix : <http://example.org/#> .
+
+:a :b "" .
+
+:c :d """""" .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-21.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org#a> <http://example.org#b> "1.0"^^<http://www.w3.org/2001/XMLSchema#decimal> .
+<http://example.org#c> <http://example.org#d> "1"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org#e> <http://example.org#f> "1.0e0"^^<http://www.w3.org/2001/XMLSchema#double> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-21.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+@prefix : <http://example.org#> .
+:a :b 1.0 .
+:c :d 1 .
+:e :f 1.0e0 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-22.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+<http://example.org#a> <http://example.org#b> "-1.0"^^<http://www.w3.org/2001/XMLSchema#decimal> .
+<http://example.org#c> <http://example.org#d> "-1"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://example.org#e> <http://example.org#f> "-1.0e0"^^<http://www.w3.org/2001/XMLSchema#double> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-22.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+@prefix : <http://example.org#> .
+:a :b -1.0 .
+:c :d -1 .
+:e :f -1.0e0 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-23.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/ex#a> <http://example.org/ex#b> "John said: \"Hello World!\"" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-23.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+# Test long literal
+@prefix :  <http://example.org/ex#> .
+:a :b """John said: "Hello World!\"""" .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-24.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+<http://example.org#a> <http://example.org#b> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .
+<http://example.org#c> <http://example.org#d> "false"^^<http://www.w3.org/2001/XMLSchema#boolean> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-24.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,3 @@
+@prefix : <http://example.org#> .
+:a :b true .
+:c :d false .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-25.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,7 @@
+<http://example.org/#a> <http://example.org/#b> <http://example.org/#c> .
+<http://example.org/#d> <http://example.org/#e> <http://example.org/#f> .
+<http://example.org/#g> <http://example.org/#h> <http://example.org/#i> .
+<http://example.org/#g> <http://example.org/#h> <http://example.org/#j> .
+<http://example.org/#k> <http://example.org/#l> <http://example.org/#m> .
+<http://example.org/#k> <http://example.org/#n> <http://example.org/#o> .
+<http://example.org/#k> <http://example.org/#p> <http://example.org/#q> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-25.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,14 @@
+# comment test
+@prefix : <http://example.org/#> .
+:a :b :c . # end of line comment
+:d # ignore me
+  :e # and me
+      :f # and me
+        .
+:g :h #ignore me
+     :i,  # and me
+     :j . # and me
+
+:k :l :m ; #ignore me
+   :n :o ; # and me
+   :p :q . # and me
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-26.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/#a> <http://example.org/#b> <http://example.org/#c> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-26.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,4 @@
+# comment line with no final newline test
+@prefix : <http://example.org/#> .
+:a :b :c .
+#foo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-27.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://example.org/bar#blah> <http://example.org/bar#blah> <http://example.org/bar#blah> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/test-27.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,5 @@
+@prefix foo: <http://example.org/foo#>  .
+@prefix foo: <http://example.org/bar#>  .
+
+foo:blah foo:blah foo:blah .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-01.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/2013/TurtleTests/s> <http://www.w3.org/2013/TurtleTests/p> <http://www.w3.org/2013/TurtleTests/~.-!$&'()*+,;=/?#@_%AA> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-01.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+@prefix : <http://www.w3.org/2013/TurtleTests/> .
+:s :p :\~\.\-\!\$\&\'\(\)\*\+\,\;\=\/\?\#\@\_\%AA .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-02.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/2013/TurtleTests/s> <http://www.w3.org/2013/TurtleTests/p> <http://www.w3.org/2013/TurtleTests/0123~.-!$&'()*+,;=/?#@_%AA123> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-02.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+@prefix : <http://www.w3.org/2013/TurtleTests/> .
+:s :p :0123\~\.\-\!\$\&\'\(\)\*\+\,\;\=\/\?\#\@\_\%AA123 .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-03.out	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,1 @@
+<http://www.w3.org/2013/TurtleTests/xyz~> <http://www.w3.org/2013/TurtleTests/abc.:> <http://www.w3.org/2013/TurtleTests/> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/turtle/turtle-syntax-pname-esc-03.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,2 @@
+@prefix : <http://www.w3.org/2013/TurtleTests/> .
+:xyz\~ :abc\.:  : .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/webid.ttl	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,15 @@
+# WebID example from: http://www.w3.org/wiki/WebID
+
+@prefix cert:  <http://www.w3.org/ns/auth/cert#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+<http://www.example.com/myfoaf#me>
+  a foaf:Person ;
+  foaf:name "My name" ;
+  foaf:homepage <http://www.example.com/> ;
+  cert:key [
+    a cert:RSAPublicKey;
+    cert:exponent 65537;
+    cert:modulus "cb24ed85d64d794b69c701c186acc059501e856000f661c93204d8380e07191c5c8b368d2ac32a428acb970398664368dc2a867320220f755e99ca2eecdae62e8d15fb58e1b76ae59cb7ace8838394d59e7250b449176e51a494951a1c366c6217d8768d682dde78dd4d55e613f8839cf275d4c8403743e7862601f3c49a6366e12bb8f498262c3c77de19bce40b32f89ae62c3780f5b6275be337e2b3153ae2ba72a9975ae71ab724649497066b660fcf774b7543d980952d2e8586200eda4158b014e75465d91ecf93efc7ac170c11fc7246fc6ded79c37780000ac4e079f671fd4f207ad770809e0e2d7b0ef5493befe73544d8e1be3dddb52455c61391a1"^^xsd:hexBinary;
+  ] .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/fixtures/xml_literal.rdf	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF
+	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+	xmlns:foaf="http://xmlns.com/foaf/0.1/"
+	xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+	xmlns:dct="http://purl.org/dc/terms/"
+>
+  <foaf:Document rdf:about="http://www.example.com/">
+    <dct:description rdf:parseType="Literal">
+      <p>Here is a block of <em>HTML text</em></p>
+    </dct:description>
+  </foaf:Document>
+</rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyrdf/test/testcases/rdfxml-testcases.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,67 @@
+<?php
+
+set_include_path(get_include_path() . PATH_SEPARATOR . '../../lib/');
+require_once "EasyRdf.php";
+
+# Load the manifest
+EasyRdf_Namespace::set('test', 'http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#');
+$manifest = parse_testdata("http://www.w3.org/2000/10/rdf-tests/rdfcore/Manifest.rdf");
+
+$passCount = 0;
+$failCount = 0;
+
+foreach ($manifest->allOfType('test:PositiveParserTest') as $test) {
+    echo "\n\n";
+
+    echo "Input: ".$test->get('test:inputDocument')."\n";
+    if (!file_exists(testdataFilepath($test->get('test:inputDocument')))) {
+        echo "File does not exist.\n";
+        continue;
+    }
+
+    echo "Output: ".$test->get('test:outputDocument')."\n";
+    if (!file_exists(testdataFilepath($test->get('test:outputDocument')))) {
+        echo "File does not exist.\n";
+        continue;
+    }
+
+    echo "Status: ".$test->get('test:status')."\n";
+    if ($test->get('test:status') != 'APPROVED') {
+        continue;
+    }
+
+    $graph = parseTestdata($test->get('test:inputDocument'));
+    $out_path = testdataFilepath($test->get('test:outputDocument'));
+
+    $easyrdf_out_path = $out_path . ".easyrdf";
+    file_put_contents($easyrdf_out_path, $graph->serialise('ntriples'));
+
+    system("rdfdiff -f ntriples -t ntriples $out_path $easyrdf_out_path", $result);
+    if ($result == 0) {
+        echo "OK!\n";
+        $passCount++;
+    } else {
+        echo "Failed!\n";
+        $failCount++;
+    }
+}
+
+echo "Tests that pass: $passCount\n";
+echo "Tests that fail: $failCount\n";
+
+
+function testdataFilepath($uri)
+{
+    return str_replace(
+        "http://www.w3.org/2000/10/rdf-tests/rdfcore/",
+        dirname(__FILE__) . '/rdfxml/',
+        $uri
+    );
+}
+
+function parseTestdata($uri)
+{
+    $filepath = testdata_filepath($uri);
+    $data = file_get_contents($filepath);
+    return new EasyRdf_Graph("$uri", $data, 'rdfxml');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phpspecgen/README.md	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,25 @@
+phpspecgen
+==========
+
+phpspecgen is a library for generating HTML documentation for Semantic Web based on ontology definitions in [RDFS] and [OWL].
+
+It is written in PHP and uses the [EasyRdf] library.
+
+
+Alternatives
+------------
+
+Some alternative RDF specification generators include:
+
+- http://github.com/specgen/specgen/
+- http://vocab.org/2004/03/toolchain
+- http://moustaki.org/ontospec/
+- http://github.com/ldodds/dowl
+- http://kantenwerk.org/vocdoc/
+- http://neologism.deri.ie/
+
+
+[RDFS]:    http://www.w3.org/TR/rdf-schema/
+[OWL]:     http://www.w3.org/TR/owl-ref/
+[EasyRdf]: http://github.com/njh/easyrdf
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phpspecgen/composer.json	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,23 @@
+{
+    "name": "njh/phpspecgen",
+    "description": "phpspecgen is a library for generating HTML documentation for Semantic Web based on ontology definitions in RDFS and OWL.",
+    "repositories": [
+        {
+            "type": "vcs",
+            "url": "https://github.com/njh/phpspecgen"
+        }
+    ],
+    "version": "0.1.0",
+    "license": "BSD-3-Clause",
+    "require": {
+        "njh/easyrdf": "0.7.0"
+    },
+    "authors": [
+        {
+            "name": "Nicholas Humfrey",
+            "email": "njh@aelius.com",
+            "homepage": "http://www.aelius.com/njh/",
+            "role": "Developer"
+        }
+     ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phpspecgen/phpspecgen.php	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,272 @@
+<?php
+    set_include_path(get_include_path() . PATH_SEPARATOR . '../easyrdf/lib/');
+    require_once "EasyRdf.php";
+
+    class Phpspecgen_Term extends EasyRdf_Resource
+    {
+        public function termLink() {
+            $name = htmlspecialchars($this->localName());
+            return "<a href=\"#term-$name\">$name</a>";
+        }
+
+        public function propertyList($property) {
+            $items = array();
+            foreach ($this->all($property) as $value) {
+                if ($value instanceof Phpspecgen_Term) {
+                    array_push($items, $value->termLink());
+                } else if ($value instanceof EasyRdf_Resource) {
+                    array_push($items, $value->htmlLink($value->shorten()));
+                } else {
+                    array_push($items, strval($value));
+                }
+            }
+            return $items;
+        }
+
+        public function propertyRow($title, $property) {
+            $items = $this->propertyList($property);
+            if (count($items) > 0) {
+                return "<tr><th>$title:</th> <td>".implode(', ', $items)."</td></tr>\n";
+            } else {
+                return '';
+            }
+        }
+    }
+
+    class Phpspecgen_Class extends Phpspecgen_Term
+    {
+        public function termType() {
+            return 'Class';
+        }
+
+        public function inheritedProperties() {
+            $properties = array();
+            foreach ($this->allParents() as $parent) {
+                foreach($parent->all('^rdfs:domain') as $property) {
+                    if ($property instanceof Phpspecgen_Term) {
+                        array_push($properties, $property->termLink());
+                    }
+                }
+            }
+            return $properties;
+        }
+
+        protected function allParents($depth=0) {
+            $parents = array();
+            foreach ($this->all('rdfs:subClassOf') as $parent) {
+                if (!$parent instanceof Phpspecgen_Class)
+                    continue;
+                array_push($parents, $parent);
+                if ($depth < 10)
+                    $parents = array_merge($parents, $parent->allParents($depth));
+            }
+            return $parents;
+        }
+    }
+
+    class Phpspecgen_Property extends Phpspecgen_Term
+    {
+        public function termType() {
+            return 'Property';
+        }
+    }
+
+    class Phpspecgen_Vocab extends EasyRdf_Resource
+    {
+        protected function propertyDefinition($title, $property) {
+            $values = $this->all($property);
+            if (count($values) < 1)
+                return '';
+
+            $html = array();
+            foreach($values as $value) {
+                if ($value instanceof EasyRdf_Literal) {
+                    array_push($html, htmlspecialchars($value));
+                } else if ($value->get('foaf:homepage')) {
+                    array_push($html, $value->get('foaf:homepage')->htmlLink( $value->label() ));
+                } else {
+                    if ($value->isBnode()) {
+                        array_push($html, htmlspecialchars($value->label()) );
+                    } else {
+                        array_push($html, $value->htmlLink($value->label()) );
+                    }
+                }
+            }
+
+            return "<dt>$title</dt><dd>".implode(', ', array_unique($html))."</dd>\n";
+        }
+
+        public function htmlHeader() {
+            $html = "<h1>".htmlspecialchars($this->label())."</h1>\n";
+            $html .= "<em>".htmlspecialchars($this->get('dc:description|dc11:description|rdfs:comment'))."</em>\n";
+
+            $html .= "<dl>\n";
+            $html .= "<dt>Latest Version</dt><dd>".$this->htmlLink()."</dd>\n";
+            $html .= $this->propertyDefinition('Created', 'dc:created|dc11:created');
+            $html .= $this->propertyDefinition('Date', 'dc:date|dc11:date');
+            $html .= $this->propertyDefinition('Revision', 'owl:versionInfo');
+            $html .= $this->propertyDefinition('Authors', 'foaf:maker|dc:creator|dc11:creator');
+            $html .= $this->propertyDefinition('Contributors', 'dc:contributor|dc11:contributor');
+            $html .= "</dl>\n";
+            return $html;
+        }
+
+        public function htmlSummaryOfTerms() {
+            $html = "<h2 id=\"sec-summary\">Summary of Terms</h2>\n";
+            $classCount = 0;
+            $properyCount = 0;
+            foreach($this->all("^rdfs:isDefinedBy") as $term) {
+                if ($term instanceof Phpspecgen_Class)
+                    $classCount++;
+                if ($term instanceof Phpspecgen_Property)
+                    $properyCount++;
+            }
+            $html .= "<p>This vocabulary defines";
+            if ($classCount == 0) {
+                $html .= " no classes";
+            } else if ($classCount == 1) {
+                $html .= " one class";
+            } else {
+                $html .= " $classCount classes";
+            }
+            if ($properyCount == 0) {
+                $html .= " and no properties.";
+            } else if ($properyCount == 1) {
+                $html .= " and one property.";
+            } else {
+                $html .= " and $properyCount properties.";
+            }
+            $html .= "</p>\n";
+
+            $html .= "<table>\n";
+            $html .= "<tr><th>Term Name</th><th>Type</th><th>Definition</th></tr>\n";
+            foreach($this->all("^rdfs:isDefinedBy") as $term) {
+                if ($term instanceof Phpspecgen_Term) {
+                    $html .= "<tr>";
+                    $html .= "<td>".$term->termLink()."</td>";
+                    $html .= "<td>".$term->termType()."</td>";
+                    $html .= "<td>".$term->getLiteral('rdfs:comment|rdfs:label')."</td>";
+                    $html .= "</tr>\n";
+                }
+            }
+            $html .= "</table>\n";
+            return $html;
+        }
+
+        public function htmlTerms($type, $title) {
+            $html = '';
+            $id = strtolower(str_replace(' ','-',$title));
+            $html .= "<h2 id=\"sec-$id\">$title</h2>\n";
+            foreach($this->all("^rdfs:isDefinedBy") as $term) {
+                if (!$term instanceof $type)
+                    continue;
+
+                $name = htmlspecialchars($term->localName());
+                $html .= "<h3 id=\"term-$name\">$name</h3\n";
+                $html .= "<p>".htmlspecialchars($term->get('rdfs:comment'))."</p>\n";
+                $html .= "<table>\n";
+                $html .= "  <tr><th>URI:</th> <td>".$term->htmlLink()."</td></tr>\n";
+                $html .= $term->propertyRow("Label", "rdfs:label");
+                $html .= $term->propertyRow("Status", "vs:term_status");
+                $html .= $term->propertyRow("Subclasses", "^rdfs:subClassOf");
+                $html .= $term->propertyRow("Parent Class", "rdfs:subClassOf");
+                $html .= $term->propertyRow("Properties", "^rdfs:domain");
+                if ($term instanceof Phpspecgen_Class) {
+                    $properties = $term->inheritedProperties();
+                    if (count($properties) > 0)
+                        $html .= "  <tr><th>Inherited Properties:</th> ".
+                                 "<td>".join(', ', $properties)."</td></tr>\n";
+                }
+                $html .= $term->propertyRow("Range", "rdfs:range");
+                $html .= $term->propertyRow("Domain", "rdfs:domain");
+                $html .= $term->propertyRow("See Also", "rdfs:seeAlso");
+                $html .= "</table>\n";
+                $html .= "</div>\n";
+            }
+            return $html;
+        }
+
+    }
+
+    # Extra namespaces we use
+    EasyRdf_Namespace::set('vann', 'http://purl.org/vocab/vann/');
+    EasyRdf_Namespace::set('vs', 'http://www.w3.org/2003/06/sw-vocab-status/ns#');
+
+    ## Add mappings
+    EasyRdf_TypeMapper::set('owl:Ontology', 'Phpspecgen_Vocab');
+    EasyRdf_TypeMapper::set('owl:Class', 'Phpspecgen_Class');
+    EasyRdf_TypeMapper::set('rdfs:Class', 'Phpspecgen_Class');
+    EasyRdf_TypeMapper::set('owl:Property', 'Phpspecgen_Property');
+    EasyRdf_TypeMapper::set('owl:DatatypeProperty', 'Phpspecgen_Property');
+    EasyRdf_TypeMapper::set('owl:ObjectProperty', 'Phpspecgen_Property');
+    EasyRdf_TypeMapper::set('owl:InverseFunctionalProperty', 'Phpspecgen_Property');
+    EasyRdf_TypeMapper::set('owl:FunctionalProperty', 'Phpspecgen_Property');
+    EasyRdf_TypeMapper::set('rdf:Property', 'Phpspecgen_Property');
+?>
+<html>
+<head>
+  <title>phpspecgen</title>
+  <link rel="stylesheet" type="text/css" href="style.css" />
+</head>
+<body>
+
+<?php
+
+    $options = getopt('u:');
+    if (!empty($_REQUEST['uri'])) {
+      $uri = $_REQUEST['uri'];
+    } elseif(array_key_exists('u', $options)) {
+      $uri = $options['u'];
+    }
+
+    if (!empty($uri)) {
+
+      // Parse the document
+      $graph = new EasyRdf_Graph($uri);
+      $graph->load($uri);
+
+      // Get the first ontology in the document
+      $vocab = $graph->get('owl:Ontology', '^rdf:type');
+      if (!isset($vocab)) {
+          print "<p>Error: No OWL ontologies defined at that URL.</p>\n";
+      } else {
+          // FIXME: register the preferredNamespacePrefix
+
+          print $vocab->htmlHeader();
+          print $vocab->htmlSummaryOfTerms();
+          print $vocab->htmlTerms('Phpspecgen_Class', 'Classes');
+          print $vocab->htmlTerms('Phpspecgen_Property', 'Properties');
+
+          print $graph->dump();
+      }
+
+    } else {
+        $examples = array(
+            'FOAF' => 'http://xmlns.com/foaf/spec/',
+            'DOAP' => 'http://usefulinc.com/ns/doap#',
+            'LODE' => 'http://linkedevents.org/ontology/',
+            'Ordered List Ontology' => 'http://purl.org/ontology/olo/core#',
+            'Whisky Vocabulary' => 'http://vocab.org/whisky/terms.rdf',
+            'Sport Ontology' => 'http://www.bbc.co.uk/ontologies/sport/2011-02-17.rdf',
+            'Music Ontology' => 'http://purl.org/ontology/mo/',
+            'Programme Ontology' => 'http://www.bbc.co.uk/ontologies/programmes/2009-09-07.rdf'
+        );
+
+        print "<h1>phpspecgen</h1>\n";
+        print "<form method='get' action='?'><div>";
+        print "<div><label for='uri'>URI of a vocabulary (OWL or RDFS):</label>\n";
+        print "<input type='text' id='uri' name='uri' size='40' />\n";
+        print "<input type='submit' value='Submit' />\n";
+        print "</div></form>\n";
+        print "<p>Or pick an example:</p>\n";
+        print "<ul>\n";
+        foreach ($examples as $name => $uri) {
+            print "<li><a href='".htmlspecialchars('?uri='.urlencode($uri))."'>".
+                  htmlspecialchars($name)."</a></li>\n";
+        }
+        print "</ul>\n";
+
+    }
+?>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phpspecgen/style.css	Mon Sep 09 21:02:53 2013 +0100
@@ -0,0 +1,116 @@
+  code.xml .text {
+    color: #000000;
+    background: transparent;
+  }
+  code.xml .elem {
+    color: #000080;
+    background: transparent;
+  }
+  code.xml .attr {
+    color: #008080;
+    background: transparent;
+  }
+  code.xml .attrVal {
+    color: #666666;
+    background: transparent;
+  }
+  code.xml .highlight {
+    background: #ffff00;
+  }
+
+  h1, h2, h3, h4, h5, h6 {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-style:italic;
+  }
+
+  pre {
+    border: 1px #9999cc dotted;
+    background-color: #f3f3ff;
+    color: #000000;
+    width: 90%;
+  }
+
+  blockquote {
+    border-style: solid;
+    border-color: #d0dbe7;
+    border-width: 0 0 0 .25em;
+    padding-left: 0.5em;
+  }
+
+  blockquote, q {
+    font-style: italic;
+  }
+
+  body {
+    font-family: verdana, geneva, arial, sans-serif;
+  }
+
+  a, p,blockquote, q, dl, dd, dt {
+    font-family: verdana, geneva, arial, sans-serif;
+    font-size: 1em;
+  }
+
+
+  dt {
+    font-weight: bold;
+  }
+
+
+:link { color: #00C; background: transparent }
+:visited { color: #609; background: transparent }
+:link:active, :visited:active { color: #C00; background: transparent }
+:link:hover, :visited:hover { background: #ffa; }
+code :link, code :visited { color: inherit; }
+
+h1, h2, h3, h4, h5, h6 { text-align: left }
+h1, h2, h3 { color: #996633; background: transparent; }
+h1 { font: 900 170% sans-serif; border-bottom: 1px solid gray; }
+h2 { font: 800 140% sans-serif; border-bottom: 1px solid gray; }
+h3 { font: 700 120% sans-serif }
+h4 { font: bold 100% sans-serif }
+h5 { font: italic 100% sans-serif }
+h6 { font: small-caps 100% sans-serif }
+
+body { padding: 0 4em 2em 4em;  line-height: 1.35; }
+
+pre { margin-left: 2em; /* overflow: auto; */ }
+h1 + h2 { margin-top: 0; }
+h2 { margin: 3em 0 1em 0; }
+h2 + h3 { margin-top: 0; }
+h3 { margin: 2em 0 1em 0; }
+h4 { margin: 1.5em 0 0.75em 0; }
+h5, h6 { margin: 1.5em 0 1em; }
+p { margin: 1em 0; }
+dl, dd { margin-top: 0; margin-bottom: 0; }
+dt { margin-top: 0.75em; margin-bottom: 0.25em; clear: left; }
+dd dt { margin-top: 0.25em; margin-bottom: 0; }
+dd p { margin-top: 0; }
+p + * &gt; li, dd li { margin: 1em 0; }
+dt, dfn { font-weight: bold; font-style: normal; }
+pre, code { font-size: inherit; font-family: monospace; }
+pre strong { color: black; font: inherit; font-weight: bold; background: yellow; }
+pre em { font-weight: bolder; font-style: normal; }
+var sub { vertical-align: bottom; font-size: smaller; position: relative; top: 0.1em; }
+blockquote { margin: 0 0 0 2em; border: 0; padding: 0; font-style: italic; }
+ins { background: green; color: white; /* color: green; border: solid thin lime; padding: 0.3em; line-height: 1.6em; */ text-decoration: none; }
+del { background: maroon; color: white; /* color: maroon; border: solid thin red; padding: 0.3em; line-height: 1.6em; */ text-decoration: line-through; }
+body ins, body del { display: block; }
+body * ins, body * del { display: inline; }
+
+table.properties { width: 90%; }
+table.properties th { text-align: right; width: 9em; font-weight: normal; }
+
+table { border-collapse: collapse;  border: solid #999999 1px;}
+table thead { border-bottom: solid #999999 2px; }
+table td, table th {
+  border-left: solid #999999 1px;
+  border-right: solid #999999 1px;
+  border-bottom: solid #999999 1px;
+  vertical-align: top;
+  padding: 0.2em;
+}
+
+.historyList {
+  font-size: 0.9em;
+}
+.termuri { margin-bottom: 0.5em;}