pax_global_header00006660000000000000000000000064123232323650014513gustar00rootroot0000000000000052 comment=223bcf05f69a9413a62ba1a55e59187097ceb98d rdflib-4.1.2/000077500000000000000000000000001232323236500127615ustar00rootroot00000000000000rdflib-4.1.2/.coveragerc000066400000000000000000000015361232323236500151070ustar00rootroot00000000000000# .coveragerc to control coverage.py [run] branch = True #source = rdflib,build/src/rdflib # specified in .travis.yml for different envs omit = */site-packages/* [report] # Regexes for lines to exclude from consideration exclude_lines = # Have to re-enable the standard pragma pragma: no cover # Don't complain about missing debug-only code: #def __repr__ #if self\.debug # Don't complain if tests don't hit defensive assertion code: #raise AssertionError #raise NotImplementedError # Don't complain if non-runnable code isn't run: if 0: if __name__ == .__main__.: if __name__==.__main__.: # path mappings for the py3 environments (doesn't seem to work on coveralls yet) [paths] source = rdflib/ build/src/rdflib/ tests = test/ build/src/test/ examples = examples/ build/src/examples/ rdflib-4.1.2/.gitignore000066400000000000000000000003211232323236500147450ustar00rootroot00000000000000RDFLib.sublime-project /docs/_build/ nosetests.xml RDFLib.sublime-workspace *.egg-info/ coverage/ dist/ __pycache__/ *.pyc /.hgtags /.hgignore build/ /.coverage /.tox/ /docs/draft/ *~ test_reports/*latest.ttl rdflib-4.1.2/.hgignore000066400000000000000000000001711232323236500145630ustar00rootroot00000000000000syntax: glob build dist *.pyc *~ *.class docs/_build .tox .coverage coverage nosetests.xml *.egg-info docs/draft .pylint rdflib-4.1.2/.pep8000066400000000000000000000001421232323236500136330ustar00rootroot00000000000000[pep8] ignore = W806 max-line-length = 85 exclude = pyRdfa,host,extras,transform,rdfs,pyMicrodata rdflib-4.1.2/.travis.yml000066400000000000000000000042661232323236500151020ustar00rootroot00000000000000# http://travis-ci.org/#!/RDFLib/rdflib language: python branches: only: - master python: # - 2.5 - 2.6 - 2.7 - 3.2 - 3.3 # - "pypy" install: # iodate0.4.8 is problematic with Pypy, use fixed version - if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors --default-timeout 60 ordereddict; pip install --use-mirrors --default-timeout 60 "simplejson"; pip install --use-mirrors --default-timeout 60 "elementtree"; pip install --use-mirrors --default-timeout 60 "html5lib==0.95"; fi - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors --default-timeout 60 ordereddict; fi - if [[ ${TRAVIS_PYTHON_VERSION%%.*} == '2' ]]; then pip install --use-mirrors --default-timeout 60 -r requirements.py2.txt; pip install --use-mirrors --default-timeout 60 "html5lib";fi - if [[ ${TRAVIS_PYTHON_VERSION%%.*} == '3' ]]; then pip install --use-mirrors --default-timeout 60 -r requirements.py3.txt; fi - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install --upgrade "https://bitbucket.org/gjhiggins/isodate/downloads/isodate-0.4.8.tar.gz"; pip install --use-mirrors --default-timeout 60 "elementtree"; fi - if [[ $TRAVIS_PYTHON_VERSION != '2.5' ]]; then pip install --use-mirrors --default-timeout 60 coverage coveralls nose-timer && export HAS_COVERALLS=1; fi - python setup.py install before_script: - if [[ ${TRAVIS_PYTHON_VERSION%%.*} == '2' ]]; then flake8 --exclude=pyRdfa,extras,host,transform,rdfs,sparql,results,pyMicrodata --exit-zero rdflib; fi script: # Must run the tests in build/src so python3 doesn't get confused and run # the python2 code from the current directory instead of the installed # 2to3 version in build/src. - if [[ ${TRAVIS_PYTHON_VERSION%%.*} == '2' ]]; then nosetests --with-timer --timer-top-n 42 --with-coverage --cover-tests --cover-package=rdflib ; fi - if [[ ${TRAVIS_PYTHON_VERSION%%.*} == '3' ]]; then nosetests --with-timer --timer-top-n 42 --with-coverage --cover-tests --cover-package=build/src/rdflib --where=./build/src; fi after_success: - if [[ $HAS_COVERALLS ]] ; then coveralls ; fi notifications: irc: channels: "chat.freenode.net#rdflib" rdflib-4.1.2/CHANGELOG.md000066400000000000000000001115011232323236500145710ustar00rootroot000000000000002014/04/15 RELEASE 4.1.2 ======================== This is a bug-fix release. * Fixed unicode/str bug in py3 for rdfpipe [#375](https://github.com/RDFLib/rdflib/issues/375) 2014/03/03 RELEASE 4.1.1 ======================== This is a bug-fix release. This will be the last RDFLib release to support python 2.5. * The RDF/XML Parser was made stricter, now raises exceptions for illegal repeated node-elements. [#363](https://github.com/RDFLib/rdflib/issues/363) * The SPARQLUpdateStore now supports non-ascii unicode in update statements [#356](https://github.com/RDFLib/rdflib/issues/356) * Fixed a bug in the NTriple/NQuad parser wrt. to unicode escape sequences [#352](https://github.com/RDFLib/rdflib/issues/352) * HTML5Lib is no longer pinned to 0.95 [#355](https://github.com/RDFLib/rdflib/issues/360) * RDF/XML Serializer now uses parseType=Literal for well-formed XML literals * A bug in the manchester OWL syntax was fixed [#355](https://github.com/RDFLib/rdflib/issues/355) 2013/12/31 RELEASE 4.1 ====================== This is a new minor version RDFLib, which includes a handful of new features: * A TriG parser was added (we already had a serializer) - it is up-to-date wrt. to the newest spec from: http://www.w3.org/TR/trig/ * The Turtle parser was made up to date wrt. to the latest Turtle spec. * Many more tests have been added - RDFLib now has over 2000 (passing!) tests. This is mainly thanks to the NT, Turtle, TriG, NQuads and SPARQL test-suites from W3C. This also included many fixes to the nt and nquad parsers. * ```ConjunctiveGraph``` and ```Dataset``` now support directly adding/removing quads with ```add/addN/remove``` methods. * ```rdfpipe``` command now supports datasets, and reading/writing context sensitive formats. * Optional graph-tracking was added to the Store interface, allowing empty graphs to be tracked for Datasets. The DataSet class also saw a general clean-up, see: [#309](https://github.com/RDFLib/rdflib/pull/309) * After long deprecation, ```BackwardCompatibleGraph``` was removed. Minor enhancements/bugs fixed: ------------------------------ * Many code samples in the documentation were fixed thanks to @PuckCh * The new ```IOMemory``` store was optimised a bit * ```SPARQL(Update)Store``` has been made more generic. * MD5 sums were never reinitialized in ```rdflib.compare``` * Correct default value for empty prefix in N3 [#312](https://github.com/RDFLib/rdflib/issues/312) * Fixed tests when running in a non UTF-8 locale [#344](https://github.com/RDFLib/rdflib/issues/344) * Prefix in the original turtle have an impact on SPARQL query resolution [#313](https://github.com/RDFLib/rdflib/issues/313) * Duplicate BNode IDs from N3 Parser [#305](https://github.com/RDFLib/rdflib/issues/305) * Use QNames for TriG graph names [#330](https://github.com/RDFLib/rdflib/issues/330) * \uXXXX escapes in Turtle/N3 were fixed [#335](https://github.com/RDFLib/rdflib/issues/335) * A way to limit the number of triples retrieved from the ```SPARQLStore``` was added [#346](https://github.com/RDFLib/rdflib/pull/346) * Dots in localnames in Turtle [#345](https://github.com/RDFLib/rdflib/issues/345) [#336](https://github.com/RDFLib/rdflib/issues/336) * ```BNode``` as Graph's public ID [#300](https://github.com/RDFLib/rdflib/issues/300) * Introduced ordering of ```QuotedGraphs``` [#291](https://github.com/RDFLib/rdflib/issues/291) 2013/05/22 RELEASE 4.0.1 ======================== Following RDFLib tradition, some bugs snuck into the 4.0 release. This is a bug-fixing release: * the new URI validation caused lots of problems, but is nescessary to avoid ''RDF injection'' vulnerabilities. In the spirit of ''be liberal in what you accept, but conservative in what you produce", we moved validation to serialisation time. * the ```rdflib.tools``` package was missing from the ```setup.py``` script, and was therefore not included in the PYPI tarballs. * RDF parser choked on empty namespace URI [#288](https://github.com/RDFLib/rdflib/issues/288) * Parsing from ```sys.stdin``` was broken [#285](https://github.com/RDFLib/rdflib/issues/285) * The new IO store had problems with concurrent modifications if several graphs used the same store [#286](https://github.com/RDFLib/rdflib/issues/286) * Moved HTML5Lib dependency to the recently released 1.0b1 which support python3 2013/05/16 RELEASE 4.0 ====================== This release includes several major changes: * The new SPARQL 1.1 engine (rdflib-sparql) has been included in the core distribution. SPARQL 1.1 queries and updates should work out of the box. * SPARQL paths are exposed as operators on ```URIRefs```, these can then be be used with graph.triples and friends: ```py # List names of friends of Bob: g.triples(( bob, FOAF.knows/FOAF.name , None )) # All super-classes: g.triples(( cls, RDFS.subClassOf * '+', None )) ``` * a new ```graph.update``` method will apply SPARQL update statements * Several RDF 1.1 features are available: * A new ```DataSet``` class * ```XMLLiteral``` and ```HTMLLiterals``` * ```BNode``` (de)skolemization is supported through ```BNode.skolemize```, ```URIRef.de_skolemize```, ```Graph.skolemize``` and ```Graph.de_skolemize``` * Handled of Literal equality was split into lexical comparison (for normal ```==``` operator) and value space (using new ```Node.eq``` methods). This introduces some slight backwards incomaptible changes, but was necessary, as the old version had inconsisten hash and equality methods that could lead the literals not working correctly in dicts/sets. The new way is more in line with how SPARQL 1.1 works. For the full details, see: https://github.com/RDFLib/rdflib/wiki/Literal-reworking * Iterating over ```QueryResults``` will generate ```ResultRow``` objects, these allow access to variable bindings as attributes or as a dict. I.e. ```py for row in graph.query('select ... ') : print row.age, row["name"] ``` * "Slicing" of Graphs and Resources as syntactic sugar: ([#271](https://github.com/RDFLib/rdflib/issues/271)) ```py graph[bob : FOAF.knows/FOAF.name] -> generator over the names of Bobs friends ``` * The ```SPARQLStore``` and ```SPARQLUpdateStore``` are now included in the RDFLib core * The documentation has been given a major overhaul, and examples for most features have been added. Minor Changes: -------------- * String operations on URIRefs return new URIRefs: ([#258](https://github.com/RDFLib/rdflib/issues/258)) ```py >>> URIRef('http://example.org/')+'test rdflib.term.URIRef('http://example.org/test') ``` * Parser/Serializer plugins are also found by mime-type, not just by plugin name: ([#277](https://github.com/RDFLib/rdflib/issues/277)) * ```Namespace``` is no longer a subclass of ```URIRef``` * URIRefs and Literal language tags are validated on construction, avoiding some "RDF-injection" issues ([#266](https://github.com/RDFLib/rdflib/issues/266)) * A new memory store needs much less memory when loading large graphs ([#268](https://github.com/RDFLib/rdflib/issues/268)) * Turtle/N3 serializer now supports the base keyword correctly ([#248](https://github.com/RDFLib/rdflib/issues/248)) * py2exe support was fixed ([#257](https://github.com/RDFLib/rdflib/issues/257)) * Several bugs in the TriG serializer were fixed * Several bugs in the NQuads parser were fixed 2013/03/01 RELEASE 3.4 ====================== This release introduced new parsers for structured data in HTML. In particular formats: hturtle, rdfa, mdata and an auto-detecting html format were added. Thanks to Ivan Herman for this! This release includes a lot of admin maintentance - correct dependencies for different python versions, etc. Several py3 bugs were also fixed. This release drops python 2.4 compatability - it was just getting too expensive for us to maintain. It should however be compatible with any cpython from 2.5 through 3.3. * ```node.md5_term``` is now deprecated, if you use it let us know. * Literal.datatype/language are now read-only properties ([#226](https://github.com/RDFLib/rdflib/issues/226)) * Serializing to file fails in py3 ([#249](https://github.com/RDFLib/rdflib/issues/249)) * TriX serializer places two xmlns attributes on same element ([#250](https://github.com/RDFLib/rdflib/issues/250)) * RDF/XML parser fails on when XML namespace is not explicitly declared ([#247](https://github.com/RDFLib/rdflib/issues/247)) * Resource class should "unbox" Resource instances on add ([#215](https://github.com/RDFLib/rdflib/issues/215)) * Turtle/N3 does not encode final quote of a string ([#239](https://github.com/RDFLib/rdflib/issues/239)) * float Literal precision lost when serializing graph to turtle or n3 ([#237](https://github.com/RDFLib/rdflib/issues/237)) * plain-literal representation of xsd:decimals fixed * allow read-only sleepycat stores * language tag parsing in N3/Turtle fixes to allow several subtags. 2012/10/10 RELEASE 3.2.3 ======================== Almost identical to 3.2.2 A stupid bug snuck into 3.2.2, and querying graphs were broken. * Fixes broken querying ([#234](https://github.com/RDFLib/rdflib/issues/234)) * graph.transitiveClosure now works with loops ([#206](https://github.com/RDFLib/rdflib/issues/206)) 2012/09/25 RELEASE 3.2.2 ======================== This is mainly a maintenance release. This release should be compatible with python 2.4 through to 3. Changes: * Improved serialization/parsing roundtrip tests led to some fixes of obscure parser/serializer bugs. In particular complex string Literals in ntriples improved a lot. * The terms of a triple are now asserted to be RDFLib Node's in graph.add This should avoid getting strings and other things in the store. ([#200](https://github.com/RDFLib/rdflib/issues/200)) * Added a specific TurtleParser that does not require the store to be non-formula aware. ([#214](https://github.com/RDFLib/rdflib/issues/214)) * A trig-serializer was added, see: http://www4.wiwiss.fu-berlin.de/bizer/trig/ * BNode generation was made thread-safe ([#209](https://github.com/RDFLib/rdflib/issues/209)) (also fixed better by dzinxed) * Illegal BNode IDs removed from NT output: ([#212](https://github.com/RDFLib/rdflib/issues/212)) * and more minor bug fixes that had no issues 2012/04/24 RELEASE 3.2.1 ======================== This is mainly a maintenance release. Changes: * New setuptools entry points for query processors and results * Literals constructed from other literals copy datatype/lang ([#188](https://github.com/RDFLib/rdflib/issues/188)) * Relative URIs are resolved incorrectly after redirects ([#130](https://github.com/RDFLib/rdflib/issues/130)) * Illegal prefixes in turtle output ([#161](https://github.com/RDFLib/rdflib/issues/161)) * Sleepcat store unstable prefixes ([#201](https://github.com/RDFLib/rdflib/issues/201)) * Consistent toPyton() for all node objects ([#174](https://github.com/RDFLib/rdflib/issues/174)) * Better random BNode ID in multi-thread environments ([#185](https://github.com/RDFLib/rdflib/issues/185)) 2012/01/19 RELEASE 3.2.0 ======================== Major changes: * Thanks to Thomas Kluyver, rdflib now works under python3, the setup.py script automatically runs 2to3. * Unit tests were updated and cleaned up. Now all tests should pass. * Documentation was updated and cleaned up. * A new resource oriented API was added: http://code.google.com/p/rdflib/issues/detail?id=166 Fixed many minor issues: * http://code.google.com/p/rdflib/issues/detail?id=177 http://code.google.com/p/rdflib/issues/detail?id=129 Restored compatability with Python 2.4 * http://code.google.com/p/rdflib/issues/detail?id=158 Reworking of Query result handling * http://code.google.com/p/rdflib/issues/detail?id=193 generating xml:base attribute in RDF/XML output * http://code.google.com/p/rdflib/issues/detail?id=180 serialize(format="pretty-xml") fails on cyclic links 2011/03/17 RELEASE 3.1.0 ======================== Fixed a range of minor issues: * http://code.google.com/p/rdflib/issues/detail?id=128 Literal.__str__ does not behave like unicode * http://code.google.com/p/rdflib/issues/detail?id=141 (RDFa Parser) Does not handle application/xhtml+xml * http://code.google.com/p/rdflib/issues/detail?id=142 RDFa TC #117: Fragment identifiers stripped from BASE * http://code.google.com/p/rdflib/issues/detail?id=146 Malformed literals produced when rdfa contains newlines * http://code.google.com/p/rdflib/issues/detail?id=152 Namespaces beginning with _ are invalid * http://code.google.com/p/rdflib/issues/detail?id=156 Turtle Files with a UTF-8 BOM fail to parse * http://code.google.com/p/rdflib/issues/detail?id=154 ClosedNamespace.__str__ returns URIRef not str * http://code.google.com/p/rdflib/issues/detail?id=150 IOMemory does not override open * http://code.google.com/p/rdflib/issues/detail?id=153 Timestamps with microseconds *and* "Z" timezone are not parsed * http://code.google.com/p/rdflib/issues/detail?id=118 DateTime literals with offsets fail to convert to Python * http://code.google.com/p/rdflib/issues/detail?id=157 Timestamps with timezone information are not parsed * http://code.google.com/p/rdflib/issues/detail?id=151 problem with unicode literals in rdflib.compare.graph_diff * http://code.google.com/p/rdflib/issues/detail?id=149 Sleepycat Store broken with create=False * http://code.google.com/p/rdflib/issues/detail?id=134 Would be useful if Graph.query could propagate kwargs to a plugin processor * http://code.google.com/p/rdflib/issues/detail?id=133 Graph.connected exception when passed empty graph * http://code.google.com/p/rdflib/issues/detail?id=129 Not compatible with Python 2.4 * http://code.google.com/p/rdflib/issues/detail?id=119 Support Python's set operations on Graph * http://code.google.com/p/rdflib/issues/detail?id=130 NT output encoding to utf-8 broken as it goes through _xmlcharrefreplace * http://code.google.com/p/rdflib/issues/detail?id=121#c1 Store SPARQL Support 2010/05/13 RELEASE 3.0.0 ======================== Working test suite with all tests passing. Removed dependency on setuptools. (Issue #43) Updated Package and Module Names to follow conventions outlined in http://www.python.org/dev/peps/pep-0008/ Removed SPARQL bits and non core plugins. They are mostly moving to http://code.google.com/p/rdfextras/ at least until they are stable. Fixed datatype for Literal(True). Fixed Literal to enforce contraint of having either a language or datatype but not both. Fixed Literal's repr. Fixed to Graph Add/Sub/Mul opterators. Upgraded RDFa parser to pyRdfa. Upgraded N3 parser to the one from CWM. Fixed unicode encoding issue involving N3Parser. N3 serializer improvments. Fixed HTTP content-negotiation Fixed Store.namespaces method (which caused a few issues depending on Store implementation being used.) Fixed interoperability issue with plugin module. Fixed use of Deprecated functionality. 2009/03/30 RELEASE 2.4.1 ======================== Fixed Literal comparison case involving Literal's with datatypes of XSD.base64Binary. Fixed case where XSD.date was matching before XSD.dateTime for datetime instances. Fixed jython interoperability issue (issue #53). Fixed Literal repr to handle apostrophes correctly (issue #28). Fixed Literal's repr to be consistent with its ```__init__``` (issue #33). 2007/04/04 RELEASE 2.4.0 ======================== Improved Literal comparison / equality Sparql cleanup. getLiteralValue now returns the Literal object instead of the result of toPython(). Now that Literals override a good coverage of comparison operators, they should be passed around as first class objects in the SPARQL evaluation engine. Added support for session bnodes re: sparql Fixed prolog reduce/reduce conflict. Added Py_None IncRefs where they were being passed into Python method invokations (per drewp's patch) Fixed sparql queries involving empty namespace prefix. Fixed the selected variables sparql issue Fixed support in SPARQL queries. Fixed involving multiple unions and queries are nested more than one level (bug in _getAllVariables causing failure when parent.top is None) Fixed test_sparql_equals.py. Fixed sparql json result comma errors issue. Fixed test_sparql_json_results.py (SELECT * variables out of order) Added a 4Suite-based SPARQL XML Writer implementation. If 4Suite is not installed, the fallback python saxutils is used instead applied patch from http://rdflib.net/issues/2007/02/23/bugs_in_rdflib.sparql.queryresult/issue The restriction on GRAPH patterns with variables has been relieved a bit to allow such usage when the variable is provided as an initial binding Fix for OPTIONAL patterns. P1 OPT P2, where P1 and P2 shared variables which were bound to BNodes were not unifying on these BNode variable efficiently / correctly. The fix was to add bindings for 'stored' BNodes so they aren't confused for wildcards Added support to n3 parser for retaining namespace bindings. Fixed several RDFaParser bugs. Added serializer specific argument support. Fixed a few PrettyXMLSerializer issues and added a max_depth option. Fixed some TurtleSerializer issues. Fixed some N3Serializer issues. Added support easy_install added link to long_descriptin for easy_install -U rdflib==dev to work; added download_url back added continuous-releases-using-subversion bit Added rdflib_tools package Added rdfpipe Added initial EARLPluging Improved test running... using nose... added tests Exposed generated test cases for nose to find. added bit to configure 'setup.py nosetests' to run doc tests added nose test bits Added md5_term_hash method to terms. Added commit_pending_transaction argument to Graph's close method. Added DeprecationWarning to rdflib.constants Added a NamespaceDict class for those who want to avoid the Namespace as subclass of URIRef issues Added bind function Fixed type of Namespace re: URIRef vs. unicode Improved ValueError message Changed value method's any argument to default to True Changed ```__repr__``` to always reflect that it's an rdf.Literal -- as this is the case even though we now have it acting like the corresponding type in some casses A DISTINCT was added to the SELECT clause to ensure duplicate triples are not returned (an RDF graph is a set of triples) - which can happen for certain join expressions. Support for ConditionalAndExpressionList and RelationalExpressionList (|| and && operators in FILTER) Fixed context column comparison. The hash integer was being compared with 'F' causing a warning:Warning: Truncated incorrect DOUBLE value: 'F' applied patch in http://rdflib.net/issues/2006/12/13/typos_in_abstractsqlstore.py/issue fix for http://rdflib.net/issues/2006/12/07/problems_with_graph.seq()_when_sequences_contain_more_than_9_items./issue General code cleanup (removing redundant imports, changing relative imports to absolute imports etc) Removed usage of deprecated bits. Added a number of test cases. Added DeprecationWarning for save method refactoring of GraphPattern ReadOnlyGraphAggregate uses Graph constructor properly to setup (optionally) a common store Fixed bug with . (fullstop) in localname parts. Changed Graph's value method to return None instead of raising an AssertionError. Fixed conversion of (exiplicit) MySQL ports to integers. Fixed MySQL store so it properly calculates ```__len__``` of individual Graphs Aligned with how Sleepycat is generating events (remove events are expressed in terms of interned strings) Added code to catch unpickling related exceptions Added BerkeleyDB store implementation. Merged TextIndex from michel-events branch. 2006/10/15 RELEASE 2.3.3 ======================== Added TriXParser, N3Serializer and TurtleSerializer. Added events to store interface: StoreCreated, TripleAdded and TripleRemoved. Added Journal Reader and Writer. Removed Sleepycat level journaling. Added support for triple quoted Literal's. Fixed some corner cases with Literal comparison. Fixed PatternResolution for patterns that return contexts only. Fixed NodePickler not to choke on unhashable objects. Fixed Namespace's ```__getattr__``` hack to ignore names starting with __ Added SPARQL != operator. Fixed query result ```__len__``` (more efficient). Fixed and improved RDFa parser. redland patches from http://rdflib.net/pipermail/dev/2006-September/000069.html various patches for the testsuite - http://rdflib.net/pipermail/dev/2006-September/000069.html 2006/08/01 RELEASE 2.3.2 ======================== Added SPARQL query support. Added XSD to/from Python datatype support to Literals. Fixed ConjunctiveGraph so that it is a proper subclass of Graph. Added Deprecation Warning when BackwardCompatGraph gets used. Added RDFa parser. Added Collection Class for working with RDF Collections. Added method to Graph for testing connectedness Fixed bug in N3 parser where identical BNodes were not being combined. Fixed literal quoting in N3 serializer. Fixed RDF/XML serializer to skip over N3 bits. Changed Literal and URIRef instanciation to catch UnicodeDecodeErrors - which were being thrown when the default decoding method (ascii) was hitting certain characters. Changed Graph's bind method to also override the binding in the case of an existing generated bindings. Added FOPLRelationalModel - a set of utility classes that implement a minimal Relational Model of FOPL implemented as a SQL database (uses identifier/value interning and integer half-md5-hashes for space and index efficiency). Changed MySQL store to use FOPLRelationalModel plus fixes and improvements. Added more test cases. Cleaned up source code to follow pep8 / pep257. 2006/02/27 RELEASE 2.3.1 ======================== Added save method to BackwardCompatibleGraph so that example.py etc work again. Applied patch from Drew Perttula to add local_time_zone argument to util's date_time method. Fixed a relativize bug in the rdf/xml serializer. Fixed NameError: global name 'URIRef' is not defined error in Sleepycat.py by adding missing import. Applied patch for Seq to sort list by integer, added by Drew Hess. Added a preserve_bnode_ids option to rdf/xml parser. Applied assorted patches for tests (see http://tracker.asemantics.com/rdflib/ticket/8 ) Applied redland.diff (see http://tracker.asemantics.com/rdflib/ticket/9 ) Applied changes specified http://tracker.asemantics.com/rdflib/ticket/7 Added a set method to Graph. Fixed RDF/XML serializer so that it does not choke on n3 bits (rather it'll just ignore them) 2005/12/23 RELEASE 2.3.0 ======================== See http://rdflib.net/2.3.0/ for most up-to-date release notes Added N3 support to Graph and Store. Added Sean's n3p parser, and ntriples parser. Sleepycat implementation has been revamped in the process of expanding it to support the new requirements n3 requirements. It also now persists a journal -- more to come. detabified source files. Literal and parsers now distinguish between datatype of None and datatype of "". Store-agnostic 'fallback' implementation of REGEX matching (inefficient but provides the capability to stores that don't support it natively). Implemented as a 'wrapper' around any Store which replaces REGEX terms with None (before dispatching to the store) and whittles out results that don't match the given REGEX term expression(s). Store-agnostic 'fallback' implementation of transactional rollbacks (also inefficient but provides the capablity to stores that don't support it natively). Implemented as a wrapper that tracks a 'thread-safe' list of reversal operations (for every add, track the remove call that reverts the store, and vice versa). Upon store.rollback(), execute the reverse operations. However, this doesn't guarantee durability, since if the system fails before the rollbacks are all executed, the store will remain in an invalid state, but it provides Atomicity in the best case scenario. 2005/10/10 RELEASE 2.2.3 ======================== Fixed Sleepycat backend to commit after an add and remove. This should help just a bit with those unclean shutdowns ;) Fixed use of logging so that it does not mess with the root logger. Thank you, Arve, for pointing this one out. Fixed Graph's value method to have default for subject in addition to predicate and object. Fixed Fourthought backend to be consistent with interface. It now supports an empty constructor and an open method that takes a configuration string. 2005/09/10 RELEASE 2.2.2 ======================== Applied patch from inkel to add encoding argument to all serialization related methods. Fixed XMLSerializer bug regarding default namespace bindings. Fixed namespace binding bug involving binding a second default namespace. Applied patch from Gunnar AAstrand Grimnes to add context support to ```__iadd__``` on Graph. (Am considering the lack of context support a bug. Any users currently using ```__iadd__```, let me know if this breaks any of your code.) Added Fourthought backend contributed by Chimezie Ogbuji. Fixed a RDF/XML parser bug relating to XMLLiteral and escaping. Fixed setup.py so that install does not try to uninstall (rename_old) before installing; there's now an uninstall command if one needs to uninstall. 2005/08/25 RELEASE 2.2.1 ======================== Fixed issue regarding Python2.3 compatibility. Fixed minor issue with URIRef's absolute method. 2005/08/12 RELEASE 2.1.4 ======================== Added optional base argument to URIRef. Fixed bug where load and parse had inconsistent behavior. Added a FileInputSource. Added skeleton sparql parser and test framework. Included pyparsing (pyparsing.sourceforge.net) for sparql parsing. Added attribute support to namespaces. 2005/06/28 RELEASE 2.1.3 ======================== Added Ivan's sparql-p implementation. Literal is now picklable. Added optional base argument to serialize methods about which to relativize. Applied patch to remove some dependencies on Python 2.4 features. Fixed BNode's n3 serialization bug (recently introduced). Fixed a collections related bug. 2005/05/13 RELEASE 2.1.2 ======================== Added patch from Sidnei da Silva that adds a sqlobject based backend. Fixed bug in PrettyXMLSerializer (rdf prefix decl was missing sometimes) Fixed bug in RDF/XML parser where empty collections where causing exceptions. 2005/05/01 RELEASE 2.1.1 ======================== Fixed a number of bugs relating to 2.0 backward compatibility. Fixed split_uri to handle URIs with _ in them properly. Fixed bug in RDF/XML handler's absolutize that would cause some URIRefs to end in ## Added check_context to Graph. Added patch the improves IOMemory implementation. 2005/04/12 RELEASE 2.1.0 ======================== Merged TripleStore and InformationStore into Graph. Added plugin support (or at least cleaned up, made consistent the plugin support that existed). Added value and seq methods to Graph. Renamed prefix_mapping to bind. Added namespaces method that is a generator over all prefix, namespace bindings. Added notion of NamespaceManager. Added couple new backends, IOMemory and ZODB. 2005/03/19 RELEASE 2.0.6 ======================== Added pretty-xml serializer (inlines BNodes where possible, typed nodes, Collections). Fixed bug in NTParser and n3 methods where not all characters where being escaped. Changed label and comment methods to return default passed in when there is no label or comment. Moved methods to Store Class. Store no longer inherits from Schema. Fixed bug involving a case with rdf:about='#' Changed InMemoryBackend to update third index in the same style it does the first two. 2005/01/08 RELEASE 2.0.5 ======================== Added publicID argument to Store's load method. Added RDF and RDFS to top level rdflib package. 2004/10/14 RELEASE 2.0.4 ======================== Removed unfinished functionality. Fixed bug where another prefix other than rdf was getting defined for the rdf namespace (causing an assertion to fail). Fixed bug in serializer where nodeIDs were not valid NCNames. 2004/04/21 RELEASE 2.0.3 ======================== Added missing "from __future__ import generators" statement to InformationStore. Simplified RDF/XML serializer fixing a few bugs involving BNodes. Added a reset method to RDF/XML parser. Changed 'if foo' to "if foo is not None" in a few places in the RDF/XML parser. Fully qualified imports in rdflib.syntax {parser, serializer}. Context now goes through InformationStore (was bypassing it going directly to backend). 2004/03/22 RELEASE 2.0.2 ======================== Improved performance of Identifier equality tests. Added missing "from __future__ import generators" statements needed to run on Python2.2. Added alternative to shlib.move() if it isn't present. Fixed bug that occured when specifying a backend to InformationStore's constructor. Fixed bug recently introduced into InformationStore's remove method. 2004/03/15 RELEASE 2.0.1 ======================== Fixed a bug in the SleepyCatBackend multi threaded concurrency support. (Tested fairly extensively under the following conditions: multi threaded, multi process, and both). > NOTE: fix involved change to database format -- so 2.0.1 will not be > able to open databases created with 2.0.0 Removed the use of the Concurrent wrapper around InMemoryBackend and modified InMemoryBackend to handle concurrent requests. (Motivated by Concurrent's poor performance on bigger TripleStores.) Improved the speed of len(store) by making backends responsible for implementing ```__len__```. Context objects now have a identifier property. 2004/03/10 RELEASE 2.0.0 ======================== Fixed a few bugs in the SleepyCatBackend multi process concurrency support. Removed rdflib.Resource Changed remove to now take a triple pattern and removed remove_triples method. Added ```__iadd__``` method to Store in support of store += another_store. 2004/01/04 RELEASE 1.3.2 ======================== Added a serialization dispatcher. Added format arg to save method. Store now remembers prefix/namespace bindings. Backends are now more pluggable ... 2003/10/14 RELEASE 1.3.1 ======================== Fixed bug in serializer where triples where only getting serialized the first time. Added type checking for contexts. Fixed bug that caused comparisons with a Literal to fail when the right hand side was not a string. Added DB_INIT_CDB flag to SCBacked for supporting multiple reader/single writer access Changed rdf:RDF to be optional to conform with latest spec. Fixed handling of XMLLiterals 2003/04/40 RELEASE 1.3.0 ======================== Removed bag_id support and added it to OLD_TERMS. Added a double hash for keys in SCBacked. Fixed _HTTPClient so that it no longer removes metadata about a context right after it adds it. Added a KDTreeStore and RedlandStore backends. Added a StoreTester. 2003/02/28 RELEASE 1.2.4 ======================== Fixed bug in SCBackend where language and datatype information where being ignored. Fixed bug in transitive_subjects. Updated some of the test cases that where not up to date. async_load now adds more http header and error information to the InformationStore. 2003/02/11 RELEASE 1.2.3 ======================== Fixed bug in load methods where relative URLs where not being absolutized correctly on Windows. Fixed serializer so that it throws an exception when trying to serialize a graph with a predicate that can not be split. 2003/02/07 RELEASE 1.2.2 ======================== Added an exists method to the BackwardCompatibility mixin. Added versions of remove, remove_triples and triples methods to the BackwardCompatility mixin for TripleStores that take an s, p, o as opposed to an (s, p, o). 2003/02/03 RELEASE 1.2.1 ======================== Added support for parsing XMLLiterals. Added support for proper charmod checking (only works in Python2.3). Fixed remaining rdfcore test cases that where not passing. Fixed windows bug in AbstractInformationStore's run method. 2003/01/02 RELEASE 1.2.0 ======================== Added systemID, line #, and column # to error messages. BNode prefix is now composed of ascii_letters instead of letters. Added a bsddb backed InformationStore. Added an asyncronous load method, methods for scheduling context updates, and a run method. 2002/12/16 RELEASE 1.1.5 ======================== Introduction of InformationStore, a TripleStore with the addition of context support. Resource ```__getitem__``` now returns object (no longer returns a Resource for the object). Fixed bug in parser that was introduced in last release regaurding unqualified names. 2002/12/10 RELEASE 1.1.4 ======================== Interface realigned with last stable release. Serializer now uses more of the abbreviated forms where possible. Parser optimized and cleaned up. Added third index to InMemoryStore. The load and parse methods now take a single argument. Added a StringInputSource for to support parsing from strings. Renamed rdflib.BTreeTripleStore.TripleStore to rdflib.BTreeTripleStore.BTreeTripleStore. Minor reorganization of mix-in classes. 2002/12/03 RELEASE 1.1.3 ======================== BNodes now created with a more unique identifier so BNodes from different sessions do not collide. Added initial support for XML Literals (for now they are parsed into Literals). Resource is no longer a special kind of URIRef. Resource no longer looks at range to determine default return type for ```__getitem__```. Instead there is now a get(predicate, default) method. 2002/11/21 RELEASE 1.1.2 ======================== Fixed Literal's ```__eq__``` method so that Literal('foo')=='foo' etc. Fixed Resource's ```__setitem__``` method so that it does not raise a dictionary changed size while iterating exception. 2002/11/09 RELEASE 1.1.1 ======================== Resource is now a special kind of URIRef Resource's ```__getitem__``` now looks at rdfs:range to determine return type in default case. 2002/11/05 RELEASE 1.1.0 ======================== # A new development branch Cleaned up interface and promoted it to SIR: Simple Interface for RDF. Updated parser to use SAX2 interfaces instead of using expat directly. Added BTreeTripleStore, a ZODB BTree TripleStore backend. And a default pre-mixed TripleStore that uses it. Synced with latest (Editor's draft) RDF/XML spec. Added datatype support. Cleaned up interfaces for load/parse: removed generate_path from loadsave andrenamed parse_URI to parse. 2002/10/08 RELEASE 0.9.6 ======================== # The end of a development branch BNode can now be created with specified value. Literal now has a language attribute. Parser now creates Literals with language attribute set appropriately as determined by xml:lang attributes. TODO: Serializer-Literals-language attribute TODO: Change ```__eq__``` so that Literal("foo")=="foo" etc TripleStores now support "in" operator. For example: if (s, p, o) in store: print "Found ", s, p, o Added APIs/object for working at level of a Resource. NOTE: This functionality is still experimental Consecutive Collections now parse correctly. 2002/08/06 RELEASE 0.9.5 ======================== Added support for rdf:parseType="Collection" Added items generator for getting items in a Collection Renamed rdflib.triple_store to rdflib.TripleStore to better follow python style conventions. Added an Identifier Class Moved each node into its own Python module. Added rdflib.util with a first and uniq function. Added a little more to example.py Removed generate_uri since we have BNodes now. 2002/07/29 RELEASE 0.9.4 ======================== Added support for proposed rdf:nodeID to both the parser and serializer. Reimplemented serializer which now nests things where possible. Added partial support for XML Literal parseTypes. 2002/07/16 RELEASE 0.9.3 ======================== Fixed bug where bNodes where being created for nested property elements when they where not supposed to be. Added lax mode that will convert rdf/xml files that contain bare IDs etc. Also, lax mode will only report parse errors instead of raising exceptions. Added missing check for valid attribute names in the case of production 5.18 of latest WD spec. 2002/07/05 RELEASE 0.9.2 ======================== Added missing constants for SUBPROPERTYOF, ISDEFINEDBY. Added test case for running all of the rdf/xml test cases. Reimplemented rdf/xml parser to conform to latest WD. 2002/06/10 RELEASE 0.9.1 ======================== There is now a remove and a remove_triples (no more overloaded remove). Layer 2 has been merged with layer 1 since there is no longer a need for them to be separate layers. The generate_uri method has moved to LoadSave since triple stores do not have a notion of a uri. [Also, with proper bNode support on its way the need for a generate_uri might not be as high.] Fixed bug in node's n3 function: URI -> URIRef. Replaced string based exceptions with class based exceptions. Added PyUnit TestCase for parser.py Added N-Triples parser. Added ```__len__``` and ```__eq__``` methods to store interface. 2002/06/04 RELEASE 0.9.0 ======================== Initial release after being split from redfootlib. rdflib-4.1.2/CONTRIBUTORS000066400000000000000000000006661232323236500146510ustar00rootroot00000000000000Aaron Swartz Andrew Eland Andrew Kuchling Arve Knudsen Chimezie Ogbuji Daniel Krech David H Jones Drew Perttula Elias Torres Gerhard Weis Graham Higgins Graham Klyne Gunnar AAstrand Grimnes Ivan Herman Jeroen van der Ham Kendall Clark Leandro López Lucio Torre Michel Pelletier Nacho Barrientos Arias Niklas Lindström Phil Dawes Phillip Pearson Ron Alford Sidnei da Silva Simon McVittie Stefan Niederhauser Thomas Kluyver William Waitesrdflib-4.1.2/LICENSE000066400000000000000000000031151232323236500137660ustar00rootroot00000000000000LICENSE AGREEMENT FOR RDFLIB ------------------------------------------------ Copyright (c) 2002-2012, RDFLib Team See CONTRIBUTORS and http://github.com/RDFLib/rdflib 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. * Neither the name of Daniel Krech nor the names of its contributors 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. rdflib-4.1.2/MANIFEST.in000066400000000000000000000004221232323236500145150ustar00rootroot00000000000000include CHANGELOG.md include LICENSE include README.md include CONTRIBUTORS include ez_setup.py include skiptests.list recursive-include rdflib *.py recursive-include examples *.py include run_tests.py graft test graft docs prune docs/_build global-exclude *.pyc *$py.class rdflib-4.1.2/README.md000066400000000000000000000054351232323236500142470ustar00rootroot00000000000000RDFLib ====== RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information as graphs. RDFLib may be installed with setuptools (easy_install) or pip:: $ easy_install rdflib or $ pip install rdflib Getting Started --------------- RDFLib aims to be a pythonic RDF API, a Graph is a python collection of RDF Subject,Predicate,Object Triples: ```python import rdflib g=rdflib.Graph() g.load('http://dbpedia.org/resource/Semantic_Web') for s,p,o in g: print s,p,o ``` The components of the triples are URIs (resources) or Literals (values), URIs are grouped together by *namespace*, common namespaces are included in RDFLib: ```python semweb=rdflib.URIRef('http://dbpedia.org/resource/Semantic_Web') type=g.value(semweb, rdflib.RDFS.label) ``` Where `rdflib.RDFS` is the RDFS Namespace, `graph.value` returns an object of the triple-pattern given (or an arbitrary one if more exist). New Namespaces can also be defined: ```python dbpedia=Namespace('http://dbpedia.org/ontology/') abstracts=list(x for x in g.objects(semweb, dbpedia['abstract']) if x.language=='en') ``` See also *./examples* Features -------- The library contains parsers and serializers for RDF/XML, N3, NTriples, N-Quads, Turtle, TriX, RDFa and Microdata. The library presents a Graph interface which can be backed by any one of a number of Store implementations. This core RDFLib package includes store implementations for in memory storage and persistent storage on top of the Berkeley DB. A SPARQL 1.1 implementation is included - supporting SPARQL 1.1 Queries and Update statements. RDFLib is open source and is maintained on [GitHub](http://github.com/RDFLib/rdflib/). RDFLib releases, current and previous are listed on [PyPI](http://pypi.python.org/pypi/rdflib/) RDFLib has a plugin-architecture for store-implementation, as well as parsers/serializers, several other projects exist which extend RDFLib features: * [rdflib-json](https://github.com/RDFLib/rdflib-jsonld) - Serializer and parser for [json-ld](http://json-ld.org) Support ------- More information is available on the project webpage: https://github.com/RDFLib/rdflib/ Continuous integration status details available from travis.ci, test coverage from coveralls: [![Build Status](https://travis-ci.org/RDFLib/rdflib.png?branch=master)](https://travis-ci.org/RDFLib/rdflib) [![Coverage Status](https://coveralls.io/repos/RDFLib/rdflib/badge.png?branch=master)](https://coveralls.io/r/RDFLib/rdflib?branch=master) The documentation can be built by doing:: $ python setup.py build_sphinx And is also available from ReadTheDocs: http://readthedocs.org/docs/rdflib/ Support is available through the rdflib-dev group: http://groups.google.com/group/rdflib-dev and on the IRC channel #rdflib on the freenode.net server rdflib-4.1.2/docs/000077500000000000000000000000001232323236500137115ustar00rootroot00000000000000rdflib-4.1.2/docs/Makefile000066400000000000000000000056611232323236500153610ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml @echo @echo "Build finished. The HTML pages are in _build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in _build/qthelp, like this:" @echo "# qcollectiongenerator _build/qthelp/rdflib.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile _build/qthelp/rdflib.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in _build/doctest/output.txt." rdflib-4.1.2/docs/_static/000077500000000000000000000000001232323236500153375ustar00rootroot00000000000000rdflib-4.1.2/docs/_static/ContextHierarchy.png000066400000000000000000000563161232323236500213430ustar00rootroot00000000000000PNG  IHDR agAMAOX2tEXtSoftwareAdobe ImageReadyqe<PLTE񑑑߷̕ǵ℄ І yyyMMMß梢 $$$͘~~~{{{œ݂DDD@@@000www***}}}Īnnn ӻ)))... !!!444֧QQQ|||(((---,,,PPPOOOZZZ;;; """WWWiii222ooosssUUU[[[999'''eee:::///xxx&&&kkk___???qqq666GGGKKKjjjaaalll<<<^^^111FFFNNN]]]fffVVV%%%EEEdddTTTHHH\\\RRRCCCppp888AAA333rrr>>>LLLhhhIII===tttggg bbbzzz+++777SSSuuu###YYY555JJJcccBBB```mmmXXXvvvZO tRNSfYXLIDATx]XU  E"(bwbwwwwwvwc]k]Wuݎ@{[͝93sΜ.Y_{nU]=haf:?;W5ίcEjXzN_s|!j6A=${5?d.P6s^a Jյ[7{VOl Qw/VO>~}%ܽmRyÚ4&)/eޮ?l{v:-s'T%&"Gmٳ&%*.62:x֞ǣ>}'iпm:xTѿ o?Mg~Qf:3}kZ<8ƈBZUrO]uiZк;sآce|c "ٜY|c-Uj:q{^}\vt0DoV.'=|in_ OYOl1A֔R KV8*woQw.o*߬z.jۑ awc%hrǺrynPoҥO妞,c?73Ӻ=j dB~ +@:;*U[oZb'IW +"9sCq}46vMeݔb&\h]èOrŬ4'Eyް*a!S!gdjá۱7o=ξ>Ҩ0$~Lx-X=Mۅo2o&x9(g|7-($)aAB?Α6sF+5#%tiA?/1[؛;읎Oo\ҶaaB "QuMwK}HNUGSgԕQ|hnX7/Mošg] ͫr]kK1 oNs$k} k\ :X +=^8gPH7Z圯9uYO. ZFݫvuWH̥Tt,- ;x2\ Ov)M9QMnXȚ_IgFkK)Lì5z kZh&nsw M{ulwYcՈճ $K?Y,\u}Tu'=ZR]{p\ W_X~/-ӧԅejTgHnKT8tr0WJCeOWRي;n38ۚog=~ 5 @p(ž,\:$@Va 濴[bIAfK]DK33s%Db1@o1,7A1ROH2sx;k2_*5Ћj=gD%%ѻ~!^5D*(Pps9Un+t msѮHF)ot>_n;]Z M0gO'xG]t~ftsH:6<[YeZ(:i4V}{k" `Y`sY.H$$Q\.2ruˎK$ .:2J~, ܙ.aSIFӽOHkXhiX-{ (( RGӀ9 㗟jcΖ([$x66!R;͊ɷ,`UYD>'bīM_d[锕ڱC`V4 wV]8l(9 %bīcySnT=n1z.Qzw+ZӇc0EB8t9GMfRvP>j#3Ir>1[h;=Lc/d8#^ WѷBGվ[h}irwVBt{ NQfkI .mr;lO6䮷GaG7@4"94@:^Hj{[߫#b j `mYʈWr9T1{?̫-,,WF:aw*rX[T ͥh/9&4f,/~".CFj۵B,!6&0~eX9Y Pדe`e;Bo7,pL$X6 *kpᛸ7>|sq'1p;<)RFJSSz|l H/,eKiN\!5 \$ǖQ6 hfo>Fa=1Ejܝla&Q[#.kHr^'?c#9s#+ Q6!vK KlMuCr>PaN pT"Sz g:fY \6i@}[2$)ؒG&/ n̛ՙB) 5z Jwɽp,Y̜\/=6)78@ʗtQG]](! P@itw>#y3PtH*C1ԉX)^U`lE5Y̭ʡ:];-tTd(t=s 3 @+[ը_fMt 5LymRq \)M2T)J؛( ]bLK#tSRgqp̉yLo5v.!d0X; c}k<Ê4Ycj$ٺon3.!&|Ȳ|Bt}co41`]""m\mfo|Ѕ3= tQ,s/l9@,~KM:@2lbeYa\W EkK|_Tպ:nX9@J㨖: nCr͓\RKk0S~OөdH*xv +˜f,0P |-`_͒B̴IQ][̲ a+qZIMť~FH{&s )zK]BHufY)Ot &=U7Ŷ*(] LNp:w=u *LvBzAF>: ws; )O~L*trF,%0z |fw,6Z!US6_,Hǒ]t9֬{|4`낪%K^j䙲st ͗j̶m?(1IvoMn"=d'/җ@ nv Z̚y~} 6Iٕ^`*nĽ32;PFoj'p/c `47)4u %;PzCݥ`DSV"UUgYxKrBRAQͪS|NH[V TV6S\a0@H& YhT5 S  hXB7bWO]@5Jtrk6y#cm+d=6}(w)UqU{X- ]#nV*9Upv.i|Ԩ%O W< tZqL[īe.7_ _,c*0TcO ڄ qP,bu.eU&Ys^y=⩝"|t;JkE Ht 3T{Uܧ-OK{KahW.iMw2PpN{Jj|PV*2"֝&-`TJo`&ۢ3DY41TƏ$Jtsi ^җ<6s&)Mv/3v|f@=xU *Xr!ޚs$z?(X&ijrx8*M lQޠ*c)P}Em+`I?ċ^,~]HYjEL28vf.sK5m/]|T 5uwo3}1Y *WHx񬧛'Xzto_OxFsH. k/WQDX^rD"W1|y+4Tr?5W`mJ< bR>]{Ԓ}٨: Hr@x=Afjtaw~@|n':USr%Ԩ@%')$E+cm ضQ烑+#}] D(o~qʅ;IpeSd1G?!mxj8̶P@L0<݆8KۙTwl ]5!o$퀿6W]E<<r34K1H|qՖE݀ 1=F+mPYi'Y5x }0oҞ(Hn.nX`""oJ2jZz oTZyOUhZ"d?nhg=Y6Fw^J/brk{}<~BG@僡|}]+CCT;>`}Kf@E[3bD^Dn׋%{R|',jiar (&@f)+ sD1t o O:.whSC`O',lO&|wl*E<"2P'Hu^yN^_!TVS%RR?e9n F ʾ5}_ |V)|Dϊ3vhw-V+;o aD1N*JN;w+G@0jJR7ƥJMRӊxj/4U}VJg藧X wQ19>Tz\/͌R zMOD9k$jgVXLk#J>iq'Ϊf5Nkr"G `))N1M}%}z>Q0Ŋ+{-N>h hf'@1inA)ayZm%z >X5RNG Z6T8y@QN:}iڭ[_\n?FscYk۱k(ev)?XeJ#|Θl3sbj)3iZj X`M:{^AI(@Jj塚<݆8H;R/ |e& lؔxF_{֒ox2} Ww=@}sw$']]wtoB l~Y}ǺRfW9#^ùchMGGkC i򿞛XLjy.=pAfh,3| < ΟWFRSwuͫqo^+h3L9pzp_ױ9Hu_Rgq{+cSďCؿ1k o7Y#fn$@aRSfG?mfx{ٍ2赽 @,Y}w@ >F΅늑m$~ۘ7s:HsD~5a.Wsx5;Q/!n@j]dS<{b2+޺S'4Eȏ @[|I ? ᨢm}^ڒrwJ FW~˽R'=O&k^3BT% >0H)~dYsdݩk&ɃH/Sbnw6;jӲJ~C?p|貸Hsa1(w/Bj^5j/ ~W2teu,Ŏ{U x jG*Dsָa%Qyz r "Khen̘(C+͓{'9>RGyD ،?I/[Ӊr1Sj1yhAt[5ḱH1:FARq)Y&Sivlc{!2,*>N EN9#"uP1uK  J&|ٸx: Jy f+r0dTB*˭v,VTGkjNRyfZ( N@5˿E~kxqdNXuZHN' %h{ }VP^)\sjXBHq:IyIga "ߗuU)&R, )媳4i5"&\fǵߗbnA_ࢰg^8!;xmnjn Am>-اⅉsj@OBvJS1o8pI!je~W}i6cp#L~MYҴߠzfAAeQh)_Lޫi!IJ #~Np#w.)Fïz6eCnWP .S[-!_ mfaIUoD}AbQdC_$%O-9rx8\ox j#[.TXTlm>jEslFd':~ gid>&E͜:5ik70R8=ɱv~:Q ~㥝c@؟}օZ7}9BXw# ^1$9FXT]@()0B/'S3`!ЎtuR&D~hFD2h5Lj{ܷw큻o}.WGt%l;6! d- S1L?@sz07ΡM,13M}j ƨK;+" &Njmfeۓ&Ra`UO&&Y~_׬fEvdgYNR5Y1:wq6uK ŮR+'? jB0zǞjUya7)V6Ȫ$㔚^Rz /yy}]j2#KbNu \g $0?P"n ٵ @AcQk W i)l D>ԅUҫ|ɛ㗓yu(#-pXFz.jbaoa*TK5F 236pCуd'=rui򿋌\UWbD28 o9js1LH'xgX#%x8xtSڔ`DӀ=թ5WL1ۘ2*#̒dt'brxsXA8  ?zI<9f]~镁.]jl[%5^3ܦ3siև3Xȃ%ez'R{vcJ8OP{K-qR)Up%Ax]UMLTa~k8hy.B@s\?3ZGȻ7%~毬Rӗ{t/jl=)6)+.-e %kDRiVD3O/k61'h-1)DB kU1.%^,0f6&9䚇#c)WNq%|٫ OQK5*tC&+ bK˲mE"rnSWtm'.J[':@t>X 8ec5h k{^j<qfC%PYzs[ +Իj- Uy[Rǡ#b̄&ZSz:*]e,P(]2o ՊGqADž<4"/F/]S]?BJ,嵹)q pPT^rݲlc诧!RxljaFqS*2s\_1Ujf¢ D#++@Ȥż5n33F)Ժ #vm7I}tӥ wt^(KcU`l tYv!IdȪP)u#vOʉ6vJ`UX#/ֵ@"l2`N=!&NcO;݆;8@hC73l3j4 B^ʑU:tAM%2@2[u^qcZTm`Lkcuh̲Gα㡍FEwc&u/v.r88YW3"#'=qFZwIB2Ew)C#/m=; AL d)Ʀ1 B\Jrd q 1(,B89PBEqm݇-5h`8~*8G M|ڧ)v]j}'9AAL7XjXplw6TJҤ^s91MG+9b= 9!ڐMeĈ֤!tɐRS {y,qDBjkU#g@u42ps -;AKSj+;ȇmB ;# dӢ x pȪSOɘ//JdtaH7ii-qڭh?;D( :/`[I[ WҮ$iV<.VbܔnL#{G/cdPցEU޾Z|τGie #}kcf[w[!M 藝C ;I !TRQHS4rqAlx0R @utѶU]8 Hfԧ UU (xBnHS^~ @Hӻe |Gls5-Mdbcc#xC8wXvi8AGrٳ0@Lx*pui,'>>o| x->B駭+Pilb3 5V+#:ܺJ4*hXcu4Do;H$J/~s{Bį)J ,Djڕ&4r-Q\ [FR`J#E9/,⌴돑&@ZF~:޾*la_xET>J[U+.E|E!#fw3 +8*8'< @rWaCGӾ2MYHa1|]vc,>9dǨcUsL)'xoD;GYRV99Y^a:M ٕ׮9)ŵ&o_>KaʧN9~u7o9_]3_ 2 GN@fE\ I-Ɩ~*ȈX{2p.ΑՖA̖<uĺArR+8BH׃7(|G72eУ4ccF|-{m)Bbׯ=?_"?H,|{>n3uMK2s`6@H5_  _!BW=UTZW}eUɝO/&dCٲFl wF~hJV&wZNƤ gUubtKWPTHҷm=(|U߄)Ʒ-2BivoONB; ys T{Cj6'l+cj`psn ̔h EHϕDd?䭕 H#Oz090zYۓ 鵇3YA9NIS>["SVBJM ƀ  y<`bc1,GRsM9@W#V @ɵ>H oVSZ8xz^{Rw{m"B z4?a:n1YɠuؙL8r_o7$7@2׬^! >@[x;dWt3&Uo#iv0Rʤ|z9+~JY1A 9!_8ޖ_O&5!KLNǛ2?>yz"@n#A0Ƞ qE QAsTxkh\5^Vd%Fn潋ͦ"v c)5\l.9zM. $!{b@Jmg$ .=/y*xt8Ib¼/=;`dZ-WS}J0D /jiCWFT@pHI(l&JfS5@6m>OD2"q&f)0j<!b`o_L;ot#VE"ͣxOZ֝P$/@%z{3ڡ=+E``hgW?!cCuI(!? ?`Ij!^vlEQMGm3E`識-cECF->T7&>@>yB^k'"o eX >%lwsPVtBN5$JKӴ0J ZP-a$ 2'ۛ hc(j2SHx K0hN #Duxo/c1 H̱r}~HC[zN3:T S9CڷmDǨn%B`:ڶ2DM9}M]" ՇԚ(fHo.ܚ$eWE)R藣g i-b'@<*o:d഼yd1PI̥gJYkv u ȾRl+;[si%a4rtYXRDW!''jq» >@2su m'd--38 Ԓ: 1[}^./@X5`ίks%Q7@5)>Rl^]MLg}K@ZwN|fVu*;6SLrFߕPDgR}^|*ۄ<| VhCnf F HW`=oM*ꪌw.a~%럻@R f@%Txh47o&ḑ2 ٧u]1E$C7ΎB;q2._u d?܄ɴmˇj]sKɍ(T|5f螐r(rƩF$D?,50=d&܀wEA;V\[^{^ReE$ڋŴgl @1Z}[c j"%;DHBD5SjxXqxV7L"Na}GTa2'$Qj'#H?*|4O$7sz?:ۯpjX:f-4=mzB8jD=Uph)n2EN$ MDi@+doarjYX&u{k/~ZL&HLͤ IRӶŷH#\W#qGa)/RqV\jv~xx/}g+ʶ™b>].|,Yյ-!m|Bm7rFwW;l6SjBj**g,%l SbtbҒ`ttIb3źOjF3龄 g4$K6QDۮ @6'}<bT;ܷ2k$쉣b.ۢX{wkm|KF^i5ji1aЭ([ӵ]o]5Y#mp6vL^k& =zK2 DɹqO|6`W%! $]*'L)]LF_bNM9N~dvmɰńt ``ċgt7NLp%מR?c]&j;Cb4SO@H0Y5't$HxBfpzM]LcԸm Bt#F:`27!K+1AT`V ]{ hGf.`C 2b!)2O kKF2`%?Ɯ.HE{+ Zzb-5ʿXZ{jq^[Nц-.m'$X_Ofh=qCZ](ߩ-)%Q n @^[- %<^9d:( : dYRni_Y L)C{zJ|yG.@$\Se}q7z`柑Υ(̉1fG۳BE \Gb _cjpaIy>4Ӕ>~`_.bd{>T<֔{ m#ƅ `OZt i;#ٯў͒X8] d֠ bw5Č=}ك˔4RIKn_ǹ @;햹:*Bx߄YJB?o&|BkHV£*Z2ۂ^9i~Eb;Ed'Ֆ\?,Y؃^ Iܒ@} Qhat^oꕎ ٲd ii͊X}Zn^!Y/Ym۶,dw{d/Ⱥ8B.$^~$&!f >buR|' ?bLk&Qs S0TTB/"MHLDdB:fu/r!s:6Vj[ovu!B=@__z\V+=1 ,O&^-e OˆG){`pB\Nl4 >ld @m.4<Țb9,{!Vr*r W%`~2v_Ƭdf^yK&ş.Nnߞ3vK1 ^w-uNs_17 |+ c4I* C~g]~MW|?uOSW uos%&u39INjvt(#^xXS'*JBr/I/pI8B"xd_oATwn* 4OokR Jg,yv M";FIQGY 8n';yOj}v[DÀa}.pt XSVoG7 B*KΖp YOEN'Bd5 1 2`5p\Lж wE>*?j+JĬDdpܝW _˜;-I! 5&ǿXܽ,ztD^TA 0G=a`"ȸz5Q2 ?&9`4lWyx’:rHғ*0*w1ꔭk'FO %J>ˁ DJqwD]gmV|)xXsHd_Ur73YCo2UkRhy#3q=/v U 7fyAg9kُy*w'3K-C9s3N1e2k'o7,+j` ^rx-Mi Kn[\JؚT;*+zvW/s=`ov@NX:QLffyPv86ea U⋸:%Ֆ'ut=r|'\h]C ![+|Zߝ 7abߚSۗ忸ɛǣ>}+i䖆Zpi9sQ Z6z떧|~ 9BRvLsKQ' 0`*zqߋ/wN|.T|'/?[%$˼]u+nU8CvR$VCwɶ1+]՟0!4LW0m2 2 2 2 2 2 2 2 2 2 1(zDQ=V 4j+¥?ϺN:S@r[Ȧr}*TxV۟ZLNϘ+݋fHvyʐ хy*=yT]H„鲼/*KVj%NA 6>QY#<ة2)~8TW}קS$i~H\Vɣf!Q?@Qmv0G >nGg{J}A]17AȪ3g~* e?U|E9QJ?c\E?Ȁ'])5Ol(pSvrʹ ܱu ' +nX&YËko1lRC{ZgmgAv,݆ٲF0Fg )m/?mew7)Ual{>lEvgZya 덇;Ź#cK%OIJ&ddP`)ׯg/Çr2yڏ]f}i%ڝQz}tQ F&#9Q{6 ħafYcD\)D@HT}`W־wnС[a2y98 ?>eFc}R Ӽs]xR\.AC~4"o9c W@g۫bI-Y~q#K Ev_.?sqlr"rzA8s[m82&[ĩW.dr/;oGJqV}$DR S+U6s@uNHlс+dbui&A_P@:7l 2UƆs@Wa ~{Le ق2>,c2n2ۯM v'](2ҭ(]ԕ  Z AO @|& DFs ̼>CNZ6ꄙ oe՞K; t6̗9uG[z3-5L5f] 敐.,29oZ.@V! [le_y{$ -k0N~@/@&d"7d"f369 F4DtӖjT+Hu@vI2!G] z…iUed Y GpdKf?>[_ICgҬ?:Z=oM/gyY~avbŅl\vq_xa|qJVPirL ijyҐ\;((h_HtH㬠.H*j$7#l"Gt:9ga1Db5k˕3f3@v xzw_F òă\fށU4*~в~X ' ɤ^,_˭a[nFd 3>H;#3_F ɩ K~ L2".V:6{z HH}8 IFuHra7X~JNߎ| 21J\  @fos>݃(F62\ .)8}7"IfE)*?)ȹܛ)%3˄91%z9@d[nQH2d/ s(ۢ~ id6dÇ/l.,st$\Bl3dUR![o Xp"x31b;eT=1M>7rQKD'-;>lBdv;cyd+w9@S?cr{TAg D]kѐ)%2YB/| fg$, pD`v˺^ NMB-d.Rd+1B:a#wectiB`r8Ku {ڭ:Z)0\NN 0p@f"mŏg)5< I NauOcO 'w .$ܬw7prA6S'1ϭ4+YYSZWdݻh^ ζ -HAF΍lf郲)H͗[E!`}C<9).9&28{aN՜K*I#zZn~ը 7ϳ`{Rr]> Sv#G' pqM&`]+ʲs^Y.W]|H%3.}`td1 \)g+8Q+UٜJH!ĺ9)u"),T/[*9*W#|:d|t_J{-v+ͺ,mFr3d}RO}>C^TeT=32ӈ-#%2/r^NUWsjum}}kqRoUN,V\NZ;p '/^^vȺ~ )/kbj947 *#ĉJ| 99"J($lYe$"u |%#"6>ZIDATx c8sn]HHh{tK w$`0|Ό+-@n %Y,fR2n6kJ.I٬-*',f&^d&Rsx8J9L/N^~꧷/sr?ɻ_[xRL7O~}_H}7'?͇ij;'o~:9y'_?N|gI9H.U=0ć?ԓkxRLe7J&~»n7G /?e+x{z۟~=y A^3^īć_?tx9I?=yy8/?9>݂'Q/|P_a`&K1+gS#BgN<%B̮[ڵ VX+,f3 `Lb&Xa1 VX+,f3 `Ll]ٳ]`I1[W3u%/YOOY%Ml߱*/;90J3k+߿:,3ǚħOSs9޸&Hzqrjz׻wͯP2A{L|>O?~A2{ #ȷ/_ >C)vī_{ۓ8.{_'^~L?_>1/?߿ۗ =_'_Pwm31$0߽|?B&p.Dte"cg'&|Ii<_峆pk|G2\> Djx߿| LDz9Z&8L/_?c'#?!nA O~xa}rBn_##0^ysA&-c"?/?7kq|||oT[f"" r ox\@/Gǟ?Lԫ,>ӧkN>=@S@  ]?-3#sw'n8b"22O_1"i\^ï'q~gn8b"2 31WsĎIpymhW"0s뜝_Kė?%^)`": 3]=8ff"|م>n'VlR/v}XϽcLb&Xa1 VX+,f3 `Lb&Xa1 VX+,f3 `Lb&Xa1 VX+,f3uM{PZ!iL21iĒӧkԲmbK7v1Z.D&qVgb^Q[p[ҍ]3n 1hV3DX33LL0a1DX33LL0a1DX0_G::c-2Q8h.FQg#O>rAxa}Z0ѽez7ݣ0*"Ր)X*p)x;1ݦTqC_(4흈ʽ&UULTV,^L.,\h YmNL)UP {s{WL57ČNF'O3Z]l!&3V*kPu'suUk* 52u@fLDDi&߻f3gՙG1Q}yJ*ExTVt 3 1Q7z+CLm(W)2QiAu-<ƙV|L%zg*AbBc2r_s׫PsT_`"ըtU+ZUgD(WeрF;)"~&嵞UM൫l'RA Y5awM3Qj4DP]]5VQ. Ǽn[rQwLf(j\T)n۫"X\ U*P4+DtA&dhdP~.e'*(әbhU2x}L,m5ܕk1\%vƕsZ5ك;ޛ% rCv4<̆_`Trߨ? !쭷tń*~?0wV.[rM8rGT 01z?*TQpsKd'7@7 Ģ֫|uz%n3`;ń[aK.a6PSr{RL`2H`B/W E:iE.&dBNj(&8~ApU 01z?FFa?2F6rڼ3xELX*KAݧVvz˄yv׻A&qpS^GEu9;V=MebFۻa&<;q%:ƉEu9_U6'"h t070/631|Řg5O1f*40sU6ts\%ctom 3 `Lb&Xa1 VX+,f3 `Lb&Xa1 { *z6,NDr>oԛa"4XX3!Vum.ֆpڰ9^6o1k7Xē4x݆1k7Xē4x݆1k7Xē4x݆1k7Xē4x݆1k7Xē4x݆1k7dWL,\_芙x IUV*PqL\DW'eI{-tRfXXV𪲚b%GB쁥*tJ)f"^W f"ܕ]0QT㕈fߡ%DsgbvD(" sg"x(p8nR=_yL]t+ ԊW(D(\QĭjEK5@yT/:+|ٔ`ڪ 26ZDZLڔ-OT3Aѕ{u&jQRkcq%?qO0VdQk_(2nq]__ L#*yWr%Nyj!t n=lbL3( LmZJE~+i&X4hf6[ gDFlu].gCc^ 0_1[:. Џf:zZnKNq'H0AH͛rKͫrQEna4"v*'̄*yE][]A勷 E:/V*Mh+hJY\4fՆ5z#UU[d ZNj6j^+ ҃j^DU!#YɆxLT͍ esNTpUMA&m;rsWLޖo>&D~W'QǣZT-PܵrBy8A%ZXꐷrs[lTa@Fh(G %r0<5NP>ՆU W*wf.w`(K{8LȞ qZ4e$5cXlxc܅<=x tzbzUHw%]W(k1gSPW~v& <4gB  砅+ WוRzZpcـVLȆᝪ|n.?w\7bK1^ $SLPb kչLñegjLs  솀״:} 3JJ |4Py%q |h(U=u.4 Mf"#](Ւ|&0]ѱtzl:=O@MçbdCnD5Y˕*g=VINLPES%2 &TU"U)D ß`J;}yTN_v=u!VjgM L:0;72kHsuL/';'*% .(UW hPpn7XXXzKpbt"D.rJEXeK,] Rf=T6>vĶb;xb[H<-RlOl )'Bm!vĶb;xb[H<-RlOl )EfYV+9RYP&\PgUp fPKf8F&ԌDZ0#f+MQ@?BڼLw77wcc"p$(]L]$*..5GBbV+Y,Jjԏz\kj-KDu v-To*W&\5puL[KqfB11ZcZS]!'#aZkN1.. xCr(fVi:~\&j㘘Z(Wɧ]DQq]Zf[9u>&B`; 9Cv!`20 LdYmQ O5h\*kc1\BP04;!nuAw<|ZC& S[SOsD0,@2UYИ&tZAwD5YhЉ zR"Xa01'Yd AGNL>*k,K=.M712v0 9F^!>Gt@h'[tL(k(#лpl 05IL6ZE>O SŰ  E #Gw;M ed-X$t.٣#hx4;Bv{0ԇl}0L(kQT0l-;5 }ba2aAT瘉Ua21 xfbb&^$لvYb$ ӡ^l )'Bm!vĶb;xb[H<-RlOl )'Bm!vĶb;xb[H<-Rklr㺿|dvזZZDrNfh.oVla&p g&hm83E;hÙ-@Llpfbv8І3[Á6آp g&hm83E;hÙ-!vvv UI~[=1}<ՙKMIsܮcxGϓ;S&XmPS8L&0TDiZ׶5}(bc03O<&,cN-_I9Gг_LL:Ѧ;sY&g=B]KObsܶ$LƋΘ{ v/;MƎu0 Ӷ/S8ez[U5 ͩצz28*Dt+Ҡ]P lwzvKn{j?0aj{<62=k~F)KNGN#gLhCL9#051}ѭaޱfgY6;SUit;P@QZL*E2JcHLԑkhjP }؃m:,*mdZiuueÖ́Na{9P=dn wxw4i1kд :{;>"&T1c)ͭQd"pTU.VvlmjƘF/b-7 U 1 9ib*l]_#egLLE>5y54d.Hï1t -2AȀ~&GŮf"H%BGrb;t=8-A&,'JÚiߛ =h҄ G{Ä64^J0\& 0(F L9LPLK2ha5.fomx*R- 2!cܰw c/^00 2afz?>I(&Cr%-3i{iFg(Dਪ<&[ s$hl 3b"kL&351>1$f'fLL 33Ab&|b&H̄O 1>1$f'fLL ҪLTfbk_1>J6aܯlD+1i{jc10vԦS̄O 1>1$f'fLL 33Ab&|b&H̄O 1>1$f'fLL 5~cOy<&*Y9=J-SR|2W'Sa$bROJl%{{Z8^>K$XGyh\Z7:<&6zW8LWA:b"ܢ\Oo>sڨ-U|&c-u6g2- _\DŽ[^q`8&Þx;0{+]}τ1 JyŽ}Lxsc VLcy5g)WTOL PVĄʭuc9 056AL dL\&yLhg/('&E䜸n2jx{g2!Ԁ 2DŽl ń?CQ?uCP;ctt1ꊱ>QKJOA&anig*룮-, Kf` BcB 3ut:lӀXC;1M tv_Gl&ppcmI?֝Ng&J[BhA&mۧ ׈2UB)&zV ;&4.4Rv tn{ tej7HF<+&:#:FpzlLk{a&TnM5xL8ןAV0>a8ExV6ISvݷ#C~?=cu!Ą,=5N8Lq0p(S)TbLھNL2soT7ST9d5a0"T8׵vt1&f[2COH&1fBɩ֬ÄaTUC : 4ҲX)LXL~tS)pvTC?NPT(LCuC(jz:w0ኍf;&0:_ K[2!sÞixLeɠ tCDŽ0Lb~i4 `"H&,Lj1pƣNWuc 1a 2naBE|[G>拞e_dbqY㍍] mCZ Q+lL &06Pi^^RF R)T:)x~ k.?:Q WF jXH:tO3tOqdM x04 2=&@k kp`Bɢx|ia;{&u6;]g {*M:1L 6ԥ{RL:i0L4j 001 $tB'1FPiv8b_ޅ2QO(\BtaL4'nτXu`e%cɍy,CUaWb@Yzm 3L1A,M#Kkmm@[h><$Sgm` SqjL@1UZ"}5m*d/Tc HТtXN'{f](V(a :Nל 4?m{ݵ&sm 2F\c8{uێ20{v{9ybUjE;{sCV-^GsZwDqc写>݋xL,֖XW+˼."fa*Tg v$xbNyVhSܻmAߙ,f"Z33}྇Lpb&v=73,f"ZIJb&h1ˊxz}g&"OS429ݐr[3X.Q:%{XێTN+ֳKFM #&64mL:˴bÓ f90k BDj!EwќU \+ruJE;boO'g"qL }._޴CdBj>xwFe]"!a)KXpCdb_ Kb)b '?-SXL̙iP;a2VEpwu}",n'p)̄*N(u&ыFiasf"r1a  MUo5l K,}lw{\Xo6rSmBL#&H࠙@? Y\kN}sҟ踚8P5}7[4ڗrDŽ*2p<9&&ڸcux4lk~wZuV[1V~L o52/DKq܉τ*W߸;G: KWWMOD6*9Ct 201f6p5T0M-"DW@j9N|8DŽA!1$_ ;i ~MDW81? (hy|80 =& ѷiiFthfk$a : LQNd͈τOF:TJ{NL3zS4LhCdg])1A3CsB!Wy+wt1AEtL :=66E2]%fe g~mUG!z#|ɄuG/\wLp rs؝7Oy6xJڸ-QLfs(t7`DipxLHxLO=0 D~?4b)NqkjBҙ;j&=&4q*<\&V~MLL<&p8]o3qL`1͟l0a%9ˮ2:yV.QNOgI2K>sw1Sb&a1 {X=,f3}྇Lpb&a1 {X=,f3Ȭ]L`bY}HH۞ F<*j6>S&6  2!dZ0<Ͱgfuh˄&䐱y'`hCK $v:I&FcN}wup]'{j{k} \N}|&yB}wf6NG*P7m}ǵ 2!W7[tK tFU.Zi>s iS>d_{CȄp7τ~W+yLjYzP.A7ՆWY4t p"moca}vI4xdLJc^ؔ edYҨ@[ Lc9nkoceƎw3KųjsW+M31nFڶ9L eQw+ǑƐ7NcOy@y# ,hp𥉉CD9D^/*ML֞ ʻY<}v;Z$0.`-VńO#JӑnCp?!H},0\/C-DD 3Ɖ\[|_1у %)4+MCGicg:=MFτ-@p'`)V}wCD:?TtQY_K*p= 1mo3iScjE&0p.i0T?Wabُph`2>n z´xsSKq ¿o!%MpeX,bX,bX,bX,bX,bX,bX,bXDWHBuXQ'A1GL1uz2d"񪓉|>oD2d6uM)PKʍPfr 994d"vBd.\<»L&H$S5 T(|?B&&$dB<@؛=JN3Ёc&\&J<0OO3)%1OJ>cZ2^dN S<yE"w tf)80=%"L{>xP2i`c4C>uM1N/wgi4bdSC'6L$Nb&.pGʝgtq6ltYgt0`"1U'鳳tdb|2ʔĕ O=9RćHܟݢ\.-@ `/H\3,Xq9yL2d BN&.Oi$&gx<(&mz?&B&/燴xE&2q{!ʒǴ80\^EN1q-!k{( ,Bqs?LmQߠ Pjt٢.2aE,bX,z?vL3qɄf퇈=&& 7er+8}tLݒYxlf&j%_Gp7Y Zߑ\Spu`C"Z7Ozp B2\~6kgց ցalnw@c`bu`x8yϟQcEׁtX,bX,k:KvLG&CP2d'W qNRM޾6%9erDj `!fNadϝP4)'Eoe!s cu8u@HExo6PNy=ν!ztTIsU\"sL83ƟJx)IE,BU5dy̹ Q5)zZc.*O_i6)^H{.]&NLwlVMަ֘,t%MmcJ8C XRex9){0_;'$i6q'Gf)5)zZc.*M_6g[}:@{|~L[L%)uY[VRdgiw{f_+{A៸OdtE>gRT:3ESm_7 =\&RyxLg"ǁE)4{gBnKf"9 ! ۦT4p:uyRnfbϐ 96?OaޣN-ӌc (`-h[<{Ȅ:HfB.`bN8{`:r"ʤ2G-Ieid"K1Hs>ƄK2dH&Ry?Ϫ.s8Zd$բ\ :.$.N"ʈ3\+]wf2!W s /&Z.Ʌ[P.TNǵkgLr|L81ry)({?4 \ے |pb©2gٔ(RqHj).$u/Yh率4>&ܘp\&{ OZ-hg9MI~?172Z*_T6ɄZ*Leb.T?frr:95V#g%tEXtdate:create2013-05-07T16:42:06+02:00m%tEXtdate:modify2013-05-07T16:41:56+02:00>IENDB`rdflib-4.1.2/docs/_static/headerbg.png000066400000000000000000000004431232323236500176070ustar00rootroot00000000000000PNG  IHDR"sRGBIDAT(mI CT}x_0@)c c KXJ>x9>x1`1zehټf™t9-8tɞOFVЗcYGXwwq+Fn>+p},\?O(NbĨ\1|4313+^'˩d᧞670I0w{dL^?MsQ+}q*NPEIENDB`rdflib-4.1.2/docs/_static/logo.svg000066400000000000000000000434311232323236500170250ustar00rootroot00000000000000 image/svg+xml R D F ib L rdflib-4.1.2/docs/_static/plugins-diagram.svg000066400000000000000000003430461232323236500211550ustar00rootroot00000000000000 image/svg+xml parsing serializing querying storing vincent_donofrio has_name Vincent D'Onofrio starred_in similar_plot_to released_in 1999 the_thirteenth_floor law_&_order_criminal_intent is_a movie tv_show chris_noth sex_and_the_city the_matrix released_in starred_in starred_in starred_in is_a is_a is_a RDF Graph RDF Triples RDF Graph RDF Graph RDFa turtle / n3 RDF/XML ntriples TriX Sleepycat SPARQLStore Memory Store-providedSPARQL programmaticaccess to triples SPARQL 1.1Engine JSON-LD RDF/JSON SPARQLStore RDF/JSON JSON-LD RDFLib nquads TriG TriX RDF/XML ntriples turtle / n3 microdata rdflib-4.1.2/docs/_static/pyramid.css000066400000000000000000000131311232323236500175150ustar00rootroot00000000000000/* * pylons.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- pylons theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: "Nobile", sans-serif; font-size: 100%; background-color: #393939; color: #ffffff; margin: 0; padding: 0; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } hr { border: 1px solid #B1B4B6; } div.document { background-color: #eee; } div.header { width:100%; background: #f4ad32 url(headerbg.png) repeat-x 0 top; border-bottom: 2px solid #ffffff; } div.logo { text-align: center; padding-top: 10px; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; font-size: 1em; border: 2px solid #ddd; border-right-style: none; overflow: auto; } div.footer { color: #ffffff; width: 100%; padding: 13px 0; text-align: center; font-size: 75%; background: transparent; clear:both; } div.footer a { color: #ffffff; text-decoration: none; } div.footer a:hover { color: #e88f00; text-decoration: underline; } div.related { line-height: 30px; color: #373839; font-size: 0.8em; background-color: #eee; } div.related a { color: #1b61d6; } div.related ul { padding-left: 240px; } div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; } div.sphinxsidebarwrapper{ padding: 10px 0; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: "Neuton", sans-serif; color: #373839; font-size: 1.4em; font-weight: normal; margin: 0; padding: 5px 10px; border-bottom: 2px solid #ddd; } div.sphinxsidebar h4{ font-size: 1.3em; } div.sphinxsidebar h3 a { color: #000000; } div.sphinxsidebar p { color: #888; padding: 5px 20px; } div.sphinxsidebar p.topless { } div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #373839; } div.sphinxsidebar a { color: #444; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; font-size: 1em; } div.sphinxsidebar input[type=text]{ margin-left: 20px; } /* -- sidebars -------------------------------------------------------------- */ div.sidebar { margin: 0 0 0.5em 1em; border: 2px solid #c6d880; background-color: #e6efc2; width: 40%; float: right; border-right-style: none; border-left-style: none; padding: 10px 20px; } p.sidebar-title { font-weight: bold; } /* -- body styles ----------------------------------------------------------- */ a, a .pre { color: #1b61d6; text-decoration: none; } a:hover, a:hover .pre { text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: "Neuton", sans-serif; background-color: #ffffff; font-weight: normal; color: #373839; margin: 30px 0px 10px 0px; padding: 5px 0; } div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #ffffff; } div.body h3 { font-size: 120%; background-color: #ffffff; } div.body h4 { font-size: 110%; background-color: #ffffff; } div.body h5 { font-size: 100%; background-color: #ffffff; } div.body h6 { font-size: 100%; background-color: #ffffff; } a.headerlink { color: #1b61d6; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } a.headerlink:hover { text-decoration: underline; } div.body p, div.body dd, div.body li { line-height: 1.5em; } div.admonition p.admonition-title + p { display: inline; } div.highlight{ background-color: white; } div.note { border: 2px solid #7a9eec; border-right-style: none; border-left-style: none; padding: 10px 20px 10px 60px; background: #e1ecfe url(dialog-note.png) no-repeat 10px 8px; } div.seealso { background: #fff6bf url(dialog-seealso.png) no-repeat 10px 8px; border: 2px solid #ffd324; border-left-style: none; border-right-style: none; padding: 10px 20px 10px 60px; } div.topic { background: #eeeeee; border: 2px solid #C6C9CB; padding: 10px 20px; border-right-style: none; border-left-style: none; } div.warning { background: #fbe3e4 url(dialog-warning.png) no-repeat 10px 8px; border: 2px solid #fbc2c4; border-right-style: none; border-left-style: none; padding: 10px 20px 10px 60px; } p.admonition-title { display: none; } p.admonition-title:after { content: ":"; } pre { padding: 10px; background-color: #fafafa; color: #222; line-height: 1.2em; border: 2px solid #C6C9CB; font-size: 1.1em; margin: 1.5em 0 1.5em 0; border-right-style: none; border-left-style: none; } tt { background-color: transparent; color: #222; font-size: 1.1em; font-family: monospace; } .viewcode-back { font-family: "Nobile", sans-serif; } div.viewcode-block:target { background-color: #fff6bf; border: 2px solid #ffd324; border-left-style: none; border-right-style: none; padding: 10px 20px; } table.highlighttable { width: 100%; } table.highlighttable td { padding: 0; } a em.std-term { color: #007f00; } a:hover em.std-term { text-decoration: underline; } .download { font-family: "Nobile", sans-serif; font-weight: normal; font-style: normal; } tt.xref { font-weight: normal; font-style: normal; }rdflib-4.1.2/docs/_themes/000077500000000000000000000000001232323236500153355ustar00rootroot00000000000000rdflib-4.1.2/docs/_themes/armstrong/000077500000000000000000000000001232323236500173515ustar00rootroot00000000000000rdflib-4.1.2/docs/_themes/armstrong/LICENSE000066400000000000000000000022151232323236500203560ustar00rootroot00000000000000Copyright (c) 2011 Bay Citizen & Texas Tribune Original ReadTheDocs.org code Copyright (c) 2010 Charles Leifer, Eric Holscher, Bobby Grace Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rdflib-4.1.2/docs/_themes/armstrong/README000066400000000000000000000001601232323236500202260ustar00rootroot00000000000000This is the Armstrong Sphinx theme from https://github.com/armstrong/armstrong_sphinx Used under BSD license. rdflib-4.1.2/docs/_themes/armstrong/layout.html000066400000000000000000000031751232323236500215620ustar00rootroot00000000000000{% extends "basic/layout.html" %} {% set script_files = script_files + [pathto("_static/searchtools.js", 1)] %} {% block htmltitle %} {{ super() }} {% endblock %} {% block footer %} {% if theme_analytics_code %} {% endif %} {% endblock %} rdflib-4.1.2/docs/_themes/armstrong/rtd-themes.conf000066400000000000000000000021731232323236500222770ustar00rootroot00000000000000[theme] inherit = default stylesheet = rtd.css pygment_style = default show_sphinx = False [options] show_rtd = True white = #ffffff almost_white = #f8f8f8 barely_white = #f2f2f2 dirty_white = #eeeeee almost_dirty_white = #e6e6e6 dirtier_white = #dddddd lighter_gray = #cccccc gray_a = #aaaaaa gray_9 = #999999 light_gray = #888888 gray_7 = #777777 gray = #666666 dark_gray = #444444 gray_2 = #222222 black = #111111 light_color = #e8ecef light_medium_color = #DDEAF0 medium_color = #8ca1af medium_color_link = #86989b medium_color_link_hover = #a6b8bb dark_color = #465158 h1 = #000000 h2 = #465158 h3 = #6c818f link_color = #444444 link_color_decoration = #CCCCCC medium_color_hover = #697983 green_highlight = #8ecc4c positive_dark = #609060 positive_medium = #70a070 positive_light = #e9ffe9 negative_dark = #900000 negative_medium = #b04040 negative_light = #ffe9e9 negative_text = #c60f0f ruler = #abc viewcode_bg = #f4debf viewcode_border = #ac9 highlight = #ffe080 code_background = #eeeeee background = #465158 background_link = #ffffff background_link_half = #ffffff background_text = #eeeeee background_text_link = #86989b rdflib-4.1.2/docs/_themes/armstrong/static/000077500000000000000000000000001232323236500206405ustar00rootroot00000000000000rdflib-4.1.2/docs/_themes/armstrong/static/rtd.css_t000066400000000000000000000407661232323236500225030ustar00rootroot00000000000000/* * rtd.css * ~~~~~~~~~~~~~~~ * * Sphinx stylesheet -- sphinxdoc theme. Originally created by * Armin Ronacher for Werkzeug. * * Customized for ReadTheDocs by Eric Pierce & Eric Holscher * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /* RTD colors * light blue: {{ theme_light_color }} * medium blue: {{ theme_medium_color }} * dark blue: {{ theme_dark_color }} * dark grey: {{ theme_grey_color }} * * medium blue hover: {{ theme_medium_color_hover }}; * green highlight: {{ theme_green_highlight }} * light blue (project bar): {{ theme_light_color }} */ @import url("basic.css"); /* PAGE LAYOUT -------------------------------------------------------------- */ body { font: 100%/1.5 "ff-meta-web-pro-1","ff-meta-web-pro-2",Arial,"Helvetica Neue",sans-serif; text-align: center; color: black; background-color: {{ theme_background }}; padding: 0; margin: 0; } div.document { text-align: left; background-color: {{ theme_light_color }}; } div.bodywrapper { background-color: {{ theme_white }}; border-left: 1px solid {{ theme_lighter_gray }}; border-bottom: 1px solid {{ theme_lighter_gray }}; margin: 0 0 0 16em; } div.body { margin: 0; padding: 0.5em 1.3em; max-width: 55em; min-width: 20em; } div.related { font-size: 1em; background-color: {{ theme_background }}; } div.documentwrapper { float: left; width: 100%; background-color: {{ theme_light_color }}; } /* HEADINGS --------------------------------------------------------------- */ h1 { margin: 0; padding: 0.7em 0 0.3em 0; font-size: 1.5em; line-height: 1.15; color: {{ theme_h1 }}; clear: both; } h2 { margin: 2em 0 0.2em 0; font-size: 1.35em; padding: 0; color: {{ theme_h2 }}; } h3 { margin: 1em 0 -0.3em 0; font-size: 1.2em; color: {{ theme_h3 }}; } div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { color: black; } h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { display: none; margin: 0 0 0 0.3em; padding: 0 0.2em 0 0.2em; color: {{ theme_gray_a }} !important; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { display: inline; } h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, h5 a.anchor:hover, h6 a.anchor:hover { color: {{ theme_gray_7 }}; background-color: {{ theme_dirty_white }}; } /* LINKS ------------------------------------------------------------------ */ /* Normal links get a pseudo-underline */ a { color: {{ theme_link_color }}; text-decoration: none; border-bottom: 1px solid {{ theme_link_color_decoration }}; } /* Links in sidebar, TOC, index trees and tables have no underline */ .sphinxsidebar a, .toctree-wrapper a, .indextable a, #indices-and-tables a { color: {{ theme_dark_gray }}; text-decoration: none; border-bottom: none; } /* Most links get an underline-effect when hovered */ a:hover, div.toctree-wrapper a:hover, .indextable a:hover, #indices-and-tables a:hover { color: {{ theme_black }}; text-decoration: none; border-bottom: 1px solid {{ theme_black }}; } /* Footer links */ div.footer a { color: {{ theme_background_text_link }}; text-decoration: none; border: none; } div.footer a:hover { color: {{ theme_medium_color_link_hover }}; text-decoration: underline; border: none; } /* Permalink anchor (subtle grey with a red hover) */ div.body a.headerlink { color: {{ theme_lighter_gray }}; font-size: 1em; margin-left: 6px; padding: 0 4px 0 4px; text-decoration: none; border: none; } div.body a.headerlink:hover { color: {{ theme_negative_text }}; border: none; } /* NAVIGATION BAR --------------------------------------------------------- */ div.related ul { height: 2.5em; } div.related ul li { margin: 0; padding: 0.65em 0; float: left; display: block; color: {{ theme_background_link_half }}; /* For the >> separators */ font-size: 0.8em; } div.related ul li.right { float: right; margin-right: 5px; color: transparent; /* Hide the | separators */ } /* "Breadcrumb" links in nav bar */ div.related ul li a { order: none; background-color: inherit; font-weight: bold; margin: 6px 0 6px 4px; line-height: 1.75em; color: {{ theme_background_link }}; text-shadow: 0 1px rgba(0, 0, 0, 0.5); padding: 0.4em 0.8em; border: none; border-radius: 3px; } /* previous / next / modules / index links look more like buttons */ div.related ul li.right a { margin: 0.375em 0; background-color: {{ theme_medium_color_hover }}; text-shadow: 0 1px rgba(0, 0, 0, 0.5); border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; } /* All navbar links light up as buttons when hovered */ div.related ul li a:hover { background-color: {{ theme_medium_color }}; color: {{ theme_white }}; text-decoration: none; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; } /* Take extra precautions for tt within links */ a tt, div.related ul li a tt { background: inherit !important; color: inherit !important; } /* SIDEBAR ---------------------------------------------------------------- */ div.sphinxsidebarwrapper { padding: 0; } div.sphinxsidebar { margin: 0; margin-left: -100%; float: left; top: 3em; left: 0; padding: 0 1em; width: 14em; font-size: 1em; text-align: left; background-color: {{ theme_light_color }}; } div.sphinxsidebar img { max-width: 12em; } div.sphinxsidebar h3, div.sphinxsidebar h4 { margin: 1.2em 0 0.3em 0; font-size: 1em; padding: 0; color: {{ theme_gray_2 }}; font-family: "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif; } div.sphinxsidebar h3 a { color: {{ theme_grey_color }}; } div.sphinxsidebar ul, div.sphinxsidebar p { margin-top: 0; padding-left: 0; line-height: 130%; background-color: {{ theme_light_color }}; } /* No bullets for nested lists, but a little extra indentation */ div.sphinxsidebar ul ul { list-style-type: none; margin-left: 1.5em; padding: 0; } /* A little top/bottom padding to prevent adjacent links' borders * from overlapping each other */ div.sphinxsidebar ul li { padding: 1px 0; } /* A little left-padding to make these align with the ULs */ div.sphinxsidebar p.topless { padding-left: 0 0 0 1em; } /* Make these into hidden one-liners */ div.sphinxsidebar ul li, div.sphinxsidebar p.topless { white-space: nowrap; overflow: hidden; } /* ...which become visible when hovered */ div.sphinxsidebar ul li:hover, div.sphinxsidebar p.topless:hover { overflow: visible; } /* Search text box and "Go" button */ #searchbox { margin-top: 2em; margin-bottom: 1em; background: {{ theme_dirtier_white }}; padding: 0.5em; border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; } #searchbox h3 { margin-top: 0; } /* Make search box and button abut and have a border */ input, div.sphinxsidebar input { border: 1px solid {{ theme_gray_9 }}; float: left; } /* Search textbox */ input[type="text"] { margin: 0; padding: 0 3px; height: 20px; width: 144px; border-top-left-radius: 3px; border-bottom-left-radius: 3px; -moz-border-radius-topleft: 3px; -moz-border-radius-bottomleft: 3px; -webkit-border-top-left-radius: 3px; -webkit-border-bottom-left-radius: 3px; } /* Search button */ input[type="submit"] { margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */ height: 22px; color: {{ theme_dark_gray }}; background-color: {{ theme_light_color }}; padding: 1px 4px; font-weight: bold; border-top-right-radius: 3px; border-bottom-right-radius: 3px; -moz-border-radius-topright: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-top-right-radius: 3px; -webkit-border-bottom-right-radius: 3px; } input[type="submit"]:hover { color: {{ theme_white }}; background-color: {{ theme_green_highlight }}; } div.sphinxsidebar p.searchtip { clear: both; padding: 0.5em 0 0 0; background: {{ theme_dirtier_white }}; color: {{ theme_gray }}; font-size: 0.9em; } /* Sidebar links are unusual */ div.sphinxsidebar li a, div.sphinxsidebar p a { background: {{ theme_light_color }}; /* In case links overlap main content */ border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; border: 1px solid transparent; /* To prevent things jumping around on hover */ padding: 0 5px 0 5px; } div.sphinxsidebar li a:hover, div.sphinxsidebar p a:hover { color: {{ theme_black }}; text-decoration: none; border: 1px solid {{ theme_light_gray }}; } /* Tweak any link appearing in a heading */ div.sphinxsidebar h3 a { } /* OTHER STUFF ------------------------------------------------------------ */ cite, code, tt { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; } tt { background-color: {{ theme_code_background }}; color: {{ theme_dark_gray }}; } tt.descname, tt.descclassname, tt.xref { border: 0; } hr { border: 1px solid {{ theme_ruler }}; margin: 2em; } pre, #_fontwidthtest { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; margin: 1em 2em; font-size: 0.95em; letter-spacing: 0.015em; line-height: 120%; padding: 0.5em; border: 1px solid {{ theme_lighter_gray }}; background-color: {{ theme_code_background }}; border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; } pre a { color: inherit; text-decoration: underline; } td.linenos pre { padding: 0.5em 0; } div.quotebar { background-color: {{ theme_almost_white }}; max-width: 250px; float: right; padding: 2px 7px; border: 1px solid {{ theme_lighter_gray }}; } div.topic { background-color: {{ theme_almost_white }}; } table { border-collapse: collapse; margin: 0 -0.5em 0 0; } table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } /* ADMONITIONS AND WARNINGS ------------------------------------------------- */ /* Shared by admonitions, warnings and sidebars */ div.admonition, div.warning, div.sidebar { font-size: 0.9em; margin: 2em; padding: 0; /* border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; */ } div.admonition p, div.warning p, div.sidebar p { margin: 0.5em 1em 0.5em 1em; padding: 0; } div.admonition pre, div.warning pre, div.sidebar pre { margin: 0.4em 1em 0.4em 1em; } div.admonition p.admonition-title, div.warning p.admonition-title, div.sidebar p.sidebar-title { margin: 0; padding: 0.1em 0 0.1em 0.5em; color: white; font-weight: bold; font-size: 1.1em; text-shadow: 0 1px rgba(0, 0, 0, 0.5); } div.admonition ul, div.admonition ol, div.warning ul, div.warning ol, div.sidebar ul, div.sidebar ol { margin: 0.1em 0.5em 0.5em 3em; padding: 0; } /* Admonitions and sidebars only */ div.admonition, div.sidebar { border: 1px solid {{ theme_positive_dark }}; background-color: {{ theme_positive_light }}; } div.admonition p.admonition-title, div.sidebar p.sidebar-title { background-color: {{ theme_positive_medium }}; border-bottom: 1px solid {{ theme_positive_dark }}; } /* Warnings only */ div.warning { border: 1px solid {{ theme_negative_dark }}; background-color: {{ theme_negative_light }}; } div.warning p.admonition-title { background-color: {{ theme_negative_medium }}; border-bottom: 1px solid {{ theme_negative_dark }}; } /* Sidebars only */ div.sidebar { max-width: 200px; } div.versioninfo { margin: 1em 0 0 0; border: 1px solid {{ theme_lighter_gray }}; background-color: {{ theme_light_medium_color }}; padding: 8px; line-height: 1.3em; font-size: 0.9em; } .viewcode-back { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; } div.viewcode-block:target { background-color: {{ theme_viewcode_bg }}; border-top: 1px solid {{ theme_viewcode_border }}; border-bottom: 1px solid {{ theme_viewcode_border }}; } dl { margin: 1em 0 2.5em 0; } /* Highlight target when you click an internal link */ dt:target { background: {{ theme_highlight }}; } /* Don't highlight whole divs */ div.highlight { background: transparent; } /* But do highlight spans (so search results can be highlighted) */ span.highlight { background: {{ theme_highlight }}; } div.footer { background-color: {{ theme_background }}; color: {{ theme_background_text }}; padding: 0 2em 2em 2em; clear: both; font-size: 0.8em; text-align: center; } p { margin: 0.8em 0 0.5em 0; } .section p img { margin: 1em 2em; } /* MOBILE LAYOUT -------------------------------------------------------------- */ @media screen and (max-width: 600px) { h1, h2, h3, h4, h5 { position: relative; } ul { padding-left: 1.75em; } div.bodywrapper a.headerlink, #indices-and-tables h1 a { color: {{ theme_almost_dirty_white }}; font-size: 80%; float: right; line-height: 1.8; position: absolute; right: -0.7em; visibility: inherit; } div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a { line-height: 1.5; } pre { font-size: 0.7em; overflow: auto; word-wrap: break-word; white-space: pre-wrap; } div.related ul { height: 2.5em; padding: 0; text-align: left; } div.related ul li { clear: both; color: {{ theme_dark_color }}; padding: 0.2em 0; } div.related ul li:last-child { border-bottom: 1px dotted {{ theme_medium_color }}; padding-bottom: 0.4em; margin-bottom: 1em; width: 100%; } div.related ul li a { color: {{ theme_dark_color }}; padding-right: 0; } div.related ul li a:hover { background: inherit; color: inherit; } div.related ul li.right { clear: none; padding: 0.65em 0; margin-bottom: 0.5em; } div.related ul li.right a { color: {{ theme_white }}; padding-right: 0.8em; } div.related ul li.right a:hover { background-color: {{ theme_medium_color }}; } div.body { clear: both; min-width: 0; word-wrap: break-word; } div.bodywrapper { margin: 0 0 0 0; } div.sphinxsidebar { float: none; margin: 0; width: auto; } div.sphinxsidebar input[type="text"] { height: 2em; line-height: 2em; width: 70%; } div.sphinxsidebar input[type="submit"] { height: 2em; margin-left: 0.5em; width: 20%; } div.sphinxsidebar p.searchtip { background: inherit; margin-bottom: 1em; } div.sphinxsidebar ul li, div.sphinxsidebar p.topless { white-space: normal; } .bodywrapper img { display: block; margin-left: auto; margin-right: auto; max-width: 100%; } div.documentwrapper { float: none; } div.admonition, div.warning, pre, blockquote { margin-left: 0em; margin-right: 0em; } .body p img { margin: 0; } #searchbox { background: transparent; } .related:not(:first-child) li { display: none; } .related:not(:first-child) li.right { display: block; } div.footer { padding: 1em; } .rtd_doc_footer .badge { float: none; margin: 1em auto; position: static; } .rtd_doc_footer .badge.revsys-inline { margin-right: auto; margin-bottom: 2em; } table.indextable { display: block; width: auto; } .indextable tr { display: block; } .indextable td { display: block; padding: 0; width: auto !important; } .indextable td dt { margin: 1em 0; } ul.search { margin-left: 0.25em; } ul.search li div.context { font-size: 90%; line-height: 1.1; margin-bottom: 1; margin-left: 0; } } rdflib-4.1.2/docs/_themes/armstrong/theme.conf000066400000000000000000000025701232323236500213260ustar00rootroot00000000000000[theme] inherit = default stylesheet = rtd.css pygment_style = default show_sphinx = False [options] show_rtd = True white = #ffffff almost_white = #f8f8f8 barely_white = #f2f2f2 dirty_white = #eeeeee almost_dirty_white = #e6e6e6 dirtier_white = #DAC6AF lighter_gray = #cccccc gray_a = #aaaaaa gray_9 = #999999 light_gray = #888888 gray_7 = #777777 gray = #666666 dark_gray = #444444 gray_2 = #222222 black = #111111 light_color = #EDE4D8 light_medium_color = #DDEAF0 medium_color = #8ca1af medium_color_link = #634320 medium_color_link_hover = #261a0c dark_color = rgba(160, 109, 52, 1.0) h1 = #1f3744 h2 = #335C72 h3 = #638fa6 link_color = #335C72 link_color_decoration = #99AEB9 medium_color_hover = rgba(255, 255, 255, 0.25) medium_color = rgba(255, 255, 255, 0.5) green_highlight = #8ecc4c positive_dark = rgba(51, 77, 0, 1.0) positive_medium = rgba(102, 153, 0, 1.0) positive_light = rgba(102, 153, 0, 0.1) negative_dark = rgba(51, 13, 0, 1.0) negative_medium = rgba(204, 51, 0, 1.0) negative_light = rgba(204, 51, 0, 0.1) negative_text = #c60f0f ruler = #abc viewcode_bg = #f4debf viewcode_border = #ac9 highlight = #ffe080 code_background = rgba(0, 0, 0, 0.075) background = rgba(135, 57, 34, 1.0) background_link = rgba(212, 195, 172, 1.0) background_link_half = rgba(212, 195, 172, 0.5) background_text = rgba(212, 195, 172, 1.0) background_text_link = rgba(171, 138, 93, 1.0) rdflib-4.1.2/docs/apidocs/000077500000000000000000000000001232323236500153335ustar00rootroot00000000000000rdflib-4.1.2/docs/apidocs/examples.rst000066400000000000000000000052361232323236500177110ustar00rootroot00000000000000examples Package ================ These examples all live in ``./examples`` in the source-distribution of RDFLib. :mod:`conjunctive_graphs` Module -------------------------------- .. automodule:: examples.conjunctive_graphs :members: :undoc-members: :show-inheritance: :mod:`custom_datatype` Module ----------------------------- .. automodule:: examples.custom_datatype :members: :undoc-members: :show-inheritance: :mod:`custom_eval` Module ------------------------- .. automodule:: examples.custom_eval :members: :undoc-members: :show-inheritance: :mod:`film` Module ------------------ .. automodule:: examples.film :members: :undoc-members: :show-inheritance: :mod:`foafpaths` Module ----------------------- .. automodule:: examples.foafpaths :members: :undoc-members: :show-inheritance: :mod:`prepared_query` Module ---------------------------- .. automodule:: examples.prepared_query :members: :undoc-members: :show-inheritance: :mod:`resource` Module ---------------------- .. automodule:: examples.resource :members: :undoc-members: :show-inheritance: :mod:`rdfa_example` Module ---------------------- .. automodule:: examples.rdfa_example :members: :undoc-members: :show-inheritance: :mod:`simple_example` Module ---------------------------- .. automodule:: examples.simple_example :members: :undoc-members: :show-inheritance: :mod:`sleepycat_example` Module ----------------------------------- .. automodule:: examples.sleepycat_example :members: :undoc-members: :show-inheritance: :mod:`slice` Module ------------------- .. automodule:: examples.slice :members: :undoc-members: :show-inheritance: :mod:`smushing` Module ------------------- .. automodule:: examples.smushing :members: :undoc-members: :show-inheritance: :mod:`sparql_query_example` Module ---------------------------------- .. automodule:: examples.sparql_query_example :members: :undoc-members: :show-inheritance: :mod:`sparql_update_example` Module ----------------------------------- .. automodule:: examples.sparql_update_example :members: :undoc-members: :show-inheritance: :mod:`sparqlstore_example` Module ----------------------------------- .. automodule:: examples.sparqlstore_example :members: :undoc-members: :show-inheritance: :mod:`swap_primer` Module ------------------------- .. automodule:: examples.swap_primer :members: :undoc-members: :show-inheritance: :mod:`transitive` Module ------------------------ .. automodule:: examples.transitive :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/modules.rst000066400000000000000000000001121232323236500175270ustar00rootroot00000000000000rdflib API docs =============== .. toctree:: :maxdepth: 10 rdflib rdflib-4.1.2/docs/apidocs/rdflib.extras.rst000066400000000000000000000012701232323236500206340ustar00rootroot00000000000000extras Package ============== :mod:`extras` Package --------------------- .. automodule:: rdflib.extras :members: :undoc-members: :show-inheritance: :mod:`cmdlineutils` Module -------------------------- .. automodule:: rdflib.extras.cmdlineutils :members: :undoc-members: :show-inheritance: :mod:`describer` Module ----------------------- .. automodule:: rdflib.extras.describer :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`infixowl` Module ---------------------- .. automodule:: rdflib.extras.infixowl :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyMicrodata.rst000066400000000000000000000012661232323236500247450ustar00rootroot00000000000000pyMicrodata Package =================== :mod:`pyMicrodata` Package -------------------------- .. automodule:: rdflib.plugins.parsers.pyMicrodata :members: :undoc-members: :show-inheritance: :mod:`microdata` Module ----------------------- .. automodule:: rdflib.plugins.parsers.pyMicrodata.microdata :members: :undoc-members: :show-inheritance: :mod:`registry` Module ---------------------- .. automodule:: rdflib.plugins.parsers.pyMicrodata.registry :members: :undoc-members: :show-inheritance: :mod:`utils` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyMicrodata.utils :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyRdfa.extras.rst000066400000000000000000000006221232323236500252160ustar00rootroot00000000000000extras Package ============== :mod:`extras` Package --------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.extras :members: :undoc-members: :show-inheritance: :mod:`httpheader` Module ------------------------ .. automodule:: rdflib.plugins.parsers.pyRdfa.extras.httpheader :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyRdfa.host.rst000066400000000000000000000007461232323236500246740ustar00rootroot00000000000000host Package ============ :mod:`host` Package ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.host :members: :undoc-members: :show-inheritance: :mod:`atom` Module ------------------ .. automodule:: rdflib.plugins.parsers.pyRdfa.host.atom :members: :undoc-members: :show-inheritance: :mod:`html5` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.host.html5 :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyRdfa.rdfs.rst000066400000000000000000000007571232323236500246570ustar00rootroot00000000000000rdfs Package ============ :mod:`rdfs` Package ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.rdfs :members: :undoc-members: :show-inheritance: :mod:`cache` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.rdfs.cache :members: :undoc-members: :show-inheritance: :mod:`process` Module --------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.rdfs.process :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyRdfa.rst000066400000000000000000000032051232323236500237110ustar00rootroot00000000000000pyRdfa Package ============== :mod:`pyRdfa` Package --------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa :members: :undoc-members: :show-inheritance: :mod:`embeddedRDF` Module ------------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.embeddedRDF :members: :undoc-members: :show-inheritance: :mod:`initialcontext` Module ---------------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.initialcontext :members: :undoc-members: :show-inheritance: :mod:`options` Module --------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.options :members: :undoc-members: :show-inheritance: :mod:`parse` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.parse :members: :undoc-members: :show-inheritance: :mod:`property` Module ---------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.property :members: :undoc-members: :show-inheritance: :mod:`state` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.state :members: :undoc-members: :show-inheritance: :mod:`termorcurie` Module ------------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.termorcurie :members: :undoc-members: :show-inheritance: :mod:`utils` Module ------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.utils :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: rdflib.plugins.parsers.pyRdfa.extras rdflib.plugins.parsers.pyRdfa.host rdflib.plugins.parsers.pyRdfa.rdfs rdflib.plugins.parsers.pyRdfa.transform rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.pyRdfa.transform.rst000066400000000000000000000020231232323236500257200ustar00rootroot00000000000000transform Package ================= :mod:`transform` Package ------------------------ .. automodule:: rdflib.plugins.parsers.pyRdfa.transform :members: :undoc-members: :show-inheritance: :mod:`DublinCore` Module ------------------------ .. automodule:: rdflib.plugins.parsers.pyRdfa.transform.DublinCore :members: :undoc-members: :show-inheritance: :mod:`OpenID` Module -------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.transform.OpenID :members: :undoc-members: :show-inheritance: :mod:`lite` Module ------------------ .. automodule:: rdflib.plugins.parsers.pyRdfa.transform.lite :members: :undoc-members: :show-inheritance: :mod:`metaname` Module ---------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.transform.metaname :members: :undoc-members: :show-inheritance: :mod:`prototype` Module ----------------------- .. automodule:: rdflib.plugins.parsers.pyRdfa.transform.prototype :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.plugins.parsers.rst000066400000000000000000000030501232323236500224630ustar00rootroot00000000000000parsers Package =============== :mod:`parsers` Package ---------------------- .. automodule:: rdflib.plugins.parsers :members: :undoc-members: :show-inheritance: :mod:`hturtle` Module --------------------- .. automodule:: rdflib.plugins.parsers.hturtle :members: :undoc-members: :show-inheritance: :mod:`notation3` Module ----------------------- .. automodule:: rdflib.plugins.parsers.notation3 :members: :undoc-members: :show-inheritance: :mod:`nquads` Module -------------------- .. automodule:: rdflib.plugins.parsers.nquads :members: :undoc-members: :show-inheritance: :mod:`nt` Module ---------------- .. automodule:: rdflib.plugins.parsers.nt :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`ntriples` Module ---------------------- .. automodule:: rdflib.plugins.parsers.ntriples :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`rdfxml` Module -------------------- .. automodule:: rdflib.plugins.parsers.rdfxml :members: :undoc-members: :show-inheritance: :mod:`structureddata` Module ---------------------------- .. automodule:: rdflib.plugins.parsers.structureddata :members: :undoc-members: :show-inheritance: :mod:`trix` Module ------------------ .. automodule:: rdflib.plugins.parsers.trix :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: rdflib.plugins.parsers.pyMicrodata rdflib.plugins.parsers.pyRdfa rdflib-4.1.2/docs/apidocs/rdflib.plugins.rst000066400000000000000000000011361232323236500210100ustar00rootroot00000000000000plugins Package =============== :mod:`plugins` Package ---------------------- .. automodule:: rdflib.plugins :members: :undoc-members: :show-inheritance: :mod:`memory` Module -------------------- .. automodule:: rdflib.plugins.memory :members: :undoc-members: :show-inheritance: :mod:`sleepycat` Module ----------------------- .. automodule:: rdflib.plugins.sleepycat :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: rdflib.plugins.parsers rdflib.plugins.serializers rdflib.plugins.sparql rdflib.plugins.stores rdflib-4.1.2/docs/apidocs/rdflib.plugins.serializers.rst000066400000000000000000000023601232323236500233430ustar00rootroot00000000000000serializers Package =================== :mod:`n3` Module ---------------- .. automodule:: rdflib.plugins.serializers.n3 :members: :undoc-members: :show-inheritance: :mod:`nquads` Module -------------------- .. automodule:: rdflib.plugins.serializers.nquads :members: :undoc-members: :show-inheritance: :mod:`nt` Module ---------------- .. automodule:: rdflib.plugins.serializers.nt :members: :undoc-members: :show-inheritance: :mod:`rdfxml` Module -------------------- .. automodule:: rdflib.plugins.serializers.rdfxml :members: :undoc-members: :show-inheritance: :mod:`trig` Module ------------------ .. automodule:: rdflib.plugins.serializers.trig :members: :undoc-members: :show-inheritance: :mod:`trix` Module ------------------ .. automodule:: rdflib.plugins.serializers.trix :members: :undoc-members: :show-inheritance: :mod:`turtle` Module -------------------- .. automodule:: rdflib.plugins.serializers.turtle :members: :undoc-members: :show-inheritance: :mod:`xmlwriter` Module ----------------------- .. automodule:: rdflib.plugins.serializers.xmlwriter :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ rdflib-4.1.2/docs/apidocs/rdflib.plugins.sparql.results.rst000066400000000000000000000020051232323236500240050ustar00rootroot00000000000000results Package =============== :mod:`csvresults` Module ------------------------ .. automodule:: rdflib.plugins.sparql.results.csvresults :members: :undoc-members: :show-inheritance: :mod:`jsonlayer` Module ----------------------- .. automodule:: rdflib.plugins.sparql.results.jsonlayer :members: :undoc-members: :show-inheritance: :mod:`jsonresults` Module ------------------------- .. automodule:: rdflib.plugins.sparql.results.jsonresults :members: :undoc-members: :show-inheritance: :mod:`rdfresults` Module ------------------------ .. automodule:: rdflib.plugins.sparql.results.rdfresults :members: :undoc-members: :show-inheritance: :mod:`tsvresults` Module ------------------------ .. automodule:: rdflib.plugins.sparql.results.tsvresults :members: :undoc-members: :show-inheritance: :mod:`xmlresults` Module ------------------------ .. automodule:: rdflib.plugins.sparql.results.xmlresults :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.plugins.sparql.rst000066400000000000000000000041541232323236500223140ustar00rootroot00000000000000sparql Package ============== :mod:`sparql` Package --------------------- .. automodule:: rdflib.plugins.sparql :members: :undoc-members: :show-inheritance: :mod:`aggregates` Module ------------------------ .. automodule:: rdflib.plugins.sparql.aggregates :members: :undoc-members: :show-inheritance: :mod:`algebra` Module --------------------- .. automodule:: rdflib.plugins.sparql.algebra :members: :undoc-members: :show-inheritance: :mod:`compat` Module -------------------- .. automodule:: rdflib.plugins.sparql.compat :members: :undoc-members: :show-inheritance: :mod:`datatypes` Module ----------------------- .. automodule:: rdflib.plugins.sparql.datatypes :members: :undoc-members: :show-inheritance: :mod:`evaluate` Module ---------------------- .. automodule:: rdflib.plugins.sparql.evaluate :members: :undoc-members: :show-inheritance: :mod:`evalutils` Module ----------------------- .. automodule:: rdflib.plugins.sparql.evalutils :members: :undoc-members: :show-inheritance: :mod:`operators` Module ----------------------- .. automodule:: rdflib.plugins.sparql.operators :members: :undoc-members: :show-inheritance: :mod:`parser` Module -------------------- .. automodule:: rdflib.plugins.sparql.parser :members: :undoc-members: :show-inheritance: :mod:`parserutils` Module ------------------------- .. automodule:: rdflib.plugins.sparql.parserutils :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`processor` Module ----------------------- .. automodule:: rdflib.plugins.sparql.processor :members: :undoc-members: :show-inheritance: :mod:`sparql` Module -------------------- .. automodule:: rdflib.plugins.sparql.sparql :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`update` Module -------------------- .. automodule:: rdflib.plugins.sparql.update :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: rdflib.plugins.sparql.results rdflib-4.1.2/docs/apidocs/rdflib.plugins.stores.rst000066400000000000000000000016031232323236500223250ustar00rootroot00000000000000stores Package ============== :mod:`stores` Package --------------------- .. automodule:: rdflib.plugins.stores :members: :undoc-members: :show-inheritance: :mod:`auditable` Module ----------------------- .. automodule:: rdflib.plugins.stores.auditable :members: :undoc-members: :show-inheritance: :mod:`concurrent` Module ------------------------ .. automodule:: rdflib.plugins.stores.concurrent :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`regexmatching` Module --------------------------- .. automodule:: rdflib.plugins.stores.regexmatching :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`sparqlstore` Module ------------------------- .. automodule:: rdflib.plugins.stores.sparqlstore :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/apidocs/rdflib.rst000066400000000000000000000062471232323236500173400ustar00rootroot00000000000000rdflib Package ============== :mod:`rdflib` Package --------------------- .. automodule:: rdflib.__init__ :members: NORMALIZE_LITERALS, DAWG_LITERAL_COLLATION :show-inheritance: :mod:`collection` Module ------------------------ .. automodule:: rdflib.collection :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`compare` Module --------------------- .. automodule:: rdflib.compare :members: :undoc-members: :show-inheritance: :mod:`compat` Module -------------------- .. automodule:: rdflib.compat :members: :undoc-members: :show-inheritance: :mod:`events` Module -------------------- .. automodule:: rdflib.events :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`exceptions` Module ------------------------ .. automodule:: rdflib.exceptions :members: :undoc-members: :show-inheritance: :mod:`graph` Module ------------------- .. automodule:: rdflib.graph :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`namespace` Module ----------------------- .. automodule:: rdflib.namespace :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`parser` Module -------------------- .. automodule:: rdflib.parser :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`paths` Module ------------------- .. automodule:: rdflib.paths :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`plugin` Module -------------------- .. automodule:: rdflib.plugin :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`py3compat` Module ----------------------- .. automodule:: rdflib.py3compat :members: :undoc-members: :show-inheritance: :mod:`query` Module ------------------- .. automodule:: rdflib.query :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ .. autoclass:: ResultRow :members: :mod:`resource` Module ---------------------- .. automodule:: rdflib.resource :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`serializer` Module ------------------------ .. automodule:: rdflib.serializer :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`store` Module ------------------- .. automodule:: rdflib.store :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`term` Module ------------------ .. automodule:: rdflib.term :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`util` Module ------------------ .. automodule:: rdflib.util :members: :undoc-members: :show-inheritance: :mod:`void` Module ------------------ .. automodule:: rdflib.void :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: rdflib.extras rdflib.plugins rdflib.tools rdflib-4.1.2/docs/apidocs/rdflib.tools.rst000066400000000000000000000017761232323236500205010ustar00rootroot00000000000000tools Package ============= These commandline-tools are installed into :samp:`{INSTALL_PREFIX}/bin` by setuptools. :mod:`tools` Package --------------------- .. automodule:: rdflib.tools :members: :undoc-members: :show-inheritance: :mod:`csv2rdf` Module --------------------- .. automodule:: rdflib.tools.csv2rdf :members: :undoc-members: :show-inheritance: :exclude-members: __dict__,__weakref__ :mod:`graphisomorphism` Module ------------------------------ .. automodule:: rdflib.tools.graphisomorphism :members: :undoc-members: :show-inheritance: :mod:`rdf2dot` Module --------------------- .. automodule:: rdflib.tools.rdf2dot :members: :undoc-members: :show-inheritance: :mod:`rdfpipe` Module --------------------- .. automodule:: rdflib.tools.rdfpipe :members: :undoc-members: :show-inheritance: :mod:`rdfs2dot` Module ---------------------- .. automodule:: rdflib.tools.rdfs2dot :members: :undoc-members: :show-inheritance: rdflib-4.1.2/docs/conf.py000066400000000000000000000163321232323236500152150ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # rdflib documentation build configuration file, created by # sphinx-quickstart on Fri May 15 15:03:54 2009. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os, re # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.doctest'] extensions = ['sphinx.ext.autodoc', #'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode'] autodoc_default_flags = [ "special-members" ] autosummary_generate = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] #epydoc_mapping = { # '/_static/api/': [r'rdflib\.'], # } # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'rdflib' copyright = u'2009 - 2013, RDFLib Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # Find version. We have to do this because we can't import it in Python 3 until # its been automatically converted in the setup process. def find_version(filename): _version_re = re.compile(r'__version__ = "(.*)"') for line in open(filename): version_match = _version_re.match(line) if version_match: return version_match.group(1) # The full version, including alpha/beta/rc tags. release = find_version('../rdflib/__init__.py') # The short X.Y version. version = re.sub("[0-9]+\\.[0-9]\\..*", "\1", release) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build', 'draft'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'armstrong' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ["_themes", ] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None html_logo = '_static/logo.svg' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'rdflibdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'rdflib.tex', u'rdflib Documentation', u'RDFLib Team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'python': ('http://docs.python.org/2.7', None), } rdflib-4.1.2/docs/developers.rst000066400000000000000000000057271232323236500166260ustar00rootroot00000000000000.. developers: RDFLib developers guide ======================= Introduction ------------ This document describes the process and conventions to follow when developing RDFLib code. Please be as Pythonic as possible (:pep:`8`). Code will occasionally be auto-formatted using ``autopep8`` - you can also do this yourself. Any new functionality being added to RDFLib should have doc tests and unit tests. Tests should be added for any functionality being changed that currently does not have any doc tests or unit tests. And all the tests should be run before committing changes to make sure the changes did not break anything. If you add a new cool feature, consider also adding an example in ``./examples`` Running tests ------------- Run tests with `nose `_: .. code-block: bash $ easy_install nose $ python run_tests.py $ python run_tests.py --attr known_issue # override attr in setup.cfg to run only tests marked with "known_issue" $ python run_tests.py --attr \!known_issue # runs all tests (including "slow" and "non_core") except those with known issues $ python run_tests.py --attr slow,!known_issue # comma separate if you want to specify more than one attr $ python run_tests.py --attr known_issue=None # use =None instead of \! if you keep forgetting to escape the ! in shell commands ;) Specific tests can either be run by module name or file name. For example:: $ python run_tests.py --tests rdflib.graph $ python run_tests.py --tests test/test_graph.py Writing documentation --------------------- We use sphinx for generating HTML docs, see :ref:`docs` Continous Integration --------------------- We used Travis for CI, see: https://travis-ci.org/RDFLib/rdflib If you make a pull-request to RDFLib on GitHub, travis will automatically test you code. Compatibility ------------- RDFLib>=3.X tries to be compatible with python versions 2.5 - 3 Some of the limitations we've come across: * Python 2.5/2.6 has no abstract base classes from collections, such ``MutableMap``, etc. * 2.5/2.6 No skipping tests using :mod:`unittest`, i.e. ``TestCase.skipTest`` and decorators are missing => use nose instead * no ``str.decode('string-escape')`` in py3 * no :mod:`json` module in 2.5 (install ``simplejson`` instead) * no ``ordereddict`` in 2.5/2.6 (install ``ordereddict`` module) * :class:`collections.Counter` was added in 2.6 Releasing --------- Set to-be-released version number in :file:`rdflib/__init__.py` Add :file:`CHANGELOG` entry. Commit this change, and tag it with:: git tag -a -m 'tagged version' X.X.X When pushing, remember to do:: git push --tags Upload tarball to pypi with:: python setup.py sdist upload Set new dev version number in the above locations, i.e. next release `-dev`: ``8.9.2-dev`` and commit again. Update the topic of #rdflib on freenode irc:: /msg ChanServ topic #rdflib https://github.com/RDFLib/rdflib | latest stable version: 4.0.1 | docs: http://readthedocs.org/docs/rdflib rdflib-4.1.2/docs/docs.rst000066400000000000000000000025351232323236500154000ustar00rootroot00000000000000.. _docs: ================================ Writing RDFLib Documentation ================================ The docs are generated with Sphinx. Sphinx makes it very easy to pull in doc-strings from modules, classes, methods, etc. When writing doc-strings, special reST fields can be used to annotate parameters, return-types, etc. This make for pretty API docs: http://sphinx-doc.org/domains.html?highlight=param#info-field-lists Building -------- To build you must have the `sphinx` package installed: .. code-block:: bash pip install sphinx Then you can do: .. code-block:: bash python setup.py build_sphinx The docs will be generated in :file:`build/sphinx/html/` Syntax highlighting ------------------- To get N3 and SPARQL syntax highlighting do: .. code-block:: bash pip install -e git+git://github.com/gjhiggins/sparql_pygments_lexer.git#egg=SPARQL_Pygments_Lexer pip install -e git+git://github.com/gjhiggins/n3_pygments_lexer.git#egg=Notation3_Pygments_Lexer API Docs -------- API Docs are automatically generated with ``sphinx-apidoc``: .. code-block:: bash sphinx-apidoc -f -d 10 -o docs/apidocs/ rdflib examples (then ``rdflib.rst`` was tweaked manually to not include all convenience imports that are directly in the ``rdflib/__init__.py``) Tables ------ The tables in ``plugin_*.rst`` were generated with ``plugintable.py`` rdflib-4.1.2/docs/faq.rst000066400000000000000000000032541232323236500152160ustar00rootroot00000000000000============================================= Frequently Asked Questions about using RDFLib ============================================= Questions about parsing ======================= Questions about manipulating ============================ Questions about serializing =========================== Which serialization method is the most efficient? ================================================= Currently, the "nt" output format uses the most efficient serialization; "rdf/xml" should also be efficient. You can serialize to these formats using code similar to the following:: myGraph.serialize(target_nt, format="nt") myGraph.serialize(target_rdfxml, format="xml") How can I use some of the abbreviated RDF/XML syntax? ===================================================== Use the "pretty-xml" `format` argument to the `serialize` method:: myGraph.serialize(target_pretty, format="pretty-xml") How can I control the binding of prefixes to XML namespaces when using RDF/XML? =============================================================================== Each graph comes with a `NamespaceManager`__ instance in the `namespace_manager` field; you can use the `bind` method of this instance to bind a prefix to a namespace URI:: myGraph.namespace_manager.bind('prefix', URIRef('scheme:my-namespace-uri:')) __ http://rdflib.net/rdflib-2.4.0/html/public/rdflib.syntax.NamespaceManager.NamespaceManager-class.html Does RDFLib support serialization to the `TriX`__ format? ========================================================= Yes, both parsing and serialising is supported:: graph.serialize(format="trix") and graph.load(source, format="trix") __ http://www.w3.org/2004/03/trix/ rdflib-4.1.2/docs/gettingstarted.rst000066400000000000000000000060271232323236500175000ustar00rootroot00000000000000.. _gettingstarted: =============================== Getting started with RDFLib =============================== Installation ============ RDFLib is open source and is maintained in a `GitHub `_ repository. RDFLib releases, current and previous are listed on `PyPi `_ The best way to install RDFLib is to use ``easy_install`` or ``pip``: .. code-block :: bash $ easy_install rdflib Support is available through the rdflib-dev group: http://groups.google.com/group/rdflib-dev and on the IRC channel `#rdflib `_ on the freenode.net server The primary interface that RDFLib exposes for working with RDF is a :class:`~rdflib.graph.Graph`. The package uses various Python idioms that offer an appropriate way to introduce RDF to a Python programmer who hasn't worked with RDF before. RDFLib graphs are not sorted containers; they have ordinary ``set`` operations (e.g. :meth:`~rdflib.Graph.add` to add a triple) plus methods that search triples and return them in arbitrary order. RDFLib graphs also redefine certain built-in Python methods in order to behave in a predictable way; they `emulate container types `_ and are best thought of as a set of 3-item triples: .. code-block:: text [ (subject, predicate, object), (subject1, predicate1, object1), ... (subjectN, predicateN, objectN) ] A tiny usage example: .. code-block:: python import rdflib g = rdflib.Graph() result = g.parse("http://www.w3.org/People/Berners-Lee/card") print("graph has %s statements." % len(g)) # prints graph has 79 statements. for subj, pred, obj in g: if (subj, pred, obj) not in g: raise Exception("It better be!") s = g.serialize(format='n3') A more extensive example: .. code-block:: python from rdflib import Graph, Literal, BNode, Namespace, RDF, URIRef from rdflib.namespace import DC, FOAF g = Graph() # Create an identifier to use as the subject for Donna. donna = BNode() # Add triples using store's add method. g.add( (donna, RDF.type, FOAF.Person) ) g.add( (donna, FOAF.nick, Literal("donna", lang="foo")) ) g.add( (donna, FOAF.name, Literal("Donna Fales")) ) g.add( (donna, FOAF.mbox, URIRef("mailto:donna@example.org")) ) # Iterate over triples in store and print them out. print("--- printing raw triples ---") for s, p, o in g: print((s, p, o)) # For each foaf:Person in the store print out its mbox property. print("--- printing mboxes ---") for person in g.subjects(RDF.type, FOAF.Person): for mbox in g.objects(person, FOAF.mbox): print(mbox) # Bind a few prefix, namespace pairs for more readable output g.bind("dc", DC) g.bind("foaf", FOAF) print( g.serialize(format='n3') ) Many more :doc:`examples ` can be found in the :file:`examples` folder in the source distribution. rdflib-4.1.2/docs/index.rst000066400000000000000000000052351232323236500155570ustar00rootroot00000000000000.. rdflib documentation documentation master file ================ rdflib |release| ================ RDFLib is a pure Python package work working with `RDF `_. RDFLib contains most things you need to work with RDF, including: * parsers and serializers for RDF/XML, N3, NTriples, N-Quads, Turtle, TriX, RDFa and Microdata. * a Graph interface which can be backed by any one of a number of Store implementations. * store implementations for in memory storage and persistent storage on top of the Berkeley DB. * a SPARQL 1.1 implementation - supporting SPARQL 1.1 Queries and Update statements. Getting started --------------- If you never used RDFLib, click through these .. toctree:: :maxdepth: 1 gettingstarted intro_to_parsing intro_to_creating_rdf intro_to_graphs intro_to_sparql utilities RDFLib examples In depth -------- If you already worked with RDF and need to know the peculiarities of RDFLib, these are for you. .. toctree:: :maxdepth: 1 rdf_terms namespaces_and_bindings persistence merging upgrade3to4 upgrade2to3 faq Reference --------- The nitty-gritty details of everything. .. toctree:: :maxdepth: 2 plugins .. toctree:: :maxdepth: 1 apidocs/modules * :ref:`genindex` * :ref:`modindex` For developers -------------- .. toctree:: :maxdepth: 1 developers docs univrdfstore persisting_n3_terms Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. glossary:: functional properties A functional property is a property that can have only one (unique) value y for each instance x, i.e. there cannot be two distinct values y1 and y2 such that the pairs (x,y1) and (x,y2) are both instances of this property. -- http://www.w3.org/TR/owl-ref/#FunctionalProperty-def graph An RDF graph is a set of RDF triples. The set of nodes of an RDF graph is the set of subjects and objects of triples in the graph. named graph Named Graphs is the idea that having multiple RDF graphs in a single document/repository and naming them with URIs provides useful additional functionality. -- http://www.w3.org/2004/03/trix/ transitivity A property is transitive: if whenever an element ``a`` is related to an element ``b``, and ``b`` is in turn related to an element ``c``, then ``a`` is also related to ``c``. -- http://en.wikipedia.org/wiki/Transitive_relation Standard examples include ``rdfs:subClassOf`` or greater-than rdflib-4.1.2/docs/intro_to_creating_rdf.rst000066400000000000000000000110031232323236500210020ustar00rootroot00000000000000.. _intro_to_creating_rdf: ==================== Creating RDF triples ==================== Creating Nodes -------------- RDF is a graph where the nodes are URI references, Blank Nodes or Literals, in RDFLib represented by the classes :class:`~rdflib.term.URIRef`, :class:`~rdflib.term.BNode`, and :class:`~rdflib.term.Literal`. ``URIRefs`` and ``BNodes`` can both be thought of as resources, such a person, a company, a web-site, etc. A ``BNode`` is a node where the exact URI is not known. ``URIRefs`` are also used to represent the properties/predicates in the RDF graph. ``Literals`` represent attribute values, such as a name, a date, a number, etc. Nodes can be created by the constructors of the node classes:: from rdflib import URIRef, BNode, Literal bob = URIRef("http://example.org/people/Bob") linda = BNode() # a GUID is generated name = Literal('Bob') # passing a string age = Literal(24) # passing a python int height = Literal(76.5) # passing a python float Literals can be created from python objects, this creates ``data-typed literals``, for the details on the mapping see :ref:`rdflibliterals`. For creating many ``URIRefs`` in the same ``namespace``, i.e. URIs with the same prefix, RDFLib has the :class:`rdflib.namespace.Namespace` class:: from rdflib import Namespace n = Namespace("http://example.org/people/") n.bob # = rdflib.term.URIRef(u'http://example.org/people/bob') n.eve # = rdflib.term.URIRef(u'http://example.org/people/eve') This is very useful for schemas where all properties and classes have the same URI prefix, RDFLib pre-defines Namespaces for the most common RDF schemas:: from rdflib.namespace import RDF, FOAF RDF.type # = rdflib.term.URIRef(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') FOAF.knows # = rdflib.term.URIRef(u'http://xmlns.com/foaf/0.1/knows') Adding Triples -------------- We already saw in :doc:`intro_to_parsing`, how triples can be added with with the :meth:`~rdflib.graph.Graph.parse` function. Triples can also be added with the :meth:`~rdflib.graph.Graph.add` function: .. automethod:: rdflib.graph.Graph.add :noindex: :meth:`~rdflib.graph.Graph.add` takes a 3-tuple of RDFLib nodes. Try the following with the nodes and namespaces we defined previously:: from rdflib import Graph g = Graph() g.add( (bob, RDF.type, FOAF.Person) ) g.add( (bob, FOAF.name, name) ) g.add( (bob, FOAF.knows, linda) ) g.add( (linda, RDF.type, FOAF.Person) ) g.add( (linda, FOAF.name, Literal('Linda') ) ) print g.serialize(format='turtle') outputs: .. code-block:: n3 @prefix foaf: . @prefix rdf: . @prefix rdfs: . @prefix xml: . a foaf:Person ; foaf:knows [ a foaf:Person ; foaf:name "Linda" ] ; foaf:name "Bob" . For some properties, only one value per resource makes sense (i.e they are *functional properties*, or have max-cardinality of 1). The :meth:`~rdflib.graph.Graph.set` method is useful for this: .. code-block:: python g.add( ( bob, FOAF.age, Literal(42) ) ) print "Bob is ", g.value( bob, FOAF.age ) # prints: Bob is 42 g.set( ( bob, age, Literal(43) ) ) # replaces 42 set above print "Bob is now ", g.value( bob, FOAF.age ) # prints: Bob is now 43 :meth:`rdflib.graph.Graph.value` is the matching query method, it will return a single value for a property, optionally raising an exception if there are more. You can also add triples by combining entire graphs, see :ref:`graph-setops`. Removing Triples ^^^^^^^^^^^^^^^^ Similarly, triples can be removed by a call to :meth:`~rdflib.graph.Graph.remove`: .. automethod:: rdflib.graph.Graph.remove :noindex: When removing, it is possible to leave parts of the triple unspecified (i.e. passing ``None``), this will remove all matching triples:: g.remove( (bob, None, None) ) # remove all triples about bob An example ^^^^^^^^^^ LiveJournal produces FOAF data for their users, but they seem to use ``foaf:member_name`` for a person's full name. To align with data from other sources, it would be nice to have ``foaf:name`` act as a synonym for ``foaf:member_name`` (a poor man's one-way ``owl:equivalentProperty``): .. code-block:: python from rdflib.namespace import FOAF g.parse("http://danbri.livejournal.com/data/foaf") for s,_,n in g.triples((None, FOAF['member_name'], None)): g.add((s, FOAF['name'], n)) rdflib-4.1.2/docs/intro_to_graphs.rst000066400000000000000000000105241232323236500176460ustar00rootroot00000000000000.. _rdflib_graph: Navigating Graphs ================= Navigating Graphs ================= An RDF Graph is a set of RDF triples, and we try to mirror exactly this in RDFLib, and the graph tries to emulate a container type: Graphs as Iterators ------------------- RDFLib graphs override :meth:`~rdflib.graph.Graph.__iter__` in order to support iteration over the contained triples: .. code-block:: python for subject,predicate,obj in someGraph: if not (subject,predicate,obj) in someGraph: raise Exception("Iterator / Container Protocols are Broken!!") Contains check -------------- Graphs implement :meth:`~rdflib.graph.Graph.__contains__`, so you can check if a triple is in a graph with ``triple in graph`` syntax:: from rdflib import URIRef from rdflib.namespace import RDF bob = URIRef("http://example.org/people/bob") if ( bob, RDF.type, FOAF.Person ) in graph: print "This graph knows that Bob is a person!" Note that this triple does not have to be completely bound:: if (bob, None, None) in graph: print "This graph contains triples about Bob!" .. _graph-setops: Set Operations on RDFLib Graphs ------------------------------- Graphs override several pythons operators: :meth:`~rdflib.graph.Graph.__iadd__`, :meth:`~rdflib.graph.Graph.__isub__`, etc. This supports addition, subtraction and other set-operations on Graphs: ============ ================================================== operation effect ============ ================================================== ``G1 + G2`` return new graph with union ``G1 += G1`` in place union / addition ``G1 - G2`` return new graph with difference ``G1 -= G2`` in place difference / subtraction ``G1 & G2`` intersection (triples in both graphs) ``G1 ^ G2`` xor (triples in either G1 or G2, but not in both) ============ ================================================== .. warning:: Set-operations on graphs assume bnodes are shared between graphs. This may or may not do what you want. See :doc:`merging` for details. Basic Triple Matching --------------------- Instead of iterating through all triples, RDFLib graphs support basic triple pattern matching with a :meth:`~rdflib.graph.Graph.triples` function. This function is a generator of triples that match the pattern given by the arguments. The arguments of these are RDF terms that restrict the triples that are returned. Terms that are :data:`None` are treated as a wildcard. For example:: g.load("some_foaf.rdf") for s,p,o in g.triples( (None, RDF.type, FOAF.Person) ): print "%s is a person"%s for s,p,o in g.triples( (None, RDF.type, None) ): print "%s is a %s"%(s,o) bobgraph = Graph() bobgraph += g.triples( (bob, None, None) ) If you are not interested in whole triples, you can get only the bits you want with the methods :meth:`~rdflib.graph.Graph.objects`, :meth:`~rdflib.graph.Graph.subjects`, :meth:`~rdflib.graph.Graph.predicates`, :meth:`~rdflib.graph.Graph.predicates_objects`, etc. Each take parameters for the components of the triple to constraint:: for person in g.subjects(RDF.type, FOAF.Person): print "%s is a person"%person Finally, for some properties, only one value per resource makes sense (i.e they are *functional properties*, or have max-cardinality of 1). The :meth:`~rdflib.graph.Graph.value` method is useful for this, as it returns just a single node, not a generator:: name = g.value(bob, FOAF.name) # get any name of bob # get the one person that knows bob and raise an exception if more are found mbox = g.value(predicate = FOAF.name, object = bob, any = False) :class:`~rdflib.graph.Graph` methods for accessing triples ----------------------------------------------------------- Here is a list of all convenience methods for querying Graphs: .. automethod:: rdflib.graph.Graph.label :noindex: .. automethod:: rdflib.graph.Graph.preferredLabel :noindex: .. automethod:: rdflib.graph.Graph.triples :noindex: .. automethod:: rdflib.graph.Graph.value :noindex: .. automethod:: rdflib.graph.Graph.subjects :noindex: .. automethod:: rdflib.graph.Graph.objects :noindex: .. automethod:: rdflib.graph.Graph.predicates :noindex: .. automethod:: rdflib.graph.Graph.subject_objects :noindex: .. automethod:: rdflib.graph.Graph.subject_predicates :noindex: .. automethod:: rdflib.graph.Graph.predicate_objects :noindex: rdflib-4.1.2/docs/intro_to_parsing.rst000066400000000000000000000041471232323236500200310ustar00rootroot00000000000000.. _intro_to_parsing: ====================== Loading and saving RDF ====================== Reading an NT file ------------------- RDF data has various syntaxes (``xml``, ``n3``, ``ntriples``, ``trix``, etc) that you might want to read. The simplest format is ``ntriples``, a line-based format. Create the file :file:`demo.nt` in the current directory with these two lines: .. code-block:: n3 . "Hello world" . You need to tell RDFLib what format to parse, use the ``format`` keyword-parameter to :meth:`~rdflib.graph.Graph.parse`, you can pass either a mime-type or the name (a :doc:`list of available parsers ` is available). If you are not sure what format your file will be, you can use :func:`rdflib.util.guess_format` which will guess based on the file extension. In an interactive python interpreter, try this:: from rdflib import Graph g = Graph() g.parse("demo.nt", format="nt") len(g) # prints 2 import pprint for stmt in g: pprint.pprint(stmt) # prints : (rdflib.term.URIRef('http://bigasterisk.com/foaf.rdf#drewp'), rdflib.term.URIRef('http://example.com/says'), rdflib.term.Literal(u'Hello world')) (rdflib.term.URIRef('http://bigasterisk.com/foaf.rdf#drewp'), rdflib.term.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), rdflib.term.URIRef('http://xmlns.com/foaf/0.1/Person')) The final lines show how RDFLib represents the two statements in the file. The statements themselves are just length-3 tuples; and the subjects, predicates, and objects are all rdflib types. Reading remote graphs --------------------- Reading graphs from the net is just as easy:: g.parse("http://bigasterisk.com/foaf.rdf") len(g) # prints 42 The format defaults to ``xml``, which is the common format for .rdf files you'll find on the net. RDFLib will also happily read RDF from any file-like object, i.e. anything with a ``.read`` method. rdflib-4.1.2/docs/intro_to_sparql.rst000066400000000000000000000070511232323236500176650ustar00rootroot00000000000000.. _intro_to_using_sparql: ==================== Querying with SPARQL ==================== Run a Query ^^^^^^^^^^^ The RDFLib comes with an implementation of the `SPARQL 1.1 Query `_ and `SPARQL 1.1 Update `_ languages. Queries can be evaluated against a graph with the :meth:`rdflib.graph.Graph.query` method, and updates with :meth:`rdflib.graph.Graph.update`. The query method returns a :class:`rdflib.query.Result` instance. For SELECT queries, iterating over this return :class:`rdflib.query.ResultRow` instances, each containing a set of variable bindings. For CONSTRUCT/DESCRIBE queries, iterating over the result object gives the triples. For ASK queries, iterating will yield the single boolean answer, or evaluating the result object in a boolean-context (i.e. ``bool(result)``) Continuing the example... .. code-block:: python import rdflib g = rdflib.Graph() # ... add some triples to g somehow ... g.parse("some_foaf_file.rdf") qres = g.query( """SELECT DISTINCT ?aname ?bname WHERE { ?a foaf:knows ?b . ?a foaf:name ?aname . ?b foaf:name ?bname . }""") for row in qres: print("%s knows %s" % row) The results are tuples of values in the same order as your SELECT arguments. Alternatively, the values can be accessed by variable name, either as attributes, or as items: ``row.b`` and ``row["b"]`` is equivalent. .. code-block:: text Timothy Berners-Lee knows Edd Dumbill Timothy Berners-Lee knows Jennifer Golbeck Timothy Berners-Lee knows Nicholas Gibbins Timothy Berners-Lee knows Nigel Shadbolt Dan Brickley knows binzac Timothy Berners-Lee knows Eric Miller Drew Perttula knows David McClosky Timothy Berners-Lee knows Dan Connolly ... As an alternative to using ``PREFIX`` in the SPARQL query, namespace bindings can be passed in with the ``initNs`` kwarg, see :doc:`namespace_and_bindings`. Variables can also be pre-bound, using ``initBindings`` kwarg can be used to pass in a ``dict`` of initial bindings, this is particularly useful for prepared queries, as described below. Prepared Queries ^^^^^^^^^^^^^^^^ RDFLib lets you *prepare* queries before execution, this saves re-parsing and translating the query into SPARQL Algebra each time. The method :meth:`rdflib.plugins.sparql.prepareQuery` takes a query as a string and will return a :class:`rdflib.plugins.sparql.sparql.Query` object. This can then be passed to the :meth:`rdflib.graph.Graph.query` method. The ``initBindings`` kwarg can be used to pass in a ``dict`` of initial bindings: .. code-block:: python q = prepareQuery( 'SELECT ?s WHERE { ?person foaf:knows ?s .}', initNs = { "foaf": FOAF }) g = rdflib.Graph() g.load("foaf.rdf") tim = rdflib.URIRef("http://www.w3.org/People/Berners-Lee/card#i") for row in g.query(q, initBindings={'person': tim}): print row Custom Evaluation Functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ For experts, it is possible to override how bits of SPARQL algebra are evaluated. By using the `setuptools entry-point `_ ``rdf.plugins.sparqleval``, or simply adding to an entry to :data:`rdflib.plugins.sparql.CUSTOM_EVALS`, a custom function can be registered. The function will be called for each algebra component and may raise ``NotImplementedError`` to indicate that this part should be handled by the default implementation. See :file:`examples/custom_eval.py` rdflib-4.1.2/docs/merging.rst000066400000000000000000000043441232323236500161000ustar00rootroot00000000000000.. _merging_graphs: ============== Merging graphs ============== A merge of a set of RDF graphs is defined as follows. If the graphs in the set have no blank nodes in common, then the union of the graphs is a merge; if they do share blank nodes, then it is the union of a set of graphs that is obtained by replacing the graphs in the set by equivalent graphs that share no blank nodes. This is often described by saying that the blank nodes have been 'standardized apart'. It is easy to see that any two merges are equivalent, so we will refer to the merge, following the convention on equivalent graphs. Using the convention on equivalent graphs and identity, any graph in the original set is considered to be a subgraph of the merge. One does not, in general, obtain the merge of a set of graphs by concatenating their corresponding N-Triples documents and constructing the graph described by the merged document. If some of the documents use the same node identifiers, the merged document will describe a graph in which some of the blank nodes have been 'accidentally' identified. To merge N-Triples documents it is necessary to check if the same nodeID is used in two or more documents, and to replace it with a distinct nodeID in each of them, before merging the documents. Similar cautions apply to merging graphs described by RDF/XML documents which contain nodeIDs *(copied directly from http://www.w3.org/TR/rdf-mt/#graphdefs)* In RDFLib, blank nodes are given unique IDs when parsing, so graph merging can be done by simply reading several files into the same graph:: from rdflib import Graph graph = Graph() graph.parse(input1) graph.parse(input2) ``graph`` now contains the merged graph of ``input1`` and ``input2``. .. note:: However, the set-theoretic graph operations in RDFLib are assumed to be performed in sub-graphs of some larger data-base (for instance, in the context of a :class:`~rdflib.graph.ConjunctiveGraph`) and assume shared blank node IDs, and therefore do NOT do *correct* merging, i.e.:: from rdflib import Graph g1 = Graph() g1.parse(input1) g2 = Graph() g2.parse(input2) graph = g1 + g2 May cause unwanted collisions of blank-nodes in ``graph``. rdflib-4.1.2/docs/namespaces_and_bindings.rst000066400000000000000000000035201232323236500212610ustar00rootroot00000000000000.. _namespaces_and_bindings: Namespaces and Bindings ======================= Namespaces and Bindings ======================= RDFLib provides several short-cuts to working with many URIs in the same namespace. The :mod:`rdflib.namespace` defines the :class:`rdflib.namespace.Namespace` class which lets you easily create URIs in a namespace:: from rdflib import Namespace n = Namespace("http://example.org/") n.Person # as attribute # = rdflib.term.URIRef(u'http://example.org/Person') n['first%20name'] # as item - for things that are not valid python identifiers # = rdflib.term.URIRef(u'http://example.org/first%20name') The ``namespace`` module also defines many common namespaces such as RDF, RDFS, OWL, FOAF, SKOS, etc. Namespaces can also be associated with prefixes, in a :class:`rdflib.namespace.NamespaceManager`, i.e. using ``foaf`` for ``http://xmlns.com/foaf/0.1/``. Each RDFLib graph has a :attr:`~rdflib.graph.Graph.namespace_manager` that keeps a list of namespace to prefix mappings. The namespace manager is populated when reading in RDF, and these prefixes are used when serialising RDF, or when parsing SPARQL queries. Additional prefixes can be bound with the :meth:`rdflib.graph.bind` method. Namespaces in SPARQL Queries ---------------------------- The ``initNs`` argument supplied to :meth:`~rdflib.graph.Graph.query` is a dictionary of namespaces to be expanded in the query string. If you pass no ``initNs`` argument, the namespaces registered with the graphs namespace_manager are used:: ... from rdflib.namespace import FOAF graph.query('SELECT * WHERE { ?p a foaf:Person }', initNs={ 'foaf': FOAF }) In order to use an empty prefix (e.g. ``?a :knows ?b``), use a ``PREFIX`` directive with no prefix in the SPARQL query to set a default namespace: .. code-block:: sparql PREFIX : rdflib-4.1.2/docs/persistence.rst000066400000000000000000000050611232323236500167710ustar00rootroot00000000000000.. _persistence: Persistence =========== Persistence =========== RDFLib provides an :class:`abstracted Store API ` for persistence of RDF and Notation 3. The :class:`~rdflib.graph.Graph` class works with instances of this API (as the first argument to its constructor) for triple-based management of an RDF store including: garbage collection, transaction management, update, pattern matching, removal, length, and database management (:meth:`~rdflib.graph.Graph.open` / :meth:`~rdflib.graph.Graph.close` / :meth:`~rdflib.graph.Graph.destroy`). Additional persistence mechanisms can be supported by implementing this API for a different store. Stores currently shipped with core RDFLib ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * :class:`Memory ` (not persistent!) * :class:`~rdflib.plugins.sleepycat.Sleepycat` (on disk persistence via Python's :ref:`bsddb` or :ref:`bsddb3` packages) * :class:`~rdflib.plugins.stores.sparqlstore.SPARQLStore` - a read-only wrapper around a remote SPARQL Query endpoint. * :class:`~rdflib.plugins.stores.sparqlstore.SPARQLUpdateStore` - a read-write wrapper around a remote SPARQL query/update endpoint pair. Usage ^^^^^ Most cases passing the name of the store to the Graph constructor is enough: .. code-block:: python from rdflib import Graph graph = Graph(store='Sleepycat') Most store offering on-disk persistence will need to be opened before reading or writing : .. code-block:: python graph = Graph('Sleepycat') # first time create the store: graph.open('/home/user/data/myRDFLibStore', create = True) # work with the graph: graph.add( mytriples ) # when done! graph.close() When done, :meth:`~rdflib.graph.Graph.close` must be called to free the resources associated with the store. Additional store plugins ^^^^^^^^^^^^^^^^^^^^^^^^ More store implementations are available in RDFLib extension projects: * `rdflib-sqlalchemy `_, which supports stored on a wide-variety of RDBMs backends, * `rdflib-leveldb `_ - a store on to of Google's `LevelDB `_ key-value store. * `rdflib-kyotocabinet `_ - a store on to of the `Kyoto Cabinet `_ key-value store. Example ^^^^^^^ * :mod:`examples.sleepycat_example` contains an example for using a Sleepycat store. * :mod:`examples.sparqlstore_example` contains an example for using a SPARQLStore. rdflib-4.1.2/docs/persisting_n3_terms.rst000066400000000000000000000116661232323236500204560ustar00rootroot00000000000000.. _persisting_n3_terms: =========================== Persisting Notation 3 Terms =========================== Using N3 Syntax for Persistence ------------------------------- Blank Nodes, Literals, URI References, and Variables can be distinguished in persistence by relying on Notation 3 syntax convention. All URI References can be expanded and persisted as: .. code-block:: text <..URI..> All Literals can be expanded and persisted as: .. code-block:: text "..value.."@lang or "..value.."^^dtype_uri .. note:: ``@lang`` is a language tag and ``^^dtype_uri`` is the URI of a data type associated with the Literal Blank Nodes can be expanded and persisted as: .. code-block:: text _:Id .. note:: where Id is an identifier as determined by skolemization. Skolemization is a syntactic transformation routinely used in automatic inference systems in which existential variables are replaced by 'new' functions - function names not used elsewhere - applied to any enclosing universal variables. In RDF, Skolemization amounts to replacing every blank node in a graph by a 'new' name, i.e. a URI reference which is guaranteed to not occur anywhere else. In effect, it gives 'arbitrary' names to the anonymous entities whose existence was asserted by the use of blank nodes: the arbitrariness of the names ensures that nothing can be inferred that would not follow from the bare assertion of existence represented by the blank node. (Using a literal would not do. Literals are never 'new' in the required sense.) Variables can be persisted as they appear in their serialization ``(?varName)`` - since they only need be unique within their scope (the context of their associated statements) These syntactic conventions can facilitate term round-tripping. Variables by Scope ------------------ Would an interface be needed in order to facilitate a quick way to aggregate all the variables in a scope (given by a formula identifier)? An interface such as: .. code-block:: python def variables(formula_identifier) The Need to Skolemize Formula Identifiers ----------------------------------------- It would seem reasonable to assume that a formula-aware store would assign Blank Node identifiers as names of formulae that appear in a N3 serialization. So for instance, the following bit of N3: .. code-block:: text {?x a :N3Programmer} => {?x :has :Migrane} Could be interpreted as the assertion of the following statement: .. code-block:: text _:a log:implies _:b However, how are ``_:a`` and ``_:b`` distinguished from other Blank Nodes? A formula-aware store would be expected to persist the first set of statements as quoted statements in a formula named ``_:a`` and the second set as quoted statements in a formula named ``_:b``, but it would not be cost-effective for a serializer to have to query the store for all statements in a context named ``_:a`` in order to determine if ``_:a`` was associated with a formula (so that it could be serialized properly). Relying on ``log:Formula`` Membership ------------------------------------- The store could rely on explicit ``log:Formula`` membership (via ``rdf:type`` statements) to model the distinction of Blank Nodes associated with formulae. However, would these statements be expected from an N3 parser or known implicitly by the store? i.e., would all such Blank Nodes match the following pattern: .. code-block:: text ?formula rdf:type log:Formula Relying on an Explicit Interface -------------------------------- A formula-aware store could also support the persistence of this distinction by implementing a method that returns an iterator over all the formulae in the store: .. code-block:: python def formulae(triple=None) This function would return all the Blank Node identifiers assigned to formulae or just those that contain statements matching the given triple pattern and would be the way a serializer determines if a term refers to a formula (in order to properly serializer it). How much would such an interface reduce the need to model formulae terms as first class objects (perhaps to be returned by the :meth:`~rdflib.Graph.triple` function)? Would it be more useful for the :class:`~rdflib.Graph` (or the store itself) to return a Context object in place of a formula term (using the formulae interface to make this determination)? Conversely, would these interfaces (variables and formulae) be considered optimizations only since you have the distinction by the kinds of terms triples returns (which would be expanded to include variables and formulae)? Persisting Formula Identifiers ------------------------------ This is the most straight forward way to maintain this distinction - without relying on extra interfaces. Formula identifiers could be persisted distinctly from other terms by using the following notation: .. code-block:: text {_:bnode} or {<.. URI ..>} This would facilitate their persistence round-trip - same as the other terms that rely on N3 syntax to distinguish between each other. rdflib-4.1.2/docs/plugin_parsers.rst000066400000000000000000000033721232323236500175050ustar00rootroot00000000000000.. _plugin_parsers: Plugin parsers ============== Plugin parsers ============== These serializers are available in default RDFLib, you can use them by passing the name to graph's :meth:`~rdflib.graph.Graph.parse` method:: graph.parse(my_url, format='n3') The ``html`` parser will auto-detect RDFa, HTurtle or Microdata. It is also possible to pass a mime-type for the ``format`` parameter:: graph.parse(my_url, format='application/rdf+xml') If you are not sure what format your file will be, you can use :func:`rdflib.util.guess_format` which will guess based on the file extension. ========= ==================================================================== Name Class ========= ==================================================================== html :class:`~rdflib.plugins.parsers.structureddata.StructuredDataParser` hturtle :class:`~rdflib.plugins.parsers.hturtle.HTurtleParser` mdata :class:`~rdflib.plugins.parsers.structureddata.MicrodataParser` microdata :class:`~rdflib.plugins.parsers.structureddata.MicrodataParser` n3 :class:`~rdflib.plugins.parsers.notation3.N3Parser` nquads :class:`~rdflib.plugins.parsers.nquads.NQuadsParser` nt :class:`~rdflib.plugins.parsers.nt.NTParser` rdfa :class:`~rdflib.plugins.parsers.structureddata.RDFaParser` rdfa1.0 :class:`~rdflib.plugins.parsers.structureddata.RDFa10Parser` rdfa1.1 :class:`~rdflib.plugins.parsers.structureddata.RDFaParser` trix :class:`~rdflib.plugins.parsers.trix.TriXParser` turtle :class:`~rdflib.plugins.parsers.notation3.TurtleParser` xml :class:`~rdflib.plugins.parsers.rdfxml.RDFXMLParser` ========= ==================================================================== rdflib-4.1.2/docs/plugin_query_results.rst000066400000000000000000000030221232323236500207440ustar00rootroot00000000000000.. _plugin_query_results: Plugin query results ==================== Plugin query results ==================== Plugins for reading and writing of (SPARQL) :class:`~rdflib.query.QueryResult` - pass ``name`` to either :meth:`~rdflib.query.QueryResult.parse` or :meth:`~rdflib.query.QueryResult.serialize` Parsers ------- ==== ==================================================================== Name Class ==== ==================================================================== csv :class:`~rdflib.plugins.sparql.results.csvresults.CSVResultParser` json :class:`~rdflib.plugins.sparql.results.jsonresults.JSONResultParser` tsv :class:`~rdflib.plugins.sparql.results.tsvresults.TSVResultParser` xml :class:`~rdflib.plugins.sparql.results.xmlresults.XMLResultParser` ==== ==================================================================== Serializers ----------- ==== ======================================================================== Name Class ==== ======================================================================== csv :class:`~rdflib.plugins.sparql.results.csvresults.CSVResultSerializer` json :class:`~rdflib.plugins.sparql.results.jsonresults.JSONResultSerializer` txt :class:`~rdflib.plugins.sparql.results.txtresults.TXTResultSerializer` xml :class:`~rdflib.plugins.sparql.results.xmlresults.XMLResultSerializer` ==== ======================================================================== rdflib-4.1.2/docs/plugin_serializers.rst000066400000000000000000000023731232323236500203620ustar00rootroot00000000000000.. _plugin_serializers: Plugin serializers ================== Plugin serializers ================== These serializers are available in default RDFLib, you can use them by passing the name to a graph's :meth:`~rdflib.graph.Graph.serialize` method:: print graph.serialize(format='n3') It is also possible to pass a mime-type for the ``format`` parameter:: graph.serialize(my_url, format='application/rdf+xml') ========== =============================================================== Name Class ========== =============================================================== n3 :class:`~rdflib.plugins.serializers.n3.N3Serializer` nquads :class:`~rdflib.plugins.serializers.nquads.NQuadsSerializer` nt :class:`~rdflib.plugins.serializers.nt.NTSerializer` pretty-xml :class:`~rdflib.plugins.serializers.rdfxml.PrettyXMLSerializer` trig :class:`~rdflib.plugins.serializers.trig.TrigSerializer` trix :class:`~rdflib.plugins.serializers.trix.TriXSerializer` turtle :class:`~rdflib.plugins.serializers.turtle.TurtleSerializer` xml :class:`~rdflib.plugins.serializers.rdfxml.XMLSerializer` ========== =============================================================== rdflib-4.1.2/docs/plugin_stores.rst000066400000000000000000000015621232323236500173440ustar00rootroot00000000000000.. _plugin_stores: Plugin stores ============= Plugin stores ============= ================= ============================================================ Name Class ================= ============================================================ Auditable :class:`~rdflib.plugins.stores.auditable.AuditableStore` Concurrent :class:`~rdflib.plugins.stores.concurrent.ConcurrentStore` IOMemory :class:`~rdflib.plugins.memory.IOMemory` SPARQLStore :class:`~rdflib.plugins.stores.sparqlstore.SPARQLStore` SPARQLUpdateStore :class:`~rdflib.plugins.stores.sparqlstore.SPARQLUpdateStore` Sleepycat :class:`~rdflib.plugins.sleepycat.Sleepycat` default :class:`~rdflib.plugins.memory.IOMemory` ================= ============================================================ rdflib-4.1.2/docs/plugins.rst000066400000000000000000000007721232323236500161320ustar00rootroot00000000000000 Plugins ======= .. image:: /_static/plugins-diagram.* :alt: rdflib plugin "architecture" :width: 450px :target: _static/plugins-diagram.svg Many parts of RDFLib are extensible with plugins through `setuptools entry-points `_. These pages list the plugins included in RDFLib core. .. toctree:: :maxdepth: 1 plugin_parsers plugin_serializers plugin_stores plugin_query_results rdflib-4.1.2/docs/plugintable.py000066400000000000000000000011231232323236500165660ustar00rootroot00000000000000""" Crappy utility for generating Sphinx tables for rdflib plugins """ import sys from rdflib.plugin import _plugins cls = sys.argv[1] p = {} for (name, kind), plugin in _plugins.items(): if "/" in name: continue # skip duplicate entries for mimetypes if cls == kind.__name__: p[name]="%s.%s"%(plugin.module_path, plugin.class_name) l1=max(len(x) for x in p) l2=max(10+len(x) for x in p.values()) def hr(): print "="*l1,"="*l2 hr() print "%-*s"%(l1,"Name"), "%-*s"%(l2, "Class") hr() for n in sorted(p): print "%-*s"%(l1,n), ":class:`~%s`"%p[n] hr() print rdflib-4.1.2/docs/rdf_terms.rst000066400000000000000000000151401232323236500164310ustar00rootroot00000000000000.. _rdf_terms: RDF terms in rdflib =================== RDF terms in rdflib =================== Terms are the kinds of objects that can appear in a quoted/asserted triples. Those that are part of core RDF concepts are: ``Blank Node``, ``URI Reference`` and ``Literal``, the latter consisting of a literal value and either a `datatype `_ or an :rfc:`3066` language tag. All terms in RDFLib are sub-classes of the :class:`rdflib.term.Identifier` class. Nodes are a subset of the Terms that the underlying store actually persists. The set of such Terms depends on whether or not the store is formula-aware. Stores that aren't formula-aware would only persist those terms core to the RDF Model, and those that are formula-aware would be able to persist the N3 extensions as well. However, utility terms that only serve the purpose for matching nodes by term-patterns probably will only be terms and not nodes. BNodes ====== In RDF, a blank node (also called BNode) is a node in an RDF graph representing a resource for which a URI or literal is not given. The resource represented by a blank node is also called an anonymous resource. By RDF standard a blank node can only be used as subject or object in an RDF triple, although in some syntaxes like Notation 3 [1] it is acceptable to use a blank node as a predicate. If a blank node has a node ID (not all blank nodes are labelled in all RDF serializations), it is limited in scope to a serialization of a particular RDF graph, i.e. the node p1 in the subsequent example does not represent the same node as a node named p1 in any other graph --`wikipedia`__ .. __: http://en.wikipedia.org/wiki/Blank_node .. autoclass:: rdflib.term.BNode :noindex: .. code-block:: python >>> from rdflib import BNode >>> anode = BNode() >>> anode rdflib.term.BNode('AFwALAKU0') >>> anode.n3() u'_:AFwALAKU0' URIRefs ======= A URI reference within an RDF graph is a Unicode string that does not contain any control characters ( #x00 - #x1F, #x7F-#x9F) and would produce a valid URI character sequence representing an absolute URI with optional fragment identifier -- `W3 RDF Concepts`__ .. __: http://www.w3.org/TR/rdf-concepts/#section-Graph-URIref .. autoclass:: rdflib.term.URIRef :noindex: .. code-block:: python >>> from rdflib import URIRef >>> aref = URIRef() Traceback (most recent call last): File "", line 1, in TypeError: __new__() takes at least 2 arguments (1 given) >>> aref = URIRef('') >>> aref rdflib.term.URIRef(u'') >>> aref = URIRef('http://example.com') >>> aref rdflib.term.URIRef(u'http://example.com') >>> aref.n3() u'' .. _rdflibliterals: Literals ======== Literals are the attribute values in RDF, for instance, a person's name, the date of birth, height, etc. Literals can have a data-type (i.e. this is a double) or a language tag (this label is in English). .. autoclass:: rdflib.term.Literal :noindex: A literal in an RDF graph contains one or two named components. All literals have a lexical form being a Unicode string, which SHOULD be in Normal Form C. Plain literals have a lexical form and optionally a language tag as defined by :rfc:`3066`, normalized to lowercase. An exception will be raised if illegal language-tags are passed to :meth:`rdflib.term.Literal.__init__`. Typed literals have a lexical form and a datatype URI being an RDF URI reference. .. note:: When using the language tag, care must be taken not to confuse language with locale. The language tag relates only to human language text. Presentational issues should be addressed in end-user applications. .. note:: The case normalization of language tags is part of the description of the abstract syntax, and consequently the abstract behaviour of RDF applications. It does not constrain an RDF implementation to actually normalize the case. Crucially, the result of comparing two language tags should not be sensitive to the case of the original input. -- `RDF Concepts and Abstract Syntax`__ .. __: http://www.w3.org/TR/rdf-concepts/#section-Graph-URIref Python support -------------- RDFLib Literals essentially behave like unicode characters with an XML Schema datatype or language attribute. .. image:: /_static/datatype_hierarchy.png :alt: datatype hierarchy :align: center :width: 629 :height: 717 The class provides a mechanism to both convert Python literals (and their built-ins such as time/date/datetime) into equivalent RDF Literals and (conversely) convert Literals to their Python equivalent. This mapping to and from Python literals is done as follows: ====================== =========== XML Datatype Python type ====================== =========== None None [#f1]_ xsd:time time [#f2]_ xsd:date date xsd:dateTime datetime xsd:string None xsd:normalizedString None xsd:token None xsd:language None xsd:boolean boolean xsd:decimal Decimal xsd:integer long xsd:nonPositiveInteger int xsd:long long xsd:nonNegativeInteger int xsd:negativeInteger int xsd:int long xsd:unsignedLong long xsd:positiveInteger int xsd:short int xsd:unsignedInt long xsd:byte int xsd:unsignedShort int xsd:unsignedByte int xsd:float float xsd:double float xsd:base64Binary :mod:`base64` xsd:anyURI None rdf:XMLLiteral :class:`xml.dom.minidom.Document` [#f3]_ rdf:HTML :class:`xml.dom.minidom.DocumentFragment` ====================== =========== .. [#f1] plain literals map directly to value space .. [#f2] Date, time and datetime literals are mapped to Python instances using the `isodate `_ package). .. [#f3] this is a bit dirty - by accident the ``html5lib`` parser produces ``DocumentFragments``, and the xml parser ``Documents``, letting us use this to decide what datatype when round-tripping. An appropriate data-type and lexical representation can be found using: .. autofunction:: rdflib.term._castPythonToLiteral and the other direction with .. autofunction:: rdflib.term._castLexicalToPython All this happens automatically when creating ``Literal`` objects by passing Python objects to the constructor, and you never have to do this manually. You can add custom data-types with :func:`rdflib.term.bind`, see also :mod:`examples.custom_datatype` rdflib-4.1.2/docs/sphinx-requirements.txt000066400000000000000000000002531232323236500205040ustar00rootroot00000000000000-e git+git://github.com/gjhiggins/n3_pygments_lexer.git#egg=Notation3_Pygments_Lexer -e git+git://github.com/gjhiggins/sparql_pygments_lexer.git#egg=SPARQL_Pygments_Lexer rdflib-4.1.2/docs/univrdfstore.rst000066400000000000000000000435311232323236500172030ustar00rootroot00000000000000.. _univrdfstore: =============================== A Universal RDF Store Interface =============================== This document attempts to summarize some fundamental components of an RDF store. The motivation is to outline a standard set of interfaces for providing the support needed to persist an `RDF Graph`_ in a way that is universal and not tied to any specific implementation. For the most part, the interface adheres to the core RDF model and uses terminology that is consistent with the RDF Model specifications. However, this suggested interface also extends an RDF store with additional requirements necessary to facilitate those aspects of `Notation 3`_ that go beyond the RDF model to provide a framework for `First Order Predicate Logic`_ processing and persistence. .. _RDF Graph: http://www.w3.org/TR/rdf-concepts/#dfn-rdf-graph .. _Notation 3: http://www.w3.org/2000/10/swap/Primer .. _First Order Predicate Logic: http://en.wikipedia.org/wiki/First-order_predicate_logic Terminology =========== .. topic:: **Context** A named, unordered set of statements (that could also be called a sub-graph). The ``named graph`` `literature`__ and `ontology`__ are relevant to this concept. The term ``context`` could be thought of as either the sub-graph itself or the relationship between an RDF triple and a sub-graph in which it is found (this latter is how the term context is used in the `Notation 3 Design Issues page`_). It is worth noting that the concept of logically grouping `triples`__ within an addressable 'set' or 'subgraph' is just barely beyond the scope of the RDF model. The RDF model defines a graph to be an arbitrary collection of triples and the semantics of these triples --- but doesn't give guidance on how to address such arbitrary collections in a consistent manner. Although a collection of triples can be thought of as a resource itself, the association between a triple and the collection (of which it is a part) is not covered. `Public RDF`_ is an example of an attempt to formally model this relationship - and includes one other unrelated extension: Articulated Text .. __: http://www.w3.org/2004/03/trix/ .. __: http://metacognition.info/Triclops/?xslt=Triclops.xslt&query=type(list(rdfs:Class,owl:Class,rdf:Property))&queryType=Graph&remoteGraph=http://www.w3.org/2004/03/trix/rdfg-1/ .. __: http://www.w3.org/TR/rdf-concepts/#section-triples .. _Notation 3 Design Issues page: http://www.w3.org/DesignIssues/Notation3.html .. _Public RDF: http://laurentszyster.be/blog/public-rdf/ .. topic:: **Conjunctive Graph** This refers to the 'top-level' Graph. It is the aggregation of all the contexts within it and is also the appropriate, absolute boundary for `closed world assumptions`__ / models. This distinction is the low-hanging fruit of RDF along the path to the semantic web and most of its value is in (corporate/enterprise) real-world problems: .. pull-quote:: There are at least two situations where the closed world assumption is used. The first is where it is assumed that a knowledge base contains all relevant facts. This is common in corporate databases. That is, the information it contains is assumed to be complete From a store perspective, closed world assumptions also provide the benefit of better query response times, due to the explicit closed world boundaries. Closed world boundaries can be made transparent by federated queries that assume each :class:`ConjunctiveGraph` is a section of a larger, unbounded universe. So a closed world assumption does not preclude you from an open world assumption. For the sake of persistence, Conjunctive Graphs must be distinguished by identifiers (which may not necessarily be RDF `identifiers`__ or may be an RDF identifier normalized - SHA1/MD5 perhaps - for database naming purposes) that could be referenced to indicate conjunctive queries (queries made across the entire conjunctive graph) or appear as nodes in asserted statements. In this latter case, such statements could be interpreted as being made about the entire 'known' universe. For example: .. code-block:: xml rdf:type :ConjunctiveGraph rdf:type log:Truth :persistedBy :MySQL .. __: http://cs.wwc.edu/~aabyan/Logic/CWA.html .. __: http://www.w3.org/2002/07/rdf-identifer-terminology/ .. topic:: **Quoted Statement** A statement that isn't asserted but is referred to in some manner. Most often, this happens when we want to make a statement about another statement (or set of statements) without necessarily saying these quoted statements (are true). For example: .. code-block:: text Chimezie said "higher-order statements are complicated" Which can be written (in N3) as: .. code-block:: n3 :chimezie :said {:higherOrderStatements rdf:type :complicated} .. topic:: **Formula** A context whose statements are quoted or hypothetical. Context quoting can be thought of as very similar to `reification`__. The main difference is that quoted statements are not asserted or considered as statements of truth about the universe and can be referenced as a group: a hypothetical RDF Graph .. __: http://www.w3.org/TR/rdf-mt/#Reif .. topic:: **Universal Quantifiers / Variables** (relevant references): * OWL `Definition`__ of `SWRL`__. * SWRL/RuleML `Variable`__ .. __: http://www.w3.org/Submission/SWRL/swrl.owl .. __: http://www.w3.org/Submission/SWRL/ .. __: http://www.w3.org/Submission/SWRL/#owls_Variable .. topic:: **Terms** Terms are the kinds of objects that can appear in a quoted/asserted triple. This includes those that are core to RDF: * Blank Nodes * URI References * Literals (which consist of a literal value, datatype and language tag) Those that extend the RDF model into N3: * Formulae * Universal Quantifications (Variables) And those that are primarily for matching against 'Nodes' in the underlying Graph: * REGEX Expressions * Date Ranges * Numerical Ranges .. topic:: **Nodes** Nodes are a subset of the Terms that the underlying store actually persists. The set of such Terms depends on whether or not the store is formula-aware. Stores that aren't formula-aware would only persist those terms core to the RDF Model, and those that are formula-aware would be able to persist the N3 extensions as well. However, utility terms that only serve the purpose for matching nodes by term-patterns probably will only be terms and not nodes. The set of nodes of an RDF graph is the set of subjects and objects of triples in the graph. .. topic:: **Context-aware** An RDF store capable of storing statements within contexts is considered context-aware. Essentially, such a store is able to partition the RDF model it represents into individual, named, and addressable sub-graphs. .. topic:: **Formula-aware** An RDF store capable of distinguishing between statements that are asserted and statements that are quoted is considered formula-aware. Such a store is responsible for maintaining this separation and ensuring that queries against the entire model (the aggregation of all the contexts - specified by not limiting a 'query' to a specifically name context) do not include quoted statements. Also, it is responsible for distinguishing universal quantifiers (variables). .. note:: These 2 additional concepts (formulae and variables) must be thought of as core extensions and distinguishable from the other terms of a triple (for the sake of the persistence round trip - at the very least). It's worth noting that the 'scope' of universal quantifiers (variables) and existential quantifiers (BNodes) is the formula (or context - to be specific) in which their statements reside. Beyond this, a Formula-aware store behaves the same as a Context-aware store. .. topic:: **Conjunctive Query** Any query that doesn't limit the store to search within a named context only. Such a query expects a context-aware store to search the entire asserted universe (the conjunctive graph). A formula-aware store is expected not to include quoted statements when matching such a query. .. topic:: **N3 Round Trip** This refers to the requirements on a formula-aware RDF store's persistence mechanism necessary for it to be properly populated by a N3 parser and rendered as syntax by a N3 serializer. .. topic:: **Transactional Store** An RDF store capable of providing transactional integrity to the RDF operations performed on it. Interpreting Syntax =================== The following `Notation 3 document`__: .. code-block:: text { ?x a :N3Programmer } => { ?x :has [a :Migraine] } Could cause the following statements to be asserted in the store: .. code-block:: text _:a log:implies _:b This statement would be asserted in the partition associated with quoted statements (in a formula named ``_:a``) .. code-block:: n3 ?x rdf:type :N3Programmer Finally, these statements would be asserted in the same partition (in a formula named ``_:b``) .. code-block:: n3 ?x :has _:c _:c rdf:type :Migraine .. __: http://metacognition.info/Triclops/?xslt=Triclops.xslt&query=log:N3Document&queryType=Triple&remoteGraph=http://www.w3.org/2000/10/swap/log# Formulae and Variables as Terms =============================== Formulae and variables are distinguishable from URI references, Literals, and BNodes by the following syntax: .. code-block:: text { .. } - Formula ?x - Variable They must also be distinguishable in persistence to ensure they can be round-tripped. .. note:: There are a number of other issues regarding the :doc:`persisting of N3 terms `_. Database Management =================== An RDF store should provide standard interfaces for the management of database connections. Such interfaces are standard to most database management systems (Oracle, MySQL, Berkeley DB, Postgres, etc..) The following methods are defined to provide this capability (see below for description of the *configuration* string): .. automethod:: rdflib.store.Store.open :noindex: .. automethod:: rdflib.store.Store.close :noindex: .. automethod:: rdflib.store.Store.destroy :noindex: The *configuration* string is understood by the store implementation and represents all the parameters needed to locate an individual instance of a store. This could be similar to an ODBC string or in fact be an ODBC string, if the connection protocol to the underlying database is ODBC. The :meth:`~rdflib.graph.Graph.open` function needs to fail intelligently in order to clearly express that a store (identified by the given configuration string) already exists or that there is no store (at the location specified by the configuration string) depending on the value of ``create``. Triple Interfaces ================= An RDF store could provide a standard set of interfaces for the manipulation, management, and/or retrieval of its contained triples (asserted or quoted): .. module:: rdflib.store .. automethod:: rdflib.store.Store.add :noindex: .. automethod:: rdflib.store.Store.remove :noindex: .. automethod:: rdflib.store.Store.triples :noindex: .. note:: The :meth:`~rdflib.store.Store.triples` method can be thought of as the primary mechanism for producing triples with nodes that match the corresponding terms in the ``(s, p, o)`` term pattern provided. The term pattern ``(None, None, None)`` matches *all* nodes. .. automethod:: rdflib.store.Store.__len__ :noindex: Formula / Context Interfaces ============================ These interfaces work on contexts and formulae (for stores that are formula-aware) interchangeably. .. automethod:: rdflib.graph.ConjunctiveGraph.contexts :noindex: .. automethod:: rdflib.graph.ConjunctiveGraph.remove_context :noindex: Interface Test Cases ==================== Basic ------------------------- Tests parsing, triple patterns, triple pattern removes, size, contextual removes Source Graph ^^^^^^^^^^^^^ .. code-block:: n3 @prefix rdf: . @prefix rdfs: . @prefix : . {:a :b :c; a :foo} => {:a :d :c} . _:foo a rdfs:Class . :a :d :c . Test code ^^^^^^^^^ .. code-block:: python implies = URIRef("http://www.w3.org/2000/10/swap/log#implies") a = URIRef('http://test/a') b = URIRef('http://test/b') c = URIRef('http://test/c') d = URIRef('http://test/d') for s,p,o in g.triples((None,implies,None)): formulaA = s formulaB = o #contexts test assert len(list(g.contexts()))==3 #contexts (with triple) test assert len(list(g.contexts((a,d,c))))==2 #triples test cases assert type(list(g.triples((None,RDF.type,RDFS.Class)))[0][0]) == BNode assert len(list(g.triples((None,implies,None))))==1 assert len(list(g.triples((None,RDF.type,None))))==3 assert len(list(g.triples((None,RDF.type,None),formulaA)))==1 assert len(list(g.triples((None,None,None),formulaA)))==2 assert len(list(g.triples((None,None,None),formulaB)))==1 assert len(list(g.triples((None,None,None))))==5 assert len(list(g.triples((None,URIRef('http://test/d'),None),formulaB)))==1 assert len(list(g.triples((None,URIRef('http://test/d'),None))))==1 #Remove test cases g.remove((None,implies,None)) assert len(list(g.triples((None,implies,None))))==0 assert len(list(g.triples((None,None,None),formulaA)))==2 assert len(list(g.triples((None,None,None),formulaB)))==1 g.remove((None,b,None),formulaA) assert len(list(g.triples((None,None,None),formulaA)))==1 g.remove((None,RDF.type,None),formulaA) assert len(list(g.triples((None,None,None),formulaA)))==0 g.remove((None,RDF.type,RDFS.Class)) #remove_context tests formulaBContext=Context(g,formulaB) g.remove_context(formulaB) assert len(list(g.triples((None,RDF.type,None))))==2 assert len(g)==3 assert len(formulaBContext)==0 g.remove((None,None,None)) assert len(g)==0 Formula and Variables Test -------------------------- Source Graph ^^^^^^^^^^^^ .. code-block:: n3 @prefix rdf: . @prefix rdfs: . @prefix : . {?x a rdfs:Class} => {?x a :Klass} . Test Code ^^^^^^^^^ .. code-block:: python implies = URIRef("http://www.w3.org/2000/10/swap/log#implies") klass = URIRef('http://test/Klass') for s,p,o in g.triples((None,implies,None)): formulaA = s formulaB = o assert type(formulaA) == Formula assert type(formulaB) == Formula for s,p,o in g.triples((None,RDF.type,RDFS.Class)),formulaA): assert type(s) == Variable for s,p,o in g.triples((None,RDF.type,klass)),formulaB): assert type(s) == Variable Transactional Tests ------------------- To be instantiated. Additional Terms to Model ========================= These are a list of additional kinds of RDF terms (all of which are special Literals) * :class:`rdflib.plugins.store.regexmatching.REGEXTerm` - a REGEX string which can be used in any term slot in order to match by applying the Regular Expression to statements in the underlying graph. * Date (could provide some utility functions for date manipulation / serialization, etc..) * DateRange Namespace Management Interfaces =============================== The following namespace management interfaces (defined in Graph) could be implemented in the RDF store. Currently, they exist as stub methods of :class:`~rdflib.store.Store` and are defined in the store subclasses (e.g. :class:`~rdflib.store.IOMemory`): .. automethod:: rdflib.store.Store.bind :noindex: .. automethod:: rdflib.store.Store.prefix :noindex: .. automethod:: rdflib.store.Store.namespace :noindex: .. automethod:: rdflib.store.Store.namespaces :noindex: Open issues =========== Does the Store interface need to have an identifier property or can we keep that at the Graph level? The Store implementation needs a mechanism to distinguish between triples (quoted or asserted) in ConjunctiveGraphs (which are mutually exclusive universes in systems that make closed world assumptions - and queried separately). This is the separation that the store identifier provides. This is different from the name of a context within a ConjunctiveGraph (or the default context of a conjunctive graph). I tried to diagram the logical separation of ConjunctiveGraphs, SubGraphs and QuotedGraphs in this diagram .. image:: _static/ContextHierarchy.png An identifier of ``None`` can be used to indicate the store (aka `all contexts`) in methods such as :meth:`~rdflib.store.Store.triples`, :meth:`~rdflib.store.Store.__len__`, etc. This works as long as we're only dealing with one Conjunctive Graph at a time -- which may not always be the case. Is there any value in persisting terms that lie outside N3 (:class:`rdflib.plugins.store.regexmatching.REGEXTerm`, Date, etc..)? Potentially, not sure yet. Should a conjunctive query always return quads instead of triples? It would seem so, since knowing the context that produced a triple match is an essential aspect of query construction / optimization. Or if having the triples function yield/produce different length tuples is problematic, could an additional - and slightly redundant - interface be introduced?: .. automethod:: rdflib.graph.ConjunctiveGraph.quads :noindex: Stores that weren't context-aware could simply return ``None`` as the 4th item in the produced/yielded tuples or simply not support this interface. rdflib-4.1.2/docs/upgrade2to3.rst000066400000000000000000000041061232323236500166030ustar00rootroot00000000000000.. _upgrade2to3: Upgrading from RDFLib version 2.X to 3.X ======================================== Upgrading from RDFLib version 2.X to 3.X ======================================== Introduction ============ This page details the changes required to upgrade from RDFLib 2.X to 3.X. Some older Linux distributions still ship 2.4.X. If needed, you can also install 2.4 using easy_install/setup tools. Version 3.0 reorganised some packages, and moved non-core parts of rdflib to the `rdfextras project `_ Features moved to rdfextras =========================== * SPARQL Support is now in rdfextras / rdflib-sparql * The RDF Commandline tools are now in rdfextras .. warning:: If you install packages with just distutils - you will need to register the sparql plugins manually - we strongly recommend installing with setuptools or distribute! To register the plugins add this somewhere in your program: .. code-block:: python rdflib.plugin.register('sparql', rdflib.query.Processor, 'rdfextras.sparql.processor', 'Processor') rdflib.plugin.register('sparql', rdflib.query.Result, 'rdfextras.sparql.query', 'SPARQLQueryResult') Unstable features that were removed =================================== The RDBMS back stores (MySQL/PostgreSQL) were removed, but are in the process of being moved to rdfextras. The Redland, SQLite and ZODB stores were all removed. Packages/Classes that were renamed ================================== Previously all packages and classes had colliding names, i.e. both package and the class was called "Graph":: from rdflib.Graph import Graph, ConjunctiveGraph Now all packages are lower-case, i.e:: from rdflib.graph import Graph, ConjunctiveGraph Most classes you need are available from the top level rdflib package:: from rdflib import Graph, URIRef, BNode, Literal Namespace classes for RDF, RDFS, OWL are now directly in the rdflib package, i.e. in 2.4:: from rdflib.RDF import RDFNS as RDF in 3.0:: from rdflib import RDF rdflib-4.1.2/docs/upgrade3to4.rst000066400000000000000000000103331232323236500166040ustar00rootroot00000000000000.. _upgrade3to4: Upgrading from RDFLib version 3.X to 4.X ======================================== Upgrading from RDFLib version 3.X to 4.X ======================================== RDFLib version 4.0 introduced a small number of backwards compatible changes that you should know about when porting code from version 3 or earlier. SPARQL and SPARQLStore are now included in core ----------------------------------------------- For version 4.0 we've merged the SPARQL implementation from ``rdflib-sparql``, the SPARQL(Update)Store from ``rdflib-sparqlstore`` and miscellaneous utilities from ``rdfextras``. If you used any of these previously, everything you need should now be included. Datatyped literals ------------------ We separate lexical and value space operations for datatyped literals. This mainly affects the way datatyped literals are compared. Lexical space comparisons are done by default for ``==`` and ``!=``, meaning the exact lexical representation and the exact data-types have to match for literals to be equal. Value space comparisons are also available through the :meth:`rdflib.term.Identifier.eq` and :meth:`rdflib.term.Identifier.neq` methods, ``< > <= >=`` are also done in value space. Most things now work in a fairly sane and sensible way, if you do not have existing stores/intermediate stored sorted lists, or hash-dependent something-or-other, you should be good to go. Things to watch out for: Literals no longer compare equal across data-types with ```==``` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ i.e. .. code-block:: python >>> Literal(2, datatype=XSD.int) == Literal(2, datatype=XSD.float) False But a new method :meth:`rdflib.term.Identifier.eq` on all Nodes has been introduced, which does semantic equality checking, i.e.: .. code-block:: python >>> Literal(2, datatype=XSD.int).eq(Literal(2, datatype=XSD.float)) True The ``eq`` method is still limited to what data-types map to the same *value space*, i.e. all numeric types map to numbers and will compare, ``xsd:string`` and ``plain literals`` both map to strings and compare fine, but: .. code-block:: python >>> Literal(2, datatype=XSD.int).eq(Literal('2')) False Literals will be normalised according to datatype ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you care about the exact lexical representation of a literal, and not just the value. Either set :data:`rdflib.NORMALIZE_LITERALS` to ``False`` before creating your literal, or pass ``normalize=False`` to the Literal constructor Ordering of literals and nodes has changed ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Comparing literals with ``<, >, <=, >=`` now work same as in SPARQL filter expressions. Greater-than/less-than ordering comparisons are also done in value space, when compatible datatypes are used. Incompatible datatypes are ordered by data-type, or by lang-tag. For other nodes the ordering is ``None < BNode < URIRef < Literal`` Any comparison with non-rdflib Node are ``NotImplemented`` In PY2.X some stable order will be made up by python. In PY3 this is an error. Custom mapping of datatypes to python objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can add new mappings of datatype URIs to python objects using the :func:`rdflib.term.bind` method. This also allows you to specify a constructor for constructing objects from the lexical string representation, and a serialization method for generating a lexical string representation from an object. Minor Changes -------------- * :class:`rdflib.namespace.Namespace` is no longer a sub-class of :class:`rdflib.term.URIRef` this was changed as it makes no sense for a namespace to be a node in a graph, and was causing numerous bug. Unless you do something very special, you should not notice this change. * The identifiers for Graphs are now converted to URIRefs if they are not a :class:`rdflib.term.Node`, i.e. no more graphs with string identifiers. Again, unless you do something quite unusual, you should not notice. * String concatenation with URIRefs now returns URIRefs, not strings:: >>> URIRef("http://example.org/people/") + "Bill" rdflib.term.URIRef(u'http://example.org/people/Bill') This is be convenient, but may cause trouble if you expected a string. rdflib-4.1.2/docs/utilities.rst000066400000000000000000000065351232323236500164670ustar00rootroot00000000000000Utilities and convenience functions =================================== For RDF programming, RDFLib and Python may not execute the fastest, but we try hard to make it the fastest and most convenient way to write! This is a collection of hints and pointers for hassle free RDF-coding. User-friendly labels -------------------- Use :meth:`~rdflib.graph.Graph.label` to quickly look up the RDFS label of something, or better use :meth:`~rdflib.graph.Graph.preferredLabel` to find a label using several different properties (i.e. either ``rdfs:label``, ``skos:preferredLabel``, ``dc:title``, etc.). Functional properties --------------------- Use :meth:`~rdflib.graph.Graph.value` and :meth:`~rdflib.graph.Graph.set` to work with :term:`functional properties`, i.e. properties than can only occur once for a resource. Slicing graphs -------------- Python allows slicing arrays with a ``slice`` object, a triple of ``start``, ``stop`` index and step-size:: >>> range(10)[2:9:3] [2, 5, 8] RDFLib graphs override ``__getitem__`` and we pervert the slice triple to be a RDF triple instead. This lets slice syntax be a shortcut for :meth:`~rdflib.graph.Graph.triples`, :meth:`~rdflib.graph.Graph.subject_predicates`, :meth:`~rdflib.graph.Graph.contains`, and other Graph query-methods:: graph[:] # same as iter(graph) graph[bob] # same as graph.predicate_objects(bob) graph[bob : FOAF.knows] # same as graph.objects(bob, FOAF.knows) graph[bob : FOAF.knows : bill] # same as (bob, FOAF.knows, bill) in graph graph[:FOAF.knows] # same as graph.subject_objects(FOAF.knows) ... See :mod:`examples.slice` for a complete example. .. note:: Slicing is convenient for run-once scripts of playing around in the Python ``REPL``. However, since slicing returns tuples of varying length depending on which parts of the slice are bound, you should be careful using it in more complicated programs. If you pass in variables, and they are ``None`` or ``False``, you may suddenly get a generator of different length tuples back than you expect. SPARQL Paths ------------ `SPARQL property paths `_ are possible using overridden operators on URIRefs. See :mod:`examples.foafpaths` and :mod:`rdflib.paths`. Serializing a single term to N3 ------------------------------- For simple output, or simple serialisation, you often want a nice readable representation of a term. All terms have a ``.n3(namespace_manager = None)`` method, which will return a suitable N3 format:: >>> from rdflib import Graph, URIRef, Literal, BNode >>> from rdflib.namespace import FOAF, NamespaceManager >>> person = URIRef('http://xmlns.com/foaf/0.1/Person') >>> person.n3() u'' >>> g = Graph() >>> g.bind("foaf", FOAF) >>> person.n3(g.namespace_manager) u'foaf:Person' >>> l = Literal(2) >>> l.n3() u'"2"^^' >>> l.n3(g.namespace_manager) u'"2"^^xsd:integer' Parsing data from a string -------------------------- You can parse data from a string with the ``data`` param:: graph.parse(data = ' .', format='n3') Commandline-tools ----------------- RDFLib includes a handful of commandline tools, see :mod:`rdflib.tools`. rdflib-4.1.2/examples/000077500000000000000000000000001232323236500145775ustar00rootroot00000000000000rdflib-4.1.2/examples/__init__.py000066400000000000000000000000001232323236500166760ustar00rootroot00000000000000rdflib-4.1.2/examples/conjunctive_graphs.py000066400000000000000000000027671232323236500210600ustar00rootroot00000000000000""" An RDFLib ConjunctiveGraph is an (unamed) aggregation of all the named graphs within a Store. The :meth:`~rdflib.graph.ConjunctiveGraph.get_context` method can be used to get a particular named graph, or triples can be added to the default graph This example shows how to create some named graphs and work with the conjunction of all the graphs. """ from rdflib import Namespace, Literal, URIRef from rdflib.graph import Graph, ConjunctiveGraph from rdflib.plugins.memory import IOMemory if __name__=='__main__': ns = Namespace("http://love.com#") mary = URIRef("http://love.com/lovers/mary#") john = URIRef("http://love.com/lovers/john#") cmary=URIRef("http://love.com/lovers/mary#") cjohn=URIRef("http://love.com/lovers/john#") store = IOMemory() g = ConjunctiveGraph(store=store) g.bind("love",ns) gmary = Graph(store=store, identifier=cmary) gmary.add((mary, ns['hasName'], Literal("Mary"))) gmary.add((mary, ns['loves'], john)) gjohn = Graph(store=store, identifier=cjohn) gjohn.add((john, ns['hasName'], Literal("John"))) #enumerate contexts for c in g.contexts(): print("-- %s " % c) #separate graphs print(gjohn.serialize(format='n3')) print("===================") print(gmary.serialize(format='n3')) print("===================") #full graph print(g.serialize(format='n3')) # query the conjunction of all graphs print 'Mary loves:' for x in g[mary : ns.loves/ns.hasName]: print x rdflib-4.1.2/examples/custom_datatype.py000066400000000000000000000016361232323236500203640ustar00rootroot00000000000000""" RDFLib can map between data-typed literals and python objects. Mapping for integers, floats, dateTimes, etc. are already added, but you can also add your own. This example shows how :meth:`rdflib.term.bind` lets you register new mappings between literal datatypes and python objects """ from rdflib import Graph, Literal, Namespace, XSD from rdflib.term import bind if __name__=='__main__': # complex numbers are not registered by default # no custom constructor/serializer needed since # complex('(2+3j)') works fine bind(XSD.complexNumber, complex) ns=Namespace("urn:my:namespace:") c=complex(2,3) l=Literal(c) g=Graph() g.add((ns.mysubject, ns.myprop, l)) n3=g.serialize(format='n3') # round-trip through n3 g2=Graph() g2.parse(data=n3, format='n3') l2=list(g2)[0][2] print l2 print l2.value == c # back to a python complex object rdflib-4.1.2/examples/custom_eval.py000066400000000000000000000033111232323236500174700ustar00rootroot00000000000000""" This example shows how a custom evaluation function can be added to handle certain SPARQL Algebra elements A custom function is added that adds ``rdfs:subClassOf`` "inference" when asking for ``rdf:type`` triples. Here the custom eval function is added manually, normally you would use setuptools and entry_points to do it: i.e. in your setup.py:: entry_points = { 'rdf.plugins.sparqleval': [ 'myfunc = mypackage:MyFunction', ], } """ import rdflib from rdflib.plugins.sparql.evaluate import evalBGP from rdflib.namespace import FOAF inferredSubClass = \ rdflib.RDFS.subClassOf * '*' # any number of rdfs.subClassOf def customEval(ctx, part): """ Rewrite triple patterns to get super-classes """ if part.name == 'BGP': # rewrite triples triples = [] for t in part.triples: if t[1] == rdflib.RDF.type: bnode = rdflib.BNode() triples.append((t[0], t[1], bnode)) triples.append((bnode, inferredSubClass, t[2])) else: triples.append(t) # delegate to normal evalBGP return evalBGP(ctx, triples) raise NotImplementedError() if __name__=='__main__': # add function directly, normally we would use setuptools and entry_points rdflib.plugins.sparql.CUSTOM_EVALS['exampleEval'] = customEval g = rdflib.Graph() g.load("foaf.rdf") # Add the subClassStmt so that we can query for it! g.add((FOAF.Person, rdflib.RDFS.subClassOf, FOAF.Agent)) # Find all FOAF Agents for x in g.query( 'PREFIX foaf: <%s> SELECT * WHERE { ?s a foaf:Agent . }' % FOAF): print x rdflib-4.1.2/examples/film.py000066400000000000000000000121661232323236500161060ustar00rootroot00000000000000#!/usr/bin/env python """ film.py: a simple tool to manage your movies review Simon Rozet, http://atonie.org/ @@ : - manage directors and writers - manage actors - handle non IMDB uri - markdown support in comment Requires download and import of Python imdb library from http://imdbpy.sourceforge.net/ - (warning: installation will trigger automatic installation of several other packages) -- Usage: film.py whoami "John Doe " Initialize the store and set your name and email. film.py whoami Tell you who you are film.py http://www.imdb.com/title/tt0105236/ Review the movie "Reservoir Dogs" """ import datetime, os, sys, re, time try: import imdb except ImportError: imdb = None from rdflib import BNode, ConjunctiveGraph, URIRef, Literal, Namespace, RDF from rdflib.namespace import FOAF, DC storefn = os.path.expanduser('~/movies.n3') #storefn = '/home/simon/codes/film.dev/movies.n3' storeuri = 'file://'+storefn title = 'Movies viewed by %s' r_who = re.compile('^(.*?) <([a-z0-9_-]+(\.[a-z0-9_-]+)*@[a-z0-9_-]+(\.[a-z0-9_-]+)+)>$') IMDB = Namespace('http://www.csd.abdn.ac.uk/~ggrimnes/dev/imdb/IMDB#') REV = Namespace('http://purl.org/stuff/rev#') class Store: def __init__(self): self.graph = ConjunctiveGraph() if os.path.exists(storefn): self.graph.load(storeuri, format='n3') self.graph.bind('dc', DC) self.graph.bind('foaf', FOAF) self.graph.bind('imdb', IMDB) self.graph.bind('rev', 'http://purl.org/stuff/rev#') def save(self): self.graph.serialize(storeuri, format='n3') def who(self, who=None): if who is not None: name, email = (r_who.match(who).group(1), r_who.match(who).group(2)) self.graph.add((URIRef(storeuri), DC['title'], Literal(title % name))) self.graph.add((URIRef(storeuri+'#author'), RDF.type, FOAF['Person'])) self.graph.add((URIRef(storeuri+'#author'), FOAF['name'], Literal(name))) self.graph.add((URIRef(storeuri+'#author'), FOAF['mbox'], Literal(email))) self.save() else: return self.graph.objects(URIRef(storeuri+'#author'), FOAF['name']) def new_movie(self, movie): movieuri = URIRef('http://www.imdb.com/title/tt%s/' % movie.movieID) self.graph.add((movieuri, RDF.type, IMDB['Movie'])) self.graph.add((movieuri, DC['title'], Literal(movie['title']))) self.graph.add((movieuri, IMDB['year'], Literal(int(movie['year'])))) self.save() def new_review(self, movie, date, rating, comment=None): review = BNode() # @@ humanize the identifier (something like #rev-$date) movieuri = URIRef('http://www.imdb.com/title/tt%s/' % movie.movieID) self.graph.add((movieuri, REV['hasReview'], URIRef('%s#%s' % (storeuri, review)))) self.graph.add((review, RDF.type, REV['Review'])) self.graph.add((review, DC['date'], Literal(date))) self.graph.add((review, REV['maxRating'], Literal(5))) self.graph.add((review, REV['minRating'], Literal(0))) self.graph.add((review, REV['reviewer'], URIRef(storeuri+'#author'))) self.graph.add((review, REV['rating'], Literal(rating))) if comment is not None: self.graph.add((review, REV['text'], Literal(comment))) self.save() def movie_is_in(self, uri): return (URIRef(uri), RDF.type, IMDB['Movie']) in self.graph def help(): print(__doc__.split('--')[1]) def main(argv=None): if not argv: argv = sys.argv s = Store() if argv[1] in ('help', '--help', 'h', '-h'): help() elif argv[1] == 'whoami': if os.path.exists(storefn): print(list(s.who())[0]) else: s.who(argv[2]) elif argv[1].startswith('http://www.imdb.com/title/tt'): if s.movie_is_in(argv[1]): raise else: i = imdb.IMDb() movie = i.get_movie(argv[1][len('http://www.imdb.com/title/tt'):-1]) print('%s (%s)' % (movie['title'].encode('utf-8'), movie['year'])) for director in movie['director']: print('directed by: %s' % director['name'].encode('utf-8')) for writer in movie['writer']: print('written by: %s' % writer['name'].encode('utf-8')) s.new_movie(movie) rating = None while not rating or (rating > 5 or rating <= 0): try: rating = int(raw_input('Rating (on five): ')) except ValueError: rating = None date = None while not date: try: i = raw_input('Review date (YYYY-MM-DD): ') date = datetime.datetime(*time.strptime(i, '%Y-%m-%d')[:6]) except: date = None comment = raw_input('Comment: ') s.new_review(movie, date, rating, comment) else: help() if __name__ == '__main__': if not imdb: raise Exception('This example requires the IMDB library! Install with "pip install imdbpy"') main() rdflib-4.1.2/examples/foaf.rdf000066400000000000000000000513761232323236500162230ustar00rootroot00000000000000 W3C Standards and Technical Reports Tim Berners-Lee's FOAF file Coralie Mercier 6de4ff27ef927b9ba21ccc88257e41a2d7e7d293 Dean Jackson Edd Dumbill edd Libby Miller Susie Stephens Henry Story John Gage John Klensin John Markoff John Seely Brown Tim Bray JoeJoe Lambda Robert Hoffmann timbl's blog Daniel Krech Christoph Bussler Nicholas Gibbins Wendy Hall Nigel Shadbolt Les Carr Sean Palmer Charles McCathieNevile 70c053d15de49ff03a1bcc374e4119b40798a66e Håkon Wium Lie Kingsley Idehen Norman Walsh Oshani Seneviratne Lalana Kagal Peter Szolovits Simon J. Hernandez Tom Ilube Henrik Nielsen Ira Fuchs Philippe Le Hégaret mc schraefel Shinnyih Huang Identity, Reference and the Web workshop 2006 Aaron Swartz Lee Feigenbaum Jim Hendler Dave Beckett The Next Wave of the Web (Plenary Panel) Yolanda Gill 5ac8032d5f6012aa1775ea2f63e1676bafd5e80b c21b7ed00d78a35efcd8e567f8fd9cca71058c5 eccd01ba8ce2391a439e9b052a9fbf37eae9f732 Ivan Herman Kjetil Kjernsmo Ora Lassila Bijan Parsia Jennifer Golbeck Amy van der Hiel van der Hiel Amy 1839a1cc2e719a85ea7d9007f587b2899cd94064 Amy van der Hiel Tim Berners-Lee 669fe353dbef63d12ba11f69ace8acbec1ac8b17 Danny Ayers Dan Connolly DanCon Eric Miller Ian Jacobs 032c319f439f63efba54f4fa51bfb3a3fafedfbe Daniel J Weitzner Karl Dubost W3C World Wide Web Consortium Weaving the Web: The Original Design and Ultimate Destiny of the World Wide Web rdflib-4.1.2/examples/foafpaths.py000066400000000000000000000022021232323236500171200ustar00rootroot00000000000000""" SPARQL 1.1 defines path operators for combining/repeating predicates in triple-patterns. We overload some python operators on URIRefs to allow creating path operators directly in python. ============ ========================================= Operator Path ============ ========================================= ``p1 / p2`` Path sequence ``p1 | p2`` Path alternative ``p1 * '*'`` chain of 0 or more p's ``p1 * '+'`` chain of 1 or more p's ``p1 * '?'`` 0 or 1 p ``~p1`` p1 inverted, i.e. (s p1 o) <=> (o ~p1 s) ``-p1`` NOT p1, i.e. any property but p1 ============ ========================================= these can then be used in property position for ``s,p,o`` triple queries for any graph method. See the docs for :mod:`rdflib.paths` for the details. This example shows how to get the name of friends with a single query. """ from rdflib import URIRef, Graph from rdflib.namespace import FOAF if __name__=='__main__': g = Graph() g.load("foaf.rdf") tim = URIRef("http://www.w3.org/People/Berners-Lee/card#i") print "Timbl knows:" for o in g.objects(tim, FOAF.knows / FOAF.name): print o rdflib-4.1.2/examples/prepared_query.py000066400000000000000000000012221232323236500201750ustar00rootroot00000000000000 """ SPARQL Queries be prepared (i.e parsed and translated to SPARQL algebra) by the :meth:`rdflib.plugins.sparql.prepareQuery` method. When executing, variables can be bound with the ``initBindings`` keyword parameter """ import rdflib from rdflib.plugins.sparql import prepareQuery from rdflib.namespace import FOAF if __name__=='__main__': q = prepareQuery( 'SELECT ?s WHERE { ?person foaf:knows ?s .}', initNs = { "foaf": FOAF }) g = rdflib.Graph() g.load("foaf.rdf") tim = rdflib.URIRef("http://www.w3.org/People/Berners-Lee/card#i") for row in g.query(q, initBindings={'person': tim}): print row rdflib-4.1.2/examples/rdfa_example.py000066400000000000000000000010011232323236500175700ustar00rootroot00000000000000""" A simple example showing how to process RDFa from the web """ from rdflib import Graph if __name__ == '__main__': g = Graph() g.parse('http://www.worldcat.org/title/library-of-babel/oclc/44089369', format='rdfa') print "Books found:" for row in g.query("""SELECT ?title ?author WHERE { [ a schema:Book ; schema:author [ rdfs:label ?author ] ; schema:name ?title ] FILTER (LANG(?title) = 'en') } """): print "%s by %s"%(row.title, row.author) rdflib-4.1.2/examples/resource.py000066400000000000000000000023561232323236500170060ustar00rootroot00000000000000""" RDFLib has a :class:`~rdflib.resource.Resource` class, for a resource-centric API. A resource acts like a URIRef with an associated graph, and allows quickly adding or querying for triples where this resource is the subject. """ from rdflib import Graph, RDF, RDFS, Literal from rdflib.namespace import FOAF if __name__=='__main__': g = Graph() bob = g.resource('urn:bob') bob.set(RDF.type, FOAF.Person) # .set replaces all other values bob.set(FOAF.name, Literal("Bob")) bill = g.resource('urn:bill') bill.add(RDF.type, FOAF.Person) # add adds to existing values bill.add(RDF.type, FOAF.Agent) bill.set(RDFS.label, Literal("Bill")) bill.add(FOAF.knows, bob) # Resources returned when querying are 'auto-boxed' as resources: print "Bill's friend: ", bill.value(FOAF.knows).value(FOAF.name) # slicing ([] syntax) can also be used: print "Bill knows: ", for friend in bill[FOAF.knows]: print friend[FOAF.name].next(), " " # or even quicker with paths: print "Bill knows: ", for friend in bill[FOAF.knows/FOAF.name]: print friend # setting single properties is also possible: bill[RDFS.label]=Literal("William") print g.serialize(format='n3') rdflib-4.1.2/examples/simple_example.py000066400000000000000000000030321232323236500201530ustar00rootroot00000000000000 from rdflib import Graph, Literal, BNode, RDF from rdflib.namespace import FOAF, DC if __name__=='__main__': store = Graph() # Bind a few prefix, namespace pairs for pretty output store.bind("dc", DC) store.bind("foaf", FOAF) # Create an identifier to use as the subject for Donna. donna = BNode() # Add triples using store's add method. store.add((donna, RDF.type, FOAF.Person)) store.add((donna, FOAF.nick, Literal("donna", lang="foo"))) store.add((donna, FOAF.name, Literal("Donna Fales"))) # Iterate over triples in store and print them out. print "--- printing raw triples ---" for s, p, o in store: print s, p, o # For each foaf:Person in the store print out its mbox property. print "--- printing mboxes ---" for person in store.subjects(RDF.type, FOAF["Person"]): for mbox in store.objects(person, FOAF["mbox"]): print mbox # Serialize the store as RDF/XML to the file donna_foaf.rdf. store.serialize("donna_foaf.rdf", format="pretty-xml", max_depth=3) # Let's show off the serializers print "RDF Serializations:" # Serialize as XML print "--- start: rdf-xml ---" print store.serialize(format="pretty-xml") print "--- end: rdf-xml ---\n" # Serialize as Turtle print "--- start: turtle ---" print store.serialize(format="turtle") print "--- end: turtle ---\n" # Serialize as NTriples print "--- start: ntriples ---" print store.serialize(format="nt") print "--- end: ntriples ---\n" rdflib-4.1.2/examples/sleepycat_example.py000066400000000000000000000031151232323236500206550ustar00rootroot00000000000000""" A simple example showing how to use a Sleepycat store to do on-disk persistence. """ from rdflib import ConjunctiveGraph, Namespace, Literal from rdflib.store import NO_STORE, VALID_STORE from tempfile import mktemp if __name__ == '__main__': path = mktemp() # Open previously created store, or create it if it doesn't exist yet graph = ConjunctiveGraph('Sleepycat') rt = graph.open(path, create=False) if rt == NO_STORE: # There is no underlying Sleepycat infrastructure, create it graph.open(path, create=True) else: assert rt == VALID_STORE, 'The underlying store is corrupt' print 'Triples in graph before add: ', len(graph) # Now we'll add some triples to the graph & commit the changes rdflib = Namespace('http://rdflib.net/test/') graph.bind('test', 'http://rdflib.net/test/') graph.add((rdflib['pic:1'], rdflib.name, Literal('Jane & Bob'))) graph.add((rdflib['pic:2'], rdflib.name, Literal('Squirrel in Tree'))) print 'Triples in graph after add: ', len(graph) # display the graph in RDF/XML print graph.serialize(format='n3') # close when done, otherwise sleepycat will leak lock entries. graph.close() graph = None # reopen the graph graph = ConjunctiveGraph('Sleepycat') graph.open(path, create = False) print 'Triples still in graph: ', len(graph) graph.close() # Clean up the temp folder to remove the Sleepycat database files... import os for f in os.listdir(path): os.unlink(path+'/'+f) os.rmdir(path) rdflib-4.1.2/examples/slice.py000066400000000000000000000012531232323236500162510ustar00rootroot00000000000000""" RDFLib Graphs (and Resources) can be "sliced" with [] syntax This is a short-hand for iterating over triples Combined with SPARQL paths (see ``foafpaths.py``) - quite complex queries can be realised. See :meth:`rdflib.graph.Graph.__getitem__` for details """ from rdflib import Graph, RDF from rdflib.namespace import FOAF if __name__=='__main__': graph = Graph() graph.load("foaf.rdf") for person in graph[: RDF.type : FOAF.Person]: friends = list(graph[person:FOAF.knows * '+'/FOAF.name]) if friends: print "%s's circle of friends:"%graph.value(person, FOAF.name) for name in friends: print name rdflib-4.1.2/examples/smushing.py000066400000000000000000000027741232323236500170200ustar00rootroot00000000000000""" A FOAF smushing example. Filter a graph by normalizing all ``foaf:Persons`` into URIs based on their ``mbox_sha1sum``. Suppose I got two `FOAF `_ documents each talking about the same person (according to ``mbox_sha1sum``) but they each used a :class:`rdflib.term.BNode` for the subject. For this demo I've combined those two documents into one file: This filters a graph by changing every subject with a ``foaf:mbox_sha1sum`` into a new subject whose URI is based on the ``sha1sum``. This new graph might be easier to do some operations on. An advantage of this approach over other methods for collapsing BNodes is that I can incrementally process new FOAF documents as they come in without having to access my ever-growing archive. Even if another ``65b983bb397fb71849da910996741752ace8369b`` document comes in next year, I would still give it the same stable subject URI that merges with my existing data. """ from rdflib import Graph, Namespace from rdflib.namespace import FOAF STABLE = Namespace("http://example.com/person/mbox_sha1sum/") if __name__=='__main__': g = Graph() g.parse("smushingdemo.n3", format="n3") newURI = {} # old subject : stable uri for s,p,o in g.triples((None, FOAF['mbox_sha1sum'], None)): newURI[s] = STABLE[o] out = Graph() out.bind('foaf', FOAF) for s,p,o in g: s = newURI.get(s, s) o = newURI.get(o, o) # might be linked to another person out.add((s,p,o)) print out.serialize(format="n3") rdflib-4.1.2/examples/smushingdemo.n3000066400000000000000000000007521232323236500175470ustar00rootroot00000000000000@prefix foaf: . ## from one document _:p1 a foaf:Person; foaf:mbox_sha1sum "65b983bb397fb71849da910996741752ace8369b"; foaf:nick "mortenf"; foaf:weblog . ## from another document _:p2 a foaf:Person; foaf:mbox_sha1sum "65b983bb397fb71849da910996741752ace8369b"; foaf:nick "mortenf"; foaf:homepage ; foaf:interest . rdflib-4.1.2/examples/sparql_query_example.py000066400000000000000000000014611232323236500214150ustar00rootroot00000000000000 """ SPARQL Query using :meth:`rdflib.graph.Graph.query` The method returns a :class:`~rdflib.query.Result`, iterating over this yields :class:`~rdflib.query.ResultRow` objects The variable bindings can be access as attributes of the row objects For variable names that are not valid python identifiers, dict access (i.e. with ``row[var] / __getitem__``) is also possible. :attr:`~rdflib.query.ResultRow.vars` contains the variables """ import rdflib if __name__=='__main__': g = rdflib.Graph() g.load("foaf.rdf") # the QueryProcessor knows the FOAF prefix from the graph # which in turn knows it from reading the RDF/XML file for row in g.query( 'select ?s where { [] foaf:knows ?s .}'): print row.s # or row["s"] # or row[rdflib.Variable("s")] rdflib-4.1.2/examples/sparql_update_example.py000066400000000000000000000007771232323236500215430ustar00rootroot00000000000000 """ SPARQL Update statements can be applied with :meth:`rdflib.graph.Graph.update` """ import rdflib if __name__=='__main__': g = rdflib.Graph() g.load("foaf.rdf") g.update(''' PREFIX foaf: PREFIX dbpedia: INSERT { ?s a dbpedia:Human . } WHERE { ?s a foaf:Person . } ''') for x in g.subjects( rdflib.RDF.type, rdflib.URIRef('http://dbpedia.org/resource/Human')): print x rdflib-4.1.2/examples/sparqlstore_example.py000066400000000000000000000007121232323236500212430ustar00rootroot00000000000000""" A simple example showing how to use the SPARQLStore """ from rdflib import Graph, URIRef, Namespace if __name__ == '__main__': dbo = Namespace('http://dbpedia.org/ontology/') graph = Graph('SPARQLStore') graph.open("http://dbpedia.org/sparql") pop = graph.value( URIRef("http://dbpedia.org/resource/Berlin"), dbo.populationTotal) print "According to DBPedia Berlin has a population of", pop rdflib-4.1.2/examples/swap_primer.py000066400000000000000000000064301232323236500175040ustar00rootroot00000000000000""" This is a simple primer using some of the example stuff in the Primer on N3: http://www.w3.org/2000/10/swap/Primer """ # Load up RDFLib from rdflib import ConjunctiveGraph, Namespace, Literal from rdflib.namespace import OWL, DC if __name__=='__main__': # Firstly, it doesn't have to be so complex. # Here we create a "Graph" of our work. # Think of it as a blank piece of graph paper! primer = ConjunctiveGraph() myNS = Namespace('#') primer.add((myNS.pat, myNS.knows, myNS.jo)) # or: primer.add((myNS['pat'], myNS['age'], Literal(24))) # Now, with just that, lets see how the system # recorded *way* too many details about what # you just asserted as fact. # from pprint import pprint pprint(list(primer)) # just think .whatever((s, p, o)) # here we report on what we know pprint(list(primer.subjects())) pprint(list(primer.predicates())) pprint(list(primer.objects())) # and other things that make sense # what do we know about pat? pprint(list(primer.predicate_objects(myNS.pat))) # who is what age? pprint(list(primer.subject_objects(myNS.age))) # Okay, so lets now work with a bigger # dataset from the example, and start # with a fresh new graph. primer = ConjunctiveGraph() # Lets start with a verbatim string straight from the primer text: mySource = """ @prefix : . @prefix rdf: . @prefix rdfs: . @prefix owl: . @prefix dc: . @prefix foo: . @prefix swap: . <> dc:title "Primer - Getting into the Semantic Web and RDF using N3". <#pat> <#knows> <#jo> . <#pat> <#age> 24 . <#al> is <#child> of <#pat> . <#pat> <#child> <#al>, <#chaz>, <#mo> ; <#age> 24 ; <#eyecolor> "blue" . :Person a rdfs:Class. :Pat a :Person. :Woman a rdfs:Class; rdfs:subClassOf :Person . :sister a rdf:Property. :sister rdfs:domain :Person; rdfs:range :Woman. :Woman = foo:FemaleAdult . :Title a rdf:Property; = dc:title . """ # --- End of primer code # To make this go easier to spit back out... # technically, we already created a namespace # with the object init (and it added some namespaces as well) # By default, your main namespace is the URI of your # current working directory, so lets make that simpler: myNS = Namespace('http://www.w3.org/2000/10/swap/Primer#') primer.bind('', myNS) primer.bind('owl', OWL) primer.bind('dc', DC) primer.bind('swap', 'http://www.w3.org/2000/10/swap/') # Lets load it up! primer.parse(data=mySource, format='n3') # Now you can query, either directly straight into a list: [(x, y, z) for x, y, z in primer] # or spit it back out (mostly) the way we created it: print primer.serialize(format='n3') # for more insight into things already done, lets see the namespaces list(primer.namespaces()) # lets ask something about the data list(primer.objects(myNS.pat, myNS.child)) rdflib-4.1.2/examples/transitive.py000066400000000000000000000051031232323236500173400ustar00rootroot00000000000000""" An example illustrating how to use the :meth:`~rdflib.graph.Graph.transitive_subjects` and :meth:`~rdflib.graph.Graph.transitive_objects` graph methods Formal definition ^^^^^^^^^^^^^^^^^^ The :meth:`~rdflib.graph.Graph.transitive_objects` method finds all nodes such that there is a path from subject to one of those nodes using only the predicate property in the triples. The :meth:`~rdflib.graph.Graph.transitive_subjects` method is similar; it finds all nodes such that there is a path from the node to the object using only the predicate property. Informal description, with an example ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In brief, :meth:`~rdflib.graph.Graph.transitive_objects` walks forward in a graph using a particular property, and :meth:`~rdflib.graph.Graph.transitive_subjects` walks backward. A good example uses a property ``ex:parent``, the semantics of which are biological parentage. The :meth:`~rdflib.graph.Graph.transitive_objects` method would get all the ancestors of a particular person (all nodes such that there is a parent path between the person and the object). The :meth:`~rdflib.graph.Graph.transitive_subjects` method would get all the descendants of a particular person (all nodes such that there is a parent path between the node and the person). So, say that your URI is ``ex:person``. This example would get all of your (known) ancestors, and then get all the (known) descendants of your maternal grandmother. .. warning:: The :meth:`transitive_objects` method has the start node as the *first* argument, but the :meth:`transitive_subjects` method has the start node as the *second* argument. User-defined transitive closures ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The method :meth:`~rdflib.graph.Graph.transitiveClosure` returns transtive closures of user-defined functions. """ if __name__=='__main__': from rdflib import ConjunctiveGraph, URIRef person = URIRef('ex:person') dad = URIRef('ex:d') mom = URIRef('ex:m') momOfDad = URIRef('ex:gm0') momOfMom = URIRef('ex:gm1') dadOfDad = URIRef('ex:gf0') dadOfMom = URIRef('ex:gf1') parent = URIRef('ex:parent') g = ConjunctiveGraph() g.add((person, parent, dad)) g.add((person, parent, mom)) g.add((dad, parent, momOfDad)) g.add((dad, parent, dadOfDad)) g.add((mom, parent, momOfMom)) g.add((mom, parent, dadOfMom)) print "Parents, forward from `ex:person`:" for i in g.transitive_objects(person, parent): print i print "Parents, *backward* from `ex:gm1`:" for i in g.transitive_subjects(parent, momOfMom): print i rdflib-4.1.2/ez_setup.py000066400000000000000000000205421232323236500151740ustar00rootroot00000000000000#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c5" DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', } import sys, os def _validate_md5(egg_name, data): if egg_name in md5_data: from md5 import md5 digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ try: import setuptools if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) except ImportError: egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg import pkg_resources try: pkg_resources.require("setuptools>="+version) except pkg_resources.VersionConflict, e: # XXX could we install in a subprocess here? print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first.\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': # tell the user to uninstall obsolete version use_setuptools(version) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re from md5 import md5 for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) rdflib-4.1.2/rdflib/000077500000000000000000000000001232323236500142235ustar00rootroot00000000000000rdflib-4.1.2/rdflib/__init__.py000066400000000000000000000057511232323236500163440ustar00rootroot00000000000000"""\ A pure Python package providing the core RDF constructs. The packages is intended to provide the core RDF types and interfaces for working with RDF. The package defines a plugin interface for parsers, stores, and serializers that other packages can use to implement parsers, stores, and serializers that will plug into the rdflib package. The primary interface `rdflib` exposes to work with RDF is `rdflib.graph.Graph`. A tiny example: >>> import rdflib >>> g = rdflib.Graph() >>> result = g.parse("http://www.w3.org/2000/10/swap/test/meet/blue.rdf") >>> print("graph has %s statements." % len(g)) graph has 9 statements. >>> >>> for s, p, o in g: ... if (s, p, o) not in g: ... raise Exception("It better be!") >>> s = g.serialize(format='n3') """ __docformat__ = "restructuredtext en" # The format of the __version__ line is matched by a regex in setup.py __version__ = "4.1.2" __date__ = "2013/12/31" __all__ = [ 'URIRef', 'BNode', 'Literal', 'Variable', 'Namespace', 'Dataset', 'Graph', 'ConjunctiveGraph', 'RDF', 'RDFS', 'OWL', 'XSD', 'util', ] import sys assert sys.version_info >= (2, 5, 0), "rdflib requires Python 2.5 or higher" del sys import logging _LOGGER = logging.getLogger("rdflib") _LOGGER.info("RDFLib Version: %s" % __version__) NORMALIZE_LITERALS = True """ If True - Literals lexical forms are normalized when created. I.e. the lexical forms is parsed according to data-type, then the stored lexical form is the re-serialized value that was parsed. Illegal values for a datatype are simply kept. The normalized keyword for Literal.__new__ can override this. For example: >>> from rdflib import Literal,XSD >>> Literal("01", datatype=XSD.int) rdflib.term.Literal(u'1', datatype=rdflib.term.URIRef(u'http://www.w3.org/2001/XMLSchema#integer')) This flag may be changed at any time, but will only affect literals created after that time, previously created literals will remain (un)normalized. """ DAWG_LITERAL_COLLATION = False """ DAWG_LITERAL_COLLATION determines how literals are ordered or compared to each other. In SPARQL, applying the >,<,>=,<= operators to literals of incompatible data-types is an error, i.e: Literal(2)>Literal('cake') is neither true nor false, but an error. This is a problem in PY3, where lists of Literals of incompatible types can no longer be sorted. Setting this flag to True gives you strict DAWG/SPARQL compliance, setting it to False will order Literals with incompatible datatypes by datatype URI In particular, this determines how the rich comparison operators for Literal work, eq, __neq__, __lt__, etc. """ from rdflib.term import ( URIRef, BNode, Literal, Variable) from rdflib.namespace import Namespace from rdflib.graph import Dataset, Graph, ConjunctiveGraph from rdflib.namespace import RDF, RDFS, OWL, XSD from rdflib import plugin from rdflib import query # tedious sop to flake8 assert plugin assert query from rdflib import util rdflib-4.1.2/rdflib/collection.py000066400000000000000000000201031232323236500167240ustar00rootroot00000000000000from rdflib.namespace import RDF from rdflib.term import BNode from rdflib.term import Literal from rdflib.graph import Graph from rdflib.py3compat import format_doctest_out __all__ = ['Collection'] class Collection(object): __doc__ = format_doctest_out(""" See 3.3.5 Emulating container types: http://docs.python.org/ref/sequence-types.html#l2h-232 >>> from rdflib.graph import Graph >>> from pprint import pprint >>> listName = BNode() >>> g = Graph('IOMemory') >>> listItem1 = BNode() >>> listItem2 = BNode() >>> g.add((listName, RDF.first, Literal(1))) >>> g.add((listName, RDF.rest, listItem1)) >>> g.add((listItem1, RDF.first, Literal(2))) >>> g.add((listItem1, RDF.rest, listItem2)) >>> g.add((listItem2, RDF.rest, RDF.nil)) >>> g.add((listItem2, RDF.first, Literal(3))) >>> c = Collection(g,listName) >>> pprint([term.n3() for term in c]) [%(u)s'"1"^^', %(u)s'"2"^^', %(u)s'"3"^^'] >>> Literal(1) in c True >>> len(c) 3 >>> c._get_container(1) == listItem1 True >>> c.index(Literal(2)) == 1 True """) def __init__(self, graph, uri, seq=[]): self.graph = graph self.uri = uri or BNode() for item in seq: self.append(item) def n3(self): """ >>> from rdflib.graph import Graph >>> listName = BNode() >>> g = Graph('IOMemory') >>> listItem1 = BNode() >>> listItem2 = BNode() >>> g.add((listName, RDF.first, Literal(1))) >>> g.add((listName, RDF.rest, listItem1)) >>> g.add((listItem1, RDF.first, Literal(2))) >>> g.add((listItem1, RDF.rest, listItem2)) >>> g.add((listItem2, RDF.rest, RDF.nil)) >>> g.add((listItem2, RDF.first, Literal(3))) >>> c = Collection(g, listName) >>> print(c.n3()) #doctest: +NORMALIZE_WHITESPACE ( "1"^^ "2"^^ "3"^^ ) """ return "( %s )" % (' '.join([i.n3() for i in self])) def _get_container(self, index): """Gets the first, rest holding node at index.""" assert isinstance(index, int) graph = self.graph container = self.uri i = 0 while i < index: i += 1 container = graph.value(container, RDF.rest) if container is None: break return container def __len__(self): """length of items in collection.""" count = 0 links = set() for item in self.graph.items(self.uri): assert item not in links, \ "There is a loop in the RDF list! " + \ "(%s has been processed before)" % item links.add(item) count += 1 return count def index(self, item): """ Returns the 0-based numerical index of the item in the list """ listName = self.uri index = 0 while True: if (listName, RDF.first, item) in self.graph: return index else: newLink = list(self.graph.objects(listName, RDF.rest)) index += 1 if newLink == [RDF.nil]: raise ValueError("%s is not in %s" % (item, self.uri)) elif not newLink: raise Exception("Malformed RDF Collection: %s" % self.uri) else: assert len(newLink) == 1, \ "Malformed RDF Collection: %s" % self.uri listName = newLink[0] def __getitem__(self, key): """TODO""" c = self._get_container(key) if c: v = self.graph.value(c, RDF.first) if v: return v else: raise KeyError(key) else: raise IndexError(key) def __setitem__(self, key, value): """TODO""" c = self._get_container(key) if c: self.graph.add((c, RDF.first, value)) else: raise IndexError(key) def __delitem__(self, key): """ >>> from rdflib.namespace import RDF, RDFS >>> from rdflib import Graph >>> from pprint import pformat >>> g = Graph() >>> a = BNode('foo') >>> b = BNode('bar') >>> c = BNode('baz') >>> g.add((a, RDF.first, RDF.type)) >>> g.add((a, RDF.rest, b)) >>> g.add((b, RDF.first, RDFS.label)) >>> g.add((b, RDF.rest, c)) >>> g.add((c, RDF.first, RDFS.comment)) >>> g.add((c, RDF.rest, RDF.nil)) >>> len(g) 6 >>> def listAncestry(node, graph): ... for i in graph.subjects(RDF.rest, node): ... yield i >>> [str(node.n3()) ... for node in g.transitiveClosure(listAncestry, RDF.nil)] ['_:baz', '_:bar', '_:foo'] >>> lst = Collection(g, a) >>> len(lst) 3 >>> b == lst._get_container(1) True >>> c == lst._get_container(2) True >>> del lst[1] >>> len(lst) 2 >>> len(g) 4 """ self[key] # to raise any potential key exceptions graph = self.graph current = self._get_container(key) assert current if len(self) == 1 and key > 0: pass elif key == len(self) - 1: # the tail priorLink = self._get_container(key - 1) self.graph.set((priorLink, RDF.rest, RDF.nil)) graph.remove((current, None, None)) else: next = self._get_container(key + 1) prior = self._get_container(key - 1) assert next and prior graph.remove((current, None, None)) graph.set((prior, RDF.rest, next)) def __iter__(self): """Iterator over items in Collections""" return self.graph.items(self.uri) def append(self, item): """ >>> from rdflib.graph import Graph >>> listName = BNode() >>> g = Graph() >>> c = Collection(g,listName,[Literal(1),Literal(2)]) >>> links = [ ... list(g.subjects(object=i, predicate=RDF.first))[0] for i in c] >>> len([i for i in links if (i,RDF.rest, RDF.nil) in g]) 1 """ container = self.uri graph = self.graph # iterate to the end of the linked list rest = graph.value(container, RDF.rest) while rest: if rest == RDF.nil: # the end, append to the end of the linked list node = BNode() graph.set((container, RDF.rest, node)) container = node break else: # move down one link if container != self.uri: rest = graph.value(rest, RDF.rest) if not rest == RDF.nil: container = rest graph.add((container, RDF.first, item)) graph.add((container, RDF.rest, RDF.nil)) def clear(self): container = self.uri graph = self.graph while container: rest = graph.value(container, RDF.rest) graph.remove((container, RDF.first, None)) graph.remove((container, RDF.rest, None)) container = rest def test(): import doctest doctest.testmod() if __name__ == "__main__": test() g = Graph() c = Collection(g, BNode()) assert len(c) == 0 c = Collection( g, BNode(), [Literal("1"), Literal("2"), Literal("3"), Literal("4")]) assert len(c) == 4 assert c[1] == Literal("2"), c[1] del c[1] assert list(c) == [Literal("1"), Literal("3"), Literal("4")], list(c) try: del c[500] except IndexError, i: pass c.append(Literal("5")) print(list(c)) for i in c: print(i) del c[3] c.clear() assert len(c) == 0 rdflib-4.1.2/rdflib/compare.py000066400000000000000000000204261232323236500162270ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ A collection of utilities for canonicalizing and inspecting graphs. Among other things, they solve of the problem of deterministic bnode comparisons. Warning: the time to canonicalize bnodes may increase exponentially on larger graphs. Use with care! Example of comparing two graphs:: >>> g1 = Graph().parse(format='n3', data=''' ... @prefix : . ... :rel ... , ... [ :label "Same" ], ... , ... [ :label "A" ] . ... ''') >>> g2 = Graph().parse(format='n3', data=''' ... @prefix : . ... :rel ... , ... [ :label "Same" ], ... , ... [ :label "B" ] . ... ''') >>> >>> iso1 = to_isomorphic(g1) >>> iso2 = to_isomorphic(g2) These are not isomorphic:: >>> iso1 == iso2 False Diff the two graphs:: >>> in_both, in_first, in_second = graph_diff(iso1, iso2) Present in both:: >>> def dump_nt_sorted(g): ... for l in sorted(g.serialize(format='nt').splitlines()): ... if l: print(l.decode('ascii')) >>> dump_nt_sorted(in_both) #doctest: +SKIP . _:cbcaabaaba17fecbc304a64f8edee4335e . _:cbcaabaaba17fecbc304a64f8edee4335e "Same" . Only in first:: >>> dump_nt_sorted(in_first) #doctest: +SKIP . _:cb124e4c6da0579f810c0ffe4eff485bd9 . _:cb124e4c6da0579f810c0ffe4eff485bd9 "A" . Only in second:: >>> dump_nt_sorted(in_second) #doctest: +SKIP . _:cb558f30e21ddfc05ca53108348338ade8 . _:cb558f30e21ddfc05ca53108348338ade8 "B" . """ # TODO: # - Doesn't handle quads. # - Add warning and/or safety mechanism before working on large graphs? # - use this in existing Graph.isomorphic? __all__ = ['IsomorphicGraph', 'to_isomorphic', 'isomorphic', 'to_canonical_graph', 'graph_diff', 'similar'] from rdflib.graph import Graph, ConjunctiveGraph, ReadOnlyGraphAggregate from rdflib.term import BNode try: import hashlib md = hashlib.md5 except ImportError: # for Python << 2.5 import md5 md = md5.new class IsomorphicGraph(ConjunctiveGraph): """ Ported from (Sean B Palmer's RDF Graph Isomorphism Tester). """ def __init__(self, **kwargs): super(IsomorphicGraph, self).__init__(**kwargs) def __eq__(self, other): """Graph isomorphism testing.""" if not isinstance(other, IsomorphicGraph): return False elif len(self) != len(other): return False elif list(self) == list(other): return True # TODO: really generally cheaper? return self.internal_hash() == other.internal_hash() def __ne__(self, other): """Negative graph isomorphism testing.""" return not self.__eq__(other) def internal_hash(self): """ This is defined instead of __hash__ to avoid a circular recursion scenario with the Memory store for rdflib which requires a hash lookup in order to return a generator of triples. """ return _TripleCanonicalizer(self).to_hash() class _TripleCanonicalizer(object): def __init__(self, graph, hashfunc=hash): self.graph = graph self.hashfunc = hashfunc def to_hash(self): return self.hashfunc(tuple(sorted( map(self.hashfunc, self.canonical_triples())))) def canonical_triples(self): for triple in self.graph: yield tuple(self._canonicalize_bnodes(triple)) def _canonicalize_bnodes(self, triple): for term in triple: if isinstance(term, BNode): yield BNode(value="cb%s" % self._canonicalize(term)) else: yield term def _canonicalize(self, term, done=False): return self.hashfunc(tuple(sorted(self._vhashtriples(term, done), key=_hetero_tuple_key))) def _vhashtriples(self, term, done): for triple in self.graph: if term in triple: yield tuple(self._vhashtriple(triple, term, done)) def _vhashtriple(self, triple, target_term, done): for i, term in enumerate(triple): if not isinstance(term, BNode): yield term elif done or (term == target_term): yield i else: yield self._canonicalize(term, done=True) def _hetero_tuple_key(x): "Sort like Python 2 - by name of type, then by value. Expects tuples." return tuple((type(a).__name__, a) for a in x) def to_isomorphic(graph): if isinstance(graph, IsomorphicGraph): return graph return IsomorphicGraph(store=graph.store) def isomorphic(graph1, graph2): """ Compare graph for equality. Uses an algorithm to compute unique hashes which takes bnodes into account. Examples:: >>> g1 = Graph().parse(format='n3', data=''' ... @prefix : . ... :rel . ... :rel . ... :rel [ :label "A bnode." ] . ... ''') >>> g2 = Graph().parse(format='n3', data=''' ... @prefix ns: . ... ns:rel [ ns:label "A bnode." ] . ... ns:rel , ... . ... ''') >>> isomorphic(g1, g2) True >>> g3 = Graph().parse(format='n3', data=''' ... @prefix : . ... :rel . ... :rel . ... :rel . ... ''') >>> isomorphic(g1, g3) False """ return _TripleCanonicalizer(graph1).to_hash() == \ _TripleCanonicalizer(graph2).to_hash() def to_canonical_graph(g1): """ Creates a canonical, read-only graph where all bnode id:s are based on deterministical MD5 checksums, correlated with the graph contents. """ graph = Graph() graph += _TripleCanonicalizer(g1, _md5_hash).canonical_triples() return ReadOnlyGraphAggregate([graph]) def graph_diff(g1, g2): """ Returns three sets of triples: "in both", "in first" and "in second". """ # bnodes have deterministic values in canonical graphs: cg1 = to_canonical_graph(g1) cg2 = to_canonical_graph(g2) in_both = cg1 * cg2 in_first = cg1 - cg2 in_second = cg2 - cg1 return (in_both, in_first, in_second) def _md5_hash(t): h = md() for i in t: if isinstance(i, tuple): h.update(_md5_hash(i).encode('ascii')) else: h.update(unicode(i).encode("utf8")) return h.hexdigest() _MOCK_BNODE = BNode() def similar(g1, g2): """ Checks if the two graphs are "similar", by comparing sorted triples where all bnodes have been replaced by a singular mock bnode (the ``_MOCK_BNODE``). This is a much cheaper, but less reliable, alternative to the comparison algorithm in ``isomorphic``. """ return all(t1 == t2 for (t1, t2) in _squashed_graphs_triples(g1, g2)) def _squashed_graphs_triples(g1, g2): for (t1, t2) in zip(sorted(_squash_graph(g1)), sorted(_squash_graph(g2))): yield t1, t2 def _squash_graph(graph): return (_squash_bnodes(triple) for triple in graph) def _squash_bnodes(triple): return tuple((isinstance(t, BNode) and _MOCK_BNODE) or t for t in triple) rdflib-4.1.2/rdflib/compat.py000066400000000000000000000007751232323236500160710ustar00rootroot00000000000000# # code to simplify supporting older python versions # import sys from decimal import Decimal if sys.version_info[:2] < (2, 7): # Pre-2.7 decimal and float did not compare correctly def numeric_greater(a, b): if isinstance(a, Decimal) and isinstance(b, float): return float(a) > b elif isinstance(a, float) and isinstance(b, Decimal): return a > float(b) else: return a > b else: def numeric_greater(a, b): return a > b rdflib-4.1.2/rdflib/events.py000066400000000000000000000050721232323236500161050ustar00rootroot00000000000000__doc__ = """ Dirt Simple Events A Dispatcher (or a subclass of Dispatcher) stores event handlers that are 'fired' simple event objects when interesting things happen. Create a dispatcher: >>> d = Dispatcher() Now create a handler for the event and subscribe it to the dispatcher to handle Event events. A handler is a simple function or method that accepts the event as an argument: >>> def handler1(event): print(repr(event)) >>> d.subscribe(Event, handler1) Now dispatch a new event into the dispatcher, and see handler1 get fired: >>> d.dispatch(Event(foo='bar', data='yours', used_by='the event handlers')) """ __all__ = ['Event', 'Dispatcher'] class Event(object): """ An event is a container for attributes. The source of an event creates this object, or a subclass, gives it any kind of data that the events handlers need to handle the event, and then calls notify(event). The target of an event registers a function to handle the event it is interested with subscribe(). When a sources calls notify(event), each subscriber to that event will be called in no particular order. """ def __init__(self, **kw): self.__dict__.update(kw) def __repr__(self): attrs = self.__dict__.keys() attrs.sort() return '' % ([a for a in attrs],) class Dispatcher(object): """ An object that can dispatch events to a privately managed group of subscribers. """ _dispatch_map = None def set_map(self, amap): self._dispatch_map = amap def get_map(self): return self._dispatch_map def subscribe(self, event_type, handler): """ Subscribe the given handler to an event_type. Handlers are called in the order they are subscribed. """ if self._dispatch_map is None: self.set_map({}) lst = self._dispatch_map.get(event_type, None) if lst is None: lst = [handler] else: lst.append(handler) self._dispatch_map[event_type] = lst def dispatch(self, event): """ Dispatch the given event to the subscribed handlers for the event's type""" if self._dispatch_map is not None: lst = self._dispatch_map.get(type(event), None) if lst is None: raise ValueError("unknown event type: %s" % type(event)) for l in lst: l(event) def test(): import doctest doctest.testmod() if __name__ == '__main__': test() rdflib-4.1.2/rdflib/exceptions.py000066400000000000000000000042141232323236500167570ustar00rootroot00000000000000""" TODO: """ __all__ = ['Error', 'TypeCheckError', 'SubjectTypeError', 'PredicateTypeError', 'ObjectTypeError', 'ContextTypeError', 'ParserError'] class Error(Exception): """Base class for rdflib exceptions.""" def __init__(self, msg=None): Exception.__init__(self, msg) self.msg = msg class TypeCheckError(Error): """Parts of assertions are subject to type checks.""" def __init__(self, node): Error.__init__(self, node) self.type = type(node) self.node = node class SubjectTypeError(TypeCheckError): """Subject of an assertion must be an instance of URIRef.""" def __init__(self, node): TypeCheckError.__init__(self, node) self.msg = "Subject must be instance of URIRef or BNode: %s(%s)" \ % (self.node, self.type) class PredicateTypeError(TypeCheckError): """Predicate of an assertion must be an instance of URIRef.""" def __init__(self, node): TypeCheckError.__init__(self, node) self.msg = "Predicate must be a URIRef instance: %s(%s)" \ % (self.node, self.type) class ObjectTypeError(TypeCheckError): """Object of an assertion must be an instance of URIRef, Literal, or BNode.""" def __init__(self, node): TypeCheckError.__init__(self, node) self.msg = "\ Object must be instance of URIRef, Literal, or BNode: %s(%s)" % \ (self.node, self.type) class ContextTypeError(TypeCheckError): """Context of an assertion must be an instance of URIRef.""" def __init__(self, node): TypeCheckError.__init__(self, node) self.msg = "Context must be instance of URIRef or BNode: %s(%s)" \ % (self.node, self.type) class ParserError(Error): """RDF Parser error.""" def __init__(self, msg): Error.__init__(self, msg) self.msg = msg def __str__(self): return self.msg class UniquenessError(Error): """A uniqueness assumption was made in the context, and that is not true""" def __init__(self, values): Error.__init__(self, "\ Uniqueness assumption is not fulfilled. Multiple values are: %s" % values) rdflib-4.1.2/rdflib/extras/000077500000000000000000000000001232323236500155315ustar00rootroot00000000000000rdflib-4.1.2/rdflib/extras/__init__.py000066400000000000000000000000301232323236500176330ustar00rootroot00000000000000# -*- coding: utf-8 -*- rdflib-4.1.2/rdflib/extras/cmdlineutils.py000066400000000000000000000034031232323236500205770ustar00rootroot00000000000000import sys import time import getopt import rdflib import codecs from rdflib.util import guess_format def _help(): sys.stderr.write(""" program.py [-f ] [-o ] [files...] Read RDF files given on STDOUT - does something to the resulting graph If no files are given, read from stdin -o specifies file for output, if not given stdout is used -f specifies parser to use, if not given it is guessed from extension """) def main(target, _help=_help, options="", stdin=True): """ A main function for tools that read RDF from files given on commandline or from STDIN (if stdin parameter is true) """ args, files = getopt.getopt(sys.argv[1:], "hf:o:" + options) dargs = dict(args) if "-h" in dargs: _help() sys.exit(-1) g = rdflib.Graph() if "-f" in dargs: f = dargs["-f"] else: f = None if "-o" in dargs: sys.stderr.write("Output to %s\n" % dargs["-o"]) out = codecs.open(dargs["-o"], "w", "utf-8") else: out = sys.stdout start = time.time() if len(files) == 0 and stdin: sys.stderr.write("Reading from stdin as %s..." % f) g.load(sys.stdin, format=f) sys.stderr.write("[done]\n") else: size = 0 for x in files: if f is None: f = guess_format(x) start1 = time.time() sys.stderr.write("Loading %s as %s... " % (x, f)) g.load(x, format=f) sys.stderr.write("done.\t(%d triples\t%.2f seconds)\n" % (len(g) - size, time.time() - start1)) size = len(g) sys.stderr.write("Loaded a total of %d triples in %.2f seconds.\n" % (len(g), time.time() - start)) target(g, out, args) rdflib-4.1.2/rdflib/extras/describer.py000066400000000000000000000226721232323236500200560ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import with_statement from rdflib import py3compat __doc__ = py3compat.format_doctest_out(""" A Describer is a stateful utility for creating RDF statements in a semi-declarative manner. It has methods for creating literal values, rel and rev resource relations (somewhat resembling RDFa). The `rel` and ``rev`` methods return a context manager which sets the current about to the referenced resource for the context scope (for use with the ``with`` statement). Full example in the ``to_rdf`` method below:: >>> import datetime >>> from rdflib.graph import Graph >>> from rdflib.namespace import Namespace, RDFS, FOAF >>> >>> ORG_URI = "http://example.org/" >>> >>> CV = Namespace("http://purl.org/captsolo/resume-rdf/0.2/cv#") >>> >>> class Person(object): ... def __init__(self): ... self.first_name = %(u)s"Some" ... self.last_name = %(u)s"Body" ... self.username = "some1" ... self.presentation = %(u)s"Just a Python & RDF hacker." ... self.image = "/images/persons/" + self.username + ".jpg" ... self.site = "http://example.net/" ... self.start_date = datetime.date(2009, 9, 4) ... def get_full_name(self): ... return %(u)s" ".join([self.first_name, self.last_name]) ... def get_absolute_url(self): ... return "/persons/" + self.username ... def get_thumbnail_url(self): ... return self.image.replace('.jpg', '-thumb.jpg') ... ... def to_rdf(self): ... graph = Graph() ... graph.bind('foaf', FOAF) ... graph.bind('cv', CV) ... lang = 'en' ... d = Describer(graph, base=ORG_URI) ... d.about(self.get_absolute_url()+'#person') ... d.rdftype(FOAF.Person) ... d.value(FOAF.name, self.get_full_name()) ... d.value(FOAF.firstName, self.first_name) ... d.value(FOAF.surname, self.last_name) ... d.rel(FOAF.homepage, self.site) ... d.value(RDFS.comment, self.presentation, lang=lang) ... with d.rel(FOAF.depiction, self.image): ... d.rdftype(FOAF.Image) ... d.rel(FOAF.thumbnail, self.get_thumbnail_url()) ... with d.rev(CV.aboutPerson): ... d.rdftype(CV.CV) ... with d.rel(CV.hasWorkHistory): ... d.value(CV.startDate, self.start_date) ... d.rel(CV.employedIn, ORG_URI+"#company") ... return graph ... >>> person_graph = Person().to_rdf() >>> expected = Graph().parse(data=''' ... ... ... Some Body ... Some ... Body ... ... ... ... ... ... ... Just a Python & RDF hacker. ... ... ... ... ... ... ... ... ... 2009-09-04 ... ... ... ... ... ... ''') >>> >>> from rdflib.compare import isomorphic >>> isomorphic(person_graph, expected) #doctest: +SKIP True """) from contextlib import contextmanager from rdflib.graph import Graph from rdflib.namespace import RDF from rdflib.term import BNode from rdflib.term import Identifier from rdflib.term import Literal from rdflib.term import URIRef from rdflib.py3compat import format_doctest_out class Describer(object): def __init__(self, graph=None, about=None, base=None): if graph is None: graph = Graph() self.graph = graph self.base = base self._subjects = [] self.about(about or None) @format_doctest_out def about(self, subject, **kws): """ Sets the current subject. Will convert the given object into an ``URIRef`` if it's not an ``Identifier``. Usage:: >>> d = Describer() >>> d._current() #doctest: +ELLIPSIS rdflib.term.BNode(...) >>> d.about("http://example.org/") >>> d._current() rdflib.term.URIRef(%(u)s'http://example.org/') """ kws.setdefault('base', self.base) subject = cast_identifier(subject, **kws) if self._subjects: self._subjects[-1] = subject else: self._subjects.append(subject) @format_doctest_out def value(self, p, v, **kws): """ Set a literal value for the given property. Will cast the value to an ``Literal`` if a plain literal is given. Usage:: >>> from rdflib import URIRef >>> from rdflib.namespace import RDF, RDFS >>> d = Describer(about="http://example.org/") >>> d.value(RDFS.label, "Example") >>> d.graph.value(URIRef('http://example.org/'), RDFS.label) rdflib.term.Literal(%(u)s'Example') """ v = cast_value(v, **kws) self.graph.add((self._current(), p, v)) @format_doctest_out def rel(self, p, o=None, **kws): """Set an object for the given property. Will convert the given object into an ``URIRef`` if it's not an ``Identifier``. If none is given, a new ``BNode`` is used. Returns a context manager for use in a ``with`` block, within which the given object is used as current subject. Usage:: >>> from rdflib import URIRef >>> from rdflib.namespace import RDF, RDFS >>> d = Describer(about="/", base="http://example.org/") >>> _ctxt = d.rel(RDFS.seeAlso, "/about") >>> d.graph.value(URIRef('http://example.org/'), RDFS.seeAlso) rdflib.term.URIRef(%(u)s'http://example.org/about') >>> with d.rel(RDFS.seeAlso, "/more"): ... d.value(RDFS.label, "More") >>> (URIRef('http://example.org/'), RDFS.seeAlso, ... URIRef('http://example.org/more')) in d.graph True >>> d.graph.value(URIRef('http://example.org/more'), RDFS.label) rdflib.term.Literal(%(u)s'More') """ kws.setdefault('base', self.base) p = cast_identifier(p) o = cast_identifier(o, **kws) self.graph.add((self._current(), p, o)) return self._subject_stack(o) @format_doctest_out def rev(self, p, s=None, **kws): """ Same as ``rel``, but uses current subject as *object* of the relation. The given resource is still used as subject in the returned context manager. Usage:: >>> from rdflib import URIRef >>> from rdflib.namespace import RDF, RDFS >>> d = Describer(about="http://example.org/") >>> with d.rev(RDFS.seeAlso, "http://example.net/"): ... d.value(RDFS.label, "Net") >>> (URIRef('http://example.net/'), RDFS.seeAlso, ... URIRef('http://example.org/')) in d.graph True >>> d.graph.value(URIRef('http://example.net/'), RDFS.label) rdflib.term.Literal(%(u)s'Net') """ kws.setdefault('base', self.base) p = cast_identifier(p) s = cast_identifier(s, **kws) self.graph.add((s, p, self._current())) return self._subject_stack(s) def rdftype(self, t): """ Shorthand for setting rdf:type of the current subject. Usage:: >>> from rdflib import URIRef >>> from rdflib.namespace import RDF, RDFS >>> d = Describer(about="http://example.org/") >>> d.rdftype(RDFS.Resource) >>> (URIRef('http://example.org/'), ... RDF.type, RDFS.Resource) in d.graph True """ self.graph.add((self._current(), RDF.type, t)) def _current(self): return self._subjects[-1] @contextmanager def _subject_stack(self, subject): self._subjects.append(subject) yield None self._subjects.pop() def cast_value(v, **kws): if not isinstance(v, Literal): v = Literal(v, **kws) return v def cast_identifier(ref, **kws): ref = ref or BNode() if not isinstance(ref, Identifier): ref = URIRef(ref, **kws) return ref rdflib-4.1.2/rdflib/extras/infixowl.py000066400000000000000000002222701232323236500177470ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from rdflib import py3compat __doc__ = py3compat.format_doctest_out(""" RDFLib Python binding for OWL Abstract Syntax see: http://www.w3.org/TR/owl-semantics/syntax.html http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf 3.2.3 Axioms for complete classes without using owl:equivalentClass Named class description of type 2 (with owl:oneOf) or type 4-6 (with owl:intersectionOf, owl:unionOf or owl:complementOf Uses Manchester Syntax for __repr__ >>> exNs = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', exNs, override=False) >>> namespace_manager.bind('owl', OWL_NS, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager Now we have an empty graph, we can construct OWL classes in it using the Python classes defined in this module >>> a = Class(exNs.Opera, graph=g) Now we can assert rdfs:subClassOf and owl:equivalentClass relationships (in the underlying graph) with other classes using the 'subClassOf' and 'equivalentClass' descriptors which can be set to a list of objects for the corresponding predicates. >>> a.subClassOf = [exNs.MusicalWork] We can then access the rdfs:subClassOf relationships >>> print(list(a.subClassOf)) [Class: ex:MusicalWork ] This can also be used against already populated graphs: >>> owlGraph = Graph().parse(OWL_NS) #doctest: +SKIP >>> namespace_manager.bind('owl', OWL_NS, override=False) #doctest: +SKIP >>> owlGraph.namespace_manager = namespace_manager #doctest: +SKIP >>> list(Class(OWL_NS.Class, graph=owlGraph).subClassOf) #doctest: +SKIP [Class: rdfs:Class ] Operators are also available. For instance we can add ex:Opera to the extension of the ex:CreativeWork class via the '+=' operator >>> a #doctest: +SKIP Class: ex:Opera SubClassOf: ex:MusicalWork >>> b = Class(exNs.CreativeWork, graph=g) >>> b += a >>> print(sorted(a.subClassOf, key=lambda c:c.identifier)) #doctest: +SKIP [Class: ex:CreativeWork , Class: ex:MusicalWork ] And we can then remove it from the extension as well >>> b -= a >>> a #doctest: +SKIP Class: ex:Opera SubClassOf: ex:MusicalWork Boolean class constructions can also be created with Python operators. For example, The | operator can be used to construct a class consisting of a owl:unionOf the operands: >>> c = a | b | Class(exNs.Work, graph=g) >>> c #doctest: +SKIP ( ex:Opera OR ex:CreativeWork OR ex:Work ) Boolean class expressions can also be operated as lists (using python list operators) >>> del c[c.index(Class(exNs.Work, graph=g))] >>> c #doctest: +SKIP ( ex:Opera OR ex:CreativeWork ) The '&' operator can be used to construct class intersection: >>> woman = Class(exNs.Female, graph=g) & Class(exNs.Human, graph=g) >>> woman.identifier = exNs.Woman >>> woman #doctest: +SKIP ( ex:Female AND ex:Human ) >>> len(woman) 2 Enumerated classes can also be manipulated >>> contList = [Class(exNs.Africa, graph=g), Class(exNs.NorthAmerica, graph=g)] >>> EnumeratedClass(members=contList, graph=g) #doctest: +SKIP { ex:Africa ex:NorthAmerica } owl:Restrictions can also be instantiated: >>> Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human) #doctest: +SKIP ( ex:hasParent ONLY ex:Human ) Restrictions can also be created using Manchester OWL syntax in 'colloquial' Python >>> exNs.hasParent | some | Class(exNs.Physician, graph=g) #doctest: +SKIP ( ex:hasParent SOME ex:Physician ) >>> Property(exNs.hasParent,graph=g) | max | Literal(1) #doctest: +SKIP ( ex:hasParent MAX 1 ) >>> print(g.serialize(format='pretty-xml')) #doctest: +SKIP """) import itertools from rdflib import ( BNode, Literal, Namespace, RDF, RDFS, URIRef, Variable ) from rdflib.graph import Graph from rdflib.collection import Collection from rdflib.namespace import XSD as _XSD_NS from rdflib.namespace import NamespaceManager from rdflib.term import Identifier from rdflib.util import first import logging def _debug(*args, **kw): # import logging logging.basicConfig(level=logging.ERROR, format="%(message)s") logger = logging.getLogger(__name__) logger.debug(*args, **kw) """ From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 Python has the wonderful "in" operator and it would be nice to have additional infix operator like this. This recipe shows how (almost) arbitrary infix operators can be defined. """ __all__ = [ 'OWL_NS', 'nsBinds', 'ACE_NS', 'CLASS_RELATIONS', 'some', 'only', 'max', 'min', 'exactly', 'value', 'PropertyAbstractSyntax', 'AllClasses', 'AllDifferent', 'AllProperties', 'AnnotatableTerms', 'BooleanClass', 'Callable', 'CastClass', 'Class', 'ClassNamespaceFactory', 'classOrIdentifier', 'classOrTerm', 'CommonNSBindings', 'ComponentTerms', 'DeepClassClear', 'EnumeratedClass', 'generateQName', 'GetIdentifiedClasses', 'Individual', 'MalformedClass', 'manchesterSyntax', 'Ontology', 'OWLRDFListProxy', 'Property', 'propertyOrIdentifier', 'Restriction', 'termDeletionDecorator', ] # definition of an Infix operator class # this recipe also works in jython # calling sequence for the infix is either: # x |op| y # or: # x <> y class Infix: def __init__(self, function): self.function = function def __ror__(self, other): return Infix(lambda x, self=self, other=other: self.function(other, x)) def __or__(self, other): return self.function(other) def __rlshift__(self, other): return Infix(lambda x, self=self, other=other: self.function(other, x)) def __rshift__(self, other): return self.function(other) def __call__(self, value1, value2): return self.function(value1, value2) OWL_NS = Namespace("http://www.w3.org/2002/07/owl#") nsBinds = { 'skos': 'http://www.w3.org/2004/02/skos/core#', 'rdf': RDF, 'rdfs': RDFS, 'owl': OWL_NS, 'list': URIRef('http://www.w3.org/2000/10/swap/list#'), 'dc': "http://purl.org/dc/elements/1.1/", } def generateQName(graph, uri): prefix, uri, localName = graph.compute_qname(classOrIdentifier(uri)) return u':'.join([prefix, localName]) def classOrTerm(thing): if isinstance(thing, Class): return thing.identifier else: assert isinstance(thing, (URIRef, BNode, Literal)) return thing def classOrIdentifier(thing): if isinstance(thing, (Property, Class)): return thing.identifier else: assert isinstance(thing, (URIRef, BNode)), \ "Expecting a Class, Property, URIRef, or BNode.. not a %s" % thing return thing def propertyOrIdentifier(thing): if isinstance(thing, Property): return thing.identifier else: assert isinstance(thing, URIRef) return thing def manchesterSyntax(thing, store, boolean=None, transientList=False): """ Core serialization """ assert thing is not None if boolean: if transientList: liveChildren = iter(thing) children = [manchesterSyntax(child, store) for child in thing] else: liveChildren = iter(Collection(store, thing)) children = [manchesterSyntax( child, store) for child in Collection(store, thing)] if boolean == OWL_NS.intersectionOf: childList = [] named = [] for child in liveChildren: if isinstance(child, URIRef): named.append(child) else: childList.append(child) if named: def castToQName(x): prefix, uri, localName = store.compute_qname(x) return ':'.join([prefix, localName]) if len(named) > 1: prefix = u'( ' + u' AND '.join(map( castToQName, named)) + u' )' else: prefix = manchesterSyntax(named[0], store) if childList: return str(prefix) + u' THAT ' + u' AND '.join( [str(manchesterSyntax(x, store)) for x in childList]) else: return prefix else: return u'( ' + u' AND '.join( [str(c) for c in children]) + u' )' elif boolean == OWL_NS.unionOf: return u'( ' + u' OR '.join([str(c) for c in children]) + ' )' elif boolean == OWL_NS.oneOf: return u'{ ' + u' '.join([str(c) for c in children]) + ' }' else: assert boolean == OWL_NS.complementOf elif OWL_NS.Restriction in store.objects( subject=thing, predicate=RDF.type): prop = list( store.objects(subject=thing, predicate=OWL_NS.onProperty))[0] prefix, uri, localName = store.compute_qname(prop) propString = u':'.join([prefix, localName]) label = first(store.objects(subject=prop, predicate=RDFS.label)) if label: propString = "'%s'" % label for onlyClass in store.objects( subject=thing, predicate=OWL_NS.allValuesFrom): return u'( %s ONLY %s )' % ( propString, manchesterSyntax(onlyClass, store)) for val in store.objects(subject=thing, predicate=OWL_NS.hasValue): return u'( %s VALUE %s )' % ( propString, manchesterSyntax(val.encode('utf-8', 'ignore'), store)) for someClass in store.objects( subject=thing, predicate=OWL_NS.someValuesFrom): return u'( %s SOME %s )' % ( propString, manchesterSyntax(someClass, store)) cardLookup = {OWL_NS.maxCardinality: 'MAX', OWL_NS.minCardinality: 'MIN', OWL_NS.cardinality: 'EQUALS'} for s, p, o in store.triples_choices( (thing, list(cardLookup.keys()), None)): return u'( %s %s %s )' % ( propString, cardLookup[p], o.encode('utf-8', 'ignore')) compl = list(store.objects(subject=thing, predicate=OWL_NS.complementOf)) if compl: return '( NOT %s )' % (manchesterSyntax(compl[0], store)) else: prolog = '\n'.join( ["PREFIX %s: <%s>" % (k, nsBinds[k]) for k in nsBinds]) qstr = \ prolog + \ "\nSELECT ?p ?bool WHERE {?class a owl:Class; ?p ?bool ." + \ "?bool rdf:first ?foo }" initb = {Variable("?class"): thing} for boolProp, col in \ store.query(qstr, processor="sparql", initBindings=initb): if not isinstance(thing, URIRef): return manchesterSyntax(col, store, boolean=boolProp) try: prefix, uri, localName = store.compute_qname(thing) qname = u':'.join([prefix, localName]) except Exception: if isinstance(thing, BNode): return thing.n3() return u"<" + thing + ">" _debug(list(store.objects(subject=thing, predicate=RDF.type))) raise return '[]' # +thing._id.encode('utf-8')+'' label = first(Class(thing, graph=store).label) if label: return label.encode('utf-8', 'ignore') else: return qname.encode('utf-8', 'ignore') def GetIdentifiedClasses(graph): for c in graph.subjects(predicate=RDF.type, object=OWL_NS.Class): if isinstance(c, URIRef): yield Class(c) def termDeletionDecorator(prop): def someFunc(func): func.property = prop return func return someFunc class TermDeletionHelper: def __init__(self, prop): self.prop = prop def __call__(self, f): def _remover(inst): inst.graph.remove((inst.identifier, self.prop, None)) return _remover class Individual(object): """ A typed individual """ factoryGraph = Graph() def serialize(self, graph): for fact in self.factoryGraph.triples((self.identifier, None, None)): graph.add(fact) def __init__(self, identifier=None, graph=None): self.__identifier = identifier is not None and identifier or BNode() if graph is None: self.graph = self.factoryGraph else: self.graph = graph self.qname = None if not isinstance(self.identifier, BNode): try: prefix, uri, localName = self.graph.compute_qname( self.identifier) self.qname = u':'.join([prefix, localName]) except: pass def clearInDegree(self): self.graph.remove((None, None, self.identifier)) def clearOutDegree(self): self.graph.remove((self.identifier, None, None)) def delete(self): self.clearInDegree() self.clearOutDegree() def replace(self, other): for s, p, o in self.graph.triples((None, None, self.identifier)): self.graph.add((s, p, classOrIdentifier(other))) self.delete() def _get_type(self): for _t in self.graph.objects( subject=self.identifier, predicate=RDF.type): yield _t def _set_type(self, kind): if not kind: return if isinstance(kind, (Individual, Identifier)): self.graph.add( (self.identifier, RDF.type, classOrIdentifier(kind))) else: for c in kind: assert isinstance(c, (Individual, Identifier)) self.graph.add( (self.identifier, RDF.type, classOrIdentifier(c))) @TermDeletionHelper(RDF.type) def _delete_type(self): """ >>> g = Graph() >>> b=Individual(OWL_NS.Restriction,g) >>> b.type = RDF.Resource >>> len(list(b.type)) 1 >>> del b.type >>> len(list(b.type)) 0 """ pass type = property(_get_type, _set_type, _delete_type) def _get_identifier(self): return self.__identifier def _set_identifier(self, i): assert i if i != self.__identifier: oldStmtsOut = [(p, o) for s, p, o in self.graph.triples( (self.__identifier, None, None))] oldStmtsIn = [(s, p) for s, p, o in self.graph.triples( (None, None, self.__identifier))] for p1, o1 in oldStmtsOut: self.graph.remove((self.__identifier, p1, o1)) for s1, p1 in oldStmtsIn: self.graph.remove((s1, p1, self.__identifier)) self.__identifier = i self.graph.addN( [(i, p1, o1, self.graph) for p1, o1 in oldStmtsOut]) self.graph.addN([(s1, p1, i, self.graph) for s1, p1 in oldStmtsIn]) if not isinstance(i, BNode): try: prefix, uri, localName = self.graph.compute_qname(i) self.qname = u':'.join([prefix, localName]) except: pass identifier = property(_get_identifier, _set_identifier) def _get_sameAs(self): for _t in self.graph.objects( subject=self.identifier, predicate=OWL_NS.sameAs): yield _t def _set_sameAs(self, term): # if not kind: # return if isinstance(term, (Individual, Identifier)): self.graph.add( (self.identifier, OWL_NS.sameAs, classOrIdentifier(term))) else: for c in term: assert isinstance(c, (Individual, Identifier)) self.graph.add( (self.identifier, OWL_NS.sameAs, classOrIdentifier(c))) @TermDeletionHelper(OWL_NS.sameAs) def _delete_sameAs(self): pass sameAs = property(_get_sameAs, _set_sameAs, _delete_sameAs) ACE_NS = Namespace('http://attempto.ifi.uzh.ch/ace_lexicon#') class AnnotatableTerms(Individual): """ Terms in an OWL ontology with rdfs:label and rdfs:comment """ def __init__(self, identifier, graph=None, nameAnnotation=None, nameIsLabel=False): super(AnnotatableTerms, self).__init__(identifier, graph) if nameAnnotation: self.setupACEAnnotations() self.PN_sgProp.extent = [(self.identifier, self.handleAnnotation(nameAnnotation))] if nameIsLabel: self.label = [nameAnnotation] def handleAnnotation(self, val): return val if isinstance(val, Literal) else Literal(val) def setupACEAnnotations(self): self.graph.bind('ace', ACE_NS, override=False) # PN_sg singular form of a proper name () self.PN_sgProp = Property(ACE_NS.PN_sg, baseType=OWL_NS.AnnotationProperty, graph=self.graph) # CN_sg singular form of a common noun self.CN_sgProp = Property(ACE_NS.CN_sg, baseType=OWL_NS.AnnotationProperty, graph=self.graph) # CN_pl plural form of a common noun self.CN_plProp = Property(ACE_NS.CN_pl, baseType=OWL_NS.AnnotationProperty, graph=self.graph) # singular form of a transitive verb self.TV_sgProp = Property(ACE_NS.TV_sg, baseType=OWL_NS.AnnotationProperty, graph=self.graph) # plural form of a transitive verb self.TV_plProp = Property(ACE_NS.TV_pl, baseType=OWL_NS.AnnotationProperty, graph=self.graph) # past participle form a transitive verb self.TV_vbgProp = Property(ACE_NS.TV_vbg, baseType=OWL_NS.AnnotationProperty, graph=self.graph) def _get_comment(self): for comment in self.graph.objects( subject=self.identifier, predicate=RDFS.comment): yield comment def _set_comment(self, comment): if not comment: return if isinstance(comment, Identifier): self.graph.add((self.identifier, RDFS.comment, comment)) else: for c in comment: self.graph.add((self.identifier, RDFS.comment, c)) @TermDeletionHelper(RDFS.comment) def _del_comment(self): pass comment = property(_get_comment, _set_comment, _del_comment) def _get_seeAlso(self): for sA in self.graph.objects( subject=self.identifier, predicate=RDFS.seeAlso): yield sA def _set_seeAlso(self, seeAlsos): if not seeAlsos: return for s in seeAlsos: self.graph.add((self.identifier, RDFS.seeAlso, s)) @TermDeletionHelper(RDFS.seeAlso) def _del_seeAlso(self): pass seeAlso = property(_get_seeAlso, _set_seeAlso, _del_seeAlso) def _get_label(self): for label in self.graph.objects( subject=self.identifier, predicate=RDFS.label): yield label def _set_label(self, label): if not label: return if isinstance(label, Identifier): self.graph.add((self.identifier, RDFS.label, label)) else: for l in label: self.graph.add((self.identifier, RDFS.label, l)) @TermDeletionHelper(RDFS.label) def _delete_label(self): """ >>> g=Graph() >>> b=Individual(OWL_NS.Restriction,g) >>> b.label = Literal('boo') >>> len(list(b.label)) 1 >>> del b.label >>> len(list(b.label)) 0 """ pass label = property(_get_label, _set_label, _delete_label) class Ontology(AnnotatableTerms): """ The owl ontology metadata""" def __init__(self, identifier=None, imports=None, comment=None, graph=None): super(Ontology, self).__init__(identifier, graph) self.imports = imports and imports or [] self.comment = comment and comment or [] if (self.identifier, RDF.type, OWL_NS.Ontology) not in self.graph: self.graph.add((self.identifier, RDF.type, OWL_NS.Ontology)) def setVersion(self, version): self.graph.set((self.identifier, OWL_NS.versionInfo, version)) def _get_imports(self): for owl in self.graph.objects( subject=self.identifier, predicate=OWL_NS['imports']): yield owl def _set_imports(self, other): if not other: return for o in other: self.graph.add((self.identifier, OWL_NS['imports'], o)) @TermDeletionHelper(OWL_NS['imports']) def _del_imports(self): pass imports = property(_get_imports, _set_imports, _del_imports) def AllClasses(graph): prevClasses = set() for c in graph.subjects(predicate=RDF.type, object=OWL_NS.Class): if c not in prevClasses: prevClasses.add(c) yield Class(c) def AllProperties(graph): prevProps = set() for s, p, o in graph.triples_choices( (None, RDF.type, [OWL_NS.SymmetricProperty, OWL_NS.FunctionalProperty, OWL_NS.InverseFunctionalProperty, OWL_NS.TransitiveProperty, OWL_NS.DatatypeProperty, OWL_NS.ObjectProperty, OWL_NS.AnnotationProperty])): if o in [OWL_NS.SymmetricProperty, OWL_NS.InverseFunctionalProperty, OWL_NS.TransitiveProperty, OWL_NS.ObjectProperty]: bType = OWL_NS.ObjectProperty else: bType = OWL_NS.DatatypeProperty if s not in prevProps: prevProps.add(s) yield Property(s, graph=graph, baseType=bType) class ClassNamespaceFactory(Namespace): def term(self, name): return Class(URIRef(self + name)) def __getitem__(self, key, default=None): return self.term(key) def __getattr__(self, name): if name.startswith("__"): # ignore any special Python names! raise AttributeError else: return self.term(name) CLASS_RELATIONS = set( OWL_NS.resourceProperties ).difference([OWL_NS.onProperty, OWL_NS.allValuesFrom, OWL_NS.hasValue, OWL_NS.someValuesFrom, OWL_NS.inverseOf, OWL_NS.imports, OWL_NS.versionInfo, OWL_NS.backwardCompatibleWith, OWL_NS.incompatibleWith, OWL_NS.unionOf, OWL_NS.intersectionOf, OWL_NS.oneOf]) def ComponentTerms(cls): """ Takes a Class instance and returns a generator over the classes that are involved in its definition, ignoring unamed classes """ if OWL_NS.Restriction in cls.type: try: cls = CastClass(cls, Individual.factoryGraph) for s, p, innerClsId in cls.factoryGraph.triples_choices( (cls.identifier, [OWL_NS.allValuesFrom, OWL_NS.someValuesFrom], None)): innerCls = Class(innerClsId, skipOWLClassMembership=True) if isinstance(innerClsId, BNode): for _c in ComponentTerms(innerCls): yield _c else: yield innerCls except: pass else: cls = CastClass(cls, Individual.factoryGraph) if isinstance(cls, BooleanClass): for _cls in cls: _cls = Class(_cls, skipOWLClassMembership=True) if isinstance(_cls.identifier, BNode): for _c in ComponentTerms(_cls): yield _c else: yield _cls else: for innerCls in cls.subClassOf: if isinstance(innerCls.identifier, BNode): for _c in ComponentTerms(innerCls): yield _c else: yield innerCls for s, p, o in cls.factoryGraph.triples_choices( (classOrIdentifier(cls), CLASS_RELATIONS, None) ): if isinstance(o, BNode): for _c in ComponentTerms( CastClass(o, Individual.factoryGraph)): yield _c else: yield innerCls def DeepClassClear(classToPrune): """ Recursively clear the given class, continuing where any related class is an anonymous class >>> EX = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', EX, override=False) >>> namespace_manager.bind('owl', OWL_NS, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager >>> Individual.factoryGraph = g >>> classB = Class(EX.B) >>> classC = Class(EX.C) >>> classD = Class(EX.D) >>> classE = Class(EX.E) >>> classF = Class(EX.F) >>> anonClass = EX.someProp | some | classD #doctest: +SKIP >>> classF += anonClass #doctest: +SKIP >>> list(anonClass.subClassOf) #doctest: +SKIP [Class: ex:F ] >>> classA = classE | classF | anonClass #doctest: +SKIP >>> classB += classA #doctest: +SKIP >>> classA.equivalentClass = [Class()] #doctest: +SKIP >>> classB.subClassOf = [EX.someProp | some | classC] #doctest: +SKIP >>> classA #doctest: +SKIP ( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) ) >>> DeepClassClear(classA) #doctest: +SKIP >>> classA #doctest: +SKIP ( ) >>> list(anonClass.subClassOf) #doctest: +SKIP [] >>> classB #doctest: +SKIP Class: ex:B SubClassOf: ( ex:someProp SOME ex:C ) >>> otherClass = classD | anonClass #doctest: +SKIP >>> otherClass #doctest: +SKIP ( ex:D OR ( ex:someProp SOME ex:D ) ) >>> DeepClassClear(otherClass) #doctest: +SKIP >>> otherClass #doctest: +SKIP ( ) >>> otherClass.delete() #doctest: +SKIP >>> list(g.triples((otherClass.identifier, None, None))) #doctest: +SKIP [] """ def deepClearIfBNode(_class): if isinstance(classOrIdentifier(_class), BNode): DeepClassClear(_class) classToPrune = CastClass(classToPrune, Individual.factoryGraph) for c in classToPrune.subClassOf: deepClearIfBNode(c) classToPrune.graph.remove((classToPrune.identifier, RDFS.subClassOf, None)) for c in classToPrune.equivalentClass: deepClearIfBNode(c) classToPrune.graph.remove( (classToPrune.identifier, OWL_NS.equivalentClass, None)) inverseClass = classToPrune.complementOf if inverseClass: classToPrune.graph.remove( (classToPrune.identifier, OWL_NS.complementOf, None)) deepClearIfBNode(inverseClass) if isinstance(classToPrune, BooleanClass): for c in classToPrune: deepClearIfBNode(c) classToPrune.clear() classToPrune.graph.remove((classToPrune.identifier, classToPrune._operator, None)) class MalformedClass(Exception): def __init__(self, msg): self.msg = msg def __repr__(self): return self.msg def CastClass(c, graph=None): graph = graph is None and c.factoryGraph or graph for kind in graph.objects(subject=classOrIdentifier(c), predicate=RDF.type): if kind == OWL_NS.Restriction: kwArgs = {'identifier': classOrIdentifier(c), 'graph': graph} for s, p, o in graph.triples((classOrIdentifier(c), None, None)): if p != RDF.type: if p == OWL_NS.onProperty: kwArgs['onProperty'] = o else: if p not in Restriction.restrictionKinds: continue kwArgs[str(p.split(OWL_NS)[-1])] = o if not set([str(i.split(OWL_NS)[-1]) for i in Restriction.restrictionKinds] ).intersection(kwArgs): raise MalformedClass("Malformed owl:Restriction") return Restriction(**kwArgs) else: for s, p, o in graph.triples_choices((classOrIdentifier(c), [OWL_NS.intersectionOf, OWL_NS.unionOf, OWL_NS.oneOf], None)): if p == OWL_NS.oneOf: return EnumeratedClass(classOrIdentifier(c), graph=graph) else: return BooleanClass( classOrIdentifier(c), operator=p, graph=graph) # assert (classOrIdentifier(c),RDF.type,OWL_NS.Class) in graph return Class( classOrIdentifier(c), graph=graph, skipOWLClassMembership=True) class Class(AnnotatableTerms): """ 'General form' for classes: The Manchester Syntax (supported in Protege) is used as the basis for the form of this class See: http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf: [Annotation] ‘Class:’ classID {Annotation ( (‘SubClassOf:’ ClassExpression) | (‘EquivalentTo’ ClassExpression) | (’DisjointWith’ ClassExpression)) } Appropriate excerpts from OWL Reference: ".. Subclass axioms provide us with partial definitions: they represent necessary but not sufficient conditions for establishing class membership of an individual." ".. A class axiom may contain (multiple) owl:equivalentClass statements" "..A class axiom may also contain (multiple) owl:disjointWith statements.." "..An owl:complementOf property links a class to precisely one class description." """ def _serialize(self, graph): for cl in self.subClassOf: CastClass(cl, self.graph).serialize(graph) for cl in self.equivalentClass: CastClass(cl, self.graph).serialize(graph) for cl in self.disjointWith: CastClass(cl, self.graph).serialize(graph) if self.complementOf: CastClass(self.complementOf, self.graph).serialize(graph) def serialize(self, graph): for fact in self.graph.triples((self.identifier, None, None)): graph.add(fact) self._serialize(graph) def setupNounAnnotations(self, nounAnnotations): if isinstance(nounAnnotations, tuple): CN_sgProp, CN_plProp = nounAnnotations else: CN_sgProp = nounAnnotations CN_plProp = nounAnnotations if CN_sgProp: self.CN_sgProp.extent = [(self.identifier, self.handleAnnotation(CN_sgProp))] if CN_plProp: self.CN_plProp.extent = [(self.identifier, self.handleAnnotation(CN_plProp))] def __init__(self, identifier=None, subClassOf=None, equivalentClass=None, disjointWith=None, complementOf=None, graph=None, skipOWLClassMembership=False, comment=None, nounAnnotations=None, nameAnnotation=None, nameIsLabel=False): super(Class, self).__init__(identifier, graph, nameAnnotation, nameIsLabel) if nounAnnotations: self.setupNounAnnotations(nounAnnotations) if not skipOWLClassMembership \ and (self.identifier, RDF.type, OWL_NS.Class) \ not in self.graph and \ (self.identifier, RDF.type, OWL_NS.Restriction) \ not in self.graph: self.graph.add((self.identifier, RDF.type, OWL_NS.Class)) self.subClassOf = subClassOf and subClassOf or [] self.equivalentClass = equivalentClass and equivalentClass or [] self.disjointWith = disjointWith and disjointWith or [] if complementOf: self.complementOf = complementOf self.comment = comment and comment or [] def _get_extent(self, graph=None): for member in ( graph is None and self.graph or graph).subjects( predicate=RDF.type, object=self.identifier): yield member def _set_extent(self, other): if not other: return for m in other: self.graph.add((classOrIdentifier(m), RDF.type, self.identifier)) @TermDeletionHelper(RDF.type) def _del_type(self): pass extent = property(_get_extent, _set_extent, _del_type) def _get_annotation(self, term=RDFS.label): for annotation in self.graph.objects(subject=self, predicate=term): yield annotation annotation = property(_get_annotation, lambda x: x) def _get_extentQuery(self): return (Variable('CLASS'), RDF.type, self.identifier) def _set_extentQuery(self, other): pass extentQuery = property(_get_extentQuery, _set_extentQuery) def __hash__(self): """ >>> b=Class(OWL_NS.Restriction) >>> c=Class(OWL_NS.Restriction) >>> len(set([b,c])) 1 """ return hash(self.identifier) def __eq__(self, other): assert isinstance(other, Class), repr(other) return self.identifier == other.identifier def __iadd__(self, other): assert isinstance(other, Class) other.subClassOf = [self] return self def __isub__(self, other): assert isinstance(other, Class) self.graph.remove( (classOrIdentifier(other), RDFS.subClassOf, self.identifier)) return self def __invert__(self): """ Shorthand for Manchester syntax's not operator """ return Class(complementOf=self) def __or__(self, other): """ Construct an anonymous class description consisting of the union of this class and 'other' and return it """ return BooleanClass( operator=OWL_NS.unionOf, members=[self, other], graph=self.graph) def __and__(self, other): """ Construct an anonymous class description consisting of the intersection of this class and 'other' and return it >>> exNs = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', exNs, override=False) >>> namespace_manager.bind('owl', OWL_NS, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager Chaining 3 intersections >>> female = Class(exNs.Female, graph=g) >>> human = Class(exNs.Human, graph=g) >>> youngPerson = Class(exNs.YoungPerson, graph=g) >>> youngWoman = female & human & youngPerson >>> youngWoman #doctest: +SKIP ex:YoungPerson THAT ( ex:Female AND ex:Human ) >>> isinstance(youngWoman, BooleanClass) True >>> isinstance(youngWoman.identifier, BNode) True """ return BooleanClass( operator=OWL_NS.intersectionOf, members=[self, other], graph=self.graph) def _get_subClassOf(self): for anc in self.graph.objects( subject=self.identifier, predicate=RDFS.subClassOf): yield Class(anc, graph=self.graph, skipOWLClassMembership=True) def _set_subClassOf(self, other): if not other: return for sc in other: self.graph.add( (self.identifier, RDFS.subClassOf, classOrIdentifier(sc))) @TermDeletionHelper(RDFS.subClassOf) def _del_subClassOf(self): pass subClassOf = property(_get_subClassOf, _set_subClassOf, _del_subClassOf) def _get_equivalentClass(self): for ec in self.graph.objects( subject=self.identifier, predicate=OWL_NS.equivalentClass): yield Class(ec, graph=self.graph) def _set_equivalentClass(self, other): if not other: return for sc in other: self.graph.add((self.identifier, OWL_NS.equivalentClass, classOrIdentifier(sc))) @TermDeletionHelper(OWL_NS.equivalentClass) def _del_equivalentClass(self): pass equivalentClass = property( _get_equivalentClass, _set_equivalentClass, _del_equivalentClass) def _get_disjointWith(self): for dc in self.graph.objects( subject=self.identifier, predicate=OWL_NS.disjointWith): yield Class(dc, graph=self.graph) def _set_disjointWith(self, other): if not other: return for c in other: self.graph.add( (self.identifier, OWL_NS.disjointWith, classOrIdentifier(c))) @TermDeletionHelper(OWL_NS.disjointWith) def _del_disjointWith(self): pass disjointWith = property( _get_disjointWith, _set_disjointWith, _del_disjointWith) def _get_complementOf(self): comp = list(self.graph.objects( subject=self.identifier, predicate=OWL_NS.complementOf)) if not comp: return None elif len(comp) == 1: return Class(comp[0], graph=self.graph) else: raise Exception(len(comp)) def _set_complementOf(self, other): if not other: return self.graph.add( (self.identifier, OWL_NS.complementOf, classOrIdentifier(other))) @TermDeletionHelper(OWL_NS.complementOf) def _del_complementOf(self): pass complementOf = property( _get_complementOf, _set_complementOf, _del_complementOf) def _get_parents(self): """ computed attributes that returns a generator over taxonomic 'parents' by disjunction, conjunction, and subsumption >>> from rdflib.util import first >>> exNs = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', exNs, override=False) >>> namespace_manager.bind('owl', OWL_NS, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager >>> Individual.factoryGraph = g >>> brother = Class(exNs.Brother) >>> sister = Class(exNs.Sister) >>> sibling = brother | sister >>> sibling.identifier = exNs.Sibling >>> sibling #doctest: +SKIP ( ex:Brother OR ex:Sister ) >>> first(brother.parents) #doctest: +SKIP Class: ex:Sibling EquivalentTo: ( ex:Brother OR ex:Sister ) >>> parent = Class(exNs.Parent) >>> male = Class(exNs.Male) >>> father = parent & male >>> father.identifier = exNs.Father >>> list(father.parents) #doctest: +SKIP [Class: ex:Parent , Class: ex:Male ] """ for parent in itertools.chain(self.subClassOf, self.equivalentClass): yield parent link = first(self.factoryGraph.subjects(RDF.first, self.identifier)) if link: listSiblings = list(self.factoryGraph.transitive_subjects(RDF.rest, link)) if listSiblings: collectionHead = listSiblings[-1] else: collectionHead = link for disjCls in self.factoryGraph.subjects( OWL_NS.unionOf, collectionHead): if isinstance(disjCls, URIRef): yield Class(disjCls, skipOWLClassMembership=True) for rdfList in self.factoryGraph.objects( self.identifier, OWL_NS.intersectionOf): for member in OWLRDFListProxy([rdfList], graph=self.factoryGraph): if isinstance(member, URIRef): yield Class(member, skipOWLClassMembership=True) parents = property(_get_parents) def isPrimitive(self): if (self.identifier, RDF.type, OWL_NS.Restriction) in self.graph: return False # sc = list(self.subClassOf) ec = list(self.equivalentClass) for boolClass, p, rdfList in self.graph.triples_choices( (self.identifier, [OWL_NS.intersectionOf, OWL_NS.unionOf], None)): ec.append(manchesterSyntax(rdfList, self.graph, boolean=p)) for e in ec: return False if self.complementOf: return False return True def subSumpteeIds(self): for s in self.graph.subjects( predicate=RDFS.subClassOf, object=self.identifier): yield s # def __iter__(self): # for s in self.graph.subjects( # predicate=RDFS.subClassOf,object=self.identifier): # yield Class(s,skipOWLClassMembership=True) def __repr__(self, full=False, normalization=True): """ Returns the Manchester Syntax equivalent for this class """ exprs = [] sc = list(self.subClassOf) ec = list(self.equivalentClass) for boolClass, p, rdfList in self.graph.triples_choices( (self.identifier, [OWL_NS.intersectionOf, OWL_NS.unionOf], None)): ec.append(manchesterSyntax(rdfList, self.graph, boolean=p)) dc = list(self.disjointWith) c = self.complementOf if c: dc.append(c) klassKind = '' label = list(self.graph.objects(self.identifier, RDFS.label)) label = label and '(' + label[0] + ')' or '' if sc: if full: scJoin = '\n ' else: scJoin = ', ' necStatements = [ isinstance(s, Class) and isinstance(self.identifier, BNode) and repr(CastClass(s, self.graph)) or # repr(BooleanClass(classOrIdentifier(s), # operator=None, # graph=self.graph)) or manchesterSyntax(classOrIdentifier(s), self.graph) for s in sc] if necStatements: klassKind = "Primitive Type %s" % label exprs.append("SubClassOf: %s" % scJoin.join( [str(n) for n in necStatements])) if full: exprs[-1] = "\n " + exprs[-1] if ec: nec_SuffStatements = [ isinstance(s, str) and s or manchesterSyntax(classOrIdentifier(s), self.graph) for s in ec] if nec_SuffStatements: klassKind = "A Defined Class %s" % label exprs.append("EquivalentTo: %s" % ', '.join(nec_SuffStatements)) if full: exprs[-1] = "\n " + exprs[-1] if dc: exprs.append("DisjointWith %s\n" % '\n '.join( [manchesterSyntax(classOrIdentifier(s), self.graph) for s in dc])) if full: exprs[-1] = "\n " + exprs[-1] descr = list(self.graph.objects(self.identifier, RDFS.comment)) if full and normalization: klassDescr = klassKind and '\n ## %s ##' % klassKind +\ (descr and "\n %s" % descr[0] or '') + \ ' . '.join(exprs) or ' . '.join(exprs) else: klassDescr = full and (descr and "\n %s" % descr[0] or '') or '' + ' . '.join(exprs) return (isinstance(self.identifier, BNode) and "Some Class " or "Class: %s " % self.qname) + klassDescr class OWLRDFListProxy(object): def __init__(self, rdfList, members=None, graph=None): if graph: self.graph = graph members = members and members or [] if rdfList: self._rdfList = Collection(self.graph, rdfList[0]) for member in members: if member not in self._rdfList: self._rdfList.append(classOrIdentifier(member)) else: self._rdfList = Collection(self.graph, BNode(), [classOrIdentifier(m) for m in members]) self.graph.add( (self.identifier, self._operator, self._rdfList.uri)) def __eq__(self, other): """ Equivalence of boolean class constructors is determined by equivalence of its members """ assert isinstance(other, Class), repr(other) + repr(type(other)) if isinstance(other, BooleanClass): length = len(self) if length != len(other): return False else: for idx in range(length): if self[idx] != other[idx]: return False return True else: return self.identifier == other.identifier # Redirect python list accessors to the underlying Collection instance def __len__(self): return len(self._rdfList) def index(self, item): return self._rdfList.index(classOrIdentifier(item)) def __getitem__(self, key): return self._rdfList[key] def __setitem__(self, key, value): self._rdfList[key] = classOrIdentifier(value) def __delitem__(self, key): del self._rdfList[key] def clear(self): self._rdfList.clear() def __iter__(self): for item in self._rdfList: yield item def __contains__(self, item): for i in self._rdfList: if i == classOrIdentifier(item): return 1 return 0 def append(self, item): self._rdfList.append(item) def __iadd__(self, other): self._rdfList.append(classOrIdentifier(other)) return self class EnumeratedClass(OWLRDFListProxy, Class): py3compat.format_doctest_out(""" Class for owl:oneOf forms: OWL Abstract Syntax is used axiom ::= 'EnumeratedClass(' classID ['Deprecated'] { annotation } { individualID } ')' >>> exNs = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', exNs, override=False) >>> namespace_manager.bind('owl', OWL_NS, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager >>> Individual.factoryGraph = g >>> ogbujiBros = EnumeratedClass(exNs.ogbujicBros, ... members=[exNs.chime, ... exNs.uche, ... exNs.ejike]) >>> ogbujiBros #doctest: +SKIP { ex:chime ex:uche ex:ejike } >>> col = Collection(g, first( ... g.objects(predicate=OWL_NS.oneOf, subject=ogbujiBros.identifier))) >>> [g.qname(item) for item in col] [%(u)s'ex:chime', %(u)s'ex:uche', %(u)s'ex:ejike'] >>> print(g.serialize(format='n3')) #doctest: +SKIP @prefix ex: . @prefix owl: . @prefix rdf: . ex:ogbujicBros a owl:Class; owl:oneOf ( ex:chime ex:uche ex:ejike ) . """) _operator = OWL_NS.oneOf def isPrimitive(self): return False def __init__(self, identifier=None, members=None, graph=None): Class.__init__(self, identifier, graph=graph) members = members and members or [] rdfList = list(self.graph.objects( predicate=OWL_NS.oneOf, subject=self.identifier)) OWLRDFListProxy.__init__(self, rdfList, members) def __repr__(self): """ Returns the Manchester Syntax equivalent for this class """ return manchesterSyntax( self._rdfList.uri, self.graph, boolean=self._operator) def serialize(self, graph): clonedList = Collection(graph, BNode()) for cl in self._rdfList: clonedList.append(cl) CastClass(cl, self.graph).serialize(graph) graph.add((self.identifier, self._operator, clonedList.uri)) for s, p, o in self.graph.triples((self.identifier, None, None)): if p != self._operator: graph.add((s, p, o)) self._serialize(graph) BooleanPredicates = [OWL_NS.intersectionOf, OWL_NS.unionOf] class BooleanClassExtentHelper: """ >>> testGraph = Graph() >>> Individual.factoryGraph = testGraph >>> EX = Namespace("http://example.com/") >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', EX, override=False) >>> testGraph.namespace_manager = namespace_manager >>> fire = Class(EX.Fire) >>> water = Class(EX.Water) >>> testClass = BooleanClass(members=[fire, water]) >>> testClass2 = BooleanClass( ... operator=OWL_NS.unionOf, members=[fire, water]) >>> for c in BooleanClass.getIntersections(): ... print(c) #doctest: +SKIP ( ex:Fire AND ex:Water ) >>> for c in BooleanClass.getUnions(): ... print(c) #doctest: +SKIP ( ex:Fire OR ex:Water ) """ def __init__(self, operator): self.operator = operator def __call__(self, f): def _getExtent(): for c in Individual.factoryGraph.subjects(self.operator): yield BooleanClass(c, operator=self.operator) return _getExtent class Callable(): def __init__(self, anycallable): self.__call__ = anycallable class BooleanClass(OWLRDFListProxy, Class): """ See: http://www.w3.org/TR/owl-ref/#Boolean owl:complementOf is an attribute of Class, however """ @BooleanClassExtentHelper(OWL_NS.intersectionOf) @Callable def getIntersections(): pass getIntersections = Callable(getIntersections) @BooleanClassExtentHelper(OWL_NS.unionOf) @Callable def getUnions(): pass getUnions = Callable(getUnions) def __init__(self, identifier=None, operator=OWL_NS.intersectionOf, members=None, graph=None): if operator is None: props = [] for s, p, o in graph.triples_choices((identifier, [OWL_NS.intersectionOf, OWL_NS.unionOf], None)): props.append(p) operator = p assert len(props) == 1, repr(props) Class.__init__(self, identifier, graph=graph) assert operator in [OWL_NS.intersectionOf, OWL_NS.unionOf], str(operator) self._operator = operator rdfList = list( self.graph.objects(predicate=operator, subject=self.identifier)) assert not members or not rdfList, \ "This is a previous boolean class description!" + \ repr(Collection(self.graph, rdfList[0]).n3()) OWLRDFListProxy.__init__(self, rdfList, members) def copy(self): """ Create a copy of this class """ copyOfClass = BooleanClass( operator=self._operator, members=list(self), graph=self.graph) return copyOfClass def serialize(self, graph): clonedList = Collection(graph, BNode()) for cl in self._rdfList: clonedList.append(cl) CastClass(cl, self.graph).serialize(graph) graph.add((self.identifier, self._operator, clonedList.uri)) for s, p, o in self.graph.triples((self.identifier, None, None)): if p != self._operator: graph.add((s, p, o)) self._serialize(graph) def isPrimitive(self): return False def changeOperator(self, newOperator): """ Converts a unionOf / intersectionOf class expression into one that instead uses the given operator >>> testGraph = Graph() >>> Individual.factoryGraph = testGraph >>> EX = Namespace("http://example.com/") >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', EX, override=False) >>> testGraph.namespace_manager = namespace_manager >>> fire = Class(EX.Fire) >>> water = Class(EX.Water) >>> testClass = BooleanClass(members=[fire,water]) >>> testClass #doctest: +SKIP ( ex:Fire AND ex:Water ) >>> testClass.changeOperator(OWL_NS.unionOf) >>> testClass #doctest: +SKIP ( ex:Fire OR ex:Water ) >>> try: testClass.changeOperator(OWL_NS.unionOf) ... except Exception%s: print(e) The new operator is already being used! """ % 'as e' if py3compat.PY3 else ', e' assert newOperator != self._operator, \ "The new operator is already being used!" self.graph.remove((self.identifier, self._operator, self._rdfList.uri)) self.graph.add((self.identifier, newOperator, self._rdfList.uri)) self._operator = newOperator def __repr__(self): """ Returns the Manchester Syntax equivalent for this class """ return manchesterSyntax( self._rdfList.uri, self.graph, boolean=self._operator) def __or__(self, other): """ Adds other to the list and returns self """ assert self._operator == OWL_NS.unionOf self._rdfList.append(classOrIdentifier(other)) return self def AllDifferent(members): """ DisjointClasses(' description description { description } ')' """ pass class Restriction(Class): """ restriction ::= 'restriction(' datavaluedPropertyID dataRestrictionComponent { dataRestrictionComponent } ')' | 'restriction(' individualvaluedPropertyID individualRestrictionComponent { individualRestrictionComponent } ')' """ restrictionKinds = [OWL_NS.allValuesFrom, OWL_NS.someValuesFrom, OWL_NS.hasValue, OWL_NS.maxCardinality, OWL_NS.minCardinality] def __init__(self, onProperty, graph=Graph(), allValuesFrom=None, someValuesFrom=None, value=None, cardinality=None, maxCardinality=None, minCardinality=None, identifier=None): super(Restriction, self).__init__(identifier, graph=graph, skipOWLClassMembership=True) if (self.identifier, OWL_NS.onProperty, propertyOrIdentifier(onProperty)) not in graph: graph.add((self.identifier, OWL_NS.onProperty, propertyOrIdentifier(onProperty))) self.onProperty = onProperty restrTypes = [ (allValuesFrom, OWL_NS.allValuesFrom), (someValuesFrom, OWL_NS.someValuesFrom), (value, OWL_NS.hasValue), (cardinality, OWL_NS.cardinality), (maxCardinality, OWL_NS.maxCardinality), (minCardinality, OWL_NS.minCardinality)] validRestrProps = [(i, oTerm) for (i, oTerm) in restrTypes if i] assert len(validRestrProps) restrictionRange, restrictionType = validRestrProps.pop() self.restrictionType = restrictionType if isinstance(restrictionRange, Identifier): self.restrictionRange = restrictionRange elif isinstance(restrictionRange, Class): self.restrictionRange = classOrIdentifier(restrictionRange) else: self.restrictionRange = first(self.graph.objects(self.identifier, restrictionType)) if (self.identifier, restrictionType, self.restrictionRange) not in self.graph: self.graph.add( (self.identifier, restrictionType, self.restrictionRange)) assert self.restrictionRange is not None, Class(self.identifier) if (self.identifier, RDF.type, OWL_NS.Restriction) not in self.graph: self.graph.add((self.identifier, RDF.type, OWL_NS.Restriction)) self.graph.remove((self.identifier, RDF.type, OWL_NS.Class)) @py3compat.format_doctest_out def serialize(self, graph): """ >>> g1 = Graph() >>> g2 = Graph() >>> EX = Namespace("http://example.com/") >>> namespace_manager = NamespaceManager(g1) >>> namespace_manager.bind('ex', EX, override=False) >>> namespace_manager = NamespaceManager(g2) >>> namespace_manager.bind('ex', EX, override=False) >>> Individual.factoryGraph = g1 >>> prop = Property(EX.someProp, baseType=OWL_NS.DatatypeProperty) >>> restr1 = (Property( ... EX.someProp, ... baseType=OWL_NS.DatatypeProperty)) | some | (Class(EX.Foo)) >>> restr1 #doctest: +SKIP ( ex:someProp SOME ex:Foo ) >>> restr1.serialize(g2) >>> Individual.factoryGraph = g2 >>> list(Property( ... EX.someProp,baseType=None).type ... ) #doctest: +NORMALIZE_WHITESPACE +SKIP [rdflib.term.URIRef( %(u)s'http://www.w3.org/2002/07/owl#DatatypeProperty')] """ Property( self.onProperty, graph=self.graph, baseType=None).serialize(graph) for s, p, o in self.graph.triples((self.identifier, None, None)): graph.add((s, p, o)) if p in [OWL_NS.allValuesFrom, OWL_NS.someValuesFrom]: CastClass(o, self.graph).serialize(graph) def isPrimitive(self): return False def __hash__(self): return hash((self.onProperty, self.restrictionRange)) def __eq__(self, other): """ Equivalence of restrictions is determined by equivalence of the property in question and the restriction 'range' """ assert isinstance(other, Class), repr(other) + repr(type(other)) if isinstance(other, Restriction): return other.onProperty == self.onProperty and \ other.restrictionRange == self.restrictionRange else: return False def _get_onProperty(self): return list(self.graph.objects( subject=self.identifier, predicate=OWL_NS.onProperty))[0] def _set_onProperty(self, prop): triple = ( self.identifier, OWL_NS.onProperty, propertyOrIdentifier(prop)) if not prop: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.onProperty) def _del_onProperty(self): pass onProperty = property(_get_onProperty, _set_onProperty, _del_onProperty) def _get_allValuesFrom(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.allValuesFrom): return Class(i, graph=self.graph) return None def _set_allValuesFrom(self, other): triple = ( self.identifier, OWL_NS.allValuesFrom, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.allValuesFrom) def _del_allValuesFrom(self): pass allValuesFrom = property( _get_allValuesFrom, _set_allValuesFrom, _del_allValuesFrom) def _get_someValuesFrom(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.someValuesFrom): return Class(i, graph=self.graph) return None def _set_someValuesFrom(self, other): triple = ( self.identifier, OWL_NS.someValuesFrom, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.someValuesFrom) def _del_someValuesFrom(self): pass someValuesFrom = property( _get_someValuesFrom, _set_someValuesFrom, _del_someValuesFrom) def _get_hasValue(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.hasValue): return Class(i, graph=self.graph) return None def _set_hasValue(self, other): triple = (self.identifier, OWL_NS.hasValue, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.hasValue) def _del_hasValue(self): pass hasValue = property(_get_hasValue, _set_hasValue, _del_hasValue) def _get_cardinality(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.cardinality): return Class(i, graph=self.graph) return None def _set_cardinality(self, other): triple = ( self.identifier, OWL_NS.cardinality, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.cardinality) def _del_cardinality(self): pass cardinality = property( _get_cardinality, _set_cardinality, _del_cardinality) def _get_maxCardinality(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.maxCardinality): return Class(i, graph=self.graph) return None def _set_maxCardinality(self, other): triple = ( self.identifier, OWL_NS.maxCardinality, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.maxCardinality) def _del_maxCardinality(self): pass maxCardinality = property( _get_maxCardinality, _set_maxCardinality, _del_maxCardinality) def _get_minCardinality(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL_NS.minCardinality): return Class(i, graph=self.graph) return None def _set_minCardinality(self, other): triple = ( self.identifier, OWL_NS.minCardinality, classOrIdentifier(other)) if not other: return elif triple in self.graph: return else: self.graph.set(triple) @TermDeletionHelper(OWL_NS.minCardinality) def _del_minCardinality(self): pass minCardinality = property( _get_minCardinality, _set_minCardinality, _del_minCardinality) def restrictionKind(self): for p in self.graph.triple_choices((self.identifier, self.restrictionKinds, None)): return p.split(OWL_NS)[-1] raise def __repr__(self): """ Returns the Manchester Syntax equivalent for this restriction """ return manchesterSyntax(self.identifier, self.graph) ### Infix Operators ### some = Infix(lambda prop, _class: Restriction(prop, graph=_class.graph, someValuesFrom=_class)) only = Infix(lambda prop, _class: Restriction(prop, graph=_class.graph, allValuesFrom=_class)) max = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, maxCardinality=_class)) min = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, minCardinality=_class)) exactly = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, cardinality=_class)) value = Infix( lambda prop, _class: Restriction(prop, graph=prop.graph, value=_class)) PropertyAbstractSyntax =\ """ %s( %s { %s } %s { 'super(' datavaluedPropertyID ')'} ['Functional'] { domain( %s ) } { range( %s ) } )""" class Property(AnnotatableTerms): """ axiom ::= 'DatatypeProperty(' datavaluedPropertyID ['Deprecated'] { annotation } { 'super(' datavaluedPropertyID ')'} ['Functional'] { 'domain(' description ')' } { 'range(' dataRange ')' } ')' | 'ObjectProperty(' individualvaluedPropertyID ['Deprecated'] { annotation } { 'super(' individualvaluedPropertyID ')' } [ 'inverseOf(' individualvaluedPropertyID ')' ] [ 'Symmetric' ] [ 'Functional' | 'InverseFunctional' | 'Functional' 'InverseFunctional' | 'Transitive' ] { 'domain(' description ')' } { 'range(' description ')' } ') """ def setupVerbAnnotations(self, verbAnnotations): if isinstance(verbAnnotations, tuple): TV_sgProp, TV_plProp, TV_vbg = verbAnnotations else: TV_sgProp = verbAnnotations TV_plProp = verbAnnotations TV_vbg = verbAnnotations if TV_sgProp: self.TV_sgProp.extent = [(self.identifier, self.handleAnnotation(TV_sgProp))] if TV_plProp: self.TV_plProp.extent = [(self.identifier, self.handleAnnotation(TV_plProp))] if TV_vbg: self.TV_vbgProp.extent = [(self.identifier, self.handleAnnotation(TV_vbg))] def __init__( self, identifier=None, graph=None, baseType=OWL_NS.ObjectProperty, subPropertyOf=None, domain=None, range=None, inverseOf=None, otherType=None, equivalentProperty=None, comment=None, verbAnnotations=None, nameAnnotation=None, nameIsLabel=False): super(Property, self).__init__(identifier, graph, nameAnnotation, nameIsLabel) if verbAnnotations: self.setupVerbAnnotations(verbAnnotations) assert not isinstance(self.identifier, BNode) if baseType is None: # None give, determine via introspection self._baseType = first( Individual(self.identifier, graph=self.graph).type) else: if (self.identifier, RDF.type, baseType) not in self.graph: self.graph.add((self.identifier, RDF.type, baseType)) self._baseType = baseType self.subPropertyOf = subPropertyOf self.inverseOf = inverseOf self.domain = domain self.range = range self.comment = comment and comment or [] def serialize(self, graph): for fact in self.graph.triples((self.identifier, None, None)): graph.add(fact) for p in itertools.chain(self.subPropertyOf, self.inverseOf): p.serialize(graph) for c in itertools.chain(self.domain, self.range): CastClass(c, self.graph).serialize(graph) def _get_extent(self, graph=None): for triple in (graph is None and self.graph or graph).triples( (None, self.identifier, None)): yield triple def _set_extent(self, other): if not other: return for subj, obj in other: self.graph.add((subj, self.identifier, obj)) extent = property(_get_extent, _set_extent) def __repr__(self): rt = [] if OWL_NS.ObjectProperty in self.type: rt.append('ObjectProperty( %s annotation(%s)' % (self.qname, first(self.comment) and first(self.comment) or '')) if first(self.inverseOf): twoLinkInverse = first(first(self.inverseOf).inverseOf) if twoLinkInverse \ and twoLinkInverse.identifier == self.identifier: inverseRepr = first(self.inverseOf).qname else: inverseRepr = repr(first(self.inverseOf)) rt.append(" inverseOf( %s )%s" % ( inverseRepr, OWL_NS.SymmetricProperty in self.type and ' Symmetric' or '')) for s, p, roleType in self.graph.triples_choices( (self.identifier, RDF.type, [OWL_NS.FunctionalProperty, OWL_NS.InverseFunctionalProperty, OWL_NS.TransitiveProperty])): rt.append(str(roleType.split(OWL_NS)[-1])) else: rt.append('DatatypeProperty( %s %s' % (self.qname, first(self.comment) and first(self.comment) or '')) for s, p, roleType in self.graph.triples(( self.identifier, RDF.type, OWL_NS.FunctionalProperty)): rt.append(' Functional') def canonicalName(term, g): normalizedName = classOrIdentifier(term) if isinstance(normalizedName, BNode): return term elif normalizedName.startswith(_XSD_NS): return str(term) elif first(g.triples_choices(( normalizedName, [OWL_NS.unionOf, OWL_NS.intersectionOf], None))): return repr(term) else: return str(term.qname) rt.append(' '.join([" super( %s )" % canonicalName( superP, self.graph) for superP in self.subPropertyOf])) rt.append(' '.join([" domain( %s )" % canonicalName( domain, self.graph) for domain in self.domain])) rt.append(' '.join([" range( %s )" % canonicalName( range, self.graph) for range in self.range])) rt = '\n'.join([expr for expr in rt if expr]) rt += '\n)' return str(rt).encode('utf-8') def _get_subPropertyOf(self): for anc in self.graph.objects( subject=self.identifier, predicate=RDFS.subPropertyOf): yield Property(anc, graph=self.graph, baseType=None) def _set_subPropertyOf(self, other): if not other: return for sP in other: self.graph.add( (self.identifier, RDFS.subPropertyOf, classOrIdentifier(sP))) @TermDeletionHelper(RDFS.subPropertyOf) def _del_subPropertyOf(self): pass subPropertyOf = property( _get_subPropertyOf, _set_subPropertyOf, _del_subPropertyOf) def _get_inverseOf(self): for anc in self.graph.objects( subject=self.identifier, predicate=OWL_NS.inverseOf): yield Property(anc, graph=self.graph, baseType=None) def _set_inverseOf(self, other): if not other: return self.graph.add( (self.identifier, OWL_NS.inverseOf, classOrIdentifier(other))) @TermDeletionHelper(OWL_NS.inverseOf) def _del_inverseOf(self): pass inverseOf = property(_get_inverseOf, _set_inverseOf, _del_inverseOf) def _get_domain(self): for dom in self.graph.objects( subject=self.identifier, predicate=RDFS.domain): yield Class(dom, graph=self.graph) def _set_domain(self, other): if not other: return if isinstance(other, (Individual, Identifier)): self.graph.add( (self.identifier, RDFS.domain, classOrIdentifier(other))) else: for dom in other: self.graph.add( (self.identifier, RDFS.domain, classOrIdentifier(dom))) @TermDeletionHelper(RDFS.domain) def _del_domain(self): pass domain = property(_get_domain, _set_domain, _del_domain) def _get_range(self): for ran in self.graph.objects( subject=self.identifier, predicate=RDFS.range): yield Class(ran, graph=self.graph) def _set_range(self, ranges): if not ranges: return if isinstance(ranges, (Individual, Identifier)): self.graph.add( (self.identifier, RDFS.range, classOrIdentifier(ranges))) else: for range in ranges: self.graph.add( (self.identifier, RDFS.range, classOrIdentifier(range))) @TermDeletionHelper(RDFS.range) def _del_range(self): pass range = property(_get_range, _set_range, _del_range) def replace(self, other): # extension = [] for s, p, o in self.extent: self.graph.add((s, propertyOrIdentifier(other), o)) self.graph.remove((None, self.identifier, None)) def CommonNSBindings(graph, additionalNS={}): """ Takes a graph and binds the common namespaces (rdf,rdfs, & owl) """ namespace_manager = NamespaceManager(graph) namespace_manager.bind('rdfs', RDFS) namespace_manager.bind('rdf', RDF) namespace_manager.bind('owl', OWL_NS) for prefix, uri in list(additionalNS.items()): namespace_manager.bind(prefix, uri, override=False) graph.namespace_manager = namespace_manager def test(): import doctest doctest.testmod() if __name__ == '__main__': test() rdflib-4.1.2/rdflib/graph.py000066400000000000000000002003721232323236500157020ustar00rootroot00000000000000from rdflib.term import Literal # required for doctests l = Literal('') del l from rdflib.namespace import Namespace # required for doctests n = Namespace('xxx') del n from rdflib.py3compat import format_doctest_out __doc__ = format_doctest_out("""\ RDFLib defines the following kinds of Graphs: * :class:`~rdflib.graph.Graph` * :class:`~rdflib.graph.QuotedGraph` * :class:`~rdflib.graph.ConjunctiveGraph` * :class:`~rdflib.graph.Dataset` Graph ----- An RDF graph is a set of RDF triples. Graphs support the python ``in`` operator, as well as iteration and some operations like union, difference and intersection. see :class:`~rdflib.graph.Graph` Conjunctive Graph ----------------- A Conjunctive Graph is the most relevant collection of graphs that are considered to be the boundary for closed world assumptions. This boundary is equivalent to that of the store instance (which is itself uniquely identified and distinct from other instances of :class:`Store` that signify other Conjunctive Graphs). It is equivalent to all the named graphs within it and associated with a ``_default_`` graph which is automatically assigned a :class:`BNode` for an identifier - if one isn't given. see :class:`~rdflib.graph.ConjunctiveGraph` Quoted graph ------------ The notion of an RDF graph [14] is extended to include the concept of a formula node. A formula node may occur wherever any other kind of node can appear. Associated with a formula node is an RDF graph that is completely disjoint from all other graphs; i.e. has no nodes in common with any other graph. (It may contain the same labels as other RDF graphs; because this is, by definition, a separate graph, considerations of tidiness do not apply between the graph at a formula node and any other graph.) This is intended to map the idea of "{ N3-expression }" that is used by N3 into an RDF graph upon which RDF semantics is defined. see :class:`~rdflib.graph.QuotedGraph` Dataset ------- The RDF 1.1 Dataset, a small extension to the Conjunctive Graph. The primary term is "graphs in the datasets" and not "contexts with quads" so there is a separate method to set/retrieve a graph in a dataset and to operate with dataset graphs. As a consequence of this approach, dataset graphs cannot be identified with blank nodes, a name is always required (RDFLib will automatically add a name if one is not provided at creation time). This implementation includes a convenience method to directly add a single quad to a dataset graph. see :class:`~rdflib.graph.Dataset` Working with graphs =================== Instantiating Graphs with default store (IOMemory) and default identifier (a BNode): >>> g = Graph() >>> g.store.__class__ >>> g.identifier.__class__ Instantiating Graphs with a IOMemory store and an identifier - : >>> g = Graph('IOMemory', URIRef("http://rdflib.net")) >>> g.identifier rdflib.term.URIRef(%(u)s'http://rdflib.net') >>> str(g) # doctest: +NORMALIZE_WHITESPACE " a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label 'IOMemory']." Creating a ConjunctiveGraph - The top level container for all named Graphs in a 'database': >>> g = ConjunctiveGraph() >>> str(g.default_context) "[a rdfg:Graph;rdflib:storage [a rdflib:Store;rdfs:label 'IOMemory']]." Adding / removing reified triples to Graph and iterating over it directly or via triple pattern: >>> g = Graph() >>> statementId = BNode() >>> print(len(g)) 0 >>> g.add((statementId, RDF.type, RDF.Statement)) >>> g.add((statementId, RDF.subject, ... URIRef(%(u)s'http://rdflib.net/store/ConjunctiveGraph'))) >>> g.add((statementId, RDF.predicate, RDFS.label)) >>> g.add((statementId, RDF.object, Literal("Conjunctive Graph"))) >>> print(len(g)) 4 >>> for s, p, o in g: ... print(type(s)) ... >>> for s, p, o in g.triples((None, RDF.object, None)): ... print(o) ... Conjunctive Graph >>> g.remove((statementId, RDF.type, RDF.Statement)) >>> print(len(g)) 3 ``None`` terms in calls to :meth:`~rdflib.graph.Graph.triples` can be thought of as "open variables". Graph support set-theoretic operators, you can add/subtract graphs, as well as intersection (with multiplication operator g1*g2) and xor (g1 ^ g2). Note that BNode IDs are kept when doing set-theoretic operations, this may or may not be what you want. Two named graphs within the same application probably want share BNode IDs, two graphs with data from different sources probably not. If your BNode IDs are all generated by RDFLib they are UUIDs and unique. >>> g1 = Graph() >>> g2 = Graph() >>> u = URIRef(%(u)s'http://example.com/foo') >>> g1.add([u, RDFS.label, Literal('foo')]) >>> g1.add([u, RDFS.label, Literal('bar')]) >>> g2.add([u, RDFS.label, Literal('foo')]) >>> g2.add([u, RDFS.label, Literal('bing')]) >>> len(g1 + g2) # adds bing as label 3 >>> len(g1 - g2) # removes foo 1 >>> len(g1 * g2) # only foo 1 >>> g1 += g2 # now g1 contains everything Graph Aggregation - ConjunctiveGraphs and ReadOnlyGraphAggregate within the same store: >>> store = plugin.get('IOMemory', Store)() >>> g1 = Graph(store) >>> g2 = Graph(store) >>> g3 = Graph(store) >>> stmt1 = BNode() >>> stmt2 = BNode() >>> stmt3 = BNode() >>> g1.add((stmt1, RDF.type, RDF.Statement)) >>> g1.add((stmt1, RDF.subject, ... URIRef(%(u)s'http://rdflib.net/store/ConjunctiveGraph'))) >>> g1.add((stmt1, RDF.predicate, RDFS.label)) >>> g1.add((stmt1, RDF.object, Literal("Conjunctive Graph"))) >>> g2.add((stmt2, RDF.type, RDF.Statement)) >>> g2.add((stmt2, RDF.subject, ... URIRef(%(u)s'http://rdflib.net/store/ConjunctiveGraph'))) >>> g2.add((stmt2, RDF.predicate, RDF.type)) >>> g2.add((stmt2, RDF.object, RDFS.Class)) >>> g3.add((stmt3, RDF.type, RDF.Statement)) >>> g3.add((stmt3, RDF.subject, ... URIRef(%(u)s'http://rdflib.net/store/ConjunctiveGraph'))) >>> g3.add((stmt3, RDF.predicate, RDFS.comment)) >>> g3.add((stmt3, RDF.object, Literal( ... "The top-level aggregate graph - The sum " + ... "of all named graphs within a Store"))) >>> len(list(ConjunctiveGraph(store).subjects(RDF.type, RDF.Statement))) 3 >>> len(list(ReadOnlyGraphAggregate([g1,g2]).subjects( ... RDF.type, RDF.Statement))) 2 ConjunctiveGraphs have a :meth:`~rdflib.graph.ConjunctiveGraph.quads` method which returns quads instead of triples, where the fourth item is the Graph (or subclass thereof) instance in which the triple was asserted: >>> uniqueGraphNames = set( ... [graph.identifier for s, p, o, graph in ConjunctiveGraph(store ... ).quads((None, RDF.predicate, None))]) >>> len(uniqueGraphNames) 3 >>> unionGraph = ReadOnlyGraphAggregate([g1, g2]) >>> uniqueGraphNames = set( ... [graph.identifier for s, p, o, graph in unionGraph.quads( ... (None, RDF.predicate, None))]) >>> len(uniqueGraphNames) 2 Parsing N3 from a string >>> g2 = Graph() >>> src = ''' ... @prefix rdf: . ... @prefix rdfs: . ... [ a rdf:Statement ; ... rdf:subject ; ... rdf:predicate rdfs:label; ... rdf:object "Conjunctive Graph" ] . ... ''' >>> g2 = g2.parse(data=src, format='n3') >>> print(len(g2)) 4 Using Namespace class: >>> RDFLib = Namespace('http://rdflib.net/') >>> RDFLib.ConjunctiveGraph rdflib.term.URIRef(%(u)s'http://rdflib.net/ConjunctiveGraph') >>> RDFLib['Graph'] rdflib.term.URIRef(%(u)s'http://rdflib.net/Graph') """) import logging _logger = logging.getLogger(__name__) # import md5 import random import warnings from hashlib import md5 try: from io import BytesIO assert BytesIO except ImportError: try: from cStringIO import StringIO as BytesIO assert BytesIO except ImportError: from StringIO import StringIO as BytesIO assert BytesIO from rdflib.namespace import RDF, RDFS, SKOS from rdflib import plugin, exceptions, query from rdflib.term import Node, URIRef, Genid from rdflib.term import BNode import rdflib.term from rdflib.paths import Path from rdflib.store import Store from rdflib.serializer import Serializer from rdflib.parser import Parser from rdflib.parser import create_input_source from rdflib.namespace import NamespaceManager from rdflib.resource import Resource from rdflib import py3compat b = py3compat.b import os import shutil import tempfile from urlparse import urlparse __all__ = [ 'Graph', 'ConjunctiveGraph', 'QuotedGraph', 'Seq', 'ModificationException', 'Dataset', 'UnSupportedAggregateOperation', 'ReadOnlyGraphAggregate'] class Graph(Node): """An RDF Graph The constructor accepts one argument, the 'store' that will be used to store the graph data (see the 'store' package for stores currently shipped with rdflib). Stores can be context-aware or unaware. Unaware stores take up (some) less space but cannot support features that require context, such as true merging/demerging of sub-graphs and provenance. The Graph constructor can take an identifier which identifies the Graph by name. If none is given, the graph is assigned a BNode for its identifier. For more on named graphs, see: http://www.w3.org/2004/03/trix/ """ def __init__(self, store='default', identifier=None, namespace_manager=None): super(Graph, self).__init__() self.__identifier = identifier or BNode() if not isinstance(self.__identifier, Node): self.__identifier = URIRef(self.__identifier) if not isinstance(store, Store): # TODO: error handling self.__store = store = plugin.get(store, Store)() else: self.__store = store self.__namespace_manager = namespace_manager self.context_aware = False self.formula_aware = False self.default_union = False def __get_store(self): return self.__store store = property(__get_store) # read-only attr def __get_identifier(self): return self.__identifier identifier = property(__get_identifier) # read-only attr def _get_namespace_manager(self): if self.__namespace_manager is None: self.__namespace_manager = NamespaceManager(self) return self.__namespace_manager def _set_namespace_manager(self, nm): self.__namespace_manager = nm namespace_manager = property(_get_namespace_manager, _set_namespace_manager, doc="this graph's namespace-manager") def __repr__(self): return "" % (self.identifier, type(self)) def __str__(self): if isinstance(self.identifier, URIRef): return ("%s a rdfg:Graph;rdflib:storage " + "[a rdflib:Store;rdfs:label '%s'].") % ( self.identifier.n3(), self.store.__class__.__name__) else: return ("[a rdfg:Graph;rdflib:storage " + "[a rdflib:Store;rdfs:label '%s']].") % ( self.store.__class__.__name__) def toPython(self): return self def destroy(self, configuration): """Destroy the store identified by `configuration` if supported""" self.__store.destroy(configuration) # Transactional interfaces (optional) def commit(self): """Commits active transactions""" self.__store.commit() def rollback(self): """Rollback active transactions""" self.__store.rollback() def open(self, configuration, create=False): """Open the graph store Might be necessary for stores that require opening a connection to a database or acquiring some resource. """ return self.__store.open(configuration, create) def close(self, commit_pending_transaction=False): """Close the graph store Might be necessary for stores that require closing a connection to a database or releasing some resource. """ self.__store.close( commit_pending_transaction=commit_pending_transaction) def add(self, (s, p, o)): """Add a triple with self as context""" assert isinstance(s, Node), \ "Subject %s must be an rdflib term" % (s,) assert isinstance(p, Node), \ "Predicate %s must be an rdflib term" % (p,) assert isinstance(o, Node), \ "Object %s must be an rdflib term" % (o,) self.__store.add((s, p, o), self, quoted=False) def addN(self, quads): """Add a sequence of triple with context""" self.__store.addN((s, p, o, c) for s, p, o, c in quads if isinstance(c, Graph) and c.identifier is self.identifier and _assertnode(s,p,o) ) def remove(self, (s, p, o)): """Remove a triple from the graph If the triple does not provide a context attribute, removes the triple from all contexts. """ self.__store.remove((s, p, o), context=self) def triples(self, (s, p, o)): """Generator over the triple store Returns triples that match the given triple pattern. If triple pattern does not provide a context, all contexts will be searched. """ if isinstance(p, Path): for _s, _o in p.eval(self, s, o): yield (_s, p, _o) else: for (s, p, o), cg in self.__store.triples((s, p, o), context=self): yield (s, p, o) @py3compat.format_doctest_out def __getitem__(self, item): """ A graph can be "sliced" as a shortcut for the triples method The python slice syntax is (ab)used for specifying triples. A generator over matches is returned, the returned tuples include only the parts not given >>> import rdflib >>> g = rdflib.Graph() >>> g.add((rdflib.URIRef('urn:bob'), rdflib.RDFS.label, rdflib.Literal('Bob'))) >>> list(g[rdflib.URIRef('urn:bob')]) # all triples about bob [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2000/01/rdf-schema#label'), rdflib.term.Literal(%(u)s'Bob'))] >>> list(g[:rdflib.RDFS.label]) # all label triples [(rdflib.term.URIRef(%(u)s'urn:bob'), rdflib.term.Literal(%(u)s'Bob'))] >>> list(g[::rdflib.Literal('Bob')]) # all triples with bob as object [(rdflib.term.URIRef(%(u)s'urn:bob'), rdflib.term.URIRef(%(u)s'http://www.w3.org/2000/01/rdf-schema#label'))] Combined with SPARQL paths, more complex queries can be written concisely: Name of all Bobs friends: g[bob : FOAF.knows/FOAF.name ] Some label for Bob: g[bob : DC.title|FOAF.name|RDFS.label] All friends and friends of friends of Bob g[bob : FOAF.knows * '+'] etc. .. versionadded:: 4.0 """ if isinstance(item, slice): s,p,o=item.start,item.stop,item.step if s is None and p is None and o is None: return self.triples((s,p,o)) elif s is None and p is None: return self.subject_predicates(o) elif s is None and o is None: return self.subject_objects(p) elif p is None and o is None: return self.predicate_objects(s) elif s is None: return self.subjects(p,o) elif p is None: return self.predicates(s,o) elif o is None: return self.objects(s,p) else: # all given return (s,p,o) in self elif isinstance(item, (Path,Node)): return self.predicate_objects(item) else: raise TypeError("You can only index a graph by a single rdflib term or path, or a slice of rdflib terms.") def __len__(self): """Returns the number of triples in the graph If context is specified then the number of triples in the context is returned instead. """ return self.__store.__len__(context=self) def __iter__(self): """Iterates over all triples in the store""" return self.triples((None, None, None)) def __contains__(self, triple): """Support for 'triple in graph' syntax""" for triple in self.triples(triple): return True return False def __hash__(self): return hash(self.identifier) def md5_term_hash(self): d = md5(str(self.identifier)) d.update("G") return d.hexdigest() def __cmp__(self, other): if other is None: return -1 elif isinstance(other, Graph): return cmp(self.identifier, other.identifier) else: # Note if None is considered equivalent to owl:Nothing # Then perhaps a graph with length 0 should be considered # equivalent to None (if compared to it)? return 1 def __eq__(self, other): return isinstance(other, Graph) \ and self.identifier == other.identifier def __lt__(self, other): return (other is None) \ or (isinstance(other, Graph) and self.identifier < other.identifier) def __le__(self, other): return self < other or self == other def __gt__(self, other): return (isinstance(other, Graph) and self.identifier > other.identifier) \ or (other is not None) def __ge__(self, other): return self > other or self == other def __iadd__(self, other): """Add all triples in Graph other to Graph. BNode IDs are not changed.""" self.addN((s, p, o, self) for s, p, o in other) return self def __isub__(self, other): """Subtract all triples in Graph other from Graph. BNode IDs are not changed.""" for triple in other: self.remove(triple) return self def __add__(self, other): """Set-theoretic union BNode IDs are not changed.""" retval = Graph() for (prefix, uri) in set( list(self.namespaces()) + list(other.namespaces())): retval.bind(prefix, uri) for x in self: retval.add(x) for y in other: retval.add(y) return retval def __mul__(self, other): """Set-theoretic intersection. BNode IDs are not changed.""" retval = Graph() for x in other: if x in self: retval.add(x) return retval def __sub__(self, other): """Set-theoretic difference. BNode IDs are not changed.""" retval = Graph() for x in self: if not x in other: retval.add(x) return retval def __xor__(self, other): """Set-theoretic XOR. BNode IDs are not changed.""" return (self - other) + (other - self) __or__ = __add__ __and__ = __mul__ # Conv. methods def set(self, triple): """Convenience method to update the value of object Remove any existing triples for subject and predicate before adding (subject, predicate, object). """ (subject, predicate, object) = triple self.remove((subject, predicate, None)) self.add((subject, predicate, object)) def subjects(self, predicate=None, object=None): """A generator of subjects with the given predicate and object""" for s, p, o in self.triples((None, predicate, object)): yield s def predicates(self, subject=None, object=None): """A generator of predicates with the given subject and object""" for s, p, o in self.triples((subject, None, object)): yield p def objects(self, subject=None, predicate=None): """A generator of objects with the given subject and predicate""" for s, p, o in self.triples((subject, predicate, None)): yield o def subject_predicates(self, object=None): """A generator of (subject, predicate) tuples for the given object""" for s, p, o in self.triples((None, None, object)): yield s, p def subject_objects(self, predicate=None): """A generator of (subject, object) tuples for the given predicate""" for s, p, o in self.triples((None, predicate, None)): yield s, o def predicate_objects(self, subject=None): """A generator of (predicate, object) tuples for the given subject""" for s, p, o in self.triples((subject, None, None)): yield p, o def triples_choices(self, (subject, predicate, object_), context=None): for (s, p, o), cg in self.store.triples_choices( (subject, predicate, object_), context=self): yield (s, p, o) def value(self, subject=None, predicate=RDF.value, object=None, default=None, any=True): """Get a value for a pair of two criteria Exactly one of subject, predicate, object must be None. Useful if one knows that there may only be one value. It is one of those situations that occur a lot, hence this 'macro' like utility Parameters: subject, predicate, object -- exactly one must be None default -- value to be returned if no values found any -- if True, return any value in the case there is more than one, else, raise UniquenessError """ retval = default if (subject is None and predicate is None) or \ (subject is None and object is None) or \ (predicate is None and object is None): return None if object is None: values = self.objects(subject, predicate) if subject is None: values = self.subjects(predicate, object) if predicate is None: values = self.predicates(subject, object) try: retval = values.next() except StopIteration: retval = default else: if any is False: try: values.next() msg = ("While trying to find a value for (%s, %s, %s) the" " following multiple values where found:\n" % (subject, predicate, object)) triples = self.store.triples( (subject, predicate, object), None) for (s, p, o), contexts in triples: msg += "(%s, %s, %s)\n (contexts: %s)\n" % ( s, p, o, list(contexts)) raise exceptions.UniquenessError(msg) except StopIteration: pass return retval def label(self, subject, default=''): """Query for the RDFS.label of the subject Return default if no label exists or any label if multiple exist. """ if subject is None: return default return self.value(subject, RDFS.label, default=default, any=True) @py3compat.format_doctest_out def preferredLabel(self, subject, lang=None, default=None, labelProperties=(SKOS.prefLabel, RDFS.label)): """ Find the preferred label for subject. By default prefers skos:prefLabels over rdfs:labels. In case at least one prefLabel is found returns those, else returns labels. In case a language string (e.g., 'en', 'de' or even '' for no lang-tagged literals) is given, only such labels will be considered. Return a list of (labelProp, label) pairs, where labelProp is either skos:prefLabel or rdfs:label. >>> from rdflib import ConjunctiveGraph, URIRef, RDFS, Literal >>> from rdflib.namespace import SKOS >>> from pprint import pprint >>> g = ConjunctiveGraph() >>> u = URIRef(%(u)s'http://example.com/foo') >>> g.add([u, RDFS.label, Literal('foo')]) >>> g.add([u, RDFS.label, Literal('bar')]) >>> pprint(sorted(g.preferredLabel(u))) [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2000/01/rdf-schema#label'), rdflib.term.Literal(%(u)s'bar')), (rdflib.term.URIRef(%(u)s'http://www.w3.org/2000/01/rdf-schema#label'), rdflib.term.Literal(%(u)s'foo'))] >>> g.add([u, SKOS.prefLabel, Literal('bla')]) >>> pprint(g.preferredLabel(u)) [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2004/02/skos/core#prefLabel'), rdflib.term.Literal(%(u)s'bla'))] >>> g.add([u, SKOS.prefLabel, Literal('blubb', lang='en')]) >>> sorted(g.preferredLabel(u)) #doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2004/02/skos/core#prefLabel'), rdflib.term.Literal(%(u)s'bla')), (rdflib.term.URIRef(%(u)s'http://www.w3.org/2004/02/skos/core#prefLabel'), rdflib.term.Literal(%(u)s'blubb', lang='en'))] >>> g.preferredLabel(u, lang='') #doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2004/02/skos/core#prefLabel'), rdflib.term.Literal(%(u)s'bla'))] >>> pprint(g.preferredLabel(u, lang='en')) [(rdflib.term.URIRef(%(u)s'http://www.w3.org/2004/02/skos/core#prefLabel'), rdflib.term.Literal(%(u)s'blubb', lang='en'))] """ if default is None: default = [] # setup the language filtering if lang is not None: if lang == '': # we only want not language-tagged literals langfilter = lambda l: l.language is None else: langfilter = lambda l: l.language == lang else: # we don't care about language tags langfilter = lambda l: True for labelProp in labelProperties: labels = filter(langfilter, self.objects(subject, labelProp)) if len(labels) == 0: continue else: return [(labelProp, l) for l in labels] return default def comment(self, subject, default=''): """Query for the RDFS.comment of the subject Return default if no comment exists """ if subject is None: return default return self.value(subject, RDFS.comment, default=default, any=True) def items(self, list): """Generator over all items in the resource specified by list list is an RDF collection. """ chain = set([list]) while list: item = self.value(list, RDF.first) if item: yield item list = self.value(list, RDF.rest) if list in chain: raise ValueError("List contains a recursive rdf:rest reference") chain.add(list) def transitiveClosure(self, func, arg, seen=None): """ Generates transitive closure of a user-defined function against the graph >>> from rdflib.collection import Collection >>> g=Graph() >>> a=BNode('foo') >>> b=BNode('bar') >>> c=BNode('baz') >>> g.add((a,RDF.first,RDF.type)) >>> g.add((a,RDF.rest,b)) >>> g.add((b,RDF.first,RDFS.label)) >>> g.add((b,RDF.rest,c)) >>> g.add((c,RDF.first,RDFS.comment)) >>> g.add((c,RDF.rest,RDF.nil)) >>> def topList(node,g): ... for s in g.subjects(RDF.rest,node): ... yield s >>> def reverseList(node,g): ... for f in g.objects(node,RDF.first): ... print(f) ... for s in g.subjects(RDF.rest,node): ... yield s >>> [rt for rt in g.transitiveClosure( ... topList,RDF.nil)] # doctest: +NORMALIZE_WHITESPACE [rdflib.term.BNode('baz'), rdflib.term.BNode('bar'), rdflib.term.BNode('foo')] >>> [rt for rt in g.transitiveClosure( ... reverseList,RDF.nil)] # doctest: +NORMALIZE_WHITESPACE http://www.w3.org/2000/01/rdf-schema#comment http://www.w3.org/2000/01/rdf-schema#label http://www.w3.org/1999/02/22-rdf-syntax-ns#type [rdflib.term.BNode('baz'), rdflib.term.BNode('bar'), rdflib.term.BNode('foo')] """ if seen is None: seen = {} elif arg in seen: return seen[arg] = 1 for rt in func(arg, self): yield rt for rt_2 in self.transitiveClosure(func, rt, seen): yield rt_2 def transitive_objects(self, subject, property, remember=None): """Transitively generate objects for the ``property`` relationship Generated objects belong to the depth first transitive closure of the ``property`` relationship starting at ``subject``. """ if remember is None: remember = {} if subject in remember: return remember[subject] = 1 yield subject for object in self.objects(subject, property): for o in self.transitive_objects(object, property, remember): yield o def transitive_subjects(self, predicate, object, remember=None): """Transitively generate objects for the ``property`` relationship Generated objects belong to the depth first transitive closure of the ``property`` relationship starting at ``subject``. """ if remember is None: remember = {} if object in remember: return remember[object] = 1 yield object for subject in self.subjects(predicate, object): for s in self.transitive_subjects(predicate, subject, remember): yield s def seq(self, subject): """Check if subject is an rdf:Seq If yes, it returns a Seq class instance, None otherwise. """ if (subject, RDF.type, RDF.Seq) in self: return Seq(self, subject) else: return None def qname(self, uri): return self.namespace_manager.qname(uri) def compute_qname(self, uri, generate=True): return self.namespace_manager.compute_qname(uri, generate) def bind(self, prefix, namespace, override=True): """Bind prefix to namespace If override is True will bind namespace to given prefix even if namespace was already bound to a different prefix. for example: graph.bind('foaf', 'http://xmlns.com/foaf/0.1/') """ return self.namespace_manager.bind( prefix, namespace, override=override) def namespaces(self): """Generator over all the prefix, namespace tuples""" for prefix, namespace in self.namespace_manager.namespaces(): yield prefix, namespace def absolutize(self, uri, defrag=1): """Turn uri into an absolute URI if it's not one already""" return self.namespace_manager.absolutize(uri, defrag) def serialize(self, destination=None, format="xml", base=None, encoding=None, **args): """Serialize the Graph to destination If destination is None serialize method returns the serialization as a string. Format defaults to xml (AKA rdf/xml). Format support can be extended with plugins, but 'xml', 'n3', 'turtle', 'nt', 'pretty-xml', trix' are built in. """ serializer = plugin.get(format, Serializer)(self) if destination is None: stream = BytesIO() serializer.serialize(stream, base=base, encoding=encoding, **args) return stream.getvalue() if hasattr(destination, "write"): stream = destination serializer.serialize(stream, base=base, encoding=encoding, **args) else: location = destination scheme, netloc, path, params, _query, fragment = urlparse(location) if netloc != "": print("WARNING: not saving as location" + "is not a local file reference") return fd, name = tempfile.mkstemp() stream = os.fdopen(fd, "wb") serializer.serialize(stream, base=base, encoding=encoding, **args) stream.close() if hasattr(shutil, "move"): shutil.move(name, path) else: shutil.copy(name, path) os.remove(name) def parse(self, source=None, publicID=None, format=None, location=None, file=None, data=None, **args): """ Parse source adding the resulting triples to the Graph. The source is specified using one of source, location, file or data. :Parameters: - `source`: An InputSource, file-like object, or string. In the case of a string the string is the location of the source. - `location`: A string indicating the relative or absolute URL of the source. Graph's absolutize method is used if a relative location is specified. - `file`: A file-like object. - `data`: A string containing the data to be parsed. - `format`: Used if format can not be determined from source. Defaults to rdf/xml. Format support can be extended with plugins, but 'xml', 'n3', 'nt', 'trix', 'rdfa' are built in. - `publicID`: the logical URI to use as the document base. If None specified the document location is used (at least in the case where there is a document location). :Returns: - self, the graph instance. Examples: >>> my_data = ''' ... ... ... Example ... This is really just an example. ... ... ... ''' >>> import tempfile >>> fd, file_name = tempfile.mkstemp() >>> f = os.fdopen(fd, 'w') >>> dummy = f.write(my_data) # Returns num bytes written on py3 >>> f.close() >>> g = Graph() >>> result = g.parse(data=my_data, format="application/rdf+xml") >>> len(g) 2 >>> g = Graph() >>> result = g.parse(location=file_name, format="application/rdf+xml") >>> len(g) 2 >>> g = Graph() >>> result = g.parse(file=open(file_name, "r"), ... format="application/rdf+xml") >>> len(g) 2 >>> os.remove(file_name) """ source = create_input_source(source=source, publicID=publicID, location=location, file=file, data=data, format=format) if format is None: format = source.content_type if format is None: # raise Exception("Could not determine format for %r. You can" + \ # "expicitly specify one with the format argument." % source) format = "application/rdf+xml" parser = plugin.get(format, Parser)() parser.parse(source, self, **args) return self def load(self, source, publicID=None, format="xml"): self.parse(source, publicID, format) def query(self, query_object, processor='sparql', result='sparql', initNs=None, initBindings=None, use_store_provided=True, **kwargs): """ Query this graph. A type of 'prepared queries' can be realised by providing initial variable bindings with initBindings Initial namespaces are used to resolve prefixes used in the query, if none are given, the namespaces from the graph's namespace manager are used. :returntype: rdflib.query.QueryResult """ initBindings = initBindings or {} initNs = initNs or dict(self.namespaces()) if hasattr(self.store, "query") and use_store_provided: try: return self.store.query( query_object, initNs, initBindings, self.default_union and '__UNION__' or self.identifier, **kwargs) except NotImplementedError: pass # store has no own implementation if not isinstance(result, query.Result): result = plugin.get(result, query.Result) if not isinstance(processor, query.Processor): processor = plugin.get(processor, query.Processor)(self) return result(processor.query( query_object, initBindings, initNs, **kwargs)) def update(self, update_object, processor='sparql', initNs={}, initBindings={}, use_store_provided=True, **kwargs): """ """ if hasattr(self.store, "update") and use_store_provided: try: return self.store.update( update_object, initNs, initBindings, self.default_union and '__UNION__' or self.identifier, **kwargs) except NotImplementedError: pass # store has no own implementation if not isinstance(processor, query.UpdateProcessor): processor = plugin.get(processor, query.UpdateProcessor)(self) return processor.update(update_object, initBindings, initNs, **kwargs) def n3(self): """return an n3 identifier for the Graph""" return "[%s]" % self.identifier.n3() def __reduce__(self): return (Graph, (self.store, self.identifier,)) def isomorphic(self, other): """ does a very basic check if these graphs are the same If no BNodes are involved, this is accurate. See rdflib.compare for a correct implementation of isomorphism checks """ # TODO: this is only an approximation. if len(self) != len(other): return False for s, p, o in self: if not isinstance(s, BNode) and not isinstance(o, BNode): if not (s, p, o) in other: return False for s, p, o in other: if not isinstance(s, BNode) and not isinstance(o, BNode): if not (s, p, o) in self: return False # TODO: very well could be a false positive at this point yet. return True def connected(self): """Check if the Graph is connected The Graph is considered undirectional. Performs a search on the Graph, starting from a random node. Then iteratively goes depth-first through the triplets where the node is subject and object. Return True if all nodes have been visited and False if it cannot continue and there are still unvisited nodes left. """ all_nodes = list(self.all_nodes()) discovered = [] # take a random one, could also always take the first one, doesn't # really matter. if not all_nodes: return False visiting = [all_nodes[random.randrange(len(all_nodes))]] while visiting: x = visiting.pop() if x not in discovered: discovered.append(x) for new_x in self.objects(subject=x): if new_x not in discovered and new_x not in visiting: visiting.append(new_x) for new_x in self.subjects(object=x): if new_x not in discovered and new_x not in visiting: visiting.append(new_x) # optimisation by only considering length, since no new objects can # be introduced anywhere. if len(all_nodes) == len(discovered): return True else: return False def all_nodes(self): obj = set(self.objects()) allNodes = obj.union(set(self.subjects())) return allNodes def resource(self, identifier): """Create a new ``Resource`` instance. Parameters: - ``identifier``: a URIRef or BNode instance. Example:: >>> graph = Graph() >>> uri = URIRef("http://example.org/resource") >>> resource = graph.resource(uri) >>> assert isinstance(resource, Resource) >>> assert resource.identifier is uri >>> assert resource.graph is graph """ if not isinstance(identifier, Node): identifier = URIRef(identifier) return Resource(self, identifier) def _process_skolem_tuples(self, target, func): for t in self.triples((None, None, None)): target.add(func(t)) def skolemize(self, new_graph=None, bnode=None): def do_skolemize(bnode, t): (s, p, o) = t if s == bnode: s = s.skolemize() if o == bnode: o = o.skolemize() return (s, p, o) def do_skolemize2(t): (s, p, o) = t if isinstance(s, BNode): s = s.skolemize() if isinstance(o, BNode): o = o.skolemize() return (s, p, o) retval = Graph() if new_graph is None else new_graph if bnode is None: self._process_skolem_tuples(retval, do_skolemize2) elif isinstance(bnode, BNode): self._process_skolem_tuples( retval, lambda t: do_skolemize(bnode, t)) return retval def de_skolemize(self, new_graph=None, uriref=None): def do_de_skolemize(uriref, t): (s, p, o) = t if s == uriref: s = s.de_skolemize() if o == uriref: o = o.de_skolemize() return (s, p, o) def do_de_skolemize2(t): (s, p, o) = t if isinstance(s, Genid): s = s.de_skolemize() if isinstance(o, Genid): o = o.de_skolemize() return (s, p, o) retval = Graph() if new_graph is None else new_graph if uriref is None: self._process_skolem_tuples(retval, do_de_skolemize2) elif isinstance(uriref, Genid): self._process_skolem_tuples( retval, lambda t: do_de_skolemize(uriref, t)) return retval class ConjunctiveGraph(Graph): """ A ConjunctiveGraph is an (unamed) aggregation of all the named graphs in a store. It has a ``default`` graph, whose name is associated with the graph throughout its life. :meth:`__init__` can take an identifier to use as the name of this default graph or it will assign a BNode. All methods that add triples work against this default graph. All queries are carried out against the union of all graphs. """ def __init__(self, store='default', identifier=None): super(ConjunctiveGraph, self).__init__(store, identifier=identifier) assert self.store.context_aware, ("ConjunctiveGraph must be backed by" " a context aware store.") self.context_aware = True self.default_union = True # Conjunctive! self.default_context = Graph(store=self.store, identifier=identifier or BNode()) def __str__(self): pattern = ("[a rdflib:ConjunctiveGraph;rdflib:storage " "[a rdflib:Store;rdfs:label '%s']]") return pattern % self.store.__class__.__name__ def _spoc(self, triple_or_quad, default=False): """ helper method for having methods that support either triples or quads """ if triple_or_quad is None: return (None, None, None, self.default_context if default else None) if len(triple_or_quad) == 3: c = self.default_context if default else None (s, p, o) = triple_or_quad elif len(triple_or_quad) == 4: (s, p, o, c) = triple_or_quad c = self._graph(c) return s,p,o,c def __contains__(self, triple_or_quad): """Support for 'triple/quad in graph' syntax""" s,p,o,c = self._spoc(triple_or_quad) for t in self.triples((s,p,o), context=c): return True return False def add(self, triple_or_quad): """ Add a triple or quad to the store. if a triple is given it is added to the default context """ s,p,o,c = self._spoc(triple_or_quad, default=True) _assertnode(s,p,o) self.store.add((s, p, o), context=c, quoted=False) def _graph(self, c): if c is None: return None if not isinstance(c, Graph): return self.get_context(c) else: return c def addN(self, quads): """Add a sequence of triples with context""" self.store.addN( (s, p, o, self._graph(c)) for s, p, o, c in quads if _assertnode(s, p, o) ) def remove(self, triple_or_quad): """ Removes a triple or quads if a triple is given it is removed from all contexts a quad is removed from the given context only """ s,p,o,c = self._spoc(triple_or_quad) self.store.remove((s, p, o), context=c) def triples(self, triple_or_quad, context=None): """ Iterate over all the triples in the entire conjunctive graph For legacy reasons, this can take the context to query either as a fourth element of the quad, or as the explicit context keyword paramater. The kw param takes precedence. """ s,p,o,c = self._spoc(triple_or_quad) context = self._graph(context or c) if self.default_union: if context==self.default_context: context = None else: if context is None: context = self.default_context if isinstance(p, Path): if context is None: context = self for s, o in p.eval(context, s, o): yield (s, p, o) else: for (s, p, o), cg in self.store.triples((s, p, o), context=context): yield s, p, o def quads(self, triple_or_quad=None): """Iterate over all the quads in the entire conjunctive graph""" s,p,o,c = self._spoc(triple_or_quad) for (s, p, o), cg in self.store.triples((s, p, o), context=c): for ctx in cg: yield s, p, o, ctx def triples_choices(self, (s, p, o), context=None): """Iterate over all the triples in the entire conjunctive graph""" if context is None: if not self.default_union: context=self.default_context else: context = self._graph(context) for (s1, p1, o1), cg in self.store.triples_choices((s, p, o), context=context): yield (s1, p1, o1) def __len__(self): """Number of triples in the entire conjunctive graph""" return self.store.__len__() def contexts(self, triple=None): """Iterate over all contexts in the graph If triple is specified, iterate over all contexts the triple is in. """ for context in self.store.contexts(triple): if isinstance(context, Graph): # TODO: One of these should never happen and probably # should raise an exception rather than smoothing over # the weirdness - see #225 yield context else: yield self.get_context(context) def get_context(self, identifier, quoted=False): """Return a context graph for the given identifier identifier must be a URIRef or BNode. """ return Graph(store=self.store, identifier=identifier, namespace_manager=self) def remove_context(self, context): """Removes the given context from the graph""" self.store.remove((None, None, None), context) def context_id(self, uri, context_id=None): """URI#context""" uri = uri.split("#", 1)[0] if context_id is None: context_id = "#context" return URIRef(context_id, base=uri) def parse(self, source=None, publicID=None, format="xml", location=None, file=None, data=None, **args): """ Parse source adding the resulting triples to its own context (sub graph of this graph). See :meth:`rdflib.graph.Graph.parse` for documentation on arguments. :Returns: The graph into which the source was parsed. In the case of n3 it returns the root context. """ source = create_input_source( source=source, publicID=publicID, location=location, file=file, data=data, format=format) g_id = publicID and publicID or source.getPublicId() if not isinstance(g_id, Node): g_id = URIRef(g_id) context = Graph(store=self.store, identifier=g_id) context.remove((None, None, None)) # hmm ? context.parse(source, publicID=publicID, format=format, location=location, file=file, data=data, **args) return context def __reduce__(self): return (ConjunctiveGraph, (self.store, self.identifier)) DATASET_DEFAULT_GRAPH_ID = URIRef('urn:x-rdflib:default') class Dataset(ConjunctiveGraph): __doc__ = format_doctest_out(""" RDF 1.1 Dataset. Small extension to the Conjunctive Graph: - the primary term is graphs in the datasets and not contexts with quads, so there is a separate method to set/retrieve a graph in a dataset and operate with graphs - graphs cannot be identified with blank nodes - added a method to directly add a single quad Examples of usage: >>> # Create a new Dataset >>> ds = Dataset() >>> # simple triples goes to default graph >>> ds.add((URIRef('http://example.org/a'), ... URIRef('http://www.example.org/b'), ... Literal('foo'))) >>> >>> # Create a graph in the dataset, if the graph name has already been >>> # used, the corresponding graph will be returned >>> # (ie, the Dataset keeps track of the constituent graphs) >>> g = ds.graph(URIRef('http://www.example.com/gr')) >>> >>> # add triples to the new graph as usual >>> g.add( ... (URIRef('http://example.org/x'), ... URIRef('http://example.org/y'), ... Literal('bar')) ) >>> # alternatively: add a quad to the dataset -> goes to the graph >>> ds.add( ... (URIRef('http://example.org/x'), ... URIRef('http://example.org/z'), ... Literal('foo-bar'),g) ) >>> >>> # querying triples return them all regardless of the graph >>> for t in ds.triples((None,None,None)): # doctest: +SKIP ... print(t) # doctest: +NORMALIZE_WHITESPACE (rdflib.term.URIRef(%(u)s'http://example.org/a'), rdflib.term.URIRef(%(u)s'http://www.example.org/b'), rdflib.term.Literal(%(u)s'foo')) (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/z'), rdflib.term.Literal(%(u)s'foo-bar')) (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/y'), rdflib.term.Literal(%(u)s'bar')) >>> >>> # querying quads return quads; the fourth argument can be unrestricted >>> # or restricted to a graph >>> for q in ds.quads((None, None, None, None)): # doctest: +SKIP ... print(q) # doctest: +NORMALIZE_WHITESPACE (rdflib.term.URIRef(%(u)s'http://example.org/a'), rdflib.term.URIRef(%(u)s'http://www.example.org/b'), rdflib.term.Literal(%(u)s'foo'), None) (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/y'), rdflib.term.Literal(%(u)s'bar'), rdflib.term.URIRef(%(u)s'http://www.example.com/gr')) (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/z'), rdflib.term.Literal(%(u)s'foo-bar'), rdflib.term.URIRef(%(u)s'http://www.example.com/gr')) >>> >>> for q in ds.quads((None,None,None,g)): # doctest: +SKIP ... print(q) # doctest: +NORMALIZE_WHITESPACE (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/y'), rdflib.term.Literal(%(u)s'bar'), rdflib.term.URIRef(%(u)s'http://www.example.com/gr')) (rdflib.term.URIRef(%(u)s'http://example.org/x'), rdflib.term.URIRef(%(u)s'http://example.org/z'), rdflib.term.Literal(%(u)s'foo-bar'), rdflib.term.URIRef(%(u)s'http://www.example.com/gr')) >>> # Note that in the call above - >>> # ds.quads((None,None,None,'http://www.example.com/gr')) >>> # would have been accepted, too >>> >>> # graph names in the dataset can be queried: >>> for c in ds.graphs(): # doctest: +SKIP ... print(c) # doctest: DEFAULT http://www.example.com/gr >>> # A graph can be created without specifying a name; a skolemized genid >>> # is created on the fly >>> h = ds.graph() >>> for c in ds.graphs(): # doctest: +SKIP ... print(c) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS DEFAULT http://rdlib.net/.well-known/genid/rdflib/N... http://www.example.com/gr >>> # Note that the Dataset.graphs() call returns names of empty graphs, >>> # too. This can be restricted: >>> for c in ds.graphs(empty=False): # doctest: +SKIP ... print(c) # doctest: +NORMALIZE_WHITESPACE DEFAULT http://www.example.com/gr >>> >>> # a graph can also be removed from a dataset via ds.remove_graph(g) .. versionadded:: 4.0 """) def __init__(self, store='default', default_union=False): super(Dataset, self).__init__(store=store, identifier=None) if not self.store.graph_aware: raise Exception("DataSet must be backed by a graph-aware store!") self.default_context = Graph(store=self.store, identifier=DATASET_DEFAULT_GRAPH_ID) self.default_union = default_union def __str__(self): pattern = ("[a rdflib:Dataset;rdflib:storage " "[a rdflib:Store;rdfs:label '%s']]") return pattern % self.store.__class__.__name__ def graph(self, identifier=None): if identifier is None: from rdflib.term import rdflib_skolem_genid self.bind( "genid", "http://rdflib.net" + rdflib_skolem_genid, override=False) identifier = BNode().skolemize() g = self._graph(identifier) self.store.add_graph(g) return g def parse(self, source=None, publicID=None, format="xml", location=None, file=None, data=None, **args): c = ConjunctiveGraph.parse(self, source, publicID, format, location, file, data, **args) self.graph(c) return c def add_graph(self, g): """alias of graph for consistency""" return self.graph(g) def remove_graph(self, g): if not isinstance(g, Graph): g = self.get_context(g) self.store.remove_graph(g) if g is None or g == self.default_context: # default graph cannot be removed # only triples deleted, so add it back in self.store.add_graph(self.default_context) def contexts(self, triple=None): default = False for c in super(Dataset, self).contexts(triple): default|=c.identifier == DATASET_DEFAULT_GRAPH_ID yield c if not default: yield self.graph(DATASET_DEFAULT_GRAPH_ID) def quads(self, quad): for s, p, o, c in super(Dataset, self).quads(quad): if c.identifier==self.default_context: yield (s, p, o, None) else: yield (s, p, o, c.identifier) class QuotedGraph(Graph): """ Quoted Graphs are intended to implement Notation 3 formulae. They are associated with a required identifier that the N3 parser *must* provide in order to maintain consistent formulae identification for scenarios such as implication and other such processing. """ def __init__(self, store, identifier): super(QuotedGraph, self).__init__(store, identifier) def add(self, (s, p, o)): """Add a triple with self as context""" assert isinstance(s, Node), \ "Subject %s must be an rdflib term" % (s,) assert isinstance(p, Node), \ "Predicate %s must be an rdflib term" % (p,) assert isinstance(o, Node), \ "Object %s must be an rdflib term" % (o,) self.store.add((s, p, o), self, quoted=True) def addN(self, quads): """Add a sequence of triple with context""" self.store.addN( (s, p, o, c) for s, p, o, c in quads if isinstance(c, QuotedGraph) and c.identifier is self.identifier and _assertnode(s, p, o) ) def n3(self): """Return an n3 identifier for the Graph""" return "{%s}" % self.identifier.n3() def __str__(self): identifier = self.identifier.n3() label = self.store.__class__.__name__ pattern = ("{this rdflib.identifier %s;rdflib:storage " "[a rdflib:Store;rdfs:label '%s']}") return pattern % (identifier, label) def __reduce__(self): return (QuotedGraph, (self.store, self.identifier)) # Make sure QuotedGraph is ordered correctly # wrt to other Terms. # this must be done here, as the QuotedGraph cannot be # circularily imported in term.py rdflib.term._ORDERING[QuotedGraph]=11 class Seq(object): """Wrapper around an RDF Seq resource It implements a container type in Python with the order of the items returned corresponding to the Seq content. It is based on the natural ordering of the predicate names _1, _2, _3, etc, which is the 'implementation' of a sequence in RDF terms. """ def __init__(self, graph, subject): """Parameters: - graph: the graph containing the Seq - subject: the subject of a Seq. Note that the init does not check whether this is a Seq, this is done in whoever creates this instance! """ _list = self._list = list() LI_INDEX = URIRef(str(RDF) + "_") for (p, o) in graph.predicate_objects(subject): if p.startswith(LI_INDEX): # != RDF.Seq: # i = int(p.replace(LI_INDEX, '')) _list.append((i, o)) # here is the trick: the predicates are _1, _2, _3, etc. Ie, # by sorting the keys (by integer) we have what we want! _list.sort() def toPython(self): return self def __iter__(self): """Generator over the items in the Seq""" for _, item in self._list: yield item def __len__(self): """Length of the Seq""" return len(self._list) def __getitem__(self, index): """Item given by index from the Seq""" index, item = self._list.__getitem__(index) return item class ModificationException(Exception): def __init__(self): pass def __str__(self): return ("Modifications and transactional operations not allowed on " "ReadOnlyGraphAggregate instances") class UnSupportedAggregateOperation(Exception): def __init__(self): pass def __str__(self): return ("This operation is not supported by ReadOnlyGraphAggregate " "instances") class ReadOnlyGraphAggregate(ConjunctiveGraph): """Utility class for treating a set of graphs as a single graph Only read operations are supported (hence the name). Essentially a ConjunctiveGraph over an explicit subset of the entire store. """ def __init__(self, graphs, store='default'): if store is not None: super(ReadOnlyGraphAggregate, self).__init__(store) Graph.__init__(self, store) self.__namespace_manager = None assert isinstance(graphs, list) \ and graphs \ and [g for g in graphs if isinstance(g, Graph)], \ "graphs argument must be a list of Graphs!!" self.graphs = graphs def __repr__(self): return "" % len(self.graphs) def destroy(self, configuration): raise ModificationException() # Transactional interfaces (optional) def commit(self): raise ModificationException() def rollback(self): raise ModificationException() def open(self, configuration, create=False): # TODO: is there a use case for this method? for graph in self.graphs: graph.open(self, configuration, create) def close(self): for graph in self.graphs: graph.close() def add(self, (s, p, o)): raise ModificationException() def addN(self, quads): raise ModificationException() def remove(self, (s, p, o)): raise ModificationException() def triples(self, (s, p, o)): for graph in self.graphs: if isinstance(p, Path): for s, o in p.eval(self, s, o): yield s, p, o else: for s1, p1, o1 in graph.triples((s, p, o)): yield (s1, p1, o1) def __contains__(self, triple_or_quad): context = None if len(triple_or_quad) == 4: context = triple_or_quad[3] for graph in self.graphs: if context is None or graph.identifier == context.identifier: if triple_or_quad[:3] in graph: return True return False def quads(self, (s, p, o)): """Iterate over all the quads in the entire aggregate graph""" for graph in self.graphs: for s1, p1, o1 in graph.triples((s, p, o)): yield (s1, p1, o1, graph) def __len__(self): return sum(len(g) for g in self.graphs) def __hash__(self): raise UnSupportedAggregateOperation() def __cmp__(self, other): if other is None: return -1 elif isinstance(other, Graph): return -1 elif isinstance(other, ReadOnlyGraphAggregate): return cmp(self.graphs, other.graphs) else: return -1 def __iadd__(self, other): raise ModificationException() def __isub__(self, other): raise ModificationException() # Conv. methods def triples_choices(self, (subject, predicate, object_), context=None): for graph in self.graphs: choices = graph.triples_choices((subject, predicate, object_)) for (s, p, o) in choices: yield (s, p, o) def qname(self, uri): if hasattr(self, 'namespace_manager') and self.namespace_manager: return self.namespace_manager.qname(uri) raise UnSupportedAggregateOperation() def compute_qname(self, uri, generate=True): if hasattr(self, 'namespace_manager') and self.namespace_manager: return self.namespace_manager.compute_qname(uri, generate) raise UnSupportedAggregateOperation() def bind(self, prefix, namespace, override=True): raise UnSupportedAggregateOperation() def namespaces(self): if hasattr(self, 'namespace_manager'): for prefix, namespace in self.namespace_manager.namespaces(): yield prefix, namespace else: for graph in self.graphs: for prefix, namespace in graph.namespaces(): yield prefix, namespace def absolutize(self, uri, defrag=1): raise UnSupportedAggregateOperation() def parse(self, source, publicID=None, format="xml", **args): raise ModificationException() def n3(self): raise UnSupportedAggregateOperation() def __reduce__(self): raise UnSupportedAggregateOperation() def _assertnode(*terms): for t in terms: assert isinstance(t, Node), \ 'Term %s must be an rdflib term' % (t,) return True def test(): import doctest doctest.testmod() if __name__ == '__main__': test() rdflib-4.1.2/rdflib/namespace.py000066400000000000000000000361511232323236500165370ustar00rootroot00000000000000from rdflib.py3compat import format_doctest_out __doc__ = format_doctest_out(""" =================== Namespace Utilities =================== RDFLib provides mechanisms for managing Namespaces. In particular, there is a :class:`~rdflib.namespace.Namespace` class that takes as its argument the base URI of the namespace. .. code-block:: pycon >>> from rdflib.namespace import Namespace >>> owl = Namespace('http://www.w3.org/2002/07/owl#') Fully qualified URIs in the namespace can be constructed either by attribute or by dictionary access on Namespace instances: .. code-block:: pycon >>> owl.seeAlso rdflib.term.URIRef(%(u)s'http://www.w3.org/2002/07/owl#seeAlso') >>> owl['seeAlso'] rdflib.term.URIRef(%(u)s'http://www.w3.org/2002/07/owl#seeAlso') Automatic handling of unknown predicates ----------------------------------------- As a programming convenience, a namespace binding is automatically created when :class:`rdflib.term.URIRef` predicates are added to the graph. Importable namespaces ----------------------- The following namespaces are available by directly importing from rdflib: * RDF * RDFS * OWL * XSD * FOAF * SKOS * DOAP * DC * DCTERMS * VOID .. code-block:: pycon >>> from rdflib import OWL >>> OWL.seeAlso rdflib.term.URIRef(%(u)s'http://www.w3.org/2002/07/owl#seeAlso') """) import logging _logger = logging.getLogger(__name__) import os from urlparse import urljoin, urldefrag from urllib import pathname2url from rdflib.term import URIRef, Variable, _XSD_PFX, _is_valid_uri __all__ = [ 'is_ncname', 'split_uri', 'Namespace', 'ClosedNamespace', 'NamespaceManager', 'XMLNS', 'RDF', 'RDFS', 'XSD', 'OWL', 'SKOS', 'DOAP', 'FOAF', 'DC', 'DCTERMS', 'VOID'] class Namespace(unicode): __doc__ = format_doctest_out(""" Utility class for quickly generating URIRefs with a common prefix >>> from rdflib import Namespace >>> n = Namespace("http://example.org/") >>> n.Person # as attribute rdflib.term.URIRef(%(u)s'http://example.org/Person') >>> n['first-name'] # as item - for things that are not valid python identifiers rdflib.term.URIRef(%(u)s'http://example.org/first-name') """) def __new__(cls, value): try: rt = unicode.__new__(cls, value) except UnicodeDecodeError: rt = unicode.__new__(cls, value, 'utf-8') return rt @property def title(self): return URIRef(self + 'title') def term(self, name): # need to handle slices explicitly because of __getitem__ override return URIRef(self + (name if isinstance(name, basestring) else '')) def __getitem__(self, key, default=None): return self.term(key) def __getattr__(self, name): if name.startswith("__"): # ignore any special Python names! raise AttributeError else: return self.term(name) def __repr__(self): return "Namespace(%s)"%unicode.__repr__(self) class URIPattern(unicode): __doc__ = format_doctest_out(""" Utility class for creating URIs according to some pattern This supports either new style formatting with .format or old-style with %% operator >>> u=URIPattern("http://example.org/%%s/%%d/resource") >>> u%%('books', 12345) rdflib.term.URIRef(%(u)s'http://example.org/books/12345/resource') """) def __new__(cls, value): try: rt = unicode.__new__(cls, value) except UnicodeDecodeError: rt = unicode.__new__(cls, value, 'utf-8') return rt def __mod__(self, *args, **kwargs): return URIRef(unicode(self).__mod__(*args, **kwargs)) def format(self, *args, **kwargs): return URIRef(unicode.format(self, *args, **kwargs)) def __repr__(self): return "URIPattern(%r)"%unicode.__repr__(self) class ClosedNamespace(object): """ A namespace with a closed list of members Trying to create terms not listen is an error """ def __init__(self, uri, terms): self.uri = uri self.__uris = {} for t in terms: self.__uris[t] = URIRef(self.uri + t) def term(self, name): uri = self.__uris.get(name) if uri is None: raise Exception( "term '%s' not in namespace '%s'" % (name, self.uri)) else: return uri def __getitem__(self, key, default=None): return self.term(key) def __getattr__(self, name): if name.startswith("__"): # ignore any special Python names! raise AttributeError else: return self.term(name) def __str__(self): return str(self.uri) def __repr__(self): return """rdf.namespace.ClosedNamespace('%s')""" % str(self.uri) class _RDFNamespace(ClosedNamespace): """ Closed namespace for RDF terms """ def __init__(self): super(_RDFNamespace, self).__init__( URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#"), terms=[ # Syntax Names "RDF", "Description", "ID", "about", "parseType", "resource", "li", "nodeID", "datatype", # RDF Classes "Seq", "Bag", "Alt", "Statement", "Property", "List", "PlainLiteral", # RDF Properties "subject", "predicate", "object", "type", "value", "first", "rest", # and _n where n is a non-negative integer # RDF Resources "nil", # Added in RDF 1.1 "XMLLiteral", "HTML", "langString"] ) def term(self, name): try: i = int(name) return URIRef("%s_%s" % (self.uri, i)) except ValueError: return super(_RDFNamespace, self).term(name) RDF = _RDFNamespace() RDFS = ClosedNamespace( uri=URIRef("http://www.w3.org/2000/01/rdf-schema#"), terms=[ "Resource", "Class", "subClassOf", "subPropertyOf", "comment", "label", "domain", "range", "seeAlso", "isDefinedBy", "Literal", "Container", "ContainerMembershipProperty", "member", "Datatype"] ) OWL = Namespace('http://www.w3.org/2002/07/owl#') XSD = Namespace(_XSD_PFX) SKOS = Namespace('http://www.w3.org/2004/02/skos/core#') DOAP = Namespace('http://usefulinc.com/ns/doap#') FOAF = Namespace('http://xmlns.com/foaf/0.1/') DC = Namespace('http://purl.org/dc/elements/1.1/') DCTERMS = Namespace('http://purl.org/dc/terms/') VOID = Namespace('http://rdfs.org/ns/void#') class NamespaceManager(object): """ Class for managing prefix => namespace mappings Sample usage from FuXi ... .. code-block:: python ruleStore = N3RuleStore(additionalBuiltins=additionalBuiltins) nsMgr = NamespaceManager(Graph(ruleStore)) ruleGraph = Graph(ruleStore,namespace_manager=nsMgr) and ... .. code-block:: pycon >>> import rdflib >>> from rdflib import Graph >>> from rdflib.namespace import Namespace, NamespaceManager >>> exNs = Namespace('http://example.com/') >>> namespace_manager = NamespaceManager(Graph()) >>> namespace_manager.bind('ex', exNs, override=False) >>> g = Graph() >>> g.namespace_manager = namespace_manager >>> all_ns = [n for n in g.namespace_manager.namespaces()] >>> assert ('ex', rdflib.term.URIRef('http://example.com/')) in all_ns >>> """ def __init__(self, graph): self.graph = graph self.__cache = {} self.__log = None self.bind("xml", u"http://www.w3.org/XML/1998/namespace") self.bind("rdf", RDF) self.bind("rdfs", RDFS) self.bind("xsd", XSD) def reset(self): self.__cache = {} def __get_store(self): return self.graph.store store = property(__get_store) def qname(self, uri): prefix, namespace, name = self.compute_qname(uri) if prefix == "": return name else: return ":".join((prefix, name)) def normalizeUri(self, rdfTerm): """ Takes an RDF Term and 'normalizes' it into a QName (using the registered prefix) or (unlike compute_qname) the Notation 3 form for URIs: <...URI...> """ try: namespace, name = split_uri(rdfTerm) namespace = URIRef(unicode(namespace)) except: if isinstance(rdfTerm, Variable): return "?%s" % rdfTerm else: return "<%s>" % rdfTerm prefix = self.store.prefix(namespace) if prefix is None and isinstance(rdfTerm, Variable): return "?%s" % rdfTerm elif prefix is None: return "<%s>" % rdfTerm else: qNameParts = self.compute_qname(rdfTerm) return ':'.join([qNameParts[0], qNameParts[-1]]) def compute_qname(self, uri, generate=True): if not _is_valid_uri(uri): raise Exception('"%s" does not look like a valid URI, I cannot serialize this. Perhaps you wanted to urlencode it?'%uri) if not uri in self.__cache: namespace, name = split_uri(uri) namespace = URIRef(namespace) prefix = self.store.prefix(namespace) if prefix is None: if not generate: raise Exception( "No known prefix for %s and generate=False") num = 1 while 1: prefix = "ns%s" % num if not self.store.namespace(prefix): break num += 1 self.bind(prefix, namespace) self.__cache[uri] = (prefix, namespace, name) return self.__cache[uri] def bind(self, prefix, namespace, override=True, replace=False): """bind a given namespace to the prefix if override, rebind, even if the given namespace is already bound to another prefix. if replace, replace any existing prefix with the new namespace """ namespace = URIRef(unicode(namespace)) # When documenting explain that override only applies in what cases if prefix is None: prefix = '' bound_namespace = self.store.namespace(prefix) # Check if the bound_namespace contains a URI # and if so convert it into a URIRef for comparison # This is to prevent duplicate namespaces with the # same URI if bound_namespace: bound_namespace = URIRef(bound_namespace) if bound_namespace and bound_namespace != namespace: if replace: self.store.bind(prefix, namespace) return # prefix already in use for different namespace # # append number to end of prefix until we find one # that's not in use. if not prefix: prefix = "default" num = 1 while 1: new_prefix = "%s%s" % (prefix, num) tnamespace = self.store.namespace(new_prefix) if tnamespace and namespace == URIRef(tnamespace): # the prefix is already bound to the correct # namespace return if not self.store.namespace(new_prefix): break num += 1 self.store.bind(new_prefix, namespace) else: bound_prefix = self.store.prefix(namespace) if bound_prefix is None: self.store.bind(prefix, namespace) elif bound_prefix == prefix: pass # already bound else: if override or bound_prefix.startswith("_"): # or a generated # prefix self.store.bind(prefix, namespace) def namespaces(self): for prefix, namespace in self.store.namespaces(): namespace = URIRef(namespace) yield prefix, namespace def absolutize(self, uri, defrag=1): base = urljoin("file:", pathname2url(os.getcwd())) result = urljoin("%s/" % base, uri, allow_fragments=not defrag) if defrag: result = urldefrag(result)[0] if not defrag: if uri and uri[-1] == "#" and result[-1] != "#": result = "%s#" % result return URIRef(result) # From: http://www.w3.org/TR/REC-xml#NT-CombiningChar # # * Name start characters must have one of the categories Ll, Lu, Lo, # Lt, Nl. # # * Name characters other than Name-start characters must have one of # the categories Mc, Me, Mn, Lm, or Nd. # # * Characters in the compatibility area (i.e. with character code # greater than #xF900 and less than #xFFFE) are not allowed in XML # names. # # * Characters which have a font or compatibility decomposition # (i.e. those with a "compatibility formatting tag" in field 5 of the # database -- marked by field 5 beginning with a "<") are not allowed. # # * The following characters are treated as name-start characters rather # than name characters, because the property file classifies them as # Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6. # # * Characters #x20DD-#x20E0 are excluded (in accordance with Unicode # 2.0, section 5.14). # # * Character #x00B7 is classified as an extender, because the property # list so identifies it. # # * Character #x0387 is added as a name character, because #x00B7 is its # canonical equivalent. # # * Characters ':' and '_' are allowed as name-start characters. # # * Characters '-' and '.' are allowed as name characters. from unicodedata import category NAME_START_CATEGORIES = ["Ll", "Lu", "Lo", "Lt", "Nl"] NAME_CATEGORIES = NAME_START_CATEGORIES + ["Mc", "Me", "Mn", "Lm", "Nd"] ALLOWED_NAME_CHARS = [u"\u00B7", u"\u0387", u"-", u".", u"_"] # http://www.w3.org/TR/REC-xml-names/#NT-NCName # [4] NCName ::= (Letter | '_') (NCNameChar)* /* An XML Name, minus # the ":" */ # [5] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar # | Extender def is_ncname(name): first = name[0] if first == "_" or category(first) in NAME_START_CATEGORIES: for i in xrange(1, len(name)): c = name[i] if not category(c) in NAME_CATEGORIES: if c in ALLOWED_NAME_CHARS: continue return 0 # if in compatibility area # if decomposition(c)!='': # return 0 return 1 else: return 0 XMLNS = "http://www.w3.org/XML/1998/namespace" def split_uri(uri): if uri.startswith(XMLNS): return (XMLNS, uri.split(XMLNS)[1]) length = len(uri) for i in xrange(0, length): c = uri[-i - 1] if not category(c) in NAME_CATEGORIES: if c in ALLOWED_NAME_CHARS: continue for j in xrange(-1 - i, length): if category(uri[j]) in NAME_START_CATEGORIES or uri[j] == "_": ns = uri[:j] if not ns: break ln = uri[j:] return (ns, ln) break raise Exception("Can't split '%s'" % uri) rdflib-4.1.2/rdflib/parser.py000066400000000000000000000131141232323236500160710ustar00rootroot00000000000000""" Parser plugin interface. This module defines the parser plugin interface and contains other related parser support code. The module is mainly useful for those wanting to write a parser that can plugin to rdflib. If you are wanting to invoke a parser you likely want to do so through the Graph class parse method. """ import os import sys from urllib import pathname2url, url2pathname from urllib2 import urlopen, Request from urlparse import urljoin from rdflib.py3compat import PY3 if PY3: from io import BytesIO assert BytesIO else: from StringIO import StringIO as BytesIO from xml.sax import xmlreader from rdflib import __version__ from rdflib.term import URIRef from rdflib.namespace import Namespace __all__ = [ 'Parser', 'InputSource', 'StringInputSource', 'URLInputSource', 'FileInputSource'] class Parser(object): def __init__(self): pass def parse(self, source, sink): pass class InputSource(xmlreader.InputSource, object): """ TODO: """ def __init__(self, system_id=None): xmlreader.InputSource.__init__(self, system_id=system_id) self.content_type = None class StringInputSource(InputSource): """ TODO: """ def __init__(self, value, system_id=None): super(StringInputSource, self).__init__(system_id) stream = BytesIO(value) self.setByteStream(stream) # TODO: # encoding = value.encoding # self.setEncoding(encoding) headers = { 'User-agent': 'rdflib-%s (http://rdflib.net/; eikeon@eikeon.com)' % __version__ } class URLInputSource(InputSource): """ TODO: """ def __init__(self, system_id=None, format=None): super(URLInputSource, self).__init__(system_id) self.url = system_id # copy headers to change myheaders = dict(headers) if format == 'application/rdf+xml': myheaders['Accept'] = 'application/rdf+xml, */*;q=0.1' elif format == 'n3': myheaders['Accept'] = 'text/n3, */*;q=0.1' elif format == 'nt': myheaders['Accept'] = 'text/plain, */*;q=0.1' else: myheaders['Accept'] = ( 'application/rdf+xml,text/rdf+n3;q=0.9,' + 'application/xhtml+xml;q=0.5, */*;q=0.1') req = Request(system_id, None, myheaders) file = urlopen(req) # Fix for issue 130 https://github.com/RDFLib/rdflib/issues/130 self.url = file.geturl() # in case redirections took place self.setPublicId(self.url) self.content_type = file.info().get('content-type') self.content_type = self.content_type.split(";", 1)[0] self.setByteStream(file) # TODO: self.setEncoding(encoding) def __repr__(self): return self.url class FileInputSource(InputSource): def __init__(self, file): base = urljoin("file:", pathname2url(os.getcwd())) system_id = URIRef(urljoin("file:", pathname2url(file.name)), base=base) super(FileInputSource, self).__init__(system_id) self.file = file self.setByteStream(file) # TODO: self.setEncoding(encoding) def __repr__(self): return repr(self.file) def create_input_source(source=None, publicID=None, location=None, file=None, data=None, format=None): """ Return an appropriate InputSource instance for the given parameters. """ # TODO: test that exactly one of source, location, file, and data # is not None. input_source = None if source is not None: if isinstance(source, InputSource): input_source = source else: if isinstance(source, basestring): location = source elif hasattr(source, "read") and not isinstance(source, Namespace): f = source input_source = InputSource() input_source.setByteStream(f) if f is sys.stdin: input_source.setSystemId("file:///dev/stdin") elif hasattr(f, "name"): input_source.setSystemId(f.name) else: raise Exception("Unexpected type '%s' for source '%s'" % (type(source), source)) absolute_location = None # Further to fix for issue 130 if location is not None: # Fix for Windows problem https://github.com/RDFLib/rdflib/issues/145 if os.path.exists(location): location = pathname2url(location) base = urljoin("file:", "%s/" % pathname2url(os.getcwd())) absolute_location = URIRef(location, base=base).defrag() if absolute_location.startswith("file:///"): filename = url2pathname(absolute_location.replace("file:///", "/")) file = open(filename, "rb") else: input_source = URLInputSource(absolute_location, format) # publicID = publicID or absolute_location # Further to fix # for issue 130 if file is not None: input_source = FileInputSource(file) if data is not None: if isinstance(data, unicode): data = data.encode('utf-8') input_source = StringInputSource(data) if input_source is None: raise Exception("could not create InputSource") else: if publicID is not None: # Further to fix for issue 130 input_source.setPublicId(publicID) # Further to fix for issue 130 elif input_source.getPublicId() is None: input_source.setPublicId(absolute_location or "") return input_source rdflib-4.1.2/rdflib/paths.py000066400000000000000000000362461232323236500157270ustar00rootroot00000000000000from rdflib.py3compat import PY3, format_doctest_out __doc__ = format_doctest_out(""" This module implements the SPARQL 1.1 Property path operators, as defined in: http://www.w3.org/TR/sparql11-query/#propertypaths In SPARQL the syntax is as follows: +--------------------+-------------------------------------------------+ |Syntax | Matches | +====================+=================================================+ |iri | An IRI. A path of length one. | +--------------------+-------------------------------------------------+ |^elt | Inverse path (object to subject). | +--------------------+-------------------------------------------------+ |elt1 / elt2 | A sequence path of elt1 followed by elt2. | +--------------------+-------------------------------------------------+ |elt1 | elt2 | A alternative path of elt1 or elt2 | | | (all possibilities are tried). | +--------------------+-------------------------------------------------+ |elt* | A path that connects the subject and object | | | of the path by zero or more matches of elt. | +--------------------+-------------------------------------------------+ |elt+ | A path that connects the subject and object | | | of the path by one or more matches of elt. | +--------------------+-------------------------------------------------+ |elt? | A path that connects the subject and object | | | of the path by zero or one matches of elt. | +--------------------+-------------------------------------------------+ |!iri or | Negated property set. An IRI which is not one of| |!(iri\ :sub:`1`\ | | iri\ :sub:`1`...iri\ :sub:`n`. | |... |iri\ :sub:`n`) | !iri is short for !(iri). | +--------------------+-------------------------------------------------+ |!^iri or | Negated property set where the excluded matches | |!(^iri\ :sub:`1`\ | | are based on reversed path. That is, not one of | |... |^iri\ :sub:`n`)| iri\ :sub:`1`...iri\ :sub:`n` as reverse paths. | | | !^iri is short for !(^iri). | +--------------------+-------------------------------------------------+ |!(iri\ :sub:`1`\ | | A combination of forward and reverse | |...|iri\ :sub:`j`\ || properties in a negated property set. | |^iri\ :sub:`j+1`\ | | | |... |^iri\ :sub:`n`)| | +--------------------+-------------------------------------------------+ |(elt) | A group path elt, brackets control precedence. | +--------------------+-------------------------------------------------+ This module is used internally be the SPARQL engine, but they property paths can also be used to query RDFLib Graphs directly. Where possible the SPARQL syntax is mapped to python operators, and property path objects can be constructed from existing URIRefs. >>> from rdflib import Graph, Namespace >>> foaf=Namespace('http://xmlns.com/foaf/0.1/') >>> ~foaf.knows Path(~http://xmlns.com/foaf/0.1/knows) >>> foaf.knows/foaf.name Path(http://xmlns.com/foaf/0.1/knows / http://xmlns.com/foaf/0.1/name) >>> foaf.name|foaf.firstName Path(http://xmlns.com/foaf/0.1/name | http://xmlns.com/foaf/0.1/firstName) Modifiers (?, *, +) are done using * (the multiplication operator) and the strings '*', '?', '+', also defined as constants in this file. >>> foaf.knows*OneOrMore Path(http://xmlns.com/foaf/0.1/knows+) The path objects can also be used with the normal graph methods. First some example data: >>> g=Graph() >>> g=g.parse(data=''' ... @prefix : . ... ... :a :p1 :c ; :p2 :f . ... :c :p2 :e ; :p3 :g . ... :g :p3 :h ; :p2 :j . ... :h :p3 :a ; :p2 :g . ... ... :q :px :q . ... ... ''', format='n3') # doctest: +ELLIPSIS >>> e=Namespace('ex:') Graph contains: >>> (e.a, e.p1/e.p2, e.e) in g True Graph generator functions, triples, subjects, objects, etc. : >>> list(g.objects(e.c, (e.p3*OneOrMore)/e.p2)) # doctest: +NORMALIZE_WHITESPACE [rdflib.term.URIRef(%(u)s'ex:j'), rdflib.term.URIRef(%(u)s'ex:g'), rdflib.term.URIRef(%(u)s'ex:f')] A more complete set of tests: >>> list(evalPath(g, (None, e.p1/e.p2, None)))==[(e.a, e.e)] True >>> list(evalPath(g, (e.a, e.p1|e.p2, None)))==[(e.a,e.c), (e.a,e.f)] True >>> list(evalPath(g, (e.c, ~e.p1, None))) == [ (e.c, e.a) ] True >>> list(evalPath(g, (e.a, e.p1*ZeroOrOne, None))) == [(e.a, e.a), (e.a, e.c)] True >>> list(evalPath(g, (e.c, e.p3*OneOrMore, None))) == [ ... (e.c, e.g), (e.c, e.h), (e.c, e.a)] True >>> list(evalPath(g, (e.c, e.p3*ZeroOrMore, None))) == [(e.c, e.c), ... (e.c, e.g), (e.c, e.h), (e.c, e.a)] True >>> list(evalPath(g, (e.a, -e.p1, None))) == [(e.a, e.f)] True >>> list(evalPath(g, (e.a, -(e.p1|e.p2), None))) == [] True >>> list(evalPath(g, (e.g, -~e.p2, None))) == [(e.g, e.j)] True >>> list(evalPath(g, (e.e, ~(e.p1/e.p2), None))) == [(e.e, e.a)] True >>> list(evalPath(g, (e.a, e.p1/e.p3/e.p3, None))) == [(e.a, e.h)] True >>> list(evalPath(g, (e.q, e.px*OneOrMore, None))) [(rdflib.term.URIRef(%(u)s'ex:q'), rdflib.term.URIRef(%(u)s'ex:q'))] >>> list(evalPath(g, (None, e.p1|e.p2, e.c))) [(rdflib.term.URIRef(%(u)s'ex:a'), rdflib.term.URIRef(%(u)s'ex:c'))] >>> list(evalPath(g, (None, ~e.p1, e.a))) == [ (e.c, e.a) ] True >>> list(evalPath(g, (None, e.p1*ZeroOrOne, e.c))) # doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:c')), (rdflib.term.URIRef(%(u)s'ex:a'), rdflib.term.URIRef(%(u)s'ex:c'))] >>> list(evalPath(g, (None, e.p3*OneOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'ex:h'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:g'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:a'))] >>> list(evalPath(g, (None, e.p3*ZeroOrMore, e.a))) # doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'ex:a'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:h'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:g'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:a'))] >>> list(evalPath(g, (None, -e.p1, e.f))) == [(e.a, e.f)] True >>> list(evalPath(g, (None, -(e.p1|e.p2), e.c))) == [] True >>> list(evalPath(g, (None, -~e.p2, e.j))) == [(e.g, e.j)] True >>> list(evalPath(g, (None, ~(e.p1/e.p2), e.a))) == [(e.e, e.a)] True >>> list(evalPath(g, (None, e.p1/e.p3/e.p3, e.h))) == [(e.a, e.h)] True >>> list(evalPath(g, (e.q, e.px*OneOrMore, None))) [(rdflib.term.URIRef(%(u)s'ex:q'), rdflib.term.URIRef(%(u)s'ex:q'))] >>> list(evalPath(g, (e.c, (e.p2|e.p3)*ZeroOrMore, e.j))) [(rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:j'))] No vars specified: >>> sorted(list(evalPath(g, (None, e.p3*OneOrMore, None)))) #doctest: +NORMALIZE_WHITESPACE [(rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:g')), (rdflib.term.URIRef(%(u)s'ex:c'), rdflib.term.URIRef(%(u)s'ex:h')), (rdflib.term.URIRef(%(u)s'ex:g'), rdflib.term.URIRef(%(u)s'ex:a')), (rdflib.term.URIRef(%(u)s'ex:g'), rdflib.term.URIRef(%(u)s'ex:h')), (rdflib.term.URIRef(%(u)s'ex:h'), rdflib.term.URIRef(%(u)s'ex:a'))] .. versionadded:: 4.0 """) from rdflib.term import URIRef # property paths ZeroOrMore = '*' OneOrMore = '+' ZeroOrOne = '?' class Path: def eval(self, graph, subj=None, obj=None): raise NotImplementedError() class InvPath(Path): def __init__(self, arg): self.arg = arg def eval(self, graph, subj=None, obj=None): for s, o in evalPath(graph, (obj, self.arg, subj)): yield o, s def __repr__(self): return "Path(~%s)" % (self.arg,) class SequencePath(Path): def __init__(self, *args): self.args = [] for a in args: if isinstance(a, SequencePath): self.args += a.args else: self.args.append(a) def eval(self, graph, subj=None, obj=None): def _eval_seq(paths, subj, obj): if paths[1:]: for s, o in evalPath(graph, (subj, paths[0], None)): for r in _eval_seq(paths[1:], o, obj): yield s, r[1] else: for s, o in evalPath(graph, (subj, paths[0], obj)): yield s, o def _eval_seq_bw(paths, subj, obj): if paths[:-1]: for s, o in evalPath(graph, (None, paths[-1], obj)): for r in _eval_seq(paths[:-1], subj, s): yield r[0], o else: for s, o in evalPath(graph, (subj, paths[0], obj)): yield s, o if subj: return _eval_seq(self.args, subj, obj) elif obj: return _eval_seq_bw(self.args, subj, obj) else: # no vars bound, we can start anywhere return _eval_seq(self.args, subj, obj) def __repr__(self): return "Path(%s)" % " / ".join(str(x) for x in self.args) class AlternativePath(Path): def __init__(self, *args): self.args = [] for a in args: if isinstance(a, AlternativePath): self.args += a.args else: self.args.append(a) def eval(self, graph, subj=None, obj=None): for x in self.args: for y in evalPath(graph, (subj, x, obj)): yield y def __repr__(self): return "Path(%s)" % " | ".join(str(x) for x in self.args) class MulPath(Path): def __init__(self, path, mod): self.path = path self.mod = mod if mod == ZeroOrOne: self.zero = True self.more = False elif mod == ZeroOrMore: self.zero = True self.more = True elif mod == OneOrMore: self.zero = False self.more = True else: raise Exception('Unknown modifier %s' % mod) def eval(self, graph, subj=None, obj=None, first=True): if self.zero and first: if subj and obj: if subj == obj: yield (subj, obj) elif subj: yield (subj, subj) elif obj: yield (obj, obj) def _fwd(subj=None, obj=None, seen=None): seen.add(subj) for s, o in evalPath(graph, (subj, self.path, None)): if not obj or o == obj: yield s, o if self.more: if o in seen: continue for s2, o2 in _fwd(o, obj, seen): yield s, o2 def _bwd(subj=None, obj=None, seen=None): seen.add(obj) for s, o in evalPath(graph, (None, self.path, obj)): if not subj or subj == s: yield s, o if self.more: if s in seen: continue for s2, o2 in _bwd(None, s, seen): yield s2, o def _fwdbwd(): if self.zero: seen1 = set() # According to the spec, ALL nodes are possible solutions # (even literals) # we cannot do this without going through ALL triples # unless we keep an index of all terms somehow # but lets just hope this query doesnt happen very often... for s, o in graph.subject_objects(None): if s not in seen1: seen1.add(s) yield s, s if o not in seen1: seen1.add(o) yield o, o for s, o in evalPath(graph, (None, self.path, None)): if not self.more: yield s, o else: seen = set() f = list(_fwd(s, None, seen)) # cache or recompute? for s3, o3 in _bwd(None, o, seen): for s2, o2 in f: yield s3, o2 # ? done = set() # the spec does by defn. not allow duplicates if subj: for x in _fwd(subj, obj, set()): if x not in done: done.add(x) yield x elif obj: for x in _bwd(subj, obj, set()): if x not in done: done.add(x) yield x else: for x in _fwdbwd(): if x not in done: done.add(x) yield x def __repr__(self): return "Path(%s%s)" % (self.path, self.mod) class NegatedPath(Path): def __init__(self, arg): if isinstance(arg, (URIRef, InvPath)): self.args = [arg] elif isinstance(arg, AlternativePath): self.args = arg.args else: raise Exception( 'Can only negate URIRefs, InvPaths or ' + 'AlternativePaths, not: %s' % (arg,)) def eval(self, graph, subj=None, obj=None): for s, p, o in graph.triples((subj, None, obj)): for a in self.args: if isinstance(a, URIRef): if p == a: break elif isinstance(a, InvPath): if (o, a.arg, s) in graph: break else: raise Exception('Invalid path in NegatedPath: %s' % a) else: yield s, o def __repr__(self): return "Path(! %s)" % ",".join(str(x) for x in self.args) class PathList(list): pass def path_alternative(self, other): """ alternative path """ if not isinstance(other, (URIRef, Path)): raise Exception('Only URIRefs or Paths can be in paths!') return AlternativePath(self, other) def path_sequence(self, other): """ sequence path """ if not isinstance(other, (URIRef, Path)): raise Exception('Only URIRefs or Paths can be in paths!') return SequencePath(self, other) def evalPath(graph, t): return ((s, o) for s, p, o in graph.triples(t)) def mul_path(p, mul): """ cardinality path """ return MulPath(p, mul) def inv_path(p): """ inverse path """ return InvPath(p) def neg_path(p): """ negated path """ return NegatedPath(p) if __name__ == '__main__': import doctest doctest.testmod() else: # monkey patch # (these cannot be directly in terms.py # as it would introduce circular imports) URIRef.__or__ = path_alternative URIRef.__mul__ = mul_path URIRef.__invert__ = inv_path URIRef.__neg__ = neg_path URIRef.__truediv__ = path_sequence if not PY3: URIRef.__div__ = path_sequence Path.__invert__ = inv_path Path.__neg__ = neg_path Path.__mul__ = mul_path Path.__or__ = path_alternative Path.__truediv__ = path_sequence if not PY3: Path.__div__ = path_sequence rdflib-4.1.2/rdflib/plugin.py000066400000000000000000000221761232323236500161030ustar00rootroot00000000000000""" Plugin support for rdf. There are a number of plugin points for rdf: parser, serializer, store, query processor, and query result. Plugins can be registered either through setuptools entry_points or by calling rdf.plugin.register directly. If you have a package that uses a setuptools based setup.py you can add the following to your setup:: entry_points = { 'rdf.plugins.parser': [ 'nt = rdf.plugins.parsers.nt:NTParser', ], 'rdf.plugins.serializer': [ 'nt = rdf.plugins.serializers.NTSerializer:NTSerializer', ], } See the `setuptools dynamic discovery of services and plugins`__ for more information. .. __: http://peak.telecommunity.com/DevCenter/setuptools#dynamic-discovery-of-services-and-plugins """ from rdflib.store import Store from rdflib.parser import Parser from rdflib.serializer import Serializer from rdflib.query import ResultParser, ResultSerializer, \ Processor, Result, UpdateProcessor from rdflib.exceptions import Error __all__ = [ 'register', 'get', 'plugins', 'PluginException', 'Plugin', 'PKGPlugin'] entry_points = {'rdf.plugins.store': Store, 'rdf.plugins.serializer': Serializer, 'rdf.plugins.parser': Parser, 'rdf.plugins.resultparser': ResultParser, 'rdf.plugins.resultserializer': ResultSerializer, 'rdf.plugins.queryprocessor': Processor, 'rdf.plugins.queryresult': Result, 'rdf.plugins.updateprocessor': UpdateProcessor } _plugins = {} class PluginException(Error): pass class Plugin(object): def __init__(self, name, kind, module_path, class_name): self.name = name self.kind = kind self.module_path = module_path self.class_name = class_name self._class = None def getClass(self): if self._class is None: module = __import__(self.module_path, globals(), locals(), [""]) self._class = getattr(module, self.class_name) return self._class class PKGPlugin(Plugin): def __init__(self, name, kind, ep): self.name = name self.kind = kind self.ep = ep self._class = None def getClass(self): if self._class is None: self._class = self.ep.load() return self._class def register(name, kind, module_path, class_name): """ Register the plugin for (name, kind). The module_path and class_name should be the path to a plugin class. """ p = Plugin(name, kind, module_path, class_name) _plugins[(name, kind)] = p def get(name, kind): """ Return the class for the specified (name, kind). Raises a PluginException if unable to do so. """ try: p = _plugins[(name, kind)] except KeyError: raise PluginException( "No plugin registered for (%s, %s)" % (name, kind)) return p.getClass() try: from pkg_resources import iter_entry_points except ImportError: pass # TODO: log a message else: # add the plugins specified via pkg_resources' EntryPoints. for entry_point, kind in entry_points.iteritems(): for ep in iter_entry_points(entry_point): _plugins[(ep.name, kind)] = PKGPlugin(ep.name, kind, ep) def plugins(name=None, kind=None): """ A generator of the plugins. Pass in name and kind to filter... else leave None to match all. """ for p in _plugins.values(): if (name is None or name == p.name) and ( kind is None or kind == p.kind): yield p register( 'default', Store, 'rdflib.plugins.memory', 'IOMemory') register( 'IOMemory', Store, 'rdflib.plugins.memory', 'IOMemory') register( 'Auditable', Store, 'rdflib.plugins.stores.auditable', 'AuditableStore') register( 'Concurrent', Store, 'rdflib.plugins.stores.concurrent', 'ConcurrentStore') register( 'Sleepycat', Store, 'rdflib.plugins.sleepycat', 'Sleepycat') register( 'SPARQLStore', Store, 'rdflib.plugins.stores.sparqlstore', 'SPARQLStore') register( 'SPARQLUpdateStore', Store, 'rdflib.plugins.stores.sparqlstore', 'SPARQLUpdateStore') register( 'application/rdf+xml', Serializer, 'rdflib.plugins.serializers.rdfxml', 'XMLSerializer') register( 'xml', Serializer, 'rdflib.plugins.serializers.rdfxml', 'XMLSerializer') register( 'text/n3', Serializer, 'rdflib.plugins.serializers.n3', 'N3Serializer') register( 'n3', Serializer, 'rdflib.plugins.serializers.n3', 'N3Serializer') register( 'text/turtle', Serializer, 'rdflib.plugins.serializers.turtle', 'TurtleSerializer') register( 'turtle', Serializer, 'rdflib.plugins.serializers.turtle', 'TurtleSerializer') register( 'trig', Serializer, 'rdflib.plugins.serializers.trig', 'TrigSerializer') register( 'application/n-triples', Serializer, 'rdflib.plugins.serializers.nt', 'NTSerializer') register( 'nt', Serializer, 'rdflib.plugins.serializers.nt', 'NTSerializer') register( 'pretty-xml', Serializer, 'rdflib.plugins.serializers.rdfxml', 'PrettyXMLSerializer') register( 'trix', Serializer, 'rdflib.plugins.serializers.trix', 'TriXSerializer') register( 'application/trix', Serializer, 'rdflib.plugins.serializers.trix', 'TriXSerializer') register( "application/n-quads", Serializer, 'rdflib.plugins.serializers.nquads', 'NQuadsSerializer') register( "nquads", Serializer, 'rdflib.plugins.serializers.nquads', 'NQuadsSerializer') register( 'application/rdf+xml', Parser, 'rdflib.plugins.parsers.rdfxml', 'RDFXMLParser') register( 'xml', Parser, 'rdflib.plugins.parsers.rdfxml', 'RDFXMLParser') register( 'text/n3', Parser, 'rdflib.plugins.parsers.notation3', 'N3Parser') register( 'n3', Parser, 'rdflib.plugins.parsers.notation3', 'N3Parser') register( 'text/turtle', Parser, 'rdflib.plugins.parsers.notation3', 'TurtleParser') register( 'turtle', Parser, 'rdflib.plugins.parsers.notation3', 'TurtleParser') register( 'application/n-triples', Parser, 'rdflib.plugins.parsers.nt', 'NTParser') register( 'nt', Parser, 'rdflib.plugins.parsers.nt', 'NTParser') register( 'application/n-quads', Parser, 'rdflib.plugins.parsers.nquads', 'NQuadsParser') register( 'nquads', Parser, 'rdflib.plugins.parsers.nquads', 'NQuadsParser') register( 'application/trix', Parser, 'rdflib.plugins.parsers.trix', 'TriXParser') register( 'trix', Parser, 'rdflib.plugins.parsers.trix', 'TriXParser') register( 'trig', Parser, 'rdflib.plugins.parsers.trig', 'TrigParser') # The basic parsers: RDFa (by default, 1.1), # microdata, and embedded turtle (a.k.a. hturtle) register( 'hturtle', Parser, 'rdflib.plugins.parsers.hturtle', 'HTurtleParser') register( 'rdfa', Parser, 'rdflib.plugins.parsers.structureddata', 'RDFaParser') register( 'mdata', Parser, 'rdflib.plugins.parsers.structureddata', 'MicrodataParser') register( 'microdata', Parser, 'rdflib.plugins.parsers.structureddata', 'MicrodataParser') # A convenience to use the RDFa 1.0 syntax (although the parse method can # be invoked with an rdfa_version keyword, too) register( 'rdfa1.0', Parser, 'rdflib.plugins.parsers.structureddata', 'RDFa10Parser') # Just for the completeness, if the user uses this register( 'rdfa1.1', Parser, 'rdflib.plugins.parsers.structureddata', 'RDFaParser') # An HTML file may contain both microdata, rdfa, or turtle. If the user # wants them all, the parser below simply invokes all: register( 'html', Parser, 'rdflib.plugins.parsers.structureddata', 'StructuredDataParser') # Some media types are also bound to RDFa register( 'application/svg+xml', Parser, 'rdflib.plugins.parsers.structureddata', 'RDFaParser') register( 'application/xhtml+xml', Parser, 'rdflib.plugins.parsers.structureddata', 'RDFaParser') # 'text/html' media type should be equivalent to html: register( 'text/html', Parser, 'rdflib.plugins.parsers.structureddata', 'StructuredDataParser') register( 'sparql', Result, 'rdflib.plugins.sparql.processor', 'SPARQLResult') register( 'sparql', Processor, 'rdflib.plugins.sparql.processor', 'SPARQLProcessor') register( 'sparql', UpdateProcessor, 'rdflib.plugins.sparql.processor', 'SPARQLUpdateProcessor') register( 'xml', ResultSerializer, 'rdflib.plugins.sparql.results.xmlresults', 'XMLResultSerializer') register( 'txt', ResultSerializer, 'rdflib.plugins.sparql.results.txtresults', 'TXTResultSerializer') register( 'json', ResultSerializer, 'rdflib.plugins.sparql.results.jsonresults', 'JSONResultSerializer') register( 'csv', ResultSerializer, 'rdflib.plugins.sparql.results.csvresults', 'CSVResultSerializer') register( 'xml', ResultParser, 'rdflib.plugins.sparql.results.xmlresults', 'XMLResultParser') register( 'json', ResultParser, 'rdflib.plugins.sparql.results.jsonresults', 'JSONResultParser') register( 'csv', ResultParser, 'rdflib.plugins.sparql.results.csvresults', 'CSVResultParser') register( 'tsv', ResultParser, 'rdflib.plugins.sparql.results.tsvresults', 'TSVResultParser') rdflib-4.1.2/rdflib/plugins/000077500000000000000000000000001232323236500157045ustar00rootroot00000000000000rdflib-4.1.2/rdflib/plugins/__init__.py000066400000000000000000000001571232323236500200200ustar00rootroot00000000000000""" Default plugins for rdflib. This is a namespace package and contains the default plugins for rdflib. """ rdflib-4.1.2/rdflib/plugins/memory.py000066400000000000000000000460021232323236500175700ustar00rootroot00000000000000from rdflib.term import BNode from rdflib.store import Store, NO_STORE, VALID_STORE __all__ = ['Memory', 'IOMemory'] ANY = Any = None class Memory(Store): """\ An in memory implementation of a triple store. This triple store uses nested dictionaries to store triples. Each triple is stored in two such indices as follows spo[s][p][o] = 1 and pos[p][o][s] = 1. Authors: Michel Pelletier, Daniel Krech, Stefan Niederhauser """ def __init__(self, configuration=None, identifier=None): super(Memory, self).__init__(configuration) self.identifier = identifier # indexed by [subject][predicate][object] self.__spo = {} # indexed by [predicate][object][subject] self.__pos = {} # indexed by [predicate][object][subject] self.__osp = {} self.__namespace = {} self.__prefix = {} def add(self, (subject, predicate, object), context, quoted=False): """\ Add a triple to the store of triples. """ # add dictionary entries for spo[s][p][p] = 1 and pos[p][o][s] # = 1, creating the nested dictionaries where they do not yet # exits. spo = self.__spo try: po = spo[subject] except: po = spo[subject] = {} try: o = po[predicate] except: o = po[predicate] = {} o[object] = 1 pos = self.__pos try: os = pos[predicate] except: os = pos[predicate] = {} try: s = os[object] except: s = os[object] = {} s[subject] = 1 osp = self.__osp try: sp = osp[object] except: sp = osp[object] = {} try: p = sp[subject] except: p = sp[subject] = {} p[predicate] = 1 def remove(self, (subject, predicate, object), context=None): for (subject, predicate, object), c in self.triples( (subject, predicate, object)): del self.__spo[subject][predicate][object] del self.__pos[predicate][object][subject] del self.__osp[object][subject][predicate] def triples(self, (subject, predicate, object), context=None): """A generator over all the triples matching """ if subject != ANY: # subject is given spo = self.__spo if subject in spo: subjectDictionary = spo[subject] if predicate != ANY: # subject+predicate is given if predicate in subjectDictionary: if object != ANY: # subject+predicate+object is given if object in subjectDictionary[predicate]: yield (subject, predicate, object), \ self.__contexts() else: # given object not found pass else: # subject+predicate is given, object unbound for o in subjectDictionary[predicate].keys(): yield (subject, predicate, o), \ self.__contexts() else: # given predicate not found pass else: # subject given, predicate unbound for p in subjectDictionary.keys(): if object != ANY: # object is given if object in subjectDictionary[p]: yield (subject, p, object), self.__contexts() else: # given object not found pass else: # object unbound for o in subjectDictionary[p].keys(): yield (subject, p, o), self.__contexts() else: # given subject not found pass elif predicate != ANY: # predicate is given, subject unbound pos = self.__pos if predicate in pos: predicateDictionary = pos[predicate] if object != ANY: # predicate+object is given, subject unbound if object in predicateDictionary: for s in predicateDictionary[object].keys(): yield (s, predicate, object), self.__contexts() else: # given object not found pass else: # predicate is given, object+subject unbound for o in predicateDictionary.keys(): for s in predicateDictionary[o].keys(): yield (s, predicate, o), self.__contexts() elif object != ANY: # object is given, subject+predicate unbound osp = self.__osp if object in osp: objectDictionary = osp[object] for s in objectDictionary.keys(): for p in objectDictionary[s].keys(): yield (s, p, object), self.__contexts() else: # subject+predicate+object unbound spo = self.__spo for s in spo.keys(): subjectDictionary = spo[s] for p in subjectDictionary.keys(): for o in subjectDictionary[p].keys(): yield (s, p, o), self.__contexts() def __len__(self, context=None): #@@ optimize i = 0 for triple in self.triples((None, None, None)): i += 1 return i def bind(self, prefix, namespace): self.__prefix[namespace] = prefix self.__namespace[prefix] = namespace def namespace(self, prefix): return self.__namespace.get(prefix, None) def prefix(self, namespace): return self.__prefix.get(namespace, None) def namespaces(self): for prefix, namespace in self.__namespace.iteritems(): yield prefix, namespace def __contexts(self): return (c for c in []) # TODO: best way to return empty generator class IOMemory(Store): """\ An integer-key-optimized context-aware in-memory store. Uses three dict indices (for subjects, objects and predicates) holding sets of triples. Context information is tracked in a separate dict, with the triple as key and a dict of {context: quoted} items as value. The context information is used to filter triple query results. Memory usage is low due to several optimizations. RDF nodes are not stored directly in the indices; instead, the indices hold integer keys and the actual nodes are only stored once in int-to-object and object-to-int mapping dictionaries. A default context is determined based on the first triple that is added to the store, and no context information is actually stored for subsequent other triples with the same context information. Most operations should be quite fast, but a triples() query with two bound parts requires a set intersection operation, which may be slow in some cases. When multiple contexts are used in the same store, filtering based on context has to be done after each query, which may also be slow. """ context_aware = True formula_aware = True graph_aware = True # The following variable name conventions are used in this class: # # subject, predicate, object unencoded triple parts # triple = (subject, predicate, object) unencoded triple # context: unencoded context # # sid, pid, oid integer-encoded triple parts # enctriple = (sid, pid, oid) integer-encoded triple # cid integer-encoded context def __init__(self, configuration=None, identifier=None): super(IOMemory, self).__init__() self.__namespace = {} self.__prefix = {} # Mappings for encoding RDF nodes using integer keys, to save memory # in the indexes Note that None is always mapped to itself, to make # it easy to test for it in either encoded or unencoded form. self.__int2obj = {None: None} # maps integer keys to objects self.__obj2int = {None: None} # maps objects to integer keys # Indexes for each triple part, and a list of contexts for each triple self.__subjectIndex = {} # key: sid val: set(enctriples) self.__predicateIndex = {} # key: pid val: set(enctriples) self.__objectIndex = {} # key: oid val: set(enctriples) self.__tripleContexts = { } # key: enctriple val: {cid1: quoted, cid2: quoted ...} self.__contextTriples = {None: set()} # key: cid val: set(enctriples) # all contexts used in store (unencoded) self.__all_contexts = set() # default context information for triples self.__defaultContexts = None def bind(self, prefix, namespace): self.__prefix[namespace] = prefix self.__namespace[prefix] = namespace def namespace(self, prefix): return self.__namespace.get(prefix, None) def prefix(self, namespace): return self.__prefix.get(namespace, None) def namespaces(self): for prefix, namespace in self.__namespace.iteritems(): yield prefix, namespace def add(self, triple, context, quoted=False): Store.add(self, triple, context, quoted) if context is not None: self.__all_contexts.add(context) enctriple = self.__encodeTriple(triple) sid, pid, oid = enctriple self.__addTripleContext(enctriple, context, quoted) if sid in self.__subjectIndex: self.__subjectIndex[sid].add(enctriple) else: self.__subjectIndex[sid] = set([enctriple]) if pid in self.__predicateIndex: self.__predicateIndex[pid].add(enctriple) else: self.__predicateIndex[pid] = set([enctriple]) if oid in self.__objectIndex: self.__objectIndex[oid].add(enctriple) else: self.__objectIndex[oid] = set([enctriple]) def remove(self, triplepat, context=None): req_cid = self.__obj2id(context) for triple, contexts in self.triples(triplepat, context): enctriple = self.__encodeTriple(triple) for cid in self.__getTripleContexts(enctriple): if context is not None and req_cid != cid: continue self.__removeTripleContext(enctriple, cid) ctxs = self.__getTripleContexts(enctriple, skipQuoted=True) if None in ctxs and (context is None or len(ctxs) == 1): self.__removeTripleContext(enctriple, None) if len(self.__getTripleContexts(enctriple)) == 0: # triple has been removed from all contexts sid, pid, oid = enctriple self.__subjectIndex[sid].remove(enctriple) self.__predicateIndex[pid].remove(enctriple) self.__objectIndex[oid].remove(enctriple) del self.__tripleContexts[enctriple] if not req_cid is None and \ req_cid in self.__contextTriples and \ len(self.__contextTriples[req_cid]) == 0: # all triples are removed out of this context # and it's not the default context so delete it del self.__contextTriples[req_cid] if triplepat == (None, None, None) and \ context in self.__all_contexts and \ not self.graph_aware: # remove the whole context self.__all_contexts.remove(context) def triples(self, triplein, context=None): if context is not None: if context == self: # hmm...does this really ever happen? context = None cid = self.__obj2id(context) enctriple = self.__encodeTriple(triplein) sid, pid, oid = enctriple # all triples case (no triple parts given as pattern) if sid is None and pid is None and oid is None: return self.__all_triples(cid) # optimize "triple in graph" case (all parts given) if sid is not None and pid is not None and oid is not None: if sid in self.__subjectIndex and \ enctriple in self.__subjectIndex[sid] and \ self.__tripleHasContext(enctriple, cid): return ((triplein, self.__contexts(enctriple)) for i in [0]) else: return self.__emptygen() # remaining cases: one or two out of three given sets = [] if sid is not None: if sid in self.__subjectIndex: sets.append(self.__subjectIndex[sid]) else: return self.__emptygen() if pid is not None: if pid in self.__predicateIndex: sets.append(self.__predicateIndex[pid]) else: return self.__emptygen() if oid is not None: if oid in self.__objectIndex: sets.append(self.__objectIndex[oid]) else: return self.__emptygen() # to get the result, do an intersection of the sets (if necessary) if len(sets) > 1: enctriples = sets[0].intersection(*sets[1:]) else: enctriples = sets[0].copy() return ((self.__decodeTriple(enctriple), self.__contexts(enctriple)) for enctriple in enctriples if self.__tripleHasContext(enctriple, cid)) def contexts(self, triple=None): if triple is None or triple is (None,None,None): return (context for context in self.__all_contexts) enctriple = self.__encodeTriple(triple) sid, pid, oid = enctriple if sid in self.__subjectIndex and enctriple in self.__subjectIndex[sid]: return self.__contexts(enctriple) else: return self.__emptygen() def __len__(self, context=None): cid = self.__obj2id(context) if cid not in self.__contextTriples: return 0 return len(self.__contextTriples[cid]) def add_graph(self, graph): if not self.graph_aware: Store.add_graph(self, graph) else: self.__all_contexts.add(graph) def remove_graph(self, graph): if not self.graph_aware: Store.remove_graph(self, graph) else: self.remove((None,None,None), graph) try: self.__all_contexts.remove(graph) except KeyError: pass # we didn't know this graph, no problem # internal utility methods below def __addTripleContext(self, enctriple, context, quoted): """add the given context to the set of contexts for the triple""" cid = self.__obj2id(context) sid, pid, oid = enctriple if sid in self.__subjectIndex and enctriple in self.__subjectIndex[sid]: # we know the triple exists somewhere in the store if enctriple not in self.__tripleContexts: # triple exists with default ctx info # start with a copy of the default ctx info self.__tripleContexts[ enctriple] = self.__defaultContexts.copy() self.__tripleContexts[enctriple][cid] = quoted if not quoted: self.__tripleContexts[enctriple][None] = quoted else: # the triple didn't exist before in the store if quoted: # this context only self.__tripleContexts[enctriple] = {cid: quoted} else: # default context as well self.__tripleContexts[enctriple] = {cid: quoted, None: quoted} # if the triple is not quoted add it to the default context if not quoted: self.__contextTriples[None].add(enctriple) # always add the triple to given context, making sure it's initialized if cid not in self.__contextTriples: self.__contextTriples[cid] = set() self.__contextTriples[cid].add(enctriple) # if this is the first ever triple in the store, set default ctx info if self.__defaultContexts is None: self.__defaultContexts = self.__tripleContexts[enctriple] # if the context info is the same as default, no need to store it if self.__tripleContexts[enctriple] == self.__defaultContexts: del self.__tripleContexts[enctriple] def __getTripleContexts(self, enctriple, skipQuoted=False): """return a list of (encoded) contexts for the triple, skipping quoted contexts if skipQuoted==True""" ctxs = self.__tripleContexts.get(enctriple, self.__defaultContexts) if not skipQuoted: return ctxs.keys() return [cid for cid, quoted in ctxs.iteritems() if not quoted] def __tripleHasContext(self, enctriple, cid): """return True iff the triple exists in the given context""" ctxs = self.__tripleContexts.get(enctriple, self.__defaultContexts) return (cid in ctxs) def __removeTripleContext(self, enctriple, cid): """remove the context from the triple""" ctxs = self.__tripleContexts.get( enctriple, self.__defaultContexts).copy() del ctxs[cid] if ctxs == self.__defaultContexts: del self.__tripleContexts[enctriple] else: self.__tripleContexts[enctriple] = ctxs self.__contextTriples[cid].remove(enctriple) def __obj2id(self, obj): """encode object, storing it in the encoding map if necessary, and return the integer key""" if obj not in self.__obj2int: id = randid() while id in self.__int2obj: id = randid() self.__obj2int[obj] = id self.__int2obj[id] = obj return id return self.__obj2int[obj] def __encodeTriple(self, triple): """encode a whole triple, returning the encoded triple""" return tuple(map(self.__obj2id, triple)) def __decodeTriple(self, enctriple): """decode a whole encoded triple, returning the original triple""" return tuple(map(self.__int2obj.get, enctriple)) def __all_triples(self, cid): """return a generator which yields all the triples (unencoded) of the given context""" if cid not in self.__contextTriples: return for enctriple in self.__contextTriples[cid].copy(): yield self.__decodeTriple(enctriple), self.__contexts(enctriple) def __contexts(self, enctriple): """return a generator for all the non-quoted contexts (unencoded) the encoded triple appears in""" return (self.__int2obj.get(cid) for cid in self.__getTripleContexts(enctriple, skipQuoted=True) if cid is not None) def __emptygen(self): """return an empty generator""" if False: yield import random def randid(randint=random.randint, choice=random.choice, signs=(-1, 1)): return choice(signs) * randint(1, 2000000000) del random rdflib-4.1.2/rdflib/plugins/parsers/000077500000000000000000000000001232323236500173635ustar00rootroot00000000000000rdflib-4.1.2/rdflib/plugins/parsers/__init__.py000066400000000000000000000000111232323236500214640ustar00rootroot00000000000000""" """ rdflib-4.1.2/rdflib/plugins/parsers/hturtle.py000066400000000000000000000077451232323236500214410ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Extraction parser RDF embedded verbatim into HTML or XML files. This is based on: * The specification on embedding turtle into html: http://www.w3.org/TR/turtle/#in-html For SVG (and currently SVG only) the method also extracts an embedded RDF/XML data, per SVG specification License: W3C Software License, http://www.w3.org/Consortium/Legal/copyright-software Author: Ivan Herman Copyright: W3C """ from rdflib.parser import Parser from .pyRdfa import pyRdfa, Options from .pyRdfa.state import ExecutionContext from .pyRdfa.embeddedRDF import handle_embeddedRDF from .structureddata import _get_orig_source, _check_error try: import html5lib assert html5lib html5lib = True except ImportError: import warnings warnings.warn( 'html5lib not found! RDFa and Microdata parsers ' + 'will not be available.') html5lib = False class HTurtle(pyRdfa): """ Bastardizing the RDFa 1.1 parser to do a hturtle extractions """ def __init__(self, options=None, base="", media_type=""): pyRdfa.__init__(self, options=options, base=base, media_type=media_type, rdfa_version="1.1") def graph_from_DOM(self, dom, graph, pgraph=None): """ Stealing the parsing function from the original class, to do turtle extraction only """ def copyGraph(tog, fromg): for t in fromg: tog.add(t) for k, ns in fromg.namespaces(): tog.bind(k, ns) def _process_one_node(node, graph, state): if handle_embeddedRDF(node, graph, state): # we got an RDF content that has been extracted into Graph; # the recursion should stop return else: # recurse through all the child elements of the current node for n in node.childNodes: if n.nodeType == node.ELEMENT_NODE: _process_one_node(n, graph, state) topElement = dom.documentElement state = ExecutionContext(topElement, graph, base=self.base, options=self.options, rdfa_version="1.1") _process_one_node(topElement, graph, state) if pgraph is not None: copyGraph(pgraph, self.options.processor_graph.graph) # This is the parser interface as it would look when called from the rest of # RDFLib class HTurtleParser(Parser): def parse(self, source, graph, pgraph=None, media_type=""): """ @param source: one of the input sources that the RDFLib package defined @type source: InputSource class instance @param graph: target graph for the triples; output graph, in RDFa spec. parlance @type graph: RDFLib Graph @keyword media_type: explicit setting of the preferred media type (a.k.a. content type) of the the RDFa source. None means the content type of the HTTP result is used, or a guess is made based on the suffix of a file @type media_type: string """ if html5lib is False: raise ImportError( 'html5lib is not installed, cannot ' + 'use RDFa and Microdata parsers.') (baseURI, orig_source) = _get_orig_source(source) self._process( graph, pgraph, baseURI, orig_source, media_type=media_type) def _process(self, graph, baseURI, orig_source, media_type=""): self.options = Options(output_processor_graph=None, embedded_rdf=True, vocab_expansion=False, vocab_cache=False) if media_type is None: media_type = "" processor = HTurtle( self.options, base=baseURI, media_type=media_type) processor.graph_from_source( orig_source, graph=graph, pgraph=None, rdfOutput=False) # get possible error triples to raise exceptions _check_error(graph) rdflib-4.1.2/rdflib/plugins/parsers/notation3.py000066400000000000000000001662521232323236500216670ustar00rootroot00000000000000#!/usr/bin/env python u""" notation3.py - Standalone Notation3 Parser Derived from CWM, the Closed World Machine Authors of the original suite: * Dan Connolly <@@> * Tim Berners-Lee <@@> * Yosi Scharf <@@> * Joseph M. Reagle Jr. * Rich Salz http://www.w3.org/2000/10/swap/notation3.py Copyright 2000-2007, World Wide Web Consortium. Copyright 2001, MIT. Copyright 2001, Zolera Systems Inc. License: W3C Software License http://www.w3.org/Consortium/Legal/copyright-software Modified by Sean B. Palmer Copyright 2007, Sean B. Palmer. Modified to work with rdflib by Gunnar Aastrand Grimnes Copyright 2010, Gunnar A. Grimnes """ # Python standard libraries import types import sys import os import re import codecs from decimal import Decimal from uuid import uuid4 from rdflib.term import URIRef, BNode, Literal, Variable, _XSD_PFX, _unique_id from rdflib.graph import QuotedGraph, ConjunctiveGraph, Graph from rdflib import py3compat b = py3compat.b __all__ = ['BadSyntax', 'N3Parser', 'TurtleParser', "splitFragP", "join", "base", "runNamespace", "uniqueURI", "hexify"] from rdflib.parser import Parser def splitFragP(uriref, punct=0): """split a URI reference before the fragment Punctuation is kept. e.g. >>> splitFragP("abc#def") ('abc', '#def') >>> splitFragP("abcdef") ('abcdef', '') """ i = uriref.rfind("#") if i >= 0: return uriref[:i], uriref[i:] else: return uriref, '' @py3compat.format_doctest_out def join(here, there): """join an absolute URI and URI reference (non-ascii characters are supported/doctested; haven't checked the details of the IRI spec though) ``here`` is assumed to be absolute. ``there`` is URI reference. >>> join('http://example/x/y/z', '../abc') 'http://example/x/abc' Raise ValueError if there uses relative path syntax but here has no hierarchical path. >>> join('mid:foo@example', '../foo') # doctest: +NORMALIZE_WHITESPACE Traceback (most recent call last): raise ValueError(here) ValueError: Base has no slash after colon - with relative '../foo'. >>> join('http://example/x/y/z', '') 'http://example/x/y/z' >>> join('mid:foo@example', '#foo') 'mid:foo@example#foo' We grok IRIs >>> len(%(u)s'Andr\\xe9') 5 >>> join('http://example.org/', %(u)s'#Andr\\xe9') %(u)s'http://example.org/#Andr\\xe9' """ assert(here.find("#") < 0), \ "Base may not contain hash: '%s'" % here # why must caller splitFrag? slashl = there.find('/') colonl = there.find(':') # join(base, 'foo:/') -- absolute if colonl >= 0 and (slashl < 0 or colonl < slashl): return there bcolonl = here.find(':') assert(bcolonl >= 0), \ "Base uri '%s' is not absolute" % here # else it's not absolute path, frag = splitFragP(there) if not path: return here + frag # join('mid:foo@example', '../foo') bzzt if here[bcolonl + 1:bcolonl + 2] != '/': raise ValueError( ("Base <%s> has no slash after " "colon - with relative '%s'.") % (here, there)) if here[bcolonl + 1:bcolonl + 3] == '//': bpath = here.find('/', bcolonl + 3) else: bpath = bcolonl + 1 # join('http://xyz', 'foo') if bpath < 0: bpath = len(here) here = here + '/' # join('http://xyz/', '//abc') => 'http://abc' if there[:2] == '//': return here[:bcolonl + 1] + there # join('http://xyz/', '/abc') => 'http://xyz/abc' if there[:1] == '/': return here[:bpath] + there slashr = here.rfind('/') while 1: if path[:2] == './': path = path[2:] if path == '.': path = '' elif path[:3] == '../' or path == '..': path = path[3:] i = here.rfind('/', bpath, slashr) if i >= 0: here = here[:i + 1] slashr = i else: break return here[:slashr + 1] + path + frag def base(): """The base URI for this process - the Web equiv of cwd Relative or abolute unix-standard filenames parsed relative to this yeild the URI of the file. If we had a reliable way of getting a computer name, we should put it in the hostname just to prevent ambiguity """ # return "file://" + hostname + os.getcwd() + "/" return "file://" + _fixslash(os.getcwd()) + "/" def _fixslash(s): """ Fix windowslike filename to unixlike - (#ifdef WINDOWS)""" s = s.replace("\\", "/") if s[0] != "/" and s[1] == ":": s = s[2:] # @@@ Hack when drive letter present return s CONTEXT = 0 PRED = 1 SUBJ = 2 OBJ = 3 PARTS = PRED, SUBJ, OBJ ALL4 = CONTEXT, PRED, SUBJ, OBJ SYMBOL = 0 FORMULA = 1 LITERAL = 2 LITERAL_DT = 21 LITERAL_LANG = 22 ANONYMOUS = 3 XMLLITERAL = 25 Logic_NS = "http://www.w3.org/2000/10/swap/log#" NODE_MERGE_URI = Logic_NS + "is" # Pseudo-property indicating node merging forSomeSym = Logic_NS + "forSome" forAllSym = Logic_NS + "forAll" RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" RDF_NS_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" OWL_NS = "http://www.w3.org/2002/07/owl#" DAML_sameAs_URI = OWL_NS + "sameAs" parsesTo_URI = Logic_NS + "parsesTo" RDF_spec = "http://www.w3.org/TR/REC-rdf-syntax/" List_NS = RDF_NS_URI # From 20030808 _Old_Logic_NS = "http://www.w3.org/2000/10/swap/log.n3#" N3_first = (SYMBOL, List_NS + "first") N3_rest = (SYMBOL, List_NS + "rest") N3_li = (SYMBOL, List_NS + "li") N3_nil = (SYMBOL, List_NS + "nil") N3_List = (SYMBOL, List_NS + "List") N3_Empty = (SYMBOL, List_NS + "Empty") runNamespaceValue = None def runNamespace(): "Return a URI suitable as a namespace for run-local objects" # @@@ include hostname (privacy?) (hash it?) global runNamespaceValue if runNamespaceValue is None: runNamespaceValue = join(base(), _unique_id()) + '#' return runNamespaceValue nextu = 0 def uniqueURI(): "A unique URI" global nextu nextu += 1 # return runNamespace() + "u_" + `nextu` return runNamespace() + "u_" + str(nextu) tracking = False chatty_flag = 50 # from why import BecauseOfData, becauseSubexpression def BecauseOfData(*args, **kargs): # print args, kargs pass def becauseSubexpression(*args, **kargs): # print args, kargs pass N3_forSome_URI = forSomeSym N3_forAll_URI = forAllSym # Magic resources we know about ADDED_HASH = "#" # Stop where we use this in case we want to remove it! # This is the hash on namespace URIs RDF_type = (SYMBOL, RDF_type_URI) DAML_sameAs = (SYMBOL, DAML_sameAs_URI) LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies" BOOLEAN_DATATYPE = _XSD_PFX + "boolean" DECIMAL_DATATYPE = _XSD_PFX + "decimal" DOUBLE_DATATYPE = _XSD_PFX + "double" FLOAT_DATATYPE = _XSD_PFX + "float" INTEGER_DATATYPE = _XSD_PFX + "integer" option_noregen = 0 # If set, do not regenerate genids on output # @@ I18n - the notname chars need extending for well known unicode non-text # characters. The XML spec switched to assuming unknown things were name # characaters. # _namechars = string.lowercase + string.uppercase + string.digits + '_-' _notQNameChars = \ "\t\r\n !\"#$&'()*,+/;<=>?@[\\]^`{|}~" # else valid qname :-/ _notKeywordsChars = _notQNameChars + "." _notNameChars = _notQNameChars + ":" # Assume anything else valid name :-/ _rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' hexChars = 'ABCDEFabcdef0123456789' escapeChars = "(_~.-!$&'()*+,;=/?#@%)" # valid for \ escapes in localnames def unicodeExpand(m): try: return unichr(int(m.group(1), 16)) except: raise Exception("Invalid unicode code point: " + m.group(1)) unicodeEscape4 = re.compile( r'\\u([0-9a-f]{4})', flags=re.I) unicodeEscape8 = re.compile( r'\\U([0-9a-f]{8})', flags=re.I) N3CommentCharacter = "#" # For unix script # ! compatabilty ########################################## Parse string to sink # # Regular expressions: eol = re.compile( r'[ \t]*(#[^\n]*)?\r?\n') # end of line, poss. w/comment eof = re.compile( r'[ \t]*(#[^\n]*)?$') # end of file, poss. w/comment ws = re.compile(r'[ \t]*') # Whitespace not including NL signed_integer = re.compile(r'[-+]?[0-9]+') # integer integer_syntax = re.compile(r'[-+]?[0-9]+') decimal_syntax = re.compile(r'[-+]?[0-9]*\.[0-9]+') exponent_syntax = re.compile(r'[-+]?(?:[0-9]+\.[0-9]*(?:e|E)[-+]?[0-9]+|'+ r'\.[0-9](?:e|E)[-+]?[0-9]+|'+ r'[0-9]+(?:e|E)[-+]?[0-9]+)') digitstring = re.compile(r'[0-9]+') # Unsigned integer interesting = re.compile(r"""[\\\r\n\"\']""") langcode = re.compile(r'[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*') class SinkParser: def __init__(self, store, openFormula=None, thisDoc="", baseURI=None, genPrefix="", why=None, turtle=False): """ note: namespace names should *not* end in # ; the # will get added during qname processing """ self._bindings = {} if thisDoc != "": assert ':' in thisDoc, "Document URI not absolute: <%s>" % thisDoc self._bindings[""] = thisDoc + "#" # default self._store = store if genPrefix: store.setGenPrefix(genPrefix) # pass it on self._thisDoc = thisDoc self.lines = 0 # for error handling self.startOfLine = 0 # For calculating character number self._genPrefix = genPrefix self.keywords = ['a', 'this', 'bind', 'has', 'is', 'of', 'true', 'false'] self.keywordsSet = 0 # Then only can others be considerd qnames self._anonymousNodes = {} # Dict of anon nodes already declared ln: Term self._variables = {} self._parentVariables = {} self._reason = why # Why the parser was asked to parse this self.turtle = turtle # raise exception when encountering N3 extensions # Turtle allows single or double quotes around strings, whereas N3 # only allows double quotes. self.string_delimiters = ('"', "'") if turtle else ('"',) self._reason2 = None # Why these triples # was: diag.tracking if tracking: self._reason2 = BecauseOfData( store.newSymbol(thisDoc), because=self._reason) if baseURI: self._baseURI = baseURI else: if thisDoc: self._baseURI = thisDoc else: self._baseURI = None assert not self._baseURI or ':' in self._baseURI if not self._genPrefix: if self._thisDoc: self._genPrefix = self._thisDoc + "#_g" else: self._genPrefix = uniqueURI() if openFormula is None: if self._thisDoc: self._formula = store.newFormula(thisDoc + "#_formula") else: self._formula = store.newFormula() else: self._formula = openFormula self._context = self._formula self._parentContext = None def here(self, i): """String generated from position in file This is for repeatability when refering people to bnodes in a document. This has diagnostic uses less formally, as it should point one to which bnode the arbitrary identifier actually is. It gives the line and character number of the '[' charcacter or path character which introduced the blank node. The first blank node is boringly _L1C1. It used to be used only for tracking, but for tests in general it makes the canonical ordering of bnodes repeatable.""" return "%s_L%iC%i" % (self._genPrefix, self.lines, i - self.startOfLine + 1) def formula(self): return self._formula def loadStream(self, stream): return self.loadBuf(stream.read()) # Not ideal def loadBuf(self, buf): """Parses a buffer and returns its top level formula""" self.startDoc() self.feed(buf) return self.endDoc() # self._formula def feed(self, octets): """Feed an octet stream tothe parser if BadSyntax is raised, the string passed in the exception object is the remainder after any statements have been parsed. So if there is more data to feed to the parser, it should be straightforward to recover.""" if not isinstance(octets, unicode): s = octets.decode('utf-8') # NB already decoded, so \ufeff if len(s) > 0 and s[0] == codecs.BOM_UTF8.decode('utf-8'): s = s[1:] else: s = octets i = 0 while i >= 0: j = self.skipSpace(s, i) if j < 0: return i = self.directiveOrStatement(s, j) if i < 0: #print("# next char: %s" % s[j]) self.BadSyntax(s, j, "expected directive or statement") def directiveOrStatement(self, argstr, h): i = self.skipSpace(argstr, h) if i < 0: return i # EOF if self.turtle: j = self.sparqlDirective(argstr, i) if j >= 0: return j j = self.directive(argstr, i) if j >= 0: return self.checkDot(argstr, j) j = self.statement(argstr, i) if j >= 0: return self.checkDot(argstr, j) return j # @@I18N # _namechars = string.lowercase + string.uppercase + string.digits + '_-' def tok(self, tok, argstr, i, colon=False): """Check for keyword. Space must have been stripped on entry and we must not be at end of file. if colon, then keyword followed by colon is ok (@prefix: is ok, rdf:type shortcut a must be followed by ws) """ assert tok[0] not in _notNameChars # not for punctuation if argstr[i:i + 1] == "@": i = i + 1 else: if tok not in self.keywords: return -1 # No, this has neither keywords declaration nor "@" if (argstr[i:i + len(tok)] == tok and ( argstr[i + len(tok)] in _notKeywordsChars) or (colon and argstr[i+len(tok)] == ':')): i = i + len(tok) return i else: return -1 def sparqlTok(self, tok, argstr, i): """Check for SPARQL keyword. Space must have been stripped on entry and we must not be at end of file. Case insensitive and not preceeded by @ """ assert tok[0] not in _notNameChars # not for punctuation if (argstr[i:i + len(tok)].lower() == tok.lower() and (argstr[i + len(tok)] in _notQNameChars)): i = i + len(tok) return i else: return -1 def directive(self, argstr, i): j = self.skipSpace(argstr, i) if j < 0: return j # eof res = [] j = self.tok('bind', argstr, i) # implied "#". Obsolete. if j > 0: self.BadSyntax(argstr, i, "keyword bind is obsolete: use @prefix") j = self.tok('keywords', argstr, i) if j > 0: if self.turtle: self.BadSyntax(argstr, i, "Found 'keywords' when in Turtle mode.") i = self.commaSeparatedList(argstr, j, res, self.bareWord) if i < 0: self.BadSyntax(argstr, i, "'@keywords' needs comma separated list of words") self.setKeywords(res[:]) return i j = self.tok('forAll', argstr, i) if j > 0: if self.turtle: self.BadSyntax(argstr, i, "Found 'forAll' when in Turtle mode.") i = self.commaSeparatedList(argstr, j, res, self.uri_ref2) if i < 0: self.BadSyntax(argstr, i, "Bad variable list after @forAll") for x in res: # self._context.declareUniversal(x) if x not in self._variables or x in self._parentVariables: self._variables[x] = self._context.newUniversal(x) return i j = self.tok('forSome', argstr, i) if j > 0: if self.turtle: self.BadSyntax(argstr, i, "Found 'forSome' when in Turtle mode.") i = self. commaSeparatedList(argstr, j, res, self.uri_ref2) if i < 0: self.BadSyntax(argstr, i, "Bad variable list after @forSome") for x in res: self._context.declareExistential(x) return i j = self.tok('prefix', argstr, i, colon=True) # no implied "#" if j >= 0: t = [] i = self.qname(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected qname after @prefix") j = self.uri_ref2(argstr, i, t) if j < 0: self.BadSyntax(argstr, i, "expected after @prefix _qname_") ns = self.uriOf(t[1]) if self._baseURI: ns = join(self._baseURI, ns) elif ":" not in ns: self.BadSyntax(argstr, j, "With no base URI, cannot use " + "relative URI in @prefix <" + ns + ">") assert ':' in ns # must be absolute self._bindings[t[0][0]] = ns self.bind(t[0][0], hexify(ns)) return j j = self.tok('base', argstr, i) # Added 2007/7/7 if j >= 0: t = [] i = self.uri_ref2(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected after @base ") ns = self.uriOf(t[0]) if self._baseURI: ns = join(self._baseURI, ns) else: self.BadSyntax(argstr, j, "With no previous base URI, cannot use " + "relative URI in @base <" + ns + ">") assert ':' in ns # must be absolute self._baseURI = ns return i return -1 # Not a directive, could be something else. def sparqlDirective(self, argstr, i): """ turtle and trig support BASE/PREFIX without @ and without terminating . """ j = self.skipSpace(argstr, i) if j < 0: return j # eof j = self.sparqlTok('PREFIX', argstr, i) if j >= 0: t = [] i = self.qname(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected qname after @prefix") j = self.uri_ref2(argstr, i, t) if j < 0: self.BadSyntax(argstr, i, "expected after @prefix _qname_") ns = self.uriOf(t[1]) if self._baseURI: ns = join(self._baseURI, ns) elif ":" not in ns: self.BadSyntax(argstr, j, "With no base URI, cannot use " + "relative URI in @prefix <" + ns + ">") assert ':' in ns # must be absolute self._bindings[t[0][0]] = ns self.bind(t[0][0], hexify(ns)) return j j = self.sparqlTok('BASE', argstr, i) if j >= 0: t = [] i = self.uri_ref2(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected after @base ") ns = self.uriOf(t[0]) if self._baseURI: ns = join(self._baseURI, ns) else: self.BadSyntax(argstr, j, "With no previous base URI, cannot use " + "relative URI in @base <" + ns + ">") assert ':' in ns # must be absolute self._baseURI = ns return i return -1 # Not a directive, could be something else. def bind(self, qn, uri): assert isinstance( uri, types.StringType), "Any unicode must be %x-encoded already" if qn == "": self._store.setDefaultNamespace(uri) else: self._store.bind(qn, uri) def setKeywords(self, k): "Takes a list of strings" if k is None: self.keywordsSet = 0 else: self.keywords = k self.keywordsSet = 1 def startDoc(self): # was: self._store.startDoc() self._store.startDoc(self._formula) def endDoc(self): """Signal end of document and stop parsing. returns formula""" self._store.endDoc(self._formula) # don't canonicalize yet return self._formula def makeStatement(self, quadruple): # $$$$$$$$$$$$$$$$$$$$$ # print "# Parser output: ", `quadruple` self._store.makeStatement(quadruple, why=self._reason2) def statement(self, argstr, i): r = [] i = self.object( argstr, i, r) # Allow literal for subject - extends RDF if i < 0: return i j = self.property_list(argstr, i, r[0]) if j < 0: self.BadSyntax( argstr, i, "expected propertylist") return j def subject(self, argstr, i, res): return self.item(argstr, i, res) def verb(self, argstr, i, res): """ has _prop_ is _prop_ of a = _prop_ >- prop -> <- prop -< _operator_""" j = self.skipSpace(argstr, i) if j < 0: return j # eof r = [] j = self.tok('has', argstr, i) if j >= 0: if self.turtle: self.BadSyntax(argstr, i, "Found 'has' keyword in Turtle mode") i = self.prop(argstr, j, r) if i < 0: self.BadSyntax(argstr, j, "expected property after 'has'") res.append(('->', r[0])) return i j = self.tok('is', argstr, i) if j >= 0: if self.turtle: self.BadSyntax(argstr, i, "Found 'is' keyword in Turtle mode") i = self.prop(argstr, j, r) if i < 0: self.BadSyntax(argstr, j, "expected after 'is'") j = self.skipSpace(argstr, i) if j < 0: self.BadSyntax(argstr, i, "End of file found, expected property after 'is'") i = j j = self.tok('of', argstr, i) if j < 0: self.BadSyntax(argstr, i, "expected 'of' after 'is' ") res.append(('<-', r[0])) return j j = self.tok('a', argstr, i) if j >= 0: res.append(('->', RDF_type)) return j if argstr[i:i + 2] == "<=": if self.turtle: self.BadSyntax(argstr, i, "Found '<=' in Turtle mode. ") res.append(('<-', self._store.newSymbol(Logic_NS + "implies"))) return i + 2 if argstr[i:i + 1] == "=": if self.turtle: self.BadSyntax(argstr, i, "Found '=' in Turtle mode") if argstr[i + 1:i + 2] == ">": res.append(('->', self._store.newSymbol(Logic_NS + "implies"))) return i + 2 res.append(('->', DAML_sameAs)) return i + 1 if argstr[i:i + 2] == ":=": if self.turtle: self.BadSyntax(argstr, i, "Found ':=' in Turtle mode") # patch file relates two formulae, uses this @@ really? res.append(('->', Logic_NS + "becomes")) return i + 2 j = self.prop(argstr, i, r) if j >= 0: res.append(('->', r[0])) return j if argstr[i:i + 2] == ">-" or argstr[i:i + 2] == "<-": self.BadSyntax(argstr, j, ">- ... -> syntax is obsolete.") return -1 def prop(self, argstr, i, res): return self.item(argstr, i, res) def item(self, argstr, i, res): return self.path(argstr, i, res) def blankNode(self, uri=None): return self._store.newBlankNode(self._context, uri, why=self._reason2) def path(self, argstr, i, res): """Parse the path production. """ j = self.nodeOrLiteral(argstr, i, res) if j < 0: return j # nope while argstr[j:j + 1] in "!^": # no spaces, must follow exactly (?) ch = argstr[j:j + 1] subj = res.pop() obj = self.blankNode(uri=self.here(j)) j = self.node(argstr, j + 1, res) if j < 0: self.BadSyntax(argstr, j, "EOF found in middle of path syntax") pred = res.pop() if ch == "^": # Reverse traverse self.makeStatement((self._context, pred, obj, subj)) else: self.makeStatement((self._context, pred, subj, obj)) res.append(obj) return j def anonymousNode(self, ln): """Remember or generate a term for one of these _: anonymous nodes""" term = self._anonymousNodes.get(ln, None) if term is not None: return term term = self._store.newBlankNode(self._context, why=self._reason2) self._anonymousNodes[ln] = term return term def node(self, argstr, i, res, subjectAlready=None): """Parse the production. Space is now skipped once at the beginning instead of in multipe calls to self.skipSpace(). """ subj = subjectAlready j = self.skipSpace(argstr, i) if j < 0: return j # eof i = j ch = argstr[i:i + 1] # Quick 1-character checks first: if ch == "[": bnodeID = self.here(i) j = self.skipSpace(argstr, i + 1) if j < 0: self.BadSyntax(argstr, i, "EOF after '['") # Hack for "is" binding name to anon node if argstr[j:j + 1] == "=": if self.turtle: self.BadSyntax(argstr, j, "Found '[=' or '[ =' when in turtle mode.") i = j + 1 objs = [] j = self.objectList(argstr, i, objs) if j >= 0: subj = objs[0] if len(objs) > 1: for obj in objs: self.makeStatement((self._context, DAML_sameAs, subj, obj)) j = self.skipSpace(argstr, j) if j < 0: self.BadSyntax(argstr, i, "EOF when objectList expected after [ = ") if argstr[j:j + 1] == ";": j = j + 1 else: self.BadSyntax(argstr, i, "objectList expected after [= ") if subj is None: subj = self.blankNode(uri=bnodeID) i = self.property_list(argstr, j, subj) if i < 0: self.BadSyntax(argstr, j, "property_list expected") j = self.skipSpace(argstr, i) if j < 0: self.BadSyntax(argstr, i, "EOF when ']' expected after [ ") if argstr[j:j + 1] != "]": self.BadSyntax(argstr, j, "']' expected") res.append(subj) return j + 1 if not self.turtle and ch == "{": # if self.turtle: # self.BadSyntax(argstr, i, # "found '{' while in Turtle mode, Formulas not supported!") ch2 = argstr[i + 1:i + 2] if ch2 == '$': # a set i += 1 j = i + 1 List = [] first_run = True while 1: i = self.skipSpace(argstr, j) if i < 0: self.BadSyntax(argstr, i, "needed '$}', found end.") if argstr[i:i + 2] == '$}': j = i + 2 break if not first_run: if argstr[i:i + 1] == ',': i += 1 else: self.BadSyntax( argstr, i, "expected: ','") else: first_run = False item = [] j = self.item( argstr, i, item) # @@@@@ should be path, was object if j < 0: self.BadSyntax(argstr, i, "expected item in set or '$}'") List.append(self._store.intern(item[0])) res.append(self._store.newSet(List, self._context)) return j else: # parse a formula j = i + 1 oldParentContext = self._parentContext self._parentContext = self._context parentAnonymousNodes = self._anonymousNodes grandParentVariables = self._parentVariables self._parentVariables = self._variables self._anonymousNodes = {} self._variables = self._variables.copy() reason2 = self._reason2 self._reason2 = becauseSubexpression if subj is None: subj = self._store.newFormula() self._context = subj while 1: i = self.skipSpace(argstr, j) if i < 0: self.BadSyntax( argstr, i, "needed '}', found end.") if argstr[i:i + 1] == "}": j = i + 1 break j = self.directiveOrStatement(argstr, i) if j < 0: self.BadSyntax( argstr, i, "expected statement or '}'") self._anonymousNodes = parentAnonymousNodes self._variables = self._parentVariables self._parentVariables = grandParentVariables self._context = self._parentContext self._reason2 = reason2 self._parentContext = oldParentContext res.append(subj.close()) # No use until closed return j if ch == "(": thing_type = self._store.newList ch2 = argstr[i + 1:i + 2] if ch2 == '$': thing_type = self._store.newSet i += 1 j = i + 1 List = [] while 1: i = self.skipSpace(argstr, j) if i < 0: self.BadSyntax( argstr, i, "needed ')', found end.") if argstr[i:i + 1] == ')': j = i + 1 break item = [] j = self.item( argstr, i, item) # @@@@@ should be path, was object if j < 0: self.BadSyntax(argstr, i, "expected item in list or ')'") List.append(self._store.intern(item[0])) res.append(thing_type(List, self._context)) return j j = self.tok('this', argstr, i) # This context if j >= 0: self.BadSyntax(argstr, i, "Keyword 'this' was ancient N3. Now use " + "@forSome and @forAll keywords.") # booleans j = self.tok('true', argstr, i) if j >= 0: res.append(True) return j j = self.tok('false', argstr, i) if j >= 0: res.append(False) return j if subj is None: # If this can be a named node, then check for a name. j = self.uri_ref2(argstr, i, res) if j >= 0: return j return -1 def property_list(self, argstr, i, subj): """Parse property list Leaves the terminating punctuation in the buffer """ while 1: while 1: # skip repeat ; j = self.skipSpace(argstr, i) if j < 0: self.BadSyntax(argstr, i, "EOF found when expected verb in property list") if argstr[j]!=';': break i = j+1 if argstr[j:j + 2] == ":-": if self.turtle: self.BadSyntax(argstr, j, "Found in ':-' in Turtle mode") i = j + 2 res = [] j = self.node(argstr, i, res, subj) if j < 0: self.BadSyntax(argstr, i, "bad {} or () or [] node after :- ") i = j continue i = j v = [] j = self.verb(argstr, i, v) if j <= 0: return i # void but valid objs = [] i = self.objectList(argstr, j, objs) if i < 0: self.BadSyntax(argstr, j, "objectList expected") for obj in objs: dira, sym = v[0] if dira == '->': self.makeStatement((self._context, sym, subj, obj)) else: self.makeStatement((self._context, sym, obj, subj)) j = self.skipSpace(argstr, i) if j < 0: self.BadSyntax(argstr, j, "EOF found in list of objects") if argstr[i:i + 1] != ";": return i i = i + 1 # skip semicolon and continue def commaSeparatedList(self, argstr, j, res, what): """return value: -1 bad syntax; >1 new position in argstr res has things found appended """ i = self.skipSpace(argstr, j) if i < 0: self.BadSyntax(argstr, i, "EOF found expecting comma sep list") if argstr[i] == ".": return j # empty list is OK i = what(argstr, i, res) if i < 0: return -1 while 1: j = self.skipSpace(argstr, i) if j < 0: return j # eof ch = argstr[j:j + 1] if ch != ",": if ch != ".": return -1 return j # Found but not swallowed "." i = what(argstr, j + 1, res) if i < 0: self.BadSyntax(argstr, i, "bad list content") def objectList(self, argstr, i, res): i = self.object(argstr, i, res) if i < 0: return -1 while 1: j = self.skipSpace(argstr, i) if j < 0: self.BadSyntax(argstr, j, "EOF found after object") if argstr[j:j + 1] != ",": return j # Found something else! i = self.object(argstr, j + 1, res) if i < 0: return i def checkDot(self, argstr, i): j = self.skipSpace(argstr, i) if j < 0: return j # eof if argstr[j:j + 1] == ".": return j + 1 # skip if argstr[j:j + 1] == "}": return j # don't skip it if argstr[j:j + 1] == "]": return j self.BadSyntax(argstr, j, "expected '.' or '}' or ']' at end of statement") def uri_ref2(self, argstr, i, res): """Generate uri from n3 representation. Note that the RDF convention of directly concatenating NS and local name is now used though I prefer inserting a '#' to make the namesapces look more like what XML folks expect. """ qn = [] j = self.qname(argstr, i, qn) if j >= 0: pfx, ln = qn[0] if pfx is None: assert 0, "not used?" ns = self._baseURI + ADDED_HASH else: try: ns = self._bindings[pfx] except KeyError: if pfx == "_": # Magic prefix 2001/05/30, can be changed res.append(self.anonymousNode(ln)) return j if not self.turtle and pfx == "": ns = join(self._baseURI or "", "#") else: self.BadSyntax(argstr, i, "Prefix \"%s:\" not bound" % (pfx)) symb = self._store.newSymbol(ns + ln) if symb in self._variables: res.append(self._variables[symb]) else: res.append(symb) # @@@ "#" CONVENTION return j i = self.skipSpace(argstr, i) if i < 0: return -1 if argstr[i] == "?": v = [] j = self.variable(argstr, i, v) if j > 0: # Forget varibles as a class, only in context. res.append(v[0]) return j return -1 elif argstr[i] == "<": i = i + 1 st = i while i < len(argstr): if argstr[i] == ">": uref = argstr[st:i] # the join should dealt with "": # expand unicode escapes uref = unicodeEscape8.sub(unicodeExpand, uref) uref = unicodeEscape4.sub(unicodeExpand, uref) if self._baseURI: uref = join(self._baseURI, uref) # was: uripath.join else: assert ":" in uref, \ "With no base URI, cannot deal with relative URIs" if argstr[i - 1:i] == "#" and not uref[-1:] == "#": uref = uref + \ "#" # She meant it! Weirdness in urlparse? symb = self._store.newSymbol(uref) if symb in self._variables: res.append(self._variables[symb]) else: res.append(symb) return i + 1 i = i + 1 self.BadSyntax(argstr, j, "unterminated URI reference") elif self.keywordsSet: v = [] j = self.bareWord(argstr, i, v) if j < 0: return -1 # Forget varibles as a class, only in context. if v[0] in self.keywords: self.BadSyntax(argstr, i, 'Keyword "%s" not allowed here.' % v[0]) res.append(self._store.newSymbol(self._bindings[""] + v[0])) return j else: return -1 def skipSpace(self, argstr, i): """Skip white space, newlines and comments. return -1 if EOF, else position of first non-ws character""" while 1: m = eol.match(argstr, i) if m is None: break self.lines = self.lines + 1 i = m.end() # Point to first character unmatched self.startOfLine = i m = ws.match(argstr, i) if m is not None: i = m.end() m = eof.match(argstr, i) if m is not None: return -1 return i def variable(self, argstr, i, res): """ ?abc -> variable(:abc) """ j = self.skipSpace(argstr, i) if j < 0: return -1 if argstr[j:j + 1] != "?": return -1 j = j + 1 i = j if argstr[j] in "0123456789-": self.BadSyntax(argstr, j, "Varible name can't start with '%s'" % argstr[j]) while i < len(argstr) and argstr[i] not in _notKeywordsChars: i = i + 1 if self._parentContext is None: varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i]) if varURI not in self._variables: self._variables[varURI] = self._context.newUniversal( varURI, why=self._reason2) res.append(self._variables[varURI]) return i # @@ was: # self.BadSyntax(argstr, j, # "Can't use ?xxx syntax for variable in outermost level: %s" # % argstr[j-1:i]) varURI = self._store.newSymbol(self._baseURI + "#" + argstr[j:i]) if varURI not in self._parentVariables: self._parentVariables[varURI] = self._parentContext.newUniversal( varURI, why=self._reason2) res.append(self._parentVariables[varURI]) return i def bareWord(self, argstr, i, res): """ abc -> :abc """ j = self.skipSpace(argstr, i) if j < 0: return -1 if argstr[j] in "0123456789-" or argstr[j] in _notKeywordsChars: return -1 i = j while i < len(argstr) and argstr[i] not in _notKeywordsChars: i = i + 1 res.append(argstr[j:i]) return i def qname(self, argstr, i, res): """ xyz:def -> ('xyz', 'def') If not in keywords and keywordsSet: def -> ('', 'def') :def -> ('', 'def') """ i = self.skipSpace(argstr, i) if i < 0: return -1 c = argstr[i] if c in "0123456789-+.": return -1 if c not in _notNameChars: ln = c i = i + 1 while i < len(argstr): c = argstr[i] if c not in _notNameChars: ln = ln + c i = i + 1 else: break if argstr[i - 1] == ".": # qname cannot end with "." ln = ln[:-1] if not ln: return -1 i -= 1 else: # First character is non-alpha ln = '' # Was: None - TBL (why? useful?) if i < len(argstr) and argstr[i] == ':': pfx = ln # bnodes names have different rules if pfx == '_': allowedChars = _notNameChars else: allowedChars = _notQNameChars i = i + 1 lastslash = False # start = i # TODO first char . ln = '' while i < len(argstr): c = argstr[i] if not lastslash and c == '\\': lastslash = True i += 1 elif lastslash or c not in allowedChars: if lastslash: if c not in escapeChars: raise BadSyntax(self._thisDoc, self.line, argstr, i, "illegal escape "+c) elif c=='%': if argstr[i+1] not in hexChars or argstr[i+2] not in hexChars: raise BadSyntax(self._thisDoc, self.line, argstr, i, "illegal hex escape "+c) ln = ln + c i = i + 1 lastslash = False else: break if lastslash: raise BadSyntax( self._thisDoc, self.line, argstr, i, "qname cannot end with \\") if argstr[i-1]=='.': # localname cannot end in . ln = ln[:-1] if not ln: return -1 i -= 1 res.append((pfx, ln)) return i else: # delimiter was not ":" if ln and self.keywordsSet and ln not in self.keywords: res.append(('', ln)) return i return -1 def object(self, argstr, i, res): j = self.subject(argstr, i, res) if j >= 0: return j else: j = self.skipSpace(argstr, i) if j < 0: return -1 else: i = j if argstr[i] in self.string_delimiters: if argstr[i:i + 3] == argstr[i] * 3: delim = argstr[i] * 3 else: delim = argstr[i] i = i + len(delim) j, s = self.strconst(argstr, i, delim) res.append(self._store.newLiteral(s)) return j else: return -1 def nodeOrLiteral(self, argstr, i, res): j = self.node(argstr, i, res) startline = self.lines # Remember where for error messages if j >= 0: return j else: j = self.skipSpace(argstr, i) if j < 0: return -1 else: i = j ch = argstr[i] if ch in "-+0987654321.": m = exponent_syntax.match(argstr, i) if m: j = m.end() res.append(float(argstr[i:j])) return j m = decimal_syntax.match(argstr, i) if m: j = m.end() res.append(Decimal(argstr[i:j])) return j m = integer_syntax.match(argstr, i) if m: j = m.end() res.append(long(argstr[i:j])) return j # return -1 ## or fall through? if argstr[i] in self.string_delimiters: if argstr[i:i + 3] == argstr[i] * 3: delim = argstr[i] * 3 else: delim = argstr[i] i = i + len(delim) dt = None j, s = self.strconst(argstr, i, delim) lang = None if argstr[j:j + 1] == "@": # Language? m = langcode.match(argstr, j + 1) if m is None: raise BadSyntax( self._thisDoc, startline, argstr, i, "Bad language code syntax on string " + "literal, after @") i = m.end() lang = argstr[j + 1:i] j = i if argstr[j:j + 2] == "^^": res2 = [] j = self.uri_ref2(argstr, j + 2, res2) # Read datatype URI dt = res2[0] res.append(self._store.newLiteral(s, dt, lang)) return j else: return -1 def uriOf(self, sym): if isinstance(sym, types.TupleType): return sym[1] # old system for --pipe # return sym.uriref() # cwm api return sym def strconst(self, argstr, i, delim): """parse an N3 string constant delimited by delim. return index, val """ delim1 = delim[0] delim2, delim3, delim4, delim5 = delim1 * 2, delim1 * 3, delim1 * 4, delim1 * 5 j = i ustr = u"" # Empty unicode string startline = self.lines # Remember where for error messages while j < len(argstr): if argstr[j] == delim1: if delim == delim1: # done when delim is " or ' i = j + 1 return i, ustr if delim == delim3: # done when delim is """ or ''' and, respectively ... if argstr[j:j + 5] == delim5: # ... we have "" or '' before i = j + 5 ustr = ustr + delim2 return i, ustr if argstr[j:j + 4] == delim4: # ... we have " or ' before i = j + 4 ustr = ustr + delim1 return i, ustr if argstr[j:j + 3] == delim3: # current " or ' is part of delim i = j + 3 return i, ustr # we are inside of the string and current char is " or ' j = j + 1 ustr = ustr + delim1 continue m = interesting.search(argstr, j) # was argstr[j:]. # Note for pos param to work, MUST be compiled ... re bug? assert m, "Quote expected in string at ^ in %s^%s" % ( argstr[j - 20:j], argstr[j:j + 20]) # at least need a quote i = m.start() try: ustr = ustr + argstr[j:i] except UnicodeError: err = "" for c in argstr[j:i]: err = err + (" %02x" % ord(c)) streason = sys.exc_info()[1].__str__() raise BadSyntax( self._thisDoc, startline, argstr, j, "Unicode error appending characters" + " %s to string, because\n\t%s" % (err, streason)) # print "@@@ i = ",i, " j=",j, "m.end=", m.end() ch = argstr[i] if ch == delim1: j = i continue elif ch in ('"', "'") and ch != delim1: ustr = ustr + ch j = i + 1 continue elif ch in "\r\n": if delim == delim1: raise BadSyntax( self._thisDoc, startline, argstr, i, "newline found in string literal") self.lines = self.lines + 1 ustr = ustr + ch j = i + 1 self.startOfLine = j elif ch == "\\": j = i + 1 ch = argstr[j:j + 1] # Will be empty if string ends if not ch: raise BadSyntax( self._thisDoc, startline, argstr, i, "unterminated string literal (2)") k = 'abfrtvn\\"'.find(ch) if k >= 0: uch = '\a\b\f\r\t\v\n\\"'[k] ustr = ustr + uch j = j + 1 elif ch == "u": j, ch = self.uEscape(argstr, j + 1, startline) ustr = ustr + ch elif ch == "U": j, ch = self.UEscape(argstr, j + 1, startline) ustr = ustr + ch else: self.BadSyntax(argstr, i, "bad escape") self.BadSyntax(argstr, i, "unterminated string literal") def _unicodeEscape(self, argstr, i, startline, reg, n): if len(argstr) 60: pre = "..." st = i - 60 else: pre = "" if len(argstr) - i > 60: post = "..." else: post = "" return 'at line %i of <%s>:\nBad syntax (%s) at ^ in:\n"%s%s^%s%s"' \ % (self.lines + 1, self._uri, self._why, pre, argstr[st:i], argstr[i:i + 60], post) @property def message(self): return str(self) ############################################################################### class Formula(object): number = 0 def __init__(self, parent): self.uuid = uuid4().hex self.counter = 0 Formula.number += 1 self.number = Formula.number self.existentials = {} self.universals = {} self.quotedgraph = QuotedGraph( store=parent.store, identifier=self.id()) def __str__(self): return '_:Formula%s' % self.number def id(self): return BNode('_:Formula%s' % self.number) def newBlankNode(self, uri=None, why=None): if uri is None: self.counter += 1 bn = BNode('f%sb%s' % (self.uuid, self.counter)) else: bn = BNode(uri.split('#').pop().replace('_', 'b')) return bn def newUniversal(self, uri, why=None): return Variable(uri.split('#').pop()) def declareExistential(self, x): self.existentials[x] = self.newBlankNode() def close(self): return self.quotedgraph r_hibyte = re.compile(r'([\x80-\xff])') class RDFSink(object): def __init__(self, graph): self.rootFormula = None self.counter = 0 self.graph = graph def newFormula(self): assert self.graph.store.formula_aware f = Formula(self.graph) return f def newGraph(self, identifier): return Graph(self.graph.store, identifier) def newSymbol(self, *args): return URIRef(args[0]) def newBlankNode(self, arg=None, uri=None, why=None): if isinstance(arg, Formula): return arg.newBlankNode(uri) elif isinstance(arg, Graph) or arg is None: self.counter += 1 bn = BNode('n' + str(self.counter)) else: bn = BNode(str(arg[0]).split('#').pop().replace('_', 'b')) return bn def newLiteral(self, s, dt, lang): if dt: return Literal(s, datatype=dt) else: return Literal(s, lang=lang) def newList(self, n, f): if not n: return self.newSymbol( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ) a = self.newBlankNode(f) first = self.newSymbol( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' ) rest = self.newSymbol( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest') self.makeStatement((f, first, a, n[0])) self.makeStatement((f, rest, a, self.newList(n[1:], f))) return a def newSet(self, *args): return set(args) def setDefaultNamespace(self, *args): return ':'.join(repr(n) for n in args) def makeStatement(self, quadruple, why=None): f, p, s, o = quadruple if hasattr(p, 'formula'): raise Exception("Formula used as predicate") s = self.normalise(f, s) p = self.normalise(f, p) o = self.normalise(f, o) if f == self.rootFormula: # print s, p, o, '.' self.graph.add((s, p, o)) elif isinstance(f, Formula): f.quotedgraph.add((s, p, o)) else: f.add((s,p,o)) # return str(quadruple) def normalise(self, f, n): if isinstance(n, tuple): return URIRef(unicode(n[1])) if isinstance(n, bool): s = Literal(str(n).lower(), datatype=BOOLEAN_DATATYPE) return s if isinstance(n, int) or isinstance(n, long): s = Literal(unicode(n), datatype=INTEGER_DATATYPE) return s if isinstance(n, Decimal): value = str(n) if value == '-0': value = '0' s = Literal(value, datatype=DECIMAL_DATATYPE) return s if isinstance(n, float): s = Literal(str(n), datatype=DOUBLE_DATATYPE) return s if isinstance(f, Formula): if n in f.existentials: return f.existentials[n] # if isinstance(n, Var): # if f.universals.has_key(n): # return f.universals[n] # f.universals[n] = f.newBlankNode() # return f.universals[n] return n def intern(self, something): return something def bind(self, pfx, uri): pass # print pfx, ':', uri def startDoc(self, formula): self.rootFormula = formula def endDoc(self, formula): pass ################################################### # # Utilities # @py3compat.format_doctest_out def hexify(ustr): """Use URL encoding to return an ASCII string corresponding to the given UTF8 string >>> hexify("http://example/a b") %(b)s'http://example/a%%20b' """ # s1=ustr.encode('utf-8') s = "" for ch in ustr: # .encode('utf-8'): if ord(ch) > 126 or ord(ch) < 33: ch = "%%%02X" % ord(ch) else: ch = "%c" % ord(ch) s = s + ch return b(s) class TurtleParser(Parser): """ An RDFLib parser for Turtle See http://www.w3.org/TR/turtle/ """ def __init__(self): pass def parse(self, source, graph, encoding="utf-8", turtle=True): if encoding not in [None, "utf-8"]: raise Exception( ("N3/Turtle files are always utf-8 encoded, ", "I was passed: %s") % encoding) sink = RDFSink(graph) baseURI = graph.absolutize( source.getPublicId() or source.getSystemId() or "") p = SinkParser(sink, baseURI=baseURI, turtle=turtle) p.loadStream(source.getByteStream()) for prefix, namespace in p._bindings.items(): graph.bind(prefix, namespace) class N3Parser(TurtleParser): """ An RDFLib parser for Notation3 See http://www.w3.org/DesignIssues/Notation3.html """ def __init__(self): pass def parse(self, source, graph, encoding="utf-8"): # we're currently being handed a Graph, not a ConjunctiveGraph assert graph.store.context_aware # is this implied by formula_aware assert graph.store.formula_aware conj_graph = ConjunctiveGraph(store=graph.store) conj_graph.default_context = graph # TODO: CG __init__ should have a # default_context arg # TODO: update N3Processor so that it can use conj_graph as the sink conj_graph.namespace_manager = graph.namespace_manager TurtleParser.parse(self, source, conj_graph, encoding, turtle=False) def _test(): import doctest doctest.testmod() # if __name__ == '__main__': # _test() def main(): g = ConjunctiveGraph() sink = RDFSink(g) base_uri = 'file://' + os.path.join(os.getcwd(), sys.argv[1]) p = SinkParser(sink, baseURI=base_uri) p._bindings[''] = p._baseURI + '#' p.startDoc() f = open(sys.argv[1], 'rb') rdbytes = f.read() f.close() p.feed(rdbytes) p.endDoc() for t in g.quads((None, None, None)): print t if __name__ == '__main__': main() # ends rdflib-4.1.2/rdflib/plugins/parsers/nquads.py000066400000000000000000000057571232323236500212460ustar00rootroot00000000000000""" This is a rdflib plugin for parsing NQuad files into Conjunctive graphs that can be used and queried. The store that backs the graph *must* be able to handle contexts. >>> from rdflib import ConjunctiveGraph, URIRef, Namespace >>> g = ConjunctiveGraph() >>> data = open("test/nquads.rdflib/example.nquads", "rb") >>> g.parse(data, format="nquads") # doctest:+ELLIPSIS )> >>> assert len(g.store) == 449 >>> # There should be 16 separate contexts >>> assert len([x for x in g.store.contexts()]) == 16 >>> # is the name of entity E10009 "Arco Publications"? >>> # (in graph http://bibliographica.org/entity/E10009) >>> # Looking for: >>> # >>> # >>> # "Arco Publications" >>> # >>> s = URIRef("http://bibliographica.org/entity/E10009") >>> FOAF = Namespace("http://xmlns.com/foaf/0.1/") >>> assert(g.value(s, FOAF.name).eq("Arco Publications")) """ from codecs import getreader from rdflib.py3compat import b from rdflib import ConjunctiveGraph # Build up from the NTriples parser: from rdflib.plugins.parsers.ntriples import NTriplesParser from rdflib.plugins.parsers.ntriples import ParseError from rdflib.plugins.parsers.ntriples import r_tail from rdflib.plugins.parsers.ntriples import r_wspace from rdflib.plugins.parsers.ntriples import r_wspaces __all__ = ['NQuadsParser'] class NQuadsParser(NTriplesParser): def parse(self, inputsource, sink, **kwargs): """Parse f as an N-Triples file.""" assert sink.store.context_aware, ("NQuadsParser must be given" " a context aware store.") self.sink = ConjunctiveGraph(store=sink.store) source = inputsource.getByteStream() if not hasattr(source, 'read'): raise ParseError("Item to parse must be a file-like object.") source = getreader('utf-8')(source) self.file = source self.buffer = '' while True: self.line = __line = self.readline() if self.line is None: break try: self.parseline() except ParseError, msg: raise ParseError("Invalid line (%s):\n%r" % (msg, __line)) return self.sink def parseline(self): self.eat(r_wspace) if (not self.line) or self.line.startswith(('#')): return # The line is empty or a comment subject = self.subject() self.eat(r_wspace) predicate = self.predicate() self.eat(r_wspace) obj = self.object() self.eat(r_wspace) context = self.uriref() or self.nodeid() self.eat(r_tail) if self.line: raise ParseError("Trailing garbage") # Must have a context aware store - add on a normal Graph # discards anything where the ctx != graph.identifier self.sink.get_context(context).add((subject, predicate, obj)) rdflib-4.1.2/rdflib/plugins/parsers/nt.py000066400000000000000000000012731232323236500203610ustar00rootroot00000000000000from rdflib.parser import Parser from rdflib.plugins.parsers.ntriples import NTriplesParser __all__ = ['NTSink', 'NTParser'] class NTSink(object): def __init__(self, graph): self.graph = graph def triple(self, s, p, o): self.graph.add((s, p, o)) class NTParser(Parser): """parser for the ntriples format, often stored with the .nt extension See http://www.w3.org/TR/rdf-testcases/#ntriples""" def __init__(self): super(NTParser, self).__init__() def parse(self, source, sink, baseURI=None): f = source.getByteStream() # TODO getCharacterStream? parser = NTriplesParser(NTSink(sink)) parser.parse(f) f.close() rdflib-4.1.2/rdflib/plugins/parsers/ntriples.py000066400000000000000000000173621232323236500216060ustar00rootroot00000000000000#!/usr/bin/env python __doc__ = """ N-Triples Parser License: GPL 2, W3C, BSD, or MIT Author: Sean B. Palmer, inamidst.com """ import re from rdflib.term import URIRef as URI from rdflib.term import BNode as bNode from rdflib.term import Literal from rdflib.py3compat import cast_bytes, decodeUnicodeEscape, ascii __all__ = ['unquote', 'uriquote', 'Sink', 'NTriplesParser'] uriref = r'<([^:]+:[^\s"<>]+)>' literal = r'"([^"\\]*(?:\\.[^"\\]*)*)"' litinfo = r'(?:@([a-z]+(?:-[a-zA-Z0-9]+)*)|\^\^' + uriref + r')?' r_line = re.compile(r'([^\r\n]*)(?:\r\n|\r|\n)') r_wspace = re.compile(r'[ \t]*') r_wspaces = re.compile(r'[ \t]+') r_tail = re.compile(r'[ \t]*\.[ \t]*(#.*)?') r_uriref = re.compile(uriref) r_nodeid = re.compile(r'_:([A-Za-z0-9]*)') r_literal = re.compile(literal + litinfo) bufsiz = 2048 validate = False class Node(unicode): pass class ParseError(Exception): pass class Sink(object): def __init__(self): self.length = 0 def triple(self, s, p, o): self.length += 1 print (s, p, o) quot = {'t': u'\t', 'n': u'\n', 'r': u'\r', '"': u'"', '\\': u'\\'} r_safe = re.compile(r'([\x20\x21\x23-\x5B\x5D-\x7E]+)') r_quot = re.compile(r'\\(t|n|r|"|\\)') r_uniquot = re.compile(r'\\u([0-9A-F]{4})|\\U([0-9A-F]{8})') def unquote(s): """Unquote an N-Triples string.""" if not validate: if isinstance(s, unicode): # nquads s = decodeUnicodeEscape(s) else: s = s.decode('unicode-escape') return s else: result = [] while s: m = r_safe.match(s) if m: s = s[m.end():] result.append(m.group(1)) continue m = r_quot.match(s) if m: s = s[2:] result.append(quot[m.group(1)]) continue m = r_uniquot.match(s) if m: s = s[m.end():] u, U = m.groups() codepoint = int(u or U, 16) if codepoint > 0x10FFFF: raise ParseError("Disallowed codepoint: %08X" % codepoint) result.append(unichr(codepoint)) elif s.startswith('\\'): raise ParseError("Illegal escape at: %s..." % s[:10]) else: raise ParseError("Illegal literal character: %r" % s[0]) return u''.join(result) r_hibyte = re.compile(ur'([\x80-\xFF])') def uriquote(uri): if not validate: return uri else: return r_hibyte.sub( lambda m: '%%%02X' % ord(m.group(1)), uri) class NTriplesParser(object): """An N-Triples Parser. Usage:: p = NTriplesParser(sink=MySink()) sink = p.parse(f) # file; use parsestring for a string """ _bnode_ids = {} def __init__(self, sink=None): if sink is not None: self.sink = sink else: self.sink = Sink() def parse(self, f): """Parse f as an N-Triples file.""" if not hasattr(f, 'read'): raise ParseError("Item to parse must be a file-like object.") f = ascii(f) self.file = f self.buffer = '' while True: self.line = self.readline() if self.line is None: break try: self.parseline() except ParseError: raise ParseError("Invalid line: %r" % self.line) return self.sink def parsestring(self, s): """Parse s as an N-Triples string.""" if not isinstance(s, basestring): raise ParseError("Item to parse must be a string instance.") try: from io import BytesIO assert BytesIO except ImportError: from cStringIO import StringIO as BytesIO assert BytesIO f = BytesIO() f.write(cast_bytes(s)) f.seek(0) self.parse(f) def readline(self): """Read an N-Triples line from buffered input.""" # N-Triples lines end in either CRLF, CR, or LF # Therefore, we can't just use f.readline() if not self.buffer: buffer = self.file.read(bufsiz) if not buffer: return None self.buffer = buffer while True: m = r_line.match(self.buffer) if m: # the more likely prospect self.buffer = self.buffer[m.end():] return m.group(1) else: buffer = self.file.read(bufsiz) if not buffer and not self.buffer.isspace(): # Last line does not need to be terminated with a newline buffer += "\n" elif not buffer: return None self.buffer += buffer def parseline(self): self.eat(r_wspace) if (not self.line) or self.line.startswith('#'): return # The line is empty or a comment subject = self.subject() self.eat(r_wspaces) predicate = self.predicate() self.eat(r_wspaces) object = self.object() self.eat(r_tail) if self.line: raise ParseError("Trailing garbage") self.sink.triple(subject, predicate, object) def peek(self, token): return self.line.startswith(token) def eat(self, pattern): m = pattern.match(self.line) if not m: # @@ Why can't we get the original pattern? # print(dir(pattern)) # print repr(self.line), type(self.line) raise ParseError("Failed to eat %s at %s" % (pattern, self.line)) self.line = self.line[m.end():] return m def subject(self): # @@ Consider using dictionary cases subj = self.uriref() or self.nodeid() if not subj: raise ParseError("Subject must be uriref or nodeID") return subj def predicate(self): pred = self.uriref() if not pred: raise ParseError("Predicate must be uriref") return pred def object(self): objt = self.uriref() or self.nodeid() or self.literal() if objt is False: raise ParseError("Unrecognised object type") return objt def uriref(self): if self.peek('<'): uri = self.eat(r_uriref).group(1) uri = unquote(uri) uri = uriquote(uri) return URI(uri) return False def nodeid(self): if self.peek('_'): # Fix for https://github.com/RDFLib/rdflib/issues/204 bnode_id = self.eat(r_nodeid).group(1) new_id = self._bnode_ids.get(bnode_id, None) if new_id is not None: # Re-map to id specfic to this doc return bNode(new_id) else: # Replace with freshly-generated document-specific BNode id bnode = bNode() # Store the mapping self._bnode_ids[bnode_id] = bnode return bnode return False def literal(self): if self.peek('"'): lit, lang, dtype = self.eat(r_literal).groups() if lang: lang = lang else: lang = None if dtype: dtype = dtype else: dtype = None if lang and dtype: raise ParseError("Can't have both a language and a datatype") lit = unquote(lit) return Literal(lit, lang, dtype) return False # # Obsolete, unused # def parseURI(uri): # import urllib # parser = NTriplesParser() # u = urllib.urlopen(uri) # sink = parser.parse(u) # u.close() # # for triple in sink: # # print triple # print 'Length of input:', sink.length rdflib-4.1.2/rdflib/plugins/parsers/pyMicrodata/000077500000000000000000000000001232323236500216375ustar00rootroot00000000000000rdflib-4.1.2/rdflib/plugins/parsers/pyMicrodata/__init__.py000066400000000000000000000426321232323236500237570ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ This module implements the microdata->RDF algorithm, as documented by the U{W3C Semantic Web Interest Group Note}. The module can be used via a stand-alone script (an example is part of the distribution) or bound to a CGI script as a Web Service. An example CGI script is also added to the distribution. Both the local script and the distribution may have to be adapted to local circumstances. (Simple) Usage ============== From a Python file, expecting a Turtle output:: from pyMicrodata import pyMicrodata print pyMicrodata().rdf_from_source('filename') Other output formats are also possible. E.g., to produce RDF/XML output, one could use:: from pyMicrodata import pyMicrodata print pyMicrodata().rdf_from_source('filename', outputFormat='pretty-xml') It is also possible to embed an RDFa processing. Eg, using:: from pyMicrodata import pyMicrodata graph = pyMicrodata().graph_from_source('filename') returns an RDFLib.Graph object instead of a serialization thereof. See the the description of the L{pyMicrodata class} for further possible entry points details. There is also, as part of this module, a L{separate entry for CGI calls}. Return formats -------------- By default, the output format for the graph is RDF/XML. At present, the following formats are also available (with the corresponding key to be used in the package entry points): - "xml": U{RDF/XML} - "turtle": U{Turtle} (default) - "nt": U{N-triple} - "json": U{JSON-LD} @summary: Microdata parser (distiller) @requires: Python version 2.5 or up @requires: U{RDFLib} @requires: U{html5lib} for the HTML5 parsing; note possible dependecies on Python's version on the project's web site @organization: U{World Wide Web Consortium} @author: U{Ivan Herman} @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} @copyright: W3C """ """ $Id: __init__.py,v 1.15 2012/09/05 16:40:43 ivan Exp $ $Date: 2012/09/05 16:40:43 $ """ __version__ = "1.2" __author__ = 'Ivan Herman' __contact__ = 'Ivan Herman, ivan@w3.org' import sys PY3 = (sys.version_info[0] >= 3) if PY3 : from io import StringIO else : from StringIO import StringIO import datetime import os import rdflib from rdflib import URIRef from rdflib import Literal from rdflib import BNode from rdflib import Namespace if rdflib.__version__ >= "3.0.0" : from rdflib import Graph from rdflib import RDF as ns_rdf from rdflib import RDFS as ns_rdfs else : from rdflib.Graph import Graph from rdflib.RDFS import RDFSNS as ns_rdfs from rdflib.RDF import RDFNS as ns_rdf if PY3 : from urllib.parse import urlparse else : from urlparse import urlparse debug = False from .utils import URIOpener from .microdata import MicrodataConversion ns_micro = Namespace("http://www.w3.org/2012/pyMicrodata/vocab#") ns_dc = Namespace("http://purl.org/dc/terms/") ns_xsd = Namespace('http://www.w3.org/2001/XMLSchema#') ns_ht = Namespace("http://www.w3.org/2006/http#") class MicrodataError(Exception) : """Superclass exceptions representing error conditions defined by the RDFa 1.1 specification. It does not add any new functionality to the Exception class.""" def __init__(self, msg) : self.msg = msg Exception.__init__(self) class HTTPError(MicrodataError) : """Raised when HTTP problems are detected. It does not add any new functionality to the Exception class.""" def __init__(self, http_msg, http_code) : self.msg = http_msg self.http_code = http_code MicrodataError.__init__(self,http_msg) # Default bindings. This is just for the beauty of things: bindings are added to the graph to make the output nicer. If this is not done, RDFlib defines prefixes like "_1:", "_2:" which is, though correct, ugly... _bindings = { 'owl' : 'http://www.w3.org/2002/07/owl#', 'gr' : 'http://purl.org/goodrelations/v1#', 'cc' : 'http://creativecommons.org/ns#', 'sioc' : 'http://rdfs.org/sioc/ns#', 'skos' : 'http://www.w3.org/2004/02/skos/core#', 'rdfs' : 'http://www.w3.org/2000/01/rdf-schema#', 'foaf' : 'http://xmlns.com/foaf/0.1/', 'void' : 'http://rdfs.org/ns/void#', 'ical' : 'http://www.w3.org/2002/12/cal/icaltzd#', 'vcard' : 'http://www.w3.org/2006/vcard/ns#', 'og' : 'http://ogp.me/ns#', 'rdf' : 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'ma' : 'http://www.w3.org/ns/ma-ont#', } ######################################################################################################### class pyMicrodata : """Main processing class for the distiller @ivar base: the base value for processing @ivar http_status: HTTP Status, to be returned when the package is used via a CGI entry. Initially set to 200, may be modified by exception handlers """ def __init__(self, base = "", vocab_expansion = False, vocab_cache = True) : """ @keyword base: URI for the default "base" value (usually the URI of the file to be processed) @keyword vocab_expansion: whether vocab expansion should be performed or not @type vocab_expansion: Boolean @keyword vocab_cache: if vocabulary expansion is done, then perform caching of the vocabulary data @type vocab_cache: Boolean """ self.http_status = 200 self.base = base self.vocab_expansion = vocab_expansion self.vocab_cache = vocab_cache def _generate_error_graph(self, pgraph, full_msg, uri = None) : """ Generate an error message into the graph. This method is usually used reacting on exceptions. Later versions of pyMicrodata may have more detailed error conditions on which it wishes to react. At the moment, this is fairly crude... """ if pgraph == None : retval = Graph() else : retval = pgraph pgraph.bind( "dc","http://purl.org/dc/terms/" ) pgraph.bind( "xsd",'http://www.w3.org/2001/XMLSchema#' ) pgraph.bind( "ht",'http://www.w3.org/2006/http#' ) pgraph.bind( "pyMicrodata",'http://www.w3.org/2012/pyMicrodata/vocab#' ) bnode = BNode() retval.add((bnode, ns_rdf["type"], ns_micro["Error"])) retval.add((bnode, ns_dc["description"], Literal(full_msg))) retval.add((bnode, ns_dc["date"], Literal(datetime.datetime.utcnow().isoformat(),datatype=ns_xsd["dateTime"]))) if uri != None : htbnode = BNode() retval.add( (bnode, ns_micro["context"],htbnode) ) retval.add( (htbnode, ns_rdf["type"], ns_ht["Request"]) ) retval.add( (htbnode, ns_ht["requestURI"], Literal(uri)) ) if self.http_status != None and self.http_status != 200: htbnode = BNode() retval.add( (bnode, ns_micro["context"],htbnode) ) retval.add( (htbnode, ns_rdf["type"], ns_ht["Response"]) ) retval.add( (htbnode, ns_ht["responseCode"], URIRef("http://www.w3.org/2006/http#%s" % self.http_status)) ) return retval def _get_input(self, name) : """ Trying to guess whether "name" is a URI, a string; it then tries to open these as such accordingly, returning a file-like object. If name is a plain string then it returns the input argument (that should be, supposidly, a file-like object already) @param name: identifier of the input source @type name: string or a file-like object @return: a file like object if opening "name" is possible and successful, "name" otherwise """ try : # Python 2 branch isstring = isinstance(name, basestring) except : # Python 3 branch isstring = isinstance(name, str) if isstring : # check if this is a URI, ie, if there is a valid 'scheme' part # otherwise it is considered to be a simple file if urlparse(name)[0] != "" : url_request = URIOpener(name) self.base = url_request.location return url_request.data else : self.base = name return open(name, 'rb') else : return name #################################################################################################################### # Externally used methods # def graph_from_DOM(self, dom, graph = None) : """ Extract the RDF Graph from a DOM tree. @param dom: a DOM Node element, the top level entry node for the whole tree (to make it clear, a dom.documentElement is used to initiate processing) @keyword graph: an RDF Graph (if None, than a new one is created) @type graph: rdflib Graph instance. If None, a new one is created. @return: an RDF Graph @rtype: rdflib Graph instance """ if graph == None : # Create the RDF Graph, that will contain the return triples... graph = Graph() conversion = MicrodataConversion(dom.documentElement, graph, base = self.base, vocab_expansion = self.vocab_expansion, vocab_cache = self.vocab_cache) conversion.convert() return graph def graph_from_source(self, name, graph = None, rdfOutput = False) : """ Extract an RDF graph from an microdata source. The source is parsed, the RDF extracted, and the RDF Graph is returned. This is a front-end to the L{pyMicrodata.graph_from_DOM} method. @param name: a URI, a file name, or a file-like object @return: an RDF Graph @rtype: rdflib Graph instance """ # First, open the source... try : # First, open the source... Possible HTTP errors are returned as error triples input = None try : input = self._get_input(name) except HTTPError : h = sys.exc_info()[1] self.http_status = h.http_code if not rdfOutput : raise h return self._generate_error_graph(graph, "HTTP Error: %s (%s)" % (h.http_code,h.msg), uri=name) except Exception : # Something nasty happened:-( e = sys.exc_info()[1] self.http_status = 500 if not rdfOutput : raise e return self._generate_error_graph(graph, str(e), uri=name) dom = None try : import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) import html5lib parser = html5lib.HTMLParser(tree=html5lib.treebuilders.getTreeBuilder("dom")) dom = parser.parse(input) return self.graph_from_DOM(dom, graph) except ImportError : msg = "HTML5 parser not available. Try installing html5lib " raise ImportError(msg) except Exception : # Something nasty happened:-( e = sys.exc_info()[1] self.http_status = 400 if not rdfOutput : raise e return self._generate_error_graph(graph, str(e), uri=name) except Exception : # Something nasty happened:-( e = sys.exc_info()[1] if isinstance(e, ImportError) : self.http_status = None else : self.http_status = 500 if not rdfOutput : raise e return self._generate_error_graph(graph, str(e), uri=name) def rdf_from_sources(self, names, outputFormat = "pretty-xml", rdfOutput = False) : """ Extract and RDF graph from a list of RDFa sources and serialize them in one graph. The sources are parsed, the RDF extracted, and serialization is done in the specified format. @param names: list of sources, each can be a URI, a file name, or a file-like object @keyword outputFormat: serialization format. Can be one of "turtle", "n3", "xml", "pretty-xml", "nt". "xml" and "pretty-xml", as well as "turtle" and "n3" are synonyms. @return: a serialized RDF Graph @rtype: string """ try : from pyRdfaExtras import MyGraph graph = MyGraph() except : graph = Graph() for prefix in _bindings : graph.bind(prefix,Namespace(_bindings[prefix])) # the value of rdfOutput determines the reaction on exceptions... for name in names : self.graph_from_source(name, graph, rdfOutput) return graph.serialize(format=outputFormat) def rdf_from_source(self, name, outputFormat = "pretty-xml", rdfOutput = False) : """ Extract and RDF graph from an RDFa source and serialize it in one graph. The source is parsed, the RDF extracted, and serialization is done in the specified format. @param name: a URI, a file name, or a file-like object @keyword outputFormat: serialization format. Can be one of "turtle", "n3", "xml", "pretty-xml", "nt". "xml" and "pretty-xml", as well as "turtle" and "n3" are synonyms. @return: a serialized RDF Graph @rtype: string """ return self.rdf_from_sources([name], outputFormat, rdfOutput) ################################################# CGI Entry point def processURI(uri, outputFormat, form) : """The standard processing of a microdata uri options in a form, ie, as an entry point from a CGI call. The call accepts extra form options (eg, HTTP GET options) as follows: @param uri: URI to access. Note that the "text:" and "uploaded:" values are treated separately; the former is for textual intput (in which case a StringIO is used to get the data) and the latter is for uploaded file, where the form gives access to the file directly. @param outputFormat: serialization formats, as understood by RDFLib. Note that though "turtle" is a possible parameter value, some versions of the RDFLib turtle generation does funny (though legal) things with namespaces, defining unusual and unwanted prefixes... @param form: extra call options (from the CGI call) to set up the local options (if any) @type form: cgi FieldStorage instance @return: serialized graph @rtype: string """ def _get_option(param, compare_value, default) : param_old = param.replace('_','-') if param in list(form.keys()) : val = form.getfirst(param).lower() return val == compare_value elif param_old in list(form.keys()) : # this is to ensure the old style parameters are still valid... # in the old days I used '-' in the parameters, the standard favours '_' val = form.getfirst(param_old).lower() return val == compare_value else : return default if uri == "uploaded:" : input = form["uploaded"].file base = "" elif uri == "text:" : input = StringIO(form.getfirst("text")) base = "" else : input = uri base = uri vocab_cache = _get_option( "vocab_cache", "true", True) vocab_expansion = _get_option( "vocab_expansion", "true", False) processor = pyMicrodata(base = base, vocab_expansion = vocab_expansion, vocab_cache = vocab_cache) # Decide the output format; the issue is what should happen in case of a top level error like an inaccessibility of # the html source: should a graph be returned or an HTML page with an error message? # decide whether HTML or RDF should be sent. htmlOutput = False #if 'HTTP_ACCEPT' in os.environ : # acc = os.environ['HTTP_ACCEPT'] # possibilities = ['text/html', # 'application/rdf+xml', # 'text/turtle; charset=utf-8', # 'application/json', # 'application/ld+json', # 'text/rdf+n3'] # # # this nice module does content negotiation and returns the preferred format # sg = httpheader.acceptable_content_type(acc, possibilities) # htmlOutput = (sg != None and sg[0] == httpheader.content_type('text/html')) # os.environ['rdfaerror'] = 'true' try : graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput) if outputFormat == "n3" : retval = 'Content-Type: text/rdf+n3; charset=utf-8\n' elif outputFormat == "nt" or outputFormat == "turtle" : retval = 'Content-Type: text/turtle; charset=utf-8\n' elif outputFormat == "json-ld" or outputFormat == "json" : retval = 'Content-Type: application/json; charset=utf-8\n' else : retval = 'Content-Type: application/rdf+xml; charset=utf-8\n' retval += '\n' retval += graph return retval except HTTPError : import cgi h = sys.exc_info()[1] retval = 'Content-type: text/html; charset=utf-8\nStatus: %s \n\n' % h.http_code retval += "\n" retval += "\n" retval += "HTTP Error in Microdata processing\n" retval += "\n" retval += "

HTTP Error in distilling Microdata

\n" retval += "

HTTP Error: %s (%s)

\n" % (h.http_code,h.msg) retval += "

On URI: '%s'

\n" % cgi.escape(uri) retval +="\n" retval +="\n" return retval except : # This branch should occur only if an exception is really raised, ie, if it is not turned # into a graph value. (type,value,traceback) = sys.exc_info() import traceback, cgi retval = 'Content-type: text/html; charset=utf-8\nStatus: %s\n\n' % processor.http_status retval += "\n" retval += "\n" retval += "Exception in Microdata processing\n" retval += "\n" retval += "

Exception in distilling Microdata

\n" retval += "
\n"
		strio  = StringIO()
		traceback.print_exc(file=strio)
		retval += strio.getvalue()
		retval +="
\n" retval +="
%s
\n" % value retval +="

Distiller request details

\n" retval +="
\n" if uri == "text:" and "text" in form and form["text"].value != None and len(form["text"].value.strip()) != 0 : retval +="
Text input:
%s
\n" % cgi.escape(form["text"].value).replace('\n','
') elif uri == "uploaded:" : retval +="
Uploaded file
\n" else : retval +="
URI received:
'%s'
\n" % cgi.escape(uri) retval +="
Output serialization format:
%s
\n" % outputFormat retval +="
\n" retval +="\n" retval +="\n" return retval ################################################################################################### rdflib-4.1.2/rdflib/plugins/parsers/pyMicrodata/microdata.py000066400000000000000000000544131232323236500241630ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ The core of the Microdata->RDF conversion, a more or less verbatim implementation of the U{W3C IG Note}. Because the implementation was also used to check the note itself, it tries to be fairly close to the text. @organization: U{World Wide Web Consortium} @author: U{Ivan Herman} @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} """ """ $Id: microdata.py,v 1.4 2012/09/05 16:40:43 ivan Exp $ $Date: 2012/09/05 16:40:43 $ Added a reaction on the RDFaStopParsing exception: if raised while setting up the local execution context, parsing is stopped (on the whole subtree) """ import sys if sys.version_info[0] >= 3 : from urllib.parse import urlsplit, urlunsplit else : from urlparse import urlsplit, urlunsplit from types import * import rdflib from rdflib import URIRef from rdflib import Literal from rdflib import BNode from rdflib import Namespace if rdflib.__version__ >= "3.0.0" : from rdflib import Graph from rdflib import RDF as ns_rdf from rdflib import RDFS as ns_rdfs else : from rdflib.Graph import Graph from rdflib.RDFS import RDFSNS as ns_rdfs from rdflib.RDF import RDFNS as ns_rdf ns_owl = Namespace("http://www.w3.org/2002/07/owl#") from .registry import registry, vocab_names from .utils import generate_RDF_collection, get_Literal, get_time_type from .utils import get_lang_from_hierarchy, is_absolute_URI, generate_URI, fragment_escape MD_VOCAB = "http://www.w3.org/ns/md#" RDFA_VOCAB = URIRef("http://www.w3.org/ns/rdfa#usesVocabulary") from . import debug # Existing predicate schemes class PropertySchemes : vocabulary = "vocabulary" contextual = "contextual" class ValueMethod : unordered = "unordered" list = "list" # ---------------------------------------------------------------------------- class Evaluation_Context : """ Evaluation context structure. See Section 4.1 of the U{W3C IG Note}for the details. @ivar current_type : an absolute URL for the current type, used when an item does not contain an item type @ivar memory: mapping from items to RDF subjects @type memory: dictionary @ivar current_name: an absolute URL for the in-scope name, used for generating URIs for properties of items without an item type @ivar current_vocabulary: an absolute URL for the current vocabulary, from the registry """ def __init__( self ) : self.current_type = None self.memory = {} self.current_name = None self.current_vocabulary = None def get_memory( self, item ) : """ Get the memory content (ie, RDF subject) for 'item', or None if not stored yet @param item: an 'item', in microdata terminology @type item: DOM Element Node @return: None, or an RDF Subject (URIRef or BNode) """ if item in self.memory : return self.memory[item] else : return None def set_memory( self, item, subject ) : """ Set the memory content, ie, the subject, for 'item'. @param item: an 'item', in microdata terminology @type item: DOM Element Node @param subject: RDF Subject @type subject: URIRef or Blank Node """ self.memory[item] = subject def new_copy(self, itype) : """ During the generation algorithm a new copy of the current context has to be done with a new current type. At the moment, the content of memory is copied, ie, a fresh dictionary is created and the content copied over. Not clear whether that is necessary, though, maybe a simple reference is enough... @param itype : an absolute URL for the current type @return: a new evaluation context instance """ retval = Evaluation_Context() for k in self.memory : retval.memory[k] = self.memory[k] retval.current_type = itype retval.current_name = self.current_name retval.current_vocabulary = self.current_vocabulary return retval def __str__(self) : retval = "Evaluation context:\n" retval += " current type: %s\n" % self.current_type retval += " current name: %s\n" % self.current_name retval += " current vocabulary: %s\n" % self.current_vocabulary retval += " memory: %s\n" % self.memory retval += "----\n" return retval class Microdata : """ This class encapsulates methods that are defined by the U{microdata spec}, as opposed to the RDF conversion note. @ivar document: top of the DOM tree, as returned by the HTML5 parser @ivar base: the base URI of the Dom tree, either set from the outside or via a @base element """ def __init__( self, document, base = None) : """ @param document: top of the DOM tree, as returned by the HTML5 parser @param base: the base URI of the Dom tree, either set from the outside or via a @base element """ self.document = document #----------------------------------------------------------------- # set the document base, will be used to generate top level URIs self.base = None # handle the base element case for HTML for set_base in document.getElementsByTagName("base") : if set_base.hasAttribute("href") : # Yep, there is a local setting for base self.base = set_base.getAttribute("href") return # If got here, ie, if no local setting for base occurs, the input argument has it self.base = base def get_top_level_items( self ) : """ A top level item is and element that has the @itemscope set, but no @itemtype. They have to be collected in pre-order and depth-first fashion. @return: list of items (ie, DOM Nodes) """ def collect_items( node ) : items = [] for child in node.childNodes : if child.nodeType == node.ELEMENT_NODE : items += collect_items( child ) if node.hasAttribute("itemscope") and not node.hasAttribute("itemprop") : # This is also a top level item items.append(node) return items return collect_items( self.document ) def get_item_properties( self, item ) : """ Collect the item's properties, ie, all DOM descendent nodes with @itemprop until the subtree hits another @itemscope. @itemrefs are also added at this point. @param item: current item @type item: DOM Node @return: array of items, ie, DOM Nodes """ # go down the tree until another itemprop is hit, take care of the itemrefs, too; see the microdata doc # probably the ugliest stuff # returns a series of element nodes. # Is it worth filtering the ones with itemprop at that level??? results = [] memory = [ item ] pending = [ child for child in item.childNodes if child.nodeType == item.ELEMENT_NODE ] if item.hasAttribute("itemref") : for id in item.getAttribute("itemref").strip().split() : obj = self.getElementById(id) if obj != None : pending.append(obj) while len(pending) > 0 : current = pending.pop(0) if current in memory : # in general this raises an error; the same item cannot be there twice. In this case this is # simply ignored continue else : # this for the check above memory.append(current) # @itemscope is the barrier... if not current.hasAttribute("itemscope") : pending = [ child for child in current.childNodes if child.nodeType == child.ELEMENT_NODE ] + pending if current.hasAttribute("itemprop") and current.getAttribute("itemprop").strip() != "" : results.append(current) return results def getElementById(self, id) : """This is a method defined for DOM 2 HTML, but the HTML5 parser does not seem to define it. Oh well... @param id: value of an @id attribute to look for @return: array of nodes whose @id attribute matches C{id} (formally, there should be only one...) """ def collect_ids( node ) : ids = [] for child in node.childNodes : if child.nodeType == node.ELEMENT_NODE : ids += collect_ids( child ) if node.hasAttribute("id") and node.getAttribute("id") == id : # This is also a top level item ids.append(node) return ids ids = collect_ids(self.document) if len(ids) > 0 : return ids[0] else : return None class MicrodataConversion(Microdata) : """ Top level class encapsulating the conversion algorithms as described in the W3C note. @ivar graph: an RDF graph; an RDFLib Graph @type graph: RDFLib Graph @ivar document: top of the DOM tree, as returned by the HTML5 parser @ivar ns_md: the Namespace for the microdata vocabulary @ivar base: the base of the Dom tree, either set from the outside or via a @base element """ def __init__( self, document, graph, base = None, vocab_expansion = False, vocab_cache = True ) : """ @param graph: an RDF graph; an RDFLib Graph @type graph: RDFLib Graph @param document: top of the DOM tree, as returned by the HTML5 parser @keyword base: the base of the Dom tree, either set from the outside or via a @base element @keyword vocab_expansion: whether vocab expansion should be performed or not @type vocab_expansion: Boolean @keyword vocab_cache: if vocabulary expansion is done, then perform caching of the vocabulary data @type vocab_cache: Boolean """ Microdata.__init__(self, document, base) self.vocab_expansion = vocab_expansion self.vocab_cache = vocab_cache self.graph = graph self.ns_md = Namespace( MD_VOCAB ) self.graph.bind( "md",MD_VOCAB ) self.vocabularies_used = False # Get the vocabularies defined in the registry bound to proper names, if any... def _use_rdfa_context () : try : from ..pyRdfa.initialcontext import initial_context except : from pyRdfa.initialcontext import initial_context retval = {} vocabs = initial_context["http://www.w3.org/2011/rdfa-context/rdfa-1.1"].ns for prefix in list(vocabs.keys()) : uri = vocabs[prefix] if uri not in vocab_names and uri not in registry : retval[uri] = prefix return retval for vocab in registry : if vocab in vocab_names : self.graph.bind( vocab_names[vocab],vocab ) else : hvocab = vocab + '#' if hvocab in vocab_names : self.graph.bind( vocab_names[hvocab],hvocab ) # Add the prefixes defined in the RDFa initial context to improve the outlook of the output # I put this into a try: except: in case the pyRdfa package is not available... try : try : from ..pyRdfa.initialcontext import initial_context except : from pyRdfa.initialcontext import initial_context vocabs = initial_context["http://www.w3.org/2011/rdfa-context/rdfa-1.1"].ns for prefix in list(vocabs.keys()) : uri = vocabs[prefix] if uri not in registry : # if it is in the registry, then it may have needed some special microdata massage... self.graph.bind( prefix,uri ) except : pass def convert( self ) : """ Top level entry to convert and generate all the triples. It finds the top level items, and generates triples for each of them; additionally, it generates a top level entry point to the items from base in the form of an RDF list. """ item_list = [] for top_level_item in self.get_top_level_items() : item_list.append( self.generate_triples(top_level_item, Evaluation_Context()) ) list = generate_RDF_collection( self.graph, item_list ) self.graph.add( (URIRef(self.base),self.ns_md["item"],list) ) # If the vocab expansion is also switched on, this is the time to do it. # This is the version with my current proposal: the basic expansion is always there; # the follow-your-nose inclusion of vocabulary is optional if self.vocabularies_used : try : try : from ..pyRdfa.rdfs.process import MiniOWL, process_rdfa_sem from ..pyRdfa.options import Options except : from pyRdfa.rdfs.process import MiniOWL, process_rdfa_sem from pyRdfa.options import Options # if we did not get here, the pyRdfa package could not be # imported. Too bad, but life should go on in the except branch... if self.vocab_expansion : # This is the full deal options = Options(vocab_expansion = self.vocab_expansion, vocab_cache = self.vocab_cache) process_rdfa_sem(self.graph, options) else : MiniOWL(self.graph).closure() except : pass def generate_triples( self, item, context ) : """ Generate the triples for a specific item. See the W3C Note for the details. @param item: the DOM Node for the specific item @type item: DOM Node @param context: an instance of an evaluation context @type context: L{Evaluation_Context} @return: a URIRef or a BNode for the (RDF) subject """ # Step 1,2: if the subject has to be set, store it in memory subject = context.get_memory( item ) if subject == None : # nop, there is no subject set. If there is a valid @itemid, that carries it if item.hasAttribute("itemid") and is_absolute_URI( item.getAttribute("itemid") ): subject = URIRef( item.getAttribute("itemid").strip() ) else : subject = BNode() context.set_memory( item, subject ) # Step 3: set the type triples if any types = [] if item.hasAttribute("itemtype") : types = item.getAttribute("itemtype").strip().split() for t in types : if is_absolute_URI( t ) : self.graph.add( (subject, ns_rdf["type"], URIRef(t)) ) # Step 4, 5 and 6 to set the typing variable if len(types) == 0 : itype = None else : if is_absolute_URI(types[0]) : itype = types[0] context.current_name = None elif context.current_type != None : itype = context.current_type else : itype = None # Step 7, 8, 9: Check the registry for possible keys and set the vocab vocab = None if itype != None : for key in list(registry.keys()) : if itype.startswith(key) : # There is a predefined vocabulary for this type... vocab = key # Step 7: Issue an rdfa usesVocabulary triple self.graph.add( (URIRef(self.base), RDFA_VOCAB, URIRef(vocab))) self.vocabularies_used = True break # The registry has not set the vocabulary; has to be extracted from the type if vocab == None : parsed = urlsplit(itype) if parsed.fragment != "" : vocab = urlunsplit( (parsed.scheme,parsed.netloc,parsed.path,parsed.query,"") ) + '#' elif parsed.path == "" and parsed.query == "" : vocab = itype if vocab[-1] != '/' : vocab += '/' else : vocab = itype.rsplit('/',1)[0] + '/' # Step 9: update vocab in the context if vocab != None : context.current_vocabulary = vocab elif item.hasAttribute("itemtype") : context.current_vocabulary = None # Step 10: set up a property list; this will be used to generate triples later. # each entry in the dictionary is an array of RDF objects property_list = {} # Step 11: Get the item properties and run a cycle on those for prop in self.get_item_properties(item) : for name in prop.getAttribute("itemprop").strip().split() : # 11.1.1. set a new context new_context = context.new_copy(itype) # 11.1.2, generate the URI for the property name, that will be the predicate # Also update the context new_context.current_name = predicate = self.generate_predicate_URI( name,new_context ) # 11.1.3, generate the property value. The extra flag signals that the value is a new item # Note that 10.1.4 step is done in the method itself, ie, a recursion may occur there # if a new item is hit (in which case the return value is a RDF resource chaining to a subject) value = self.get_property_value( prop, new_context ) # 11.1.5, store all the values if predicate in property_list : property_list[predicate].append(value) else : property_list[predicate] = [ value ] # step 12: generate the triples for property in list(property_list.keys()) : self.generate_property_values( subject, URIRef(property), property_list[property], context ) # Step 13: return the subject to the caller return subject def generate_predicate_URI( self, name, context ) : """ Generate a full URI for a predicate, using the type, the vocabulary, etc. For details of this entry, see Section 4.4 @param name: name of the property, ie, what appears in @itemprop @param context: an instance of an evaluation context @type context: L{Evaluation_Context} """ if debug: print( "name: %s, %s" % (name,context) ) # Step 1: absolute URI-s are fine, take them as they are if is_absolute_URI(name) : return name # Step 2: if type is none, that this is just used as a fragment # if not context.current_type : if context.current_type == None and context.current_vocabulary == None : if self.base[-1] == '#' : b = self.base[:-1] else : b = self.base return b + '#' + fragment_escape(name) #if context.current_type == None : # return generate_URI( self.base, name ) # Step 3: set the scheme try : if context.current_vocabulary in registry and "propertyURI" in registry[context.current_vocabulary] : scheme = registry[context.current_vocabulary]["propertyURI"] else : scheme = PropertySchemes.vocabulary except : # This is when the structure of the registry is broken scheme = PropertySchemes.vocabulary name = fragment_escape( name ) if scheme == PropertySchemes.contextual : # Step 5.1 s = context.current_name # s = context.current_type if s != None and s.startswith("http://www.w3.org/ns/md?type=") : # Step 5.2 expandedURI = s + '.' + name else : # Step 5.3 expandedURI = "http://www.w3.org/ns/md?type=" + fragment_escape(context.current_type) + "&prop=" + name else : # Step 4 if context.current_vocabulary[-1] == '#' or context.current_vocabulary[-1] == '/' : expandedURI = context.current_vocabulary + name else : expandedURI = context.current_vocabulary + '#' + name # see if there are subproperty/equivalentproperty relations try : vocab_mapping = registry[context.current_vocabulary]["properties"][name] # if we got that far, we may have some mappings expandedURIRef = URIRef(expandedURI) try : subpr = vocab_mapping["subPropertyOf"] if subpr != None : if isinstance(subpr,list) : for p in subpr : self.graph.add( (expandedURIRef, ns_rdfs["subPropertyOf"], URIRef(p)) ) else : self.graph.add( (expandedURIRef, ns_rdfs["subPropertyOf"], URIRef(subpr)) ) except : # Ok, no sub property pass try : subpr = vocab_mapping["equivalentProperty"] if subpr != None : if isinstance(subpr,list) : for p in subpr : self.graph.add( (expandedURIRef, ns_owl["equivalentProperty"], URIRef(p)) ) else : self.graph.add( (expandedURIRef, ns_owl["equivalentProperty"], URIRef(subpr)) ) except : # Ok, no sub property pass except : # no harm done, no extra vocabulary term pass return expandedURI def get_property_value(self, node, context) : """ Generate an RDF object, ie, the value of a property. Note that if this element contains an @itemscope, then a recursive call to L{MicrodataConversion.generate_triples} is done and the return value of that method (ie, the subject for the corresponding item) is return as an object. Otherwise, either URIRefs are created for , , etc, elements, or a Literal; the latter gets a time-related type for the } @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} """ """ $Id: registry.py,v 1.5 2012/09/05 16:40:43 ivan Exp $ $Date: 2012/09/05 16:40:43 $ """ import sys (py_v_major, py_v_minor, py_v_micro, py_v_final, py_v_serial) = sys.version_info # To be added soon: # "Class" : {"subPropertyOf" : "http://www.w3.org/2000/01/rdf-schema#Class"}, # "Property" : {"subPropertyOf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"} _registry = """ { "http://schema.org/": { "propertyURI": "vocabulary", "multipleValues": "unordered", "properties": { "additionalType": {"subPropertyOf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}, "blogPosts": {"multipleValues": "list"}, "breadcrumb": {"multipleValues": "list"}, "byArtist": {"multipleValues": "list"}, "creator": {"multipleValues": "list"}, "episode": {"multipleValues": "list"}, "episodes": {"multipleValues": "list"}, "event": {"multipleValues": "list"}, "events": {"multipleValues": "list"}, "founder": {"multipleValues": "list"}, "founders": {"multipleValues": "list"}, "itemListElement": {"multipleValues": "list"}, "musicGroupMember": {"multipleValues": "list"}, "performerIn": {"multipleValues": "list"}, "actor": {"multipleValues": "list"}, "actors": {"multipleValues": "list"}, "performer": {"multipleValues": "list"}, "performers": {"multipleValues": "list"}, "producer": {"multipleValues": "list"}, "recipeInstructions": {"multipleValues": "list"}, "season": {"multipleValues": "list"}, "seasons": {"multipleValues": "list"}, "subEvent": {"multipleValues": "list"}, "subEvents": {"multipleValues": "list"}, "track": {"multipleValues": "list"}, "tracks": {"multipleValues": "list"} } }, "http://microformats.org/profile/hcard": { "propertyURI": "vocabulary", "multipleValues": "unordered" }, "http://microformats.org/profile/hcalendar#": { "propertyURI": "vocabulary", "multipleValues": "unordered", "properties": { "categories": {"multipleValues": "list"} } } } """ vocab_names = { "http://schema.org/" : "schema", "http://xmlns.com/foaf/0.1/" : "foaf", "http://microformats.org/profile/hcard#" : "hcard", "http://microformats.org/profile/hcalendar#" : "hcalendar" } # This is the local version, added mainly for testing _myRegistry = """ { "http://vocabulary.list/": { "propertyURI": "vocabulary", "multipleValues": "list", "properties": { "list": {"multipleValues": "list"}, "typed": {"datatype": "http://typed"} } }, "http://vocabulary.unordered/": { "propertyURI": "vocabulary", "multipleValues": "unordered", "properties": { "list": {"multipleValues": "list"}, "typed": {"datatype": "http://typed"} } }, "http://contextual.unordered/": { "propertyURI": "contextual", "multipleValues": "unordered", "properties": { "list": {"multipleValues": "list"}, "typed": {"datatype": "http://typed"} } }, "http://contextual.list/": { "propertyURI": "contextual", "multipleValues": "list", "properties": { "list": {"multipleValues": "list"}, "typed": {"datatype": "http://typed"} } }, "http://n.whatwg.org/work": { "propertyURI" : "contextual", "multipleValues" : "list" } } """ registry = [] myRegistry = [] if py_v_major >= 3 or (py_v_major == 2 and py_v_minor >= 6) : import json registry = json.loads(_registry) myRegistry = json.loads(_myRegistry) else : import simplejson registry = simplejson.loads(_registry) myRegistry = simplejson.loads(_myRegistry) for (k,v) in list(myRegistry.items()) : registry[k] = v rdflib-4.1.2/rdflib/plugins/parsers/pyMicrodata/utils.py000066400000000000000000000232211232323236500233510ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Various utilities for pyMicrodata @organization: U{World Wide Web Consortium} @author: U{Ivan Herman} @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} """ """ $Id: utils.py,v 1.7 2012/09/01 15:17:28 ivan Exp $ $Date: 2012/09/01 15:17:28 $ """ import os, os.path, sys (py_v_major, py_v_minor, py_v_micro, py_v_final, py_v_serial) = sys.version_info if py_v_major >= 3 : from urllib.request import Request, urlopen from urllib.parse import urljoin, quote, urlparse from http.server import BaseHTTPRequestHandler from urllib.error import HTTPError as urllib_HTTPError else : from urllib2 import Request, urlopen from urllib2 import HTTPError as urllib_HTTPError from urlparse import urljoin, urlparse from urllib import quote from BaseHTTPServer import BaseHTTPRequestHandler import re from datetime import datetime from rdflib import BNode import rdflib if rdflib.__version__ >= "3.0.0" : from rdflib import RDF as ns_rdf else : from rdflib.RDF import RDFNS as ns_rdf ################################################################################# def is_absolute_URI( uri ) : return urlparse(uri)[0] != "" ################################################################################# def fragment_escape( name ) : return quote(name, '/~:-.') ################################################################################# def generate_URI(base, v) : """ Generate an (absolute) URI; if val is a fragment, then using it with base, otherwise just return the value @param base: Absolute URI for base @param v: relative or absolute URI """ if is_absolute_URI( v ) : return v else : # UGLY!!! There is a bug for a corner case in python version <= 2.5.X if len(v) > 0 and v[0] == '?' and (py_v_major < 3 and py_v_minor <= 5) : return base+val #### # Trust the python library... # Well, not quite:-) there is what is, in my view, a bug in the urljoin; in some cases it # swallows the '#' or '?' character at the end. This is clearly a problem with # Semantic Web URI-s v = fragment_escape(v.strip()) joined = urljoin(base, v) try : if v[-1] != joined[-1] and (v[-1] == "#" or v[-1] == "?") : return joined + v[-1] else : return joined except : return joined ################################################################################# def generate_RDF_collection( graph, vals ) : """ Generate an RDF List from vals, returns the head of the list @param graph: RDF graph @type graph: RDFLib Graph @param vals: array of RDF Resources @return: head of the List (an RDF Resource) """ # generate an RDF List, returns the head # list has all the elements in RDF format already heads = [ BNode() for r in vals ] + [ ns_rdf["nil"] ] for i in range(0, len(vals)) : graph.add( (heads[i], ns_rdf["first"], vals[i]) ) graph.add( (heads[i], ns_rdf["rest"], heads[i+1]) ) return heads[0] ################################################################################# def get_Literal(Pnode): """ Get (recursively) the full text from a DOM Node. @param Pnode: DOM Node @return: string """ rc = "" for node in Pnode.childNodes: if node.nodeType == node.TEXT_NODE: rc = rc + node.data elif node.nodeType == node.ELEMENT_NODE : rc = rc + get_Literal(node) # This presupposes that all spaces and such should be stripped. I am not sure it is true in the spec, # but this is what the examples show # return re.sub(r'(\r| |\n|\t)+'," ",rc).strip() # at present, the agreement seems to say that white spaces are maintained: return rc ################################################################################# def get_lang(node) : # we may have lang and xml:lang retval = None if node.hasAttribute("lang") : retval = node.getAttribute("lang") if retval and node.hasAttribute("xml:lang") : xmllang = node.getAttribute("xml:lang").lower() if not( xmllang != None and xmllang == retval.lower() ) : # This is an error, in which case retval must be invalidated... retval = None return retval def get_lang_from_hierarchy(document, node) : lang = get_lang(node) if lang == None : parent = node.parentNode if parent != None and parent != document : return get_lang_from_hierarchy(document, parent) else : return get_lang(document) else : return lang ################################################################################# datetime_type = "http://www.w3.org/2001/XMLSchema#dateTime" time_type = "http://www.w3.org/2001/XMLSchema#time" date_type = "http://www.w3.org/2001/XMLSchema#date" date_gYear = "http://www.w3.org/2001/XMLSchema#gYear" date_gYearMonth = "http://www.w3.org/2001/XMLSchema#gYearMonth" date_gMonthDay = "http://www.w3.org/2001/XMLSchema#gMonthDay" duration_type = "http://www.w3.org/2001/XMLSchema#duration" _formats = { date_gMonthDay : [ "%m-%d" ], date_gYearMonth : [ "%Y-%m"], date_gYear : [ "%Y" ], date_type : [ "%Y-%m-%d", "%Y-%m-%dZ" ], time_type : [ "%H:%M", "%H:%M:%S", "%H:%M:%SZ", "%H:%M:%S.%f" ], datetime_type : [ "%Y-%m-%dT%H:%M", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%MZ", "%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S.%fZ" ], duration_type : [ "P%dD", "P%YY%mM%dD", "P%YY%mM", "P%YY%dD", "P%YY", "P%mM", "P%mM%dD", ], } _dur_times = [ "%HH%MM%SS", "%HH", "%MM", "%SS", "%HH%MM", "%HH%SS", "%MM%SS" ] def get_time_type(string) : """ Check whether the string abides to one of the accepted time related datatypes, and returns that one if yes @param string: the attribute value to be checked @return : a datatype URI or None """ for key in _formats : for format in _formats[key] : try : # try to check if the syntax is fine d = datetime.strptime(string, format) # bingo! return key except ValueError : pass # Now come the special cases:-( # Check first for the duration stuff, that is the nastiest. if len(string) > 2 and string[0] == 'P' or (string [0] == '-' and string[1] == 'P') : # this is meant to be a duration type # first of all, get rid of the leading '-' and check again if string[0] == '-' : for format in _formats[duration_type] : try : # try to check if the syntax is fine d = datetime.strptime(string, format) # bingo! return duration_type except ValueError : pass # Let us see if the value contains a separate time portion, and cut that one durs = string.split('T') if len(durs) == 2 : # yep, so we should check again dur = durs[0] tm = durs[1] # Check the duration part td = False for format in _formats[duration_type] : try : # try to check if the syntax is fine d = datetime.strptime(dur, format) # bingo! td = True break except ValueError : pass if td == True : # Getting there... for format in _dur_times : try : # try to check if the syntax is fine d = datetime.strptime(tm, format) # bingo! return duration_type except ValueError : pass # something went wrong... return None else : # Well, no more tricks, this is a plain type return None # If we got here, we should check the time zone # there is a discrepancy betwen the python and the HTML5/XSD lexical string, # which means that this has to handled separately for the date and the timezone portion try : # The time-zone-less portion of the string str = string[0:-6] # The time-zone portion tz = string[-5:] try : t = datetime.strptime(tz,"%H:%M") except ValueError : # Bummer, this is not a correct time return None # The time-zone is fine, the datetime portion has to be checked for format in _formats[datetime_type] : try : # try to check if it is fine d = datetime.strptime(str, format) # Bingo! return datetime_type except ValueError : pass except : pass return None ######################################################################################################### # Handling URIs class URIOpener : """A wrapper around the urllib2 method to open a resource. Beyond accessing the data itself, the class sets the content location. The class also adds an accept header to the outgoing request, namely text/html and application/xhtml+xml (unless set explicitly by the caller). @ivar data: the real data, ie, a file-like object @ivar headers: the return headers as sent back by the server @ivar location: the real location of the data (ie, after possible redirection and content negotiation) """ CONTENT_LOCATION = 'Content-Location' def __init__(self, name) : """ @param name: URL to be opened @keyword additional_headers: additional HTTP request headers to be added to the call """ try : # Note the removal of the fragment ID. This is necessary, per the HTTP spec req = Request(url=name.split('#')[0]) req.add_header('Accept', 'text/html, application/xhtml+xml') self.data = urlopen(req) self.headers = self.data.info() if URIOpener.CONTENT_LOCATION in self.headers : self.location = urlparse.urljoin(self.data.geturl(),self.headers[URIOpener.CONTENT_LOCATION]) else : self.location = name except urllib_HTTPError : e = sys.exc_info()[1] from pyMicrodata import HTTPError msg = BaseHTTPRequestHandler.responses[e.code] raise HTTPError('%s' % msg[1], e.code) except Exception : e = sys.exc_info()[1] from pyMicrodata import MicrodataError raise MicrodataError('%s' % e) rdflib-4.1.2/rdflib/plugins/parsers/pyRdfa/000077500000000000000000000000001232323236500206105ustar00rootroot00000000000000rdflib-4.1.2/rdflib/plugins/parsers/pyRdfa/__init__.py000066400000000000000000001340011232323236500227200ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ RDFa 1.1 parser, also referred to as a “RDFa Distiller”. It is deployed, via a CGI front-end, on the U{W3C RDFa 1.1 Distiller page}. For details on RDFa, the reader should consult the U{RDFa Core 1.1}, U{XHTML+RDFa1.1}, and the U{RDFa 1.1 Lite} documents. The U{RDFa 1.1 Primer} may also prove helpful. This package can also be downloaded U{from GitHub}. The distribution also includes the CGI front-end and a separate utility script to be run locally. Note that this package is an updated version of a U{previous RDFa distiller} that was developed for RDFa 1.0. Although it reuses large portions of that code, it has been quite thoroughly rewritten, hence put in a completely different project. (The version numbering has been continued, though, to avoid any kind of misunderstandings. This version has version numbers "3.0.0" or higher.) (Simple) Usage ============== From a Python file, expecting a Turtle output:: from pyRdfa import pyRdfa print pyRdfa().rdf_from_source('filename') Other output formats are also possible. E.g., to produce RDF/XML output, one could use:: from pyRdfa import pyRdfa print pyRdfa().rdf_from_source('filename', outputFormat='pretty-xml') It is also possible to embed an RDFa processing. Eg, using:: from pyRdfa import pyRdfa graph = pyRdfa().graph_from_source('filename') returns an RDFLib.Graph object instead of a serialization thereof. See the the description of the L{pyRdfa class} for further possible entry points details. There is also, as part of this module, a L{separate entry for CGI calls}. Return (serialization) formats ------------------------------ The package relies on RDFLib. By default, it relies therefore on the serializers coming with the local RDFLib distribution. However, there has been some issues with serializers of older RDFLib releases; also, some output formats, like JSON-LD, are not (yet) part of the standard RDFLib distribution. A companion package, called pyRdfaExtras, is part of the download, and it includes some of those extra serializers. The extra format (not part of the RDFLib core) is U{JSON-LD}, whose 'key' is 'json', when used in the 'parse' method of an RDFLib graph. Options ======= The package also implements some optional features that are not part of the RDFa recommendations. At the moment these are: - possibility for plain literals to be normalized in terms of white spaces. Default: false. (The RDFa specification requires keeping the white spaces and leave applications to normalize them, if needed) - inclusion of embedded RDF: Turtle content may be enclosed in a C{script} element and typed as C{text/turtle}, U{defined by the RDF Working Group}. Alternatively, some XML dialects (e.g., SVG) allows the usage of RDF/XML as part of their core content to define metadata in RDF. For both of these cases pyRdfa parses these serialized RDF content and adds the resulting triples to the output Graph. Default: true. - extra, built-in transformers are executed on the DOM tree prior to RDFa processing (see below). These transformers can be provided by the end user. Options are collected in an instance of the L{Options} class and may be passed to the processing functions as an extra argument. E.g., to allow the inclusion of embedded content:: from pyRdfa.options import Options options = Options(embedded_rdf=True) print pyRdfa(options=options).rdf_from_source('filename') See the description of the L{Options} class for the details. Host Languages ============== RDFa 1.1. Core is defined for generic XML; there are specific documents to describe how the generic specification is applied to XHTML and HTML5. pyRdfa makes an automatic switch among these based on the content type of the source as returned by an HTTP request. The following are the possible host languages: - if the content type is C{text/html}, the content is HTML5 - if the content type is C{application/xhtml+xml} I{and} the right DTD is used, the content is XHTML1 - if the content type is C{application/xhtml+xml} and no or an unknown DTD is used, the content is XHTML5 - if the content type is C{application/svg+xml}, the content type is SVG - if the content type is C{application/atom+xml}, the content type is SVG - if the content type is C{application/xml} or C{application/xxx+xml} (but 'xxx' is not 'atom' or 'svg'), the content type is XML If local files are used, pyRdfa makes a guess on the content type based on the file name suffix: C{.html} is for HTML5, C{.xhtml} for XHTML1, C{.svg} for SVG, anything else is considered to be general XML. Finally, the content type may be set by the caller when initializing the L{pyRdfa class}. Beyond the differences described in the RDFa specification, the main difference is the parser used to parse the source. In the case of HTML5, pyRdfa uses an U{HTML5 parser}; for all other cases the simple XML parser, part of the core Python environment, is used. This may be significant in the case of erronuous sources: indeed, the HTML5 parser may do adjustments on the DOM tree before handing it over to the distiller. Furthermore, SVG is also recognized as a type that allows embedded RDF in the form of RDF/XML. See the variables in the L{host} module if a new host language is added to the system. The current host language information is available for transformers via the option argument, too, and can be used to control the effect of the transformer. Vocabularies ============ RDFa 1.1 has the notion of vocabulary files (using the C{@vocab} attribute) that may be used to expand the generated RDF graph. Expansion is based on some very simply RDF Schema and OWL statements on sub-properties and sub-classes, and equivalences. pyRdfa implements this feature, although it does not do this by default. The extra C{vocab_expansion} parameter should be used for this extra step, for example:: from pyRdfa.options import Options options = Options(vocab_expansion=True) print pyRdfa(options=options).rdf_from_source('filename') The triples in the vocabulary files themselves (i.e., the small ontology in RDF Schema and OWL) are removed from the result, leaving the inferred property and type relationships only (additionally to the “core” RDF content). Vocabulary caching ------------------ By default, pyRdfa uses a caching mechanism instead of fetching the vocabulary files each time their URI is met as a C{@vocab} attribute value. (This behavior can be switched off setting the C{vocab_cache} option to false.) Caching happens in a file system directory. The directory itself is determined by the platform the tool is used on, namely: - On Windows, it is the C{pyRdfa-cache} subdirectory of the C{%APPDATA%} environment variable - On MacOS, it is the C{~/Library/Application Support/pyRdfa-cache} - Otherwise, it is the C{~/.pyRdfa-cache} This automatic choice can be overridden by the C{PyRdfaCacheDir} environment variable. Caching can be set to be read-only, i.e., the setup might generate the cache files off-line instead of letting the tool writing its own cache when operating, e.g., as a service on the Web. This can be achieved by making the cache directory read only. If the directories are neither readable nor writable, the vocabulary files are retrieved via HTTP every time they are hit. This may slow down processing, it is advised to avoid such a setup for the package. The cache includes a separate index file and a file for each vocabulary file. Cache control is based upon the C{EXPIRES} header of a vocabulary file’s HTTP return header: when first seen, this data is stored in the index file and controls whether the cache has to be renewed or not. If the HTTP return header does not have this entry, the date is artificially set ot the current date plus one day. (The cache files themselves are dumped and loaded using U{Python’s built in cPickle package}. These are binary files. Care should be taken if they are managed by CVS: they must be declared as binary files when adding them to the repository.) RDFa 1.1 vs. RDFa 1.0 ===================== Unfortunately, RDFa 1.1 is I{not} fully backward compatible with RDFa 1.0, meaning that, in a few cases, the triples generated from an RDFa 1.1 source are not the same as for RDFa 1.0. (See the separate U{section in the RDFa 1.1 specification} for some further details.) This distiller’s default behavior is RDFa 1.1. However, if the source includes, in the top element of the file (e.g., the C{html} element) a C{@version} attribute whose value contains the C{RDFa 1.0} string, then the distiller switches to a RDFa 1.0 mode. (Although the C{@version} attribute is not required in RDFa 1.0, it is fairly commonly used.) Similarly, if the RDFa 1.0 DTD is used in the XHTML source, it will be taken into account (a very frequent setup is that an XHTML file is defined with that DTD and is served as text/html; pyRdfa will consider that file as XHTML5, i.e., parse it with the HTML5 parser, but interpret the RDFa attributes under the RDFa 1.0 rules). Transformers ============ The package uses the concept of 'transformers': the parsed DOM tree is possibly transformed I{before} performing the real RDFa processing. This transformer structure makes it possible to add additional 'services' without distoring the core code of RDFa processing. A transformer is a function with three arguments: - C{node}: a DOM node for the top level element of the DOM tree - C{options}: the current L{Options} instance - C{state}: the current L{ExecutionContext} instance, corresponding to the top level DOM Tree element The function may perform any type of change on the DOM tree; the typical behaviour is to add or remove attributes on specific elements. Some transformations are included in the package and can be used as examples; see the L{transform} module of the distribution. These are: - The C{@name} attribute of the C{meta} element is copied into a C{@property} attribute of the same element - Interpreting the 'openid' references in the header. See L{transform.OpenID} for further details. - Implementing the Dublin Core dialect to include DC statements from the header. See L{transform.DublinCore} for further details. The user of the package may refer add these transformers to L{Options} instance. Here is a possible usage with the “openid” transformer added to the call:: from pyRdfa.options import Options from pyRdfa.transform.OpenID import OpenID_transform options = Options(transformers=[OpenID_transform]) print pyRdfa(options=options).rdf_from_source('filename') @summary: RDFa parser (distiller) @requires: Python version 2.5 or up; 2.7 is preferred @requires: U{RDFLib}; version 3.X is preferred. @requires: U{html5lib} for the HTML5 parsing. @requires: U{httpheader}; however, a small modification had to make on the original file, so for this reason and to make distribution easier this module (single file) is added to the package. @organization: U{World Wide Web Consortium} @author: U{Ivan Herman} @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} @copyright: W3C @var builtInTransformers: List of built-in transformers that are to be run regardless, because they are part of the RDFa spec @var CACHE_DIR_VAR: Environment variable used to define cache directories for RDFa vocabularies in case the default setting does not work or is not appropriate. @var rdfa_current_version: Current "official" version of RDFa that this package implements by default. This can be changed at the invocation of the package @var uri_schemes: List of registered (or widely used) URI schemes; used for warnings... """ """ $Id: __init__.py,v 1.91 2013-10-16 11:48:54 ivan Exp $ """ __version__ = "3.4.3" __author__ = 'Ivan Herman' __contact__ = 'Ivan Herman, ivan@w3.org' __license__ = 'W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231' import sys PY3 = (sys.version_info[0] >= 3) if PY3 : from io import StringIO else : from StringIO import StringIO import os import xml.dom.minidom if PY3 : from urllib.parse import urlparse else : from urlparse import urlparse import rdflib from rdflib import URIRef from rdflib import Literal from rdflib import BNode from rdflib import Namespace if rdflib.__version__ >= "3.0.0" : from rdflib import RDF as ns_rdf from rdflib import RDFS as ns_rdfs from rdflib import Graph else : from rdflib.RDFS import RDFSNS as ns_rdfs from rdflib.RDF import RDFNS as ns_rdf from rdflib.Graph import Graph # Namespace, in the RDFLib sense, for the rdfa vocabulary ns_rdfa = Namespace("http://www.w3.org/ns/rdfa#") from .extras.httpheader import acceptable_content_type, content_type from .transform.prototype import handle_prototypes # Vocabulary terms for vocab reporting RDFA_VOCAB = ns_rdfa["usesVocabulary"] # Namespace, in the RDFLib sense, for the XSD Datatypes ns_xsd = Namespace('http://www.w3.org/2001/XMLSchema#') # Namespace, in the RDFLib sense, for the distiller vocabulary, used as part of the processor graph ns_distill = Namespace("http://www.w3.org/2007/08/pyRdfa/vocab#") debug = False ######################################################################################################### # Exception/error handling. Essentially, all the different exceptions are re-packaged into # separate exception class, to allow for an easier management on the user level class RDFaError(Exception) : """Superclass exceptions representing error conditions defined by the RDFa 1.1 specification. It does not add any new functionality to the Exception class.""" def __init__(self, msg) : self.msg = msg Exception.__init__(self) class FailedSource(RDFaError) : """Raised when the original source cannot be accessed. It does not add any new functionality to the Exception class.""" def __init__(self, msg, http_code = None) : self.msg = msg self.http_code = http_code RDFaError.__init__(self, msg) class HTTPError(RDFaError) : """Raised when HTTP problems are detected. It does not add any new functionality to the Exception class.""" def __init__(self, http_msg, http_code) : self.msg = http_msg self.http_code = http_code RDFaError.__init__(self,http_msg) class ProcessingError(RDFaError) : """Error found during processing. It does not add any new functionality to the Exception class.""" pass class pyRdfaError(Exception) : """Superclass exceptions representing error conditions outside the RDFa 1.1 specification.""" pass # Error and Warning RDFS classes RDFA_Error = ns_rdfa["Error"] RDFA_Warning = ns_rdfa["Warning"] RDFA_Info = ns_rdfa["Information"] NonConformantMarkup = ns_rdfa["DocumentError"] UnresolvablePrefix = ns_rdfa["UnresolvedCURIE"] UnresolvableReference = ns_rdfa["UnresolvedCURIE"] UnresolvableTerm = ns_rdfa["UnresolvedTerm"] VocabReferenceError = ns_rdfa["VocabReferenceError"] PrefixRedefinitionWarning = ns_rdfa["PrefixRedefinition"] FileReferenceError = ns_distill["FileReferenceError"] HTError = ns_distill["HTTPError"] IncorrectPrefixDefinition = ns_distill["IncorrectPrefixDefinition"] IncorrectBlankNodeUsage = ns_distill["IncorrectBlankNodeUsage"] IncorrectLiteral = ns_distill["IncorrectLiteral"] # Error message texts err_no_blank_node = "Blank node in %s position is not allowed; ignored" err_redefining_URI_as_prefix = "'%s' a registered or an otherwise used URI scheme, but is defined as a prefix here; is this a mistake? (see, eg, http://en.wikipedia.org/wiki/URI_scheme or http://www.iana.org/assignments/uri-schemes.html for further information for most of the URI schemes)" err_xmlns_deprecated = "The usage of 'xmlns' for prefix definition is deprecated; please use the 'prefix' attribute instead (definition for '%s')" err_bnode_local_prefix = "The '_' local CURIE prefix is reserved for blank nodes, and cannot be defined as a prefix" err_col_local_prefix = "The character ':' is not valid in a CURIE Prefix, and cannot be used in a prefix definition (definition for '%s')" err_missing_URI_prefix = "Missing URI in prefix declaration for '%s' (in '%s')" err_invalid_prefix = "Invalid prefix declaration '%s' (in '%s')" err_no_default_prefix = "Default prefix cannot be changed (in '%s')" err_prefix_and_xmlns = "@prefix setting for '%s' overrides the 'xmlns:%s' setting; may be a source of problem if same file is run through RDFa 1.0" err_non_ncname_prefix = "Non NCNAME '%s' in prefix definition (in '%s'); ignored" err_absolute_reference = "CURIE Reference part contains an authority part: %s (in '%s'); ignored" err_query_reference = "CURIE Reference query part contains an unauthorized character: %s (in '%s'); ignored" err_fragment_reference = "CURIE Reference fragment part contains an unauthorized character: %s (in '%s'); ignored" err_lang = "There is a problem with language setting; either both xml:lang and lang used on an element with different values, or, for (X)HTML5, only xml:lang is used." err_URI_scheme = "Unusual URI scheme used in <%s>; may that be a mistake, e.g., resulting from using an undefined CURIE prefix or an incorrect CURIE?" err_illegal_safe_CURIE = "Illegal safe CURIE: %s; ignored" err_no_CURIE_in_safe_CURIE = "Safe CURIE is used, but the value does not correspond to a defined CURIE: [%s]; ignored" err_undefined_terms = "'%s' is used as a term, but has not been defined as such; ignored" err_non_legal_CURIE_ref = "Relative URI is not allowed in this position (or not a legal CURIE reference) '%s'; ignored" err_undefined_CURIE = "Undefined CURIE: '%s'; ignored" err_prefix_redefinition = "Prefix '%s' (defined in the initial RDFa context or in an ancestor) is redefined" err_unusual_char_in_URI = "Unusual character in uri: %s; possible error?" ############################################################################################# from .state import ExecutionContext from .parse import parse_one_node from .options import Options from .transform import top_about, empty_safe_curie, vocab_for_role from .utils import URIOpener from .host import HostLanguage, MediaTypes, preferred_suffixes, content_to_host_language # Environment variable used to characterize cache directories for RDFa vocabulary files. CACHE_DIR_VAR = "PyRdfaCacheDir" # current "official" version of RDFa that this package implements. This can be changed at the invocation of the package rdfa_current_version = "1.1" # I removed schemes that would not appear as a prefix anyway, like iris.beep # http://en.wikipedia.org/wiki/URI_scheme seems to be a good source of information # as well as http://www.iana.org/assignments/uri-schemes.html # There are some overlaps here, but better more than not enough... # This comes from wikipedia registered_iana_schemes = [ "aaa","aaas","acap","cap","cid","crid","data","dav","dict","dns","fax","file", "ftp","geo","go", "gopher","h323","http","https","iax","icap","im","imap","info","ipp","iris","ldap", "lsid", "mailto","mid","modem","msrp","msrps", "mtqp", "mupdate","news","nfs","nntp","opaquelocktoken", "pop","pres", "prospero","rstp","rsync", "service","shttp","sieve","sip","sips", "sms", "snmp", "soap", "tag", "tel","telnet", "tftp", "thismessage","tn3270","tip","tv","urn","vemmi","wais","ws", "wss", "xmpp" ] # This comes from wikipedia, too unofficial_common = [ "about", "adiumxtra", "aim", "apt", "afp", "aw", "bitcoin", "bolo", "callto", "chrome", "coap", "content", "cvs", "doi", "ed2k", "facetime", "feed", "finger", "fish", "git", "gg", "gizmoproject", "gtalk", "irc", "ircs", "irc6", "itms", "jar", "javascript", "keyparc", "lastfm", "ldaps", "magnet", "maps", "market", "message", "mms", "msnim", "mumble", "mvn", "notes", "palm", "paparazzi", "psync", "rmi", "secondlife", "sgn", "skype", "spotify", "ssh", "sftp", "smb", "soldat", "steam", "svn", "teamspeak", "things", "udb", "unreal", "ut2004", "ventrillo", "view-source", "webcal", "wtai", "wyciwyg", "xfire", "xri", "ymsgr" ] # These come from the IANA page historical_iana_schemes = [ "fax", "mailserver", "modem", "pack", "prospero", "snews", "videotex", "wais" ] provisional_iana_schemes = [ "afs", "dtn", "dvb", "icon", "ipn", "jms", "oid", "rsync", "ni" ] other_used_schemes = [ "hdl", "isbn", "issn", "mstp", "rtmp", "rtspu", "stp" ] uri_schemes = registered_iana_schemes + unofficial_common + historical_iana_schemes + provisional_iana_schemes + other_used_schemes # List of built-in transformers that are to be run regardless, because they are part of the RDFa spec builtInTransformers = [ empty_safe_curie, top_about, vocab_for_role ] ######################################################################################################### class pyRdfa : """Main processing class for the distiller @ivar options: an instance of the L{Options} class @ivar media_type: the preferred default media type, possibly set at initialization @ivar base: the base value, possibly set at initialization @ivar http_status: HTTP Status, to be returned when the package is used via a CGI entry. Initially set to 200, may be modified by exception handlers """ def __init__(self, options = None, base = "", media_type = "", rdfa_version = None) : """ @keyword options: Options for the distiller @type options: L{Options} @keyword base: URI for the default "base" value (usually the URI of the file to be processed) @keyword media_type: explicit setting of the preferred media type (a.k.a. content type) of the the RDFa source @keyword rdfa_version: the RDFa version that should be used. If not set, the value of the global L{rdfa_current_version} variable is used """ self.http_status = 200 self.base = base if base == "" : self.required_base = None else : self.required_base = base self.charset = None # predefined content type self.media_type = media_type if options == None : self.options = Options() else : self.options = options if media_type != "" : self.options.set_host_language(self.media_type) if rdfa_version is not None : self.rdfa_version = rdfa_version else : self.rdfa_version = None def _get_input(self, name) : """ Trying to guess whether "name" is a URI or a string (for a file); it then tries to open this source accordingly, returning a file-like object. If name is none of these, it returns the input argument (that should be, supposedly, a file-like object already). If the media type has not been set explicitly at initialization of this instance, the method also sets the media_type based on the HTTP GET response or the suffix of the file. See L{host.preferred_suffixes} for the suffix to media type mapping. @param name: identifier of the input source @type name: string or a file-like object @return: a file like object if opening "name" is possible and successful, "name" otherwise """ try : # Python 2 branch isstring = isinstance(name, basestring) except : # Python 3 branch isstring = isinstance(name, str) try : if isstring : # check if this is a URI, ie, if there is a valid 'scheme' part # otherwise it is considered to be a simple file if urlparse(name)[0] != "" : url_request = URIOpener(name) self.base = url_request.location if self.media_type == "" : if url_request.content_type in content_to_host_language : self.media_type = url_request.content_type else : self.media_type = MediaTypes.xml self.options.set_host_language(self.media_type) self.charset = url_request.charset if self.required_base == None : self.required_base = name return url_request.data else : # Creating a File URI for this thing if self.required_base == None : self.required_base = "file://" + os.path.join(os.getcwd(),name) if self.media_type == "" : self.media_type = MediaTypes.xml # see if the default should be overwritten for suffix in preferred_suffixes : if name.endswith(suffix) : self.media_type = preferred_suffixes[suffix] self.charset = 'utf-8' break self.options.set_host_language(self.media_type) return open(name, 'rb') else : return name except HTTPError : raise sys.exc_info()[1] except : (type, value, traceback) = sys.exc_info() raise FailedSource(value) #################################################################################################################### # Externally used methods # def graph_from_DOM(self, dom, graph = None, pgraph = None) : """ Extract the RDF Graph from a DOM tree. This is where the real processing happens. All other methods get down to this one, eventually (e.g., after opening a URI and parsing it into a DOM). @param dom: a DOM Node element, the top level entry node for the whole tree (i.e., the C{dom.documentElement} is used to initiate processing down the node hierarchy) @keyword graph: an RDF Graph (if None, than a new one is created) @type graph: rdflib Graph instance. @keyword pgraph: an RDF Graph to hold (possibly) the processor graph content. If None, and the error/warning triples are to be generated, they will be added to the returned graph. Otherwise they are stored in this graph. @type pgraph: rdflib Graph instance @return: an RDF Graph @rtype: rdflib Graph instance """ def copyGraph(tog, fromg) : for t in fromg : tog.add(t) for k,ns in fromg.namespaces() : tog.bind(k,ns) if graph == None : # Create the RDF Graph, that will contain the return triples... graph = Graph() # this will collect the content, the 'default graph', as called in the RDFa spec default_graph = Graph() # get the DOM tree topElement = dom.documentElement # Create the initial state. This takes care of things # like base, top level namespace settings, etc. state = ExecutionContext(topElement, default_graph, base=self.required_base if self.required_base != None else "", options=self.options, rdfa_version=self.rdfa_version) # Perform the built-in and external transformations on the HTML tree. for trans in self.options.transformers + builtInTransformers : trans(topElement, self.options, state) # This may have changed if the state setting detected an explicit version information: self.rdfa_version = state.rdfa_version # The top level subject starts with the current document; this # is used by the recursion # this function is the real workhorse parse_one_node(topElement, default_graph, None, state, []) # Massage the output graph in term of rdfa:Pattern and rdfa:copy handle_prototypes(default_graph) # If the RDFS expansion has to be made, here is the place... if self.options.vocab_expansion : from .rdfs.process import process_rdfa_sem process_rdfa_sem(default_graph, self.options) # Experimental feature: nothing for now, this is kept as a placeholder if self.options.experimental_features : pass # What should be returned depends on the way the options have been set up if self.options.output_default_graph : copyGraph(graph, default_graph) if self.options.output_processor_graph : if pgraph != None : copyGraph(pgraph, self.options.processor_graph.graph) else : copyGraph(graph, self.options.processor_graph.graph) elif self.options.output_processor_graph : if pgraph != None : copyGraph(pgraph, self.options.processor_graph.graph) else : copyGraph(graph, self.options.processor_graph.graph) # this is necessary if several DOM trees are handled in a row... self.options.reset_processor_graph() return graph def graph_from_source(self, name, graph = None, rdfOutput = False, pgraph = None) : """ Extract an RDF graph from an RDFa source. The source is parsed, the RDF extracted, and the RDFa Graph is returned. This is a front-end to the L{pyRdfa.graph_from_DOM} method. @param name: a URI, a file name, or a file-like object @param graph: rdflib Graph instance. If None, a new one is created. @param pgraph: rdflib Graph instance for the processor graph. If None, and the error/warning triples are to be generated, they will be added to the returned graph. Otherwise they are stored in this graph. @param rdfOutput: whether runtime exceptions should be turned into RDF and returned as part of the processor graph @return: an RDF Graph @rtype: rdflib Graph instance """ def copyErrors(tog, options) : if tog == None : tog = Graph() if options.output_processor_graph : for t in options.processor_graph.graph : tog.add(t) if pgraph != None : pgraph.add(t) for k,ns in options.processor_graph.graph.namespaces() : tog.bind(k,ns) if pgraph != None : pgraph.bind(k,ns) options.reset_processor_graph() return tog # Separating this for a forward Python 3 compatibility try : # Python 2 branch isstring = isinstance(name, basestring) except : # Python 3 branch isstring = isinstance(name, str) try : # First, open the source... Possible HTTP errors are returned as error triples input = None try : input = self._get_input(name) except FailedSource : f = sys.exc_info()[1] self.http_status = 400 if not rdfOutput : raise f err = self.options.add_error(f.msg, FileReferenceError, name) self.options.processor_graph.add_http_context(err, 400) return copyErrors(graph, self.options) except HTTPError : h = sys.exc_info()[1] self.http_status = h.http_code if not rdfOutput : raise h err = self.options.add_error("HTTP Error: %s (%s)" % (h.http_code,h.msg), HTError, name) self.options.processor_graph.add_http_context(err, h.http_code) return copyErrors(graph, self.options) except Exception : e = sys.exc_info()[1] self.http_status = 500 # Something nasty happened:-( if not rdfOutput : raise e err = self.options.add_error(str(e), context = name) self.options.processor_graph.add_http_context(err, 500) return copyErrors(graph, self.options) dom = None try : msg = "" parser = None if self.options.host_language == HostLanguage.html5 : import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) import html5lib parser = html5lib.HTMLParser(tree=html5lib.treebuilders.getTreeBuilder("dom")) if self.charset : # This means the HTTP header has provided a charset, or the # file is a local file when we suppose it to be a utf-8 dom = parser.parse(input, encoding=self.charset) else : # No charset set. The HTMLLib parser tries to sniff into the # the file to find a meta header for the charset; if that # works, fine, otherwise it falls back on window-... dom = parser.parse(input) try : if isstring : input.close() input = self._get_input(name) else : input.seek(0) from .host import adjust_html_version self.rdfa_version = adjust_html_version(input, self.rdfa_version) except : # if anyting goes wrong, it is not really important; rdfa version stays what it was... pass else : # in other cases an XML parser has to be used from .host import adjust_xhtml_and_version parse = xml.dom.minidom.parse dom = parse(input) (adjusted_host_language, version) = adjust_xhtml_and_version(dom, self.options.host_language, self.rdfa_version) self.options.host_language = adjusted_host_language self.rdfa_version = version except ImportError : msg = "HTML5 parser not available. Try installing html5lib " raise ImportError(msg) except Exception : e = sys.exc_info()[1] # These are various parsing exception. Per spec, this is a case when # error triples MUST be returned, ie, the usage of rdfOutput (which switches between an HTML formatted # return page or a graph with error triples) does not apply err = self.options.add_error(str(e), context = name) self.http_status = 400 self.options.processor_graph.add_http_context(err, 400) return copyErrors(graph, self.options) # If we got here, we have a DOM tree to operate on... return self.graph_from_DOM(dom, graph, pgraph) except Exception : # Something nasty happened during the generation of the graph... (a,b,c) = sys.exc_info() sys.excepthook(a,b,c) if isinstance(b, ImportError) : self.http_status = None else : self.http_status = 500 if not rdfOutput : raise b err = self.options.add_error(str(b), context = name) self.options.processor_graph.add_http_context(err, 500) return copyErrors(graph, self.options) def rdf_from_sources(self, names, outputFormat = "turtle", rdfOutput = False) : """ Extract and RDF graph from a list of RDFa sources and serialize them in one graph. The sources are parsed, the RDF extracted, and serialization is done in the specified format. @param names: list of sources, each can be a URI, a file name, or a file-like object @keyword outputFormat: serialization format. Can be one of "turtle", "n3", "xml", "pretty-xml", "nt". "xml", "pretty-xml", "json" or "json-ld". "turtle" and "n3", "xml" and "pretty-xml", and "json" and "json-ld" are synonyms, respectively. Note that the JSON-LD serialization works with RDFLib 3.* only. @keyword rdfOutput: controls what happens in case an exception is raised. If the value is False, the caller is responsible handling it; otherwise a graph is returned with an error message included in the processor graph @type rdfOutput: boolean @return: a serialized RDF Graph @rtype: string """ # This is better because it gives access to the various, non-standard serializations # If it does not work because the extra are not installed, fall back to the standard # rdlib distribution... try : from pyRdfaExtras import MyGraph graph = MyGraph() except : graph = Graph() # graph.bind("xsd", Namespace('http://www.w3.org/2001/XMLSchema#')) # the value of rdfOutput determines the reaction on exceptions... for name in names : self.graph_from_source(name, graph, rdfOutput) retval = graph.serialize(format=outputFormat) return retval def rdf_from_source(self, name, outputFormat = "turtle", rdfOutput = False) : """ Extract and RDF graph from an RDFa source and serialize it in one graph. The source is parsed, the RDF extracted, and serialization is done in the specified format. @param name: a URI, a file name, or a file-like object @keyword outputFormat: serialization format. Can be one of "turtle", "n3", "xml", "pretty-xml", "nt". "xml", "pretty-xml", "json" or "json-ld". "turtle" and "n3", "xml" and "pretty-xml", and "json" and "json-ld" are synonyms, respectively. Note that the JSON-LD serialization works with RDFLib 3.* only. @keyword rdfOutput: controls what happens in case an exception is raised. If the value is False, the caller is responsible handling it; otherwise a graph is returned with an error message included in the processor graph @type rdfOutput: boolean @return: a serialized RDF Graph @rtype: string """ return self.rdf_from_sources([name], outputFormat, rdfOutput) ################################################# CGI Entry point def processURI(uri, outputFormat, form={}) : """The standard processing of an RDFa uri options in a form; used as an entry point from a CGI call. The call accepts extra form options (i.e., HTTP GET options) as follows: - C{graph=[output|processor|output,processor|processor,output]} specifying which graphs are returned. Default: C{output} - C{space_preserve=[true|false]} means that plain literals are normalized in terms of white spaces. Default: C{false} - C{rfa_version} provides the RDFa version that should be used for distilling. The string should be of the form "1.0" or "1.1". Default is the highest version the current package implements, currently "1.1" - C{host_language=[xhtml,html,xml]} : the host language. Used when files are uploaded or text is added verbatim, otherwise the HTTP return header should be used. Default C{xml} - C{embedded_rdf=[true|false]} : whether embedded turtle or RDF/XML content should be added to the output graph. Default: C{false} - C{vocab_expansion=[true|false]} : whether the vocabularies should be expanded through the restricted RDFS entailment. Default: C{false} - C{vocab_cache=[true|false]} : whether vocab caching should be performed or whether it should be ignored and vocabulary files should be picked up every time. Default: C{false} - C{vocab_cache_report=[true|false]} : whether vocab caching details should be reported. Default: C{false} - C{vocab_cache_bypass=[true|false]} : whether vocab caches have to be regenerated every time. Default: C{false} - C{rdfa_lite=[true|false]} : whether warnings should be generated for non RDFa Lite attribute usage. Default: C{false} @param uri: URI to access. Note that the C{text:} and C{uploaded:} fake URI values are treated separately; the former is for textual intput (in which case a StringIO is used to get the data) and the latter is for uploaded file, where the form gives access to the file directly. @param outputFormat: serialization format, as defined by the package. Currently "xml", "turtle", "nt", or "json". Default is "turtle", also used if any other string is given. @param form: extra call options (from the CGI call) to set up the local options @type form: cgi FieldStorage instance @return: serialized graph @rtype: string """ def _get_option(param, compare_value, default) : param_old = param.replace('_','-') if param in list(form.keys()) : val = form.getfirst(param).lower() return val == compare_value elif param_old in list(form.keys()) : # this is to ensure the old style parameters are still valid... # in the old days I used '-' in the parameters, the standard favours '_' val = form.getfirst(param_old).lower() return val == compare_value else : return default if uri == "uploaded:" : input = form["uploaded"].file base = "" elif uri == "text:" : input = StringIO(form.getfirst("text")) base = "" else : input = uri base = uri if "rdfa_version" in list(form.keys()) : rdfa_version = form.getfirst("rdfa_version") else : rdfa_version = None # working through the possible options # Host language: HTML, XHTML, or XML # Note that these options should be used for the upload and inline version only in case of a form # for real uris the returned content type should be used if "host_language" in list(form.keys()) : if form.getfirst("host_language").lower() == "xhtml" : media_type = MediaTypes.xhtml elif form.getfirst("host_language").lower() == "html" : media_type = MediaTypes.html elif form.getfirst("host_language").lower() == "svg" : media_type = MediaTypes.svg elif form.getfirst("host_language").lower() == "atom" : media_type = MediaTypes.atom else : media_type = MediaTypes.xml else : media_type = "" transformers = [] check_lite = "rdfa_lite" in list(form.keys()) and form.getfirst("rdfa_lite").lower() == "true" # The code below is left for backward compatibility only. In fact, these options are not exposed any more, # they are not really in use if "extras" in list(form.keys()) and form.getfirst("extras").lower() == "true" : from .transform.metaname import meta_transform from .transform.OpenID import OpenID_transform from .transform.DublinCore import DC_transform for t in [OpenID_transform, DC_transform, meta_transform] : transformers.append(t) else : if "extra-meta" in list(form.keys()) and form.getfirst("extra-meta").lower() == "true" : from .transform.metaname import meta_transform transformers.append(meta_transform) if "extra-openid" in list(form.keys()) and form.getfirst("extra-openid").lower() == "true" : from .transform.OpenID import OpenID_transform transformers.append(OpenID_transform) if "extra-dc" in list(form.keys()) and form.getfirst("extra-dc").lower() == "true" : from .transform.DublinCore import DC_transform transformers.append(DC_transform) output_default_graph = True output_processor_graph = False # Note that I use the 'graph' and the 'rdfagraph' form keys here. Reason is that # I used 'graph' in the previous versions, including the RDFa 1.0 processor, # so if I removed that altogether that would create backward incompatibilities # On the other hand, the RDFa 1.1 doc clearly refers to 'rdfagraph' as the standard # key. a = None if "graph" in list(form.keys()) : a = form.getfirst("graph").lower() elif "rdfagraph" in list(form.keys()) : a = form.getfirst("rdfagraph").lower() if a != None : if a == "processor" : output_default_graph = False output_processor_graph = True elif a == "processor,output" or a == "output,processor" : output_processor_graph = True embedded_rdf = _get_option( "embedded_rdf", "true", False) space_preserve = _get_option( "space_preserve", "true", True) vocab_cache = _get_option( "vocab_cache", "true", True) vocab_cache_report = _get_option( "vocab_cache_report", "true", False) refresh_vocab_cache = _get_option( "vocab_cache_refresh", "true", False) vocab_expansion = _get_option( "vocab_expansion", "true", False) if vocab_cache_report : output_processor_graph = True options = Options(output_default_graph = output_default_graph, output_processor_graph = output_processor_graph, space_preserve = space_preserve, transformers = transformers, vocab_cache = vocab_cache, vocab_cache_report = vocab_cache_report, refresh_vocab_cache = refresh_vocab_cache, vocab_expansion = vocab_expansion, embedded_rdf = embedded_rdf, check_lite = check_lite ) processor = pyRdfa(options = options, base = base, media_type = media_type, rdfa_version = rdfa_version) # Decide the output format; the issue is what should happen in case of a top level error like an inaccessibility of # the html source: should a graph be returned or an HTML page with an error message? # decide whether HTML or RDF should be sent. htmlOutput = False #if 'HTTP_ACCEPT' in os.environ : # acc = os.environ['HTTP_ACCEPT'] # possibilities = ['text/html', # 'application/rdf+xml', # 'text/turtle; charset=utf-8', # 'application/json', # 'application/ld+json', # 'text/rdf+n3'] # # # this nice module does content negotiation and returns the preferred format # sg = acceptable_content_type(acc, possibilities) # htmlOutput = (sg != None and sg[0] == content_type('text/html')) # os.environ['rdfaerror'] = 'true' # This is really for testing purposes only, it is an unpublished flag to force RDF output no # matter what try : graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput) if outputFormat == "n3" : retval = 'Content-Type: text/rdf+n3; charset=utf-8\n' elif outputFormat == "nt" or outputFormat == "turtle" : retval = 'Content-Type: text/turtle; charset=utf-8\n' elif outputFormat == "json-ld" or outputFormat == "json" : retval = 'Content-Type: application/ld+json; charset=utf-8\n' else : retval = 'Content-Type: application/rdf+xml; charset=utf-8\n' retval += '\n' retval += graph return retval except HTTPError : (type,h,traceback) = sys.exc_info() import cgi retval = 'Content-type: text/html; charset=utf-8\nStatus: %s \n\n' % h.http_code retval += "\n" retval += "\n" retval += "HTTP Error in distilling RDFa content\n" retval += "\n" retval += "

HTTP Error in distilling RDFa content

\n" retval += "

HTTP Error: %s (%s)

\n" % (h.http_code,h.msg) retval += "

On URI: '%s'

\n" % cgi.escape(uri) retval +="\n" retval +="\n" return retval except : # This branch should occur only if an exception is really raised, ie, if it is not turned # into a graph value. (type,value,traceback) = sys.exc_info() import traceback, cgi retval = 'Content-type: text/html; charset=utf-8\nStatus: %s\n\n' % processor.http_status retval += "\n" retval += "\n" retval += "Exception in RDFa processing\n" retval += "\n" retval += "

Exception in distilling RDFa

\n" retval += "
\n"
		strio  = StringIO()
		traceback.print_exc(file=strio)
		retval += strio.getvalue()
		retval +="
\n" retval +="
%s
\n" % value retval +="

Distiller request details

\n" retval +="
\n" if uri == "text:" and "text" in form and form["text"].value != None and len(form["text"].value.strip()) != 0 : retval +="
Text input:
%s
\n" % cgi.escape(form["text"].value).replace('\n','
') elif uri == "uploaded:" : retval +="
Uploaded file
\n" else : retval +="
URI received:
'%s'
\n" % cgi.escape(uri) if "host_language" in list(form.keys()) : retval +="
Media Type:
%s
\n" % media_type if "graph" in list(form.keys()) : retval +="
Requested graphs:
%s
\n" % form.getfirst("graph").lower() else : retval +="
Requested graphs:
default
\n" retval +="
Output serialization format:
%s
\n" % outputFormat if "space_preserve" in form : retval +="
Space preserve:
%s
\n" % form["space_preserve"].value retval +="
\n" retval +="\n" retval +="\n" return retval rdflib-4.1.2/rdflib/plugins/parsers/pyRdfa/embeddedRDF.py000066400000000000000000000067471232323236500232650ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Extracting possible embedded RDF/XML content from the file and parse it separately into the Graph. This is used, for example by U{SVG 1.2 Tiny}. @author: U{Ivan Herman
} @license: This software is available for use under the U{W3C® SOFTWARE NOTICE AND LICENSE} @contact: Ivan Herman, ivan@w3.org @version: $Id: embeddedRDF.py,v 1.15 2012/11/16 17:51:53 ivan Exp $ """ # Python 3 foolproof way... try : from io import StringIO except : from StringIO import StringIO from .host import HostLanguage, accept_embedded_rdf_xml, accept_embedded_turtle from .utils import return_XML import re, sys def handle_embeddedRDF(node, graph, state) : """ Handles embedded RDF. There are two possibilities: - the file is one of the XML dialects that allows for an embedded RDF/XML portion. See the L{host.accept_embedded_rdf_xml} for those (a typical example is SVG). - the file is HTML and there is a turtle portion in the C{
Buying Options
Natural Language Processing with Python
Print $44.99
Add to Cart
Print+Ebook $49.49
Add to Cart
Ebook $35.99
Add to Cart
Safari Books Online
Add to Cart
What is this?
Print £34.50
Add to Cart
What is this?
Description
This book offers a highly accessible introduction to Natural Language Processing, the field that underpins a variety of language technologies ranging from predictive text and email filtering to automatic summarization and translation. You'll learn how to write Python programs to analyze the structure and meaning of texts, drawing on techniques from the fields of linguistics and artificial intelligence.
Full Description
Table of Contents
  1. Chapter 1 Language Processing and Python

    1. Computing with Language: Texts and Words

    2. A Closer Look at Python: Texts as Lists of Words

    3. Computing with Language: Simple Statistics

    4. Back to Python: Making Decisions and Taking Control

    5. Automatic Natural Language Understanding

    6. Summary

    7. Further Reading

    8. Exercises

  2. Chapter 2 Accessing Text Corpora and Lexical Resources

    1. Accessing Text Corpora

    2. Conditional Frequency Distributions

    3. More Python: Reusing Code

    4. Lexical Resources

    5. WordNet

    6. Summary

    7. Further Reading

    8. Exercises

  3. Chapter 3 Processing Raw Text

    1. Accessing Text from the Web and from Disk

    2. Strings: Text Processing at the Lowest Level

    3. Text Processing with Unicode

    4. Regular Expressions for Detecting Word Patterns

    5. Useful Applications of Regular Expressions

    6. Normalizing Text

    7. Regular Expressions for Tokenizing Text

    8. Segmentation

    9. Formatting: From Lists to Strings

    10. Summary

    11. Further Reading

    12. Exercises

  4. Chapter 4 Writing Structured Programs

    1. Back to the Basics

    2. Sequences

    3. Questions of Style

    4. Functions: The Foundation of Structured Programming

    5. Doing More with Functions

    6. Program Development

    7. Algorithm Design

    8. A Sample of Python Libraries

    9. Summary

    10. Further Reading

    11. Exercises

  5. Chapter 5 Categorizing and Tagging Words

    1. Using a Tagger

    2. Tagged Corpora

    3. Mapping Words to Properties Using Python Dictionaries

    4. Automatic Tagging

    5. N-Gram Tagging

    6. Transformation-Based Tagging

    7. How to Determine the Category of a Word

    8. Summary

    9. Further Reading

    10. Exercises

  6. Chapter 6 Learning to Classify Text

    1. Supervised Classification

    2. Further Examples of Supervised Classification

    3. Evaluation

    4. Decision Trees

    5. Naive Bayes Classifiers

    6. Maximum Entropy Classifiers

    7. Modeling Linguistic Patterns

    8. Summary

    9. Further Reading

    10. Exercises

  7. Chapter 7 Extracting Information from Text

    1. Information Extraction

    2. Chunking

    3. Developing and Evaluating Chunkers

    4. Recursion in Linguistic Structure

    5. Named Entity Recognition

    6. Relation Extraction

    7. Summary

    8. Further Reading

    9. Exercises

  8. Chapter 8 Analyzing Sentence Structure

    1. Some Grammatical Dilemmas

    2. What’s the Use of Syntax?

    3. Context-Free Grammar

    4. Parsing with Context-Free Grammar

    5. Dependencies and Dependency Grammar

    6. Grammar Development

    7. Summary

    8. Further Reading

    9. Exercises

  9. Chapter 9 Building Feature-Based Grammars

    1. Grammatical Features

    2. Processing Feature Structures

    3. Extending a Feature-Based Grammar

    4. Summary

    5. Further Reading

    6. Exercises

  10. Chapter 10 Analyzing the Meaning of Sentences

    1. Natural Language Understanding

    2. Propositional Logic

    3. First-Order Logic

    4. The Semantics of English Sentences

    5. Discourse Semantics

    6. Summary

    7. Further Reading

    8. Exercises

  11. Chapter 11 Managing Linguistic Data

    1. Corpus Structure: A Case Study

    2. The Life Cycle of a Corpus

    3. Acquiring Data

    4. Working with XML

    5. Working with Toolbox Data

    6. Describing Language Resources Using OLAC Metadata

    7. Summary

    8. Further Reading

    9. Exercises

  1. Appendix Afterword: The Language Challenge

    1. Language Processing Versus Symbol Processing

    2. Contemporary Philosophical Divides

    3. NLTK Roadmap

    4. Envoi...

  2. Appendix Bibliography

  3. NLTK Index

  4. General Index

  5. Colophon

View Full Table of Contents
Product Details
Title:
Natural Language Processing with Python
By:
Steven Bird, Ewan Klein, Edward Loper
Publisher:
O'Reilly Media
Formats:
  • Print
  • Ebook
  • Safari Books Online
Print Release:
June 2009
Ebook Release:
June 2009
Pages:
512
Print ISBN:
978-0-596-51649-9
| ISBN 10:
0-596-51649-5
Ebook ISBN:
978-0-596-80339-1
| ISBN 10:
0-596-80339-7
Customer Reviews
About the Authors
  1. Steven Bird

    Steven Bird is Associate Professor in the Department of Computer Science and Software Engineering at the University of Melbourne, and Senior Research Associate in the Linguistic Data Consortium at the University of Pennsylvania. He completed a PhD on computational phonology at the University of Edinburgh in 1990, supervised by Ewan Klein. He later moved to Cameroon to conduct linguistic fieldwork on the Grassfields Bantu languages under the auspices of the Summer Institute of Linguistics. More recently, he spent several years as Associate Director of the Linguistic Data Consortium where he led an R&D team to create models and tools for large databases of annotated text. At Melbourne University, he established a language technology research group and has taught at all levels of the undergraduate computer science curriculum. In 2009, Steven is President of the Association for Computational Linguistics.

    View Steven Bird's full profile page.

  2. Ewan Klein

    Ewan Klein is Professor of Language Technology in the School of Informatics at the University of Edinburgh. He completed a PhD on formal semantics at the University of Cambridge in 1978. After some years working at the Universities of Sussex and Newcastle upon Tyne, Ewan took up a teaching position at Edinburgh. He was involved in the establishment of Edinburgh's Language Technology Group in 1993, and has been closely associated with it ever since. From 2000-2002, he took leave from the University to act as Research Manager for the Edinburgh-based Natural Language Research Group of Edify Corporation, Santa Clara, and was responsible for spoken dialogue processing. Ewan is a past President of the European Chapter of the Association for Computational Linguistics and was a founding member and Coordinator of the European Network of Excellence in Human Language Technologies (ELSNET).

    View Ewan Klein's full profile page.

  3. Edward Loper

    Edward Loper has recently completed a PhD on machine learning for natural language processing at the the University of Pennsylvania. Edward was a student in Steven's graduate course on computational linguistics in the fall of 2000, and went on to be a TA and share in the development of NLTK. In addition to NLTK, he has helped develop two packages for documenting and testing Python software, epydoc, and doctest.

    View Edward Loper's full profile page.

Colophon
The animal on the cover of Natural Language Processing with Python is a right whale, the rarest of all large whales. It is identifiable by its enormous head, which can measure up to one-third of its total body length. It lives in temperate and cool seas in both hemispheres at the surface of the ocean. It's believed that the right whale may have gotten its name from whalers who thought that it was the "right" whale to kill for oil. Even though it has been protected since the 1930s, the right whale is still the most endangered of all the great whales.The large and bulky right whale is easily distinguished from other whales by the calluses on its head. It has a broad back without a dorsal fin and a long arching mouth that begins above the eye. Its body is black, except for a white patch on its belly. Wounds and scars may appear bright orange, often becoming infested with whale lice or cyamids. The calluses-which are also found near the blowholes, above the eyes, and on the chin, and upper lip-are black or gray. It has large flippers that are shaped like paddles, and a distinctive V-shaped blow, caused by the widely spaced blowholes on the top of its head, which rises to 16 feet above the ocean's surface.The right whale feeds on planktonic organisms, including shrimp-like krill and copepods. As baleen whales, they have a series of 225-250 fringed overlapping plates hanging from each side of the upper jaw, where teeth would otherwise be located. The plates are black and can be as long as 7.2 feet. Right whales are "grazers of the sea," often swimming slowly with their mouths open. As water flows into the mouth and through the baleen, prey is trapped near the tongue.Because females are not sexually mature until 10 years of age and they give birth to a single calf after a year-long pregnancy, populations grow slowly. The young right whale stays with its mother for one year.Right whales are found worldwide but in very small numbers. A right whale is commonly found alone or in small groups of 1 to 3, but when courting, they may form groups of up to 30. Like most baleen whales, they are seasonally migratory. They inhabit colder waters for feeding and then migrate to warmer waters for breeding and calving. Although they may move far out to sea during feeding seasons, right whales give birth in coastal areas. Interestingly, many of the females do not return to these coastal breeding areas every year, but visit the area only in calving years. Where they go in other years remains a mysteryThe right whale's only predators are orcas and humans. When danger lurks, a group of right whales may come together in a circle, with their tails pointing outward, to deter a predator. This defense is not always successful and calves are occasionally separated from their mother and killed.Right whales are among the slowest swimming whales, although they may reach speeds up to 10 mph in short spurts. They can dive to at least 1,000 feet and can stay submerged for up to 40 minutes. The right whale is extremely endangered, even after years of protected status. Only in the past 15 years is there evidence of a population recovery in the Southern Hemisphere, and it is still not known if the right whale will survive at all in the Northern Hemisphere. Although not presently hunted, current conservation problems include collisions with ships, conflicts with fishing activities, habitat destruction, oil drilling, and possible competition from other whale species. Right whales have no teeth, so ear bones and, in some cases, eye lenses can be used to estimate the age of a right whale at death. It is believed that right whales live at least 50 years, but there is little data on their longevity.
  • Book cover of Natural Language Processing with Python

rdflib-4.1.2/test/rdfa/run_w3c_rdfa_testsuite.py000066400000000000000000000131501232323236500217130ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: UTF-8 -*- """ ========================== W3C RDFa Test Suite Runner ========================== This test suite generates test functions with ``all_tests`` which runs the ``RDFaParser`` against the official RDFa testsuite (found via ``XHTML_RDFA_TEST_MANIFEST_URL``). It is intended to be run by Nose (but can also be invoked as a script). If files in "test/rdfa/w3c_rdfa_suite" are removed, the test module automatically downloads them (to allow for "manual+automatic" update). """ from operator import attrgetter import re import os from urllib2 import urlopen from urllib import url2pathname from rdflib.graph import Graph from rdflib.namespace import Namespace, RDF from rdflib.parser import create_input_source # from rdflib.plugins.parsers.rdfa import RDFaParser from rdflib.plugins.parsers.structureddata import RDFa10Parser as RDFaParser DC = Namespace("http://purl.org/dc/elements/1.1/") TEST = Namespace("http://www.w3.org/2006/03/test-description#") XHTML_RDFA_TEST_MANIFEST_URL = ("http://www.w3.org/2006/07/SWD/RDFa/" "testsuite/xhtml1-testcases/rdfa-xhtml1-test-manifest.rdf") class TestCase(object): def __init__(self, graph, tc_uri): val = lambda p: graph.value(tc_uri, p) self.number = int(re.search(r'/Test(\d+)$', tc_uri).group(1)) self.title = val(DC.title) self.html_url = val(TEST.informationResourceInput) self.sparql_url = val(TEST.informationResourceResults) self.status = val(TEST.reviewStatus).split("#")[-1] self.expected = val(TEST.expectedResults) in (None, 'true') @classmethod def all(cls, graph): for tc_uri in graph.subjects(RDF.type, TEST.TestCase): yield cls(graph, tc_uri) def get_tcs(manifest_url=XHTML_RDFA_TEST_MANIFEST_URL, status="approved"): graph = Graph().parse(cached_file(manifest_url), publicID=manifest_url) return sorted((tc for tc in TestCase.all(graph) if tc.status == status), key=attrgetter('number')) def run_tc(tc): parser = RDFaParser() graph = Graph() source = create_input_source(cached_file(tc.html_url), publicID=tc.html_url) parser.parse(source, graph) sparql = open(cached_file(tc.sparql_url)).read() ok = verify_ask(sparql, graph, tc.expected) return ok, sparql, graph def verify_ask(sparql, graph, expected): try: result = graph.query(sparql.decode('utf-8')) ok = result.serialize('python') == expected except: # TODO: parse failures are probably sparql processor bugs ok = False if ok: return ok # TODO: sparql bugs cause a bunch to fail (at least bnodes and xmlliterals) # .. extract N3 from ASK and compare graphs instead: from rdflib.compare import isomorphic for ask_graph in _sparql_to_graphs(sparql): if isomorphic(graph, ask_graph) == expected: return True #else: print ask_graph.serialize(format='nt') return False def _sparql_to_graphs(sparql): # turn sparql into n3 # try to turn bnode sparql into bnode n3 # NOTE: this requires *all* FILTER tests to use isBlank! if re.search(r'(?i)isBlank', sparql): sparql = re.sub(r'(?im)^\s*FILTER.+ISBLANK.*$', '', sparql) sparql = re.sub(r'\?(\w+)', r'_:\1', sparql) # remove ASK block n3 = re.sub(r'(?s)ASK\s+WHERE\s*{(.*)}', r'\1', sparql) # split union into chunks n3chunks = [re.sub(r'(?s)\s*{(.*)}\s*', r'\1', block) for block in n3.split('UNION')] for chunk in n3chunks: yield Graph().parse(data=chunk, format='n3') CACHE_DIR = os.path.join(os.path.dirname(__file__), "w3c_rdfa_testsuite") def cached_file(url): fname = os.path.basename(url2pathname(url.split(':', 1)[1])) fpath = os.path.join(CACHE_DIR, fname) if not os.path.exists(fpath): f = open(fpath, 'w') try: f.write(urlopen(url).read()) finally: f.close() return fpath KNOWN_ISSUES = set([11, 92, 94, 100, 101, 102, 103, 114]) KNOWN_ISSUES |= set([105, 106]) def all_tests(skip_known_issues=True): """ Generator used to expose test functions. The Nose test runner use this. """ from nose import SkipTest raise SkipTest("Suspended until test suite is updated, use 'manual_run' instead.") import platform if platform.system() == 'Java': from nose import SkipTest raise SkipTest('html5lib unavailable in Jython2.5') for tc in get_tcs(): label = "RDFa TC #%(number)s: %(title)s (%(status)s)"%vars(tc) urls = "[<%(html_url)s>, <%(sparql_url)s>]"%vars(tc) def do_test(): ok, sparql, graph = run_tc(tc) if not ok: n3 = graph.serialize(format='nt') raise AssertionError( "The SPARQL:\n%(sparql)s\nDid not match:\n%(n3)s"%vars()) if skip_known_issues and tc.number in KNOWN_ISSUES: # NOTE: nose doesn't support attr-filtering on generated test funcs.. #do_test.known_issue = True continue do_test.description = label do_test._source_urls = urls yield do_test, def manual_run(): errors, failed, count = 0, 0, 0 for test, in all_tests(skip_known_issues=False): count += 1 print(test.description) try: test() print "PASSED" except AssertionError, e: failed += 1 print "****FAILED****", e; except Exception, e: errors += 1; print "****ERROR**** in %s" % test._source_urls, e print "Ran %(count)s tests. Failed: %(failed)s. Errors: %(errors)s."%vars() if __name__ == '__main__': manual_run() rdflib-4.1.2/test/rdfa/test_non_xhtml.py000066400000000000000000000023641232323236500203000ustar00rootroot00000000000000from unittest import TestCase from urllib2 import URLError from rdflib.graph import ConjunctiveGraph from nose import SkipTest raise SkipTest("Suspended while test suite is being updated.") class NonXhtmlTest(TestCase): """ RDFa that is in not well-formed XHTML is passed through html5lib. These tests make sure that this RDFa can be processed both from a file, and from a URL. We can only run these tests if html5lib is installed. Currently html5lib isn't a dependency. """ def test_url(self): if self.html5lib_installed(): try: g = ConjunctiveGraph() g.parse(location='http://oreilly.com/catalog/9780596516499/', format='rdfa') self.assertTrue(len(g), 77) except URLError: from nose import SkipTest raise SkipTest('No networking, test skipped') def test_file(self): if self.html5lib_installed(): g = ConjunctiveGraph() g.parse(location='test/rdfa/oreilly.html', format='rdfa') self.assertEqual(len(g), 77) def html5lib_installed(self): try: import html5lib return True except: return False rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/000077500000000000000000000000001232323236500204555ustar00rootroot00000000000000rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0001.sparql000066400000000000000000000002241232323236500222570ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0001.xhtml000066400000000000000000000006401232323236500221130ustar00rootroot00000000000000 Test 0001

This photo was taken by Mark Birbeck.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0006.sparql000066400000000000000000000005141232323236500222660ustar00rootroot00000000000000ASK WHERE { . . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0006.xhtml000066400000000000000000000010121232323236500221120ustar00rootroot00000000000000 Test 0006

This photo was taken by Mark Birbeck.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0007.sparql000066400000000000000000000007161232323236500222730ustar00rootroot00000000000000ASK WHERE { . "Portrait of Mark" . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0007.xhtml000066400000000000000000000010761232323236500221250ustar00rootroot00000000000000 Test 0007

This photo was taken by Mark Birbeck.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0008.sparql000066400000000000000000000002671232323236500222750ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0008.xhtml000066400000000000000000000007451232323236500221300ustar00rootroot00000000000000 Test 0008

This document is licensed under a Creative Commons .

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0009.sparql000066400000000000000000000001721232323236500222710ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0009.xhtml000066400000000000000000000006741232323236500221320ustar00rootroot00000000000000 Test 0009

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0010.sparql000066400000000000000000000003471232323236500222650ustar00rootroot00000000000000ASK WHERE { . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0010.xhtml000066400000000000000000000007111232323236500221120ustar00rootroot00000000000000 Test 0010

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0011.sparql000066400000000000000000000020521232323236500222610ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { "Albert Einstein" . { "E = mc2: The Most Urgent Problem of Our Time"^^ . } UNION { "E = mc2: The Most Urgent Problem of Our Time"^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0011.xhtml000066400000000000000000000007521232323236500221200ustar00rootroot00000000000000 Test 0011
Author: Albert Einstein

E = mc2: The Most Urgent Problem of Our Time

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0012.sparql000066400000000000000000000001231232323236500222570ustar00rootroot00000000000000ASK WHERE { "chat"@fr . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0012.xhtml000066400000000000000000000006341232323236500221200ustar00rootroot00000000000000 Test 0012

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0013.sparql000066400000000000000000000001221232323236500222570ustar00rootroot00000000000000ASK WHERE { "chat"@fr . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0013.xhtml000066400000000000000000000006541232323236500221230ustar00rootroot00000000000000 Test 0013

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0014.sparql000066400000000000000000000001631232323236500222650ustar00rootroot00000000000000ASK WHERE { "10"^^ . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0014.xhtml000066400000000000000000000007341232323236500221230ustar00rootroot00000000000000 Test 0014

ten

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0015.sparql000066400000000000000000000004461232323236500222720ustar00rootroot00000000000000ASK WHERE { "Fyodor Dostoevsky" . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0015.xhtml000066400000000000000000000006641232323236500221260ustar00rootroot00000000000000 Test 0015

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0017.sparql000066400000000000000000000003121232323236500222640ustar00rootroot00000000000000ASK WHERE { ?x "Manu Sporny" . ?x ?y . ?y "Ralph Swick" . FILTER (ISBLANK(?x) && ISBLANK(?y)) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0017.xhtml000066400000000000000000000010451232323236500221220ustar00rootroot00000000000000 Test 0017

Manu Sporny knows Ralph Swick.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0018.sparql000066400000000000000000000002561232323236500222740ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0018.xhtml000066400000000000000000000007161232323236500221270ustar00rootroot00000000000000 Test 0018

This photo was taken by Mark Birbeck.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0019.sparql000066400000000000000000000002011232323236500222630ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0019.xhtml000066400000000000000000000006641232323236500221320ustar00rootroot00000000000000 Test 0019
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0020.sparql000066400000000000000000000002241232323236500222600ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0020.xhtml000066400000000000000000000007421232323236500221170ustar00rootroot00000000000000 Test 0020
this photo was taken by Mark Birbeck
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0021.sparql000066400000000000000000000002241232323236500222610ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0021.xhtml000066400000000000000000000007071232323236500221210ustar00rootroot00000000000000 Test 0021
this photo was taken by Mark Birbeck
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0023.sparql000066400000000000000000000002241232323236500222630ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0023.xhtml000066400000000000000000000006601232323236500221210ustar00rootroot00000000000000 Test 0023
This photo was taken by Mark Birbeck
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0025.sparql000066400000000000000000000005211232323236500222650ustar00rootroot00000000000000ASK WHERE { . "Ben Adida" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0025.xhtml000066400000000000000000000007771232323236500221340ustar00rootroot00000000000000 Test 0025

This paper was written by Ben Adida.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0026.sparql000066400000000000000000000001561232323236500222720ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0026.xhtml000066400000000000000000000006621232323236500221260ustar00rootroot00000000000000 Test 0026

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0027.sparql000066400000000000000000000001561232323236500222730ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0027.xhtml000066400000000000000000000007071232323236500221270ustar00rootroot00000000000000 Test 0027

Mark B.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0029.sparql000066400000000000000000000002151232323236500222710ustar00rootroot00000000000000ASK WHERE { "Mark Birbeck"^^ . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0029.xhtml000066400000000000000000000010001232323236500221140ustar00rootroot00000000000000 Test 0029

Mark Birbeck.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0030.sparql000066400000000000000000000002671232323236500222700ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0030.xhtml000066400000000000000000000007501232323236500221170ustar00rootroot00000000000000 Test 0030

This document is licensed under a Creative Commons License .

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0031.sparql000066400000000000000000000002421232323236500222620ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0031.xhtml000066400000000000000000000007411232323236500221200ustar00rootroot00000000000000 Test 0031

The book Weaving the Web (hardcover) has the ISBN 0752820907.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0032.sparql000066400000000000000000000002421232323236500222630ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0032.xhtml000066400000000000000000000010461232323236500221200ustar00rootroot00000000000000 Test 0032

The book Weaving the Web (hardcover) has the ISBN 0752820907.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0033.sparql000066400000000000000000000003171232323236500222670ustar00rootroot00000000000000ASK WHERE { ?a . ?a "Ben Adida" . FILTER isBlank(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0033.xhtml000066400000000000000000000007601232323236500221230ustar00rootroot00000000000000 Test 0033

This paper was written by Ben Adida.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0034.sparql000066400000000000000000000001701232323236500222650ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0034.xhtml000066400000000000000000000007411232323236500221230ustar00rootroot00000000000000 Test 0034
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0035.sparql000066400000000000000000000001701232323236500222660ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0035.xhtml000066400000000000000000000010531232323236500221210ustar00rootroot00000000000000 Test 0035
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0036.sparql000066400000000000000000000001701232323236500222670ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0036.xhtml000066400000000000000000000010571232323236500221260ustar00rootroot00000000000000 Test 0036
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0037.sparql000066400000000000000000000001641232323236500222730ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0037.xhtml000066400000000000000000000011401232323236500221200ustar00rootroot00000000000000 Test 0037
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0038.sparql000066400000000000000000000001741232323236500222750ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0038.xhtml000066400000000000000000000007451232323236500221330ustar00rootroot00000000000000 Test 0038
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0039.sparql000066400000000000000000000001741232323236500222760ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0039.xhtml000066400000000000000000000010571232323236500221310ustar00rootroot00000000000000 Test 0039
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0040.sparql000066400000000000000000000002201232323236500222560ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0040.xhtml000066400000000000000000000010051232323236500221120ustar00rootroot00000000000000 Test 0040
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0041.sparql000066400000000000000000000001701232323236500222630ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0041.xhtml000066400000000000000000000011441232323236500221170ustar00rootroot00000000000000 Test 0041
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0042.sparql000066400000000000000000000004201232323236500222620ustar00rootroot00000000000000# This test should result in a 'NO', i.e. no triples should be generated from the XHTML+RDFa input document. ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0042.xhtml000066400000000000000000000007031232323236500221200ustar00rootroot00000000000000 Test 0042
A photo depicting Michael
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0046.sparql000066400000000000000000000003571232323236500222770ustar00rootroot00000000000000ASK WHERE { ?a . ?a ?b . ?b "John Doe" . FILTER ( isBlank(?a) && isBlank(?b) ) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0046.xhtml000066400000000000000000000006341232323236500221270ustar00rootroot00000000000000 Test 0046

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0047.sparql000066400000000000000000000004171232323236500222750ustar00rootroot00000000000000ASK WHERE { ?a . ?a . "John Doe" . FILTER isBlank(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0047.xhtml000066400000000000000000000007021232323236500221240ustar00rootroot00000000000000 Test 0047

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0048.sparql000066400000000000000000000004151232323236500222740ustar00rootroot00000000000000ASK WHERE { . ?a . ?a "John Doe" . FILTER isBlank(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0048.xhtml000066400000000000000000000007011232323236500221240ustar00rootroot00000000000000 Test 0048

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0049.sparql000066400000000000000000000003161232323236500222750ustar00rootroot00000000000000ASK WHERE { "John Doe" . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0049.xhtml000066400000000000000000000006601232323236500221310ustar00rootroot00000000000000 Test 0049

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0050.sparql000066400000000000000000000002561232323236500222700ustar00rootroot00000000000000ASK WHERE { ?a "John Doe" . ?a . FILTER isBlank(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0050.xhtml000066400000000000000000000006151232323236500221210ustar00rootroot00000000000000 Test 0050

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0051.sparql000066400000000000000000000004571232323236500222740ustar00rootroot00000000000000ASK WHERE { . "John Doe" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0051.xhtml000066400000000000000000000006031232323236500221170ustar00rootroot00000000000000 Test 0051

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0052.sparql000066400000000000000000000002021232323236500222610ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0052.xhtml000066400000000000000000000006171232323236500221250ustar00rootroot00000000000000 Test 0052

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0053.sparql000066400000000000000000000003161232323236500222700ustar00rootroot00000000000000ASK WHERE { . "John Doe" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0053.xhtml000066400000000000000000000006611232323236500221250ustar00rootroot00000000000000 Test 0053

John Doe

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0054.sparql000066400000000000000000000004371232323236500222750ustar00rootroot00000000000000ASK WHERE { "Fabien Gandon" . "Fabien Gandon" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0054.xhtml000066400000000000000000000007041232323236500221240ustar00rootroot00000000000000 Test 0054

This document was authored and published by Fabien Gandon.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0055.sparql000066400000000000000000000005211232323236500222700ustar00rootroot00000000000000ASK WHERE { . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0055.xhtml000066400000000000000000000007441232323236500221310ustar00rootroot00000000000000 Test 0055

This document was authored and published by Fabien Gandon.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0056.sparql000066400000000000000000000004671232323236500223020ustar00rootroot00000000000000ASK WHERE { . . "Mark Birbeck" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0056.xhtml000066400000000000000000000007461232323236500221340ustar00rootroot00000000000000 Test 0056

Mark Birbeck

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0057.sparql000066400000000000000000000005641232323236500223010ustar00rootroot00000000000000ASK WHERE { . . "Mark Birbeck" . "Ivan Herman" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0057.xhtml000066400000000000000000000010441232323236500221250ustar00rootroot00000000000000 Test 0057

Mark Birbeck

Ivan Herman

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0058.sparql000066400000000000000000000007411232323236500222770ustar00rootroot00000000000000ASK WHERE { ?a . ?b . ?a . ?a "Mark Birbeck" . ?b . ?b "Ivan Herman" . FILTER ( isBlank(?a) && isBlank(?b) ) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0058.xhtml000066400000000000000000000010041232323236500221220ustar00rootroot00000000000000 Test 0058

Mark Birbeck

Ivan Herman

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0059.sparql000066400000000000000000000014271232323236500223020ustar00rootroot00000000000000ASK WHERE { . . . . "Manu Sporny" . "Fabien Gandon" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0059.xhtml000066400000000000000000000011721232323236500221310ustar00rootroot00000000000000 Test 0059

This document was authored and published by:

  • Manu Sporny
  • Fabien Gandon
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0060.sparql000066400000000000000000000003551232323236500222710ustar00rootroot00000000000000ASK WHERE { . "松本 后子" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0060.xhtml000066400000000000000000000007071232323236500221240ustar00rootroot00000000000000 Test 0060

松本 后子

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0061.sparql000066400000000000000000000003201232323236500222620ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0061.xhtml000066400000000000000000000006651232323236500221300ustar00rootroot00000000000000 Test 0061

This is the first chapter in a series of chapters.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0062.sparql000066400000000000000000000003201232323236500222630ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0062.xhtml000066400000000000000000000007121232323236500221220ustar00rootroot00000000000000 Test 0062

This is unit test #62. The next unit test is #63.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0063.sparql000066400000000000000000000003201232323236500222640ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0063.xhtml000066400000000000000000000006731232323236500221310ustar00rootroot00000000000000 Test 0063

This is the 63rd test. The next test is #64.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0064.sparql000066400000000000000000000001601232323236500222670ustar00rootroot00000000000000ASK WHERE { ?a . FILTER isBlank(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0064.xhtml000066400000000000000000000006651232323236500221330ustar00rootroot00000000000000 Test 0064

Michael knows Manu.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0065.sparql000066400000000000000000000003741232323236500222770ustar00rootroot00000000000000ASK WHERE { ?a . ?b . ?a ?b . FILTER ( isBlank(?a) && isBlank(?b) ) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0065.xhtml000066400000000000000000000012741232323236500221310ustar00rootroot00000000000000 Test 0065
Manu Sporny can be reached via email. He knows Michael.
Michael can be reached via email.
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0066.sparql000066400000000000000000000002621232323236500222740ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0066.xhtml000066400000000000000000000005571232323236500221350ustar00rootroot00000000000000 Test 0066

This is test #66.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0067.sparql000066400000000000000000000002111232323236500222670ustar00rootroot00000000000000ASK WHERE { "Test 0067" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0067.xhtml000066400000000000000000000005561232323236500221350ustar00rootroot00000000000000 Test 0067

This is test #67.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0068.sparql000066400000000000000000000002171232323236500222760ustar00rootroot00000000000000ASK WHERE { "Test 0067" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0068.xhtml000066400000000000000000000006711232323236500221340ustar00rootroot00000000000000 Test 0068

The previous test was Test 0067.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0069.sparql000066400000000000000000000003201232323236500222720ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0069.xhtml000066400000000000000000000006761232323236500221420ustar00rootroot00000000000000 Test 0069

The next test will be .

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0070.sparql000066400000000000000000000003201232323236500222620ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0070.xhtml000066400000000000000000000006261232323236500221250ustar00rootroot00000000000000 Test 0070

The previous test was .

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0071.sparql000066400000000000000000000002641232323236500222720ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0071.xhtml000066400000000000000000000010411232323236500221160ustar00rootroot00000000000000 Test 0071

This page is under a Creative Commons Attribution-No Derivatives 3.0 license.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0072.sparql000066400000000000000000000001431232323236500222670ustar00rootroot00000000000000ASK WHERE { "Example FAQ" . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0072.xhtml000066400000000000000000000010151232323236500221200ustar00rootroot00000000000000 Test 0072

Learn more by reading the example.org Example FAQ.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0073.sparql000066400000000000000000000001621232323236500222710ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0073.xhtml000066400000000000000000000007721232323236500221320ustar00rootroot00000000000000 Test 0073

This article was written by Jane.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0074.sparql000066400000000000000000000001621232323236500222720ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0074.xhtml000066400000000000000000000007521232323236500221310ustar00rootroot00000000000000 Test 0074

This article was written by Jane.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0075.sparql000066400000000000000000000002101232323236500222650ustar00rootroot00000000000000ASK WHERE { . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0075.xhtml000066400000000000000000000010761232323236500221320ustar00rootroot00000000000000 Test 0075

This page is under a Creative Commons Attribution-No Derivatives 3.0 license.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0076.sparql000066400000000000000000000071131232323236500222770ustar00rootroot00000000000000 ASK WHERE { . . . . . . . . . . . . . . . . . . . . . . . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0076.xhtml000066400000000000000000000035521232323236500221340ustar00rootroot00000000000000 Test 0076

alternate appendix bookmark cite chapter contents copyright glossary help index last license meta p3pv1 role section subsection start stylesheet up

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0077.sparql000066400000000000000000000071111232323236500222760ustar00rootroot00000000000000ASK WHERE { . . . . . . . . . . . . . . . . . . . . . . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0077.xhtml000066400000000000000000000054101232323236500221300ustar00rootroot00000000000000 Test 0077

alternate appendix bookmark cite chapter contents copyright glossary help icon index last license meta next p3pv1 prev role section subsection start stylesheet up

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0078.sparql000066400000000000000000000005441232323236500223020ustar00rootroot00000000000000ASK WHERE { [ "Ivan Herman"; ], [ ; "Mark Birbeck" ] . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0078.xhtml000066400000000000000000000010751232323236500221340ustar00rootroot00000000000000 Test 0078

Ivan Herman

mailto:ivan@w3.org

Mark Birbeck

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0079.sparql000066400000000000000000000003361232323236500223020ustar00rootroot00000000000000ASK WHERE { , , . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0079.xhtml000066400000000000000000000012201232323236500221250ustar00rootroot00000000000000 Test 0079

Ivan Herman

Tim Berners Lee

Dan Brickley

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0080.sparql000066400000000000000000000001751232323236500222730ustar00rootroot00000000000000ASK WHERE { . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0080.xhtml000066400000000000000000000007641232323236500221310ustar00rootroot00000000000000 Test 0080

Dan Brickley

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0081.sparql000066400000000000000000000007201232323236500222700ustar00rootroot00000000000000ASK WHERE { ?a . ?a . ?a "Ivan Herman" . ?b . ?b . ?b "Mark Birbeck" . FILTER ( isBlank(?a) && isBlank(?b) ) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0081.xhtml000066400000000000000000000010711232323236500221220ustar00rootroot00000000000000 Test 0081

Ivan Herman

mailto:ivan@w3.org

Mark Birbeck

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0082.sparql000066400000000000000000000011501232323236500222670ustar00rootroot00000000000000ASK WHERE { ?a . ?b . ?a . ?a . ?a "Ivan Herman" . ?b . ?b . ?b "Mark Birbeck" . FILTER ( isBlank(?a) && isBlank(?b) ) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0082.xhtml000066400000000000000000000011121232323236500221170ustar00rootroot00000000000000 Test 0082

Ivan Herman

mailto:ivan@w3.org

Mark Birbeck

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0083.sparql000066400000000000000000000010511232323236500222700ustar00rootroot00000000000000ASK WHERE { ?a . . ?a "Ivan Herman" . ?a . . "Dan Brickley" . FILTER isBlank(?a) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0083.xhtml000066400000000000000000000011421232323236500221230ustar00rootroot00000000000000 Test 0083

Ivan Herman

mailto:ivan@w3.org

Dan Brickley

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0084.sparql000066400000000000000000000013321232323236500222730ustar00rootroot00000000000000ASK WHERE { ?a . . ?a . ?a . ?a "Ivan Herman" . . . "Dan Brickley" . FILTER isBlank(?a) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0084.xhtml000066400000000000000000000012171232323236500221270ustar00rootroot00000000000000 Test 0084

Ivan Herman

mailto:ivan@w3.org

Dan Brickley

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0085.sparql000066400000000000000000000004101232323236500222700ustar00rootroot00000000000000ASK WHERE { _:a. _:a , , . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0085.xhtml000066400000000000000000000012651232323236500221330ustar00rootroot00000000000000 Test 0085

Ivan Herman

Tim Berners Lee

Dan Brickley

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0086.sparql000066400000000000000000000003011232323236500222700ustar00rootroot00000000000000# This test should result in a 'NO', i.e. no triples should be generated from the XHTML+RDFa input document. ASK WHERE { ?undefprop . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0086.xhtml000066400000000000000000000006641232323236500221360ustar00rootroot00000000000000 Test 0086

mailto:ivan@w3.org

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0087.sparql000066400000000000000000000071031232323236500223000ustar00rootroot00000000000000ASK WHERE { . . . . . . . . . . . . . . . . . . . . . . . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0087.xhtml000066400000000000000000000036071232323236500221370ustar00rootroot00000000000000 Test 0087

alternate appendix bookmark cite chapter contents copyright glossary help icon index last license meta next p3pv1 prev role section subsection start stylesheet up

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0088.sparql000066400000000000000000000003761232323236500223060ustar00rootroot00000000000000ASK WHERE { ?a . ?a . ?a "Dan Brickley" . FILTER isBlank(?a) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0088.xhtml000066400000000000000000000007761232323236500221440ustar00rootroot00000000000000 Test 0088

Dan Brickley

Dan Brickley again:-)

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0089.sparql000066400000000000000000000002061232323236500222770ustar00rootroot00000000000000ASK WHERE { . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0089.xhtml000066400000000000000000000007311232323236500221340ustar00rootroot00000000000000 Test 0089
example image
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0090.sparql000066400000000000000000000002231232323236500222660ustar00rootroot00000000000000ASK WHERE { . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0090.xhtml000066400000000000000000000010431232323236500221210ustar00rootroot00000000000000 Test 0090
example image
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0091.sparql000066400000000000000000000003521232323236500222720ustar00rootroot00000000000000ASK WHERE { ?a "a bi-pedal primate" . ?a "confused animal" . ?a "Milky Way" . FILTER isBlank(?a) } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0091.xhtml000066400000000000000000000011271232323236500221250ustar00rootroot00000000000000 Test 0091

A human is a bi-pedal primate. They are quite possibly one of the most confused animals residing in the Milky Way.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0092.sparql000066400000000000000000000021451232323236500222750ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { "Albert Einstein" . { "E = mc2: The Most Urgent Problem of Our Time"^^ . } UNION { "E = mc2: The Most Urgent Problem of Our Time"^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0092.xhtml000066400000000000000000000011541232323236500221260ustar00rootroot00000000000000 Test 0092
Author: Albert Einstein

E = mc2: The Most Urgent Problem of Our Time

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0093.sparql000066400000000000000000000005411232323236500222740ustar00rootroot00000000000000ASK WHERE { "Albert Einstein" . "E = mc2: The Most Urgent Problem of Our Time"^^ . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0093.xhtml000066400000000000000000000011271232323236500221270ustar00rootroot00000000000000 Test 0093
Author: Albert Einstein

E = mc2: The Most Urgent Problem of Our Time

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0094.sparql000066400000000000000000000021441232323236500222760ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { "Albert Einstein" . { "E = mc2: The Most Urgent Problem of Our Time"^^ . } UNION { "E = mc2: The Most Urgent Problem of Our Time"^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0094.xhtml000066400000000000000000000011611232323236500221260ustar00rootroot00000000000000 Test 0094
Author: Albert Einstein

E = mc2: The Most Urgent Problem of Our Time

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0099.sparql000066400000000000000000000011761232323236500223070ustar00rootroot00000000000000ASK WHERE { "\n We put thirty spokes together and call it a wheel;\n But it is on the space where there is nothing that the usefulness of the wheel depends.\n We turn clay to make a vessel;\n But it is on the space where there is nothing that the usefulness of the vessel depends.\n We pierce doors and windows to make a house;\n And it is on these spaces where there is nothing that the usefulness of the house depends.\n Therefore just as we take advantage of what is, we should recognize the usefulness of what is not.\n\n Lao Tzu: Tao Te Ching" . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0099.xhtml000066400000000000000000000017151232323236500221400ustar00rootroot00000000000000 Test 0099

We put thirty spokes together and call it a wheel; But it is on the space where there is nothing that the usefulness of the wheel depends. We turn clay to make a vessel; But it is on the space where there is nothing that the usefulness of the vessel depends. We pierce doors and windows to make a house; And it is on these spaces where there is nothing that the usefulness of the house depends. Therefore just as we take advantage of what is, we should recognize the usefulness of what is not. Lao Tzu: Tao Te Ching

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0100.sparql000066400000000000000000000025441232323236500222660ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { { "Some text here in bold and an svg rectangle: "^^ . } UNION { "Some text here in bold and an svg rectangle: "^^ . } } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0100.xhtml000066400000000000000000000013731232323236500221170ustar00rootroot00000000000000 Test 0100

Some text here in bold and an svg rectangle:

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0101.sparql000066400000000000000000000026421232323236500222660ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { { "Du texte ici en gras et un rectangle en svg: "^^ . } UNION { "Du texte ici en gras et un rectangle en svg: "^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0101.xhtml000066400000000000000000000014111232323236500221110ustar00rootroot00000000000000 Test 0101

Du texte ici en gras et un rectangle en svg:

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0102.sparql000066400000000000000000000026121232323236500222640ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { { "Du texte ici en gras et un rectangle en svg: "^^ . } UNION { "Du texte ici en gras et un rectangle en svg: "^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0102.xhtml000066400000000000000000000014271232323236500221210ustar00rootroot00000000000000 Test 0102

Du texte ici en gras et un rectangle en svg:

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0103.sparql000066400000000000000000000023311232323236500222630ustar00rootroot00000000000000# Some parsers may generate XML Literals that differ from the ones # shown below. The only requirement for XML Literal tests is that # the RDF graph that is generated is equivalent to the one expressed # in the XHTML (preservation of whitespace and namespaces that are # utilized in the XML Literal). ASK WHERE { { "Some text here in bold and an svg rectangle: "^^ . } UNION { "Some text here in bold and an svg rectangle: "^^ . } }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0103.xhtml000066400000000000000000000013401232323236500221140ustar00rootroot00000000000000 Test 0103

Some text here in bold and an svg rectangle:

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0104.sparql000066400000000000000000000004041232323236500222630ustar00rootroot00000000000000ASK WHERE { _:a . _:a "17" . _:a "character" . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0104.xhtml000066400000000000000000000012051232323236500221150ustar00rootroot00000000000000 Test 0104

The word "interfenestration" has 17 characters.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0105.sparql000066400000000000000000000004351232323236500222700ustar00rootroot00000000000000ASK WHERE { ?a . OPTIONAL { ?x ?y . } FILTER (ISBLANK(?a) && !BOUND(?x) && !BOUND(?y)) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0105.xhtml000066400000000000000000000006661232323236500221300ustar00rootroot00000000000000 Test 0105
Ben created this page.
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0106.sparql000066400000000000000000000004371232323236500222730ustar00rootroot00000000000000ASK WHERE { ?a . OPTIONAL { ?x ?y . } FILTER (ISBLANK(?a) && !BOUND(?x) && !BOUND(?y)) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0106.xhtml000066400000000000000000000006551232323236500221270ustar00rootroot00000000000000 Test 0106
Manu created this page.
rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0107.sparql000066400000000000000000000003661232323236500222750ustar00rootroot00000000000000# This test should result in a 'NO', i.e. no triples should be generated from the XHTML+RDFa input document. ASK WHERE { ?a . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0107.xhtml000066400000000000000000000005111232323236500221170ustar00rootroot00000000000000 Test 0107 rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0108.sparql000066400000000000000000000002001232323236500222610ustar00rootroot00000000000000ASK WHERE { "ελληνικό\nάσπρο διάστημα\n"@el . }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0108.xhtml000066400000000000000000000007041232323236500221240ustar00rootroot00000000000000 Test 0108

ελληνικό άσπρο διάστημα

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0109.sparql000066400000000000000000000002211232323236500222650ustar00rootroot00000000000000ASK WHERE { "Test 0109" . } rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0109.xhtml000066400000000000000000000010741232323236500221260ustar00rootroot00000000000000 Test 0109

This is Test 0109.

rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0110.sparql000066400000000000000000000002341232323236500222610ustar00rootroot00000000000000ASK WHERE { ?a . FILTER ISBLANK(?a) }rdflib-4.1.2/test/rdfa/w3c_rdfa_testsuite/0110.xhtml000066400000000000000000000005021232323236500221110ustar00rootroot00000000000000 Test 0110