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' comma