summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Herman <ivan@ivan-herman.net>2014-12-08 12:53:28 +0100
committerIvan Herman <ivan@ivan-herman.net>2014-12-08 12:53:28 +0100
commitb082c4851840f4c2c83910f84331fb07fca16f4c (patch)
treeb73b000661b528f2ce1f41d8e66c275931169c51
parentf21e62d2cc6406870685faaeeffc0ef2afc1a499 (diff)
downloadrdflib-microdata-to-rdf-second-edition-bak.tar.gz
Microdata parser: updated the parser to the latest version of the microdata->rdf note (published in December 2014)microdata-to-rdf-second-edition-bak
-rw-r--r--rdflib/plugins/parsers/pyMicrodata/__init__.py136
-rw-r--r--rdflib/plugins/parsers/pyMicrodata/microdata.py523
-rw-r--r--rdflib/plugins/parsers/pyMicrodata/registry.py112
-rw-r--r--rdflib/plugins/parsers/pyMicrodata/utils.py73
-rw-r--r--rdflib/plugins/parsers/structureddata.py32
5 files changed, 306 insertions, 570 deletions
diff --git a/rdflib/plugins/parsers/pyMicrodata/__init__.py b/rdflib/plugins/parsers/pyMicrodata/__init__.py
index 58fd29d0..2d8c8ccd 100644
--- a/rdflib/plugins/parsers/pyMicrodata/__init__.py
+++ b/rdflib/plugins/parsers/pyMicrodata/__init__.py
@@ -48,14 +48,13 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-__version__ = "1.2"
+__version__ = "2.0"
__author__ = 'Ivan Herman'
__contact__ = 'Ivan Herman, ivan@w3.org'
import sys
import datetime
-import os
import rdflib
from rdflib import URIRef
@@ -92,7 +91,7 @@ class MicrodataError(Exception) :
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."""
@@ -105,19 +104,15 @@ class HTTPError(MicrodataError) :
# 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#',
+ 'xsd' : 'http://www.w3.org/2001/XMLSchema#'
}
#########################################################################################################
@@ -126,65 +121,64 @@ class pyMicrodata :
@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) :
+ def __init__(self, base = "") :
"""
@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 :
+ if pgraph is 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#' )
+
+ 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 :
+
+ if uri is not 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:
+ 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 is not 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)) )
+ 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)
+ be, supposedly, 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
"""
- isstring = isinstance(name, string_types)
+ 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
@@ -194,11 +188,11 @@ class pyMicrodata :
self.base = url_request.location
return url_request.data
else :
- self.base = 'file://'+name
- return open(name, 'rb')
+ self.base = name
+ return file(name)
else :
return name
-
+
####################################################################################################################
# Externally used methods
#
@@ -212,23 +206,19 @@ class pyMicrodata :
@return: an RDF Graph
@rtype: rdflib Graph instance
"""
- if graph == None :
+ if graph is None :
# Create the RDF Graph, that will contain the return triples...
- graph = Graph()
+ graph = Graph()
- conversion = MicrodataConversion(dom.documentElement,
- graph,
- base = self.base,
- vocab_expansion = self.vocab_expansion,
- vocab_cache = self.vocab_cache)
+ conversion = MicrodataConversion(dom.documentElement, graph, base = self.base)
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
@@ -250,7 +240,7 @@ class pyMicrodata :
self.http_status = 500
if not rdfOutput : raise e
return self._generate_error_graph(graph, str(e), uri=name)
-
+
dom = None
try :
import warnings
@@ -267,7 +257,7 @@ class pyMicrodata :
e = sys.exc_info()[1]
self.http_status = 400
if not rdfOutput : raise e
- return self._generate_error_graph(graph, str(e), uri=name)
+ return self._generate_error_graph(graph, str(e), uri=name)
except Exception :
# Something nasty happened:-(
@@ -278,8 +268,8 @@ class pyMicrodata :
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) :
+
+ 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.
@@ -295,14 +285,14 @@ class pyMicrodata :
graph = Graph()
for prefix in _bindings :
- graph.bind(prefix,Namespace(_bindings[prefix]))
+ 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) :
+ 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.
@@ -318,7 +308,7 @@ 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
@@ -328,39 +318,25 @@ def processURI(uri, outputFormat, form) :
@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 = ""
+ input = form["uploaded"].file
+ base = ""
elif uri == "text:" :
- input = StringIO(form.getfirst("text"))
- base = ""
+ 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)
+ input = uri
+ base = uri
- processor = pyMicrodata(base = base, vocab_expansion = vocab_expansion, vocab_cache = vocab_cache)
+ processor = pyMicrodata(base = base)
# 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.
+ # decide whether HTML or RDF should be sent.
htmlOutput = False
+ #import os
#if 'HTTP_ACCEPT' in os.environ :
# acc = os.environ['HTTP_ACCEPT']
# possibilities = ['text/html',
@@ -393,7 +369,7 @@ def processURI(uri, outputFormat, form) :
import cgi
h = sys.exc_info()[1]
retval = 'Content-type: text/html; charset=utf-8\nStatus: %s \n\n' % h.http_code
- retval += "<html>\n"
+ retval += "<html>\n"
retval += "<head>\n"
retval += "<title>HTTP Error in Microdata processing</title>\n"
retval += "</head><body>\n"
@@ -411,7 +387,7 @@ def processURI(uri, outputFormat, form) :
import traceback, cgi
retval = 'Content-type: text/html; charset=utf-8\nStatus: %s\n\n' % processor.http_status
- retval += "<html>\n"
+ retval += "<html>\n"
retval += "<head>\n"
retval += "<title>Exception in Microdata processing</title>\n"
retval += "</head><body>\n"
@@ -424,7 +400,7 @@ def processURI(uri, outputFormat, form) :
retval +="<pre>%s</pre>\n" % value
retval +="<h1>Distiller request details</h1>\n"
retval +="<dl>\n"
- if uri == "text:" and "text" in form and form["text"].value != None and len(form["text"].value.strip()) != 0 :
+ if uri == "text:" and "text" in form and form["text"].value is not None and len(form["text"].value.strip()) != 0 :
retval +="<dt>Text input:</dt><dd>%s</dd>\n" % cgi.escape(form["text"].value).replace('\n','<br/>')
elif uri == "uploaded:" :
retval +="<dt>Uploaded file</dt>\n"
diff --git a/rdflib/plugins/parsers/pyMicrodata/microdata.py b/rdflib/plugins/parsers/pyMicrodata/microdata.py
index a783839c..611585cd 100644
--- a/rdflib/plugins/parsers/pyMicrodata/microdata.py
+++ b/rdflib/plugins/parsers/pyMicrodata/microdata.py
@@ -34,41 +34,26 @@ 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
from rdflib import XSD as ns_xsd
else :
- from rdflib.Graph import Graph
- from rdflib.RDFS import RDFSNS as ns_rdfs
- from rdflib.Literal import _XSD_NS as ns_xsd
from rdflib.RDF import RDFNS as ns_rdf
+ from rdflib.Literal import _XSD_NS as ns_xsd
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_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 :
+
+class EvaluationContext :
"""
- Evaluation context structure. See Section 4.1 of the U{W3C IG Note<http://www.w3.org/TR/microdata-rdf/>}for the details.
+ Evaluation context structure. See Section 6.1 of the U{W3C IG Note<http://www.w3.org/TR/microdata-rdf/>}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
@@ -76,13 +61,13 @@ class Evaluation_Context :
@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 ) :
+ def __init__(self) :
self.current_type = None
self.memory = {}
self.current_name = None
self.current_vocabulary = None
- def get_memory( self, item ) :
+ 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
@@ -94,7 +79,7 @@ class Evaluation_Context :
else :
return None
- def set_memory( self, item, subject ) :
+ def set_memory(self, item, subject) :
"""
Set the memory content, ie, the subject, for 'item'.
@param item: an 'item', in microdata terminology
@@ -113,7 +98,7 @@ class Evaluation_Context :
@param itype : an absolute URL for the current type
@return: a new evaluation context instance
"""
- retval = Evaluation_Context()
+ retval = EvaluationContext()
for k in self.memory :
retval.memory[k] = self.memory[k]
@@ -130,23 +115,22 @@ class Evaluation_Context :
retval += " memory: %s\n" % self.memory
retval += "----\n"
return retval
-
+
+
class Microdata :
"""
- This class encapsulates methods that are defined by the U{microdata spec<http://dev.w3.org/html5/md/Overview.html>},
+ This class encapsulates methods that are defined by the U{microdata spec<http://www.w3.org/TR/microdata/>},
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) :
+ 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
@@ -158,14 +142,14 @@ class Microdata :
# 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 ) :
+ 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.
+ A top level item is and element that has the @itemscope set, but no @itemtype. They are
+ collected in pre-order and depth-first fashion.
@return: list of items (ie, DOM Nodes)
"""
- def collect_items( node ) :
+ def collect_items(node) :
items = []
for child in node.childNodes :
if child.nodeType == node.ELEMENT_NODE :
@@ -177,29 +161,29 @@ class Microdata :
return items
- return collect_items( self.document )
-
- def get_item_properties( self, item ) :
+ 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.
+ Collect the item's properties, ie, all DOM descendant 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
+ # probably the ugliest stuff around!
# 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 ]
-
+ memory = [item]
+ pending = [child for child in item.childNodes if child.nodeType == item.ELEMENT_NODE]
+
+ # Add the possible "@itemref" targets to the nodes to work on
if item.hasAttribute("itemref") :
- for id in item.getAttribute("itemref").strip().split() :
- obj = self.getElementById(id)
- if obj != None : pending.append(obj)
+ for it in item.getAttribute("itemref").strip().split() :
+ obj = self.getElementById(it)
+ if obj is not None : pending.append(obj)
while len(pending) > 0 :
current = pending.pop(0)
@@ -213,10 +197,12 @@ class Microdata :
# @itemscope is the barrier...
if not current.hasAttribute("itemscope") :
- pending = [ child for child in current.childNodes if child.nodeType == child.ELEMENT_NODE ] + pending
+ 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)
+ elif current.hasAttribute("itemprop-reverse") and current.getAttribute("itemprop-reverse").strip() != "" :
+ results.append(current)
return results
@@ -225,24 +211,25 @@ class Microdata :
@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 = []
+ def collect_ids(node) :
+ lids = []
for child in node.childNodes :
if child.nodeType == node.ELEMENT_NODE :
- ids += collect_ids( child )
+ lids += collect_ids(child)
if node.hasAttribute("id") and node.getAttribute("id") == id :
# This is also a top level item
- ids.append(node)
+ lids.append(node)
- return ids
+ return lids
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.
@@ -250,42 +237,23 @@ class MicrodataConversion(Microdata) :
@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
+ @ivar subs: dictionary mapping predicates to possible superproperties
+ @ivar bnodes: dictionary mapping items to bnodes (to be used when an item is the target of an @itemref)
"""
- def __init__( self, document, graph, base = None, vocab_expansion = False, vocab_cache = True ) :
+ def __init__(self, document, graph, base = None) :
"""
@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
+ self.graph = graph
+ self.subs = {}
+ self.bnodes = {}
# 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 )
@@ -296,241 +264,210 @@ class MicrodataConversion(Microdata) :
# 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 ) :
+ # This is put in a debug branch; in general, the RDFLib Turtle serializer adds all the
+ # namespace declarations, which can be a bit of a problem for reading the results...
+
+ # 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.
+ and generates triples for each of them.
"""
- 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.
+ self.generate_triples(top_level_item, EvaluationContext())
- # 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 ) :
+ 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}
+ @type context: L{EvaluationContext}
@return: a URIRef or a BNode for the (RDF) subject
"""
+ def _get_predicate_object(prop, name, item_type) :
+ """
+ Generate the predicate and the object for an item that contains either "itemprop" or "itemprop-reverse".
+ Steps 9.1.1 to 9.1.3 of the processing steps
+
+ @param prop: the item that should produce a predicate
+ @type prop: a DOM Node for an element
+ @param name: an itemprop or itemprop-reverse item
+ @type name: string
+ @param item_type: the type of the item; necessary for the creation of a new context
+ @type item_type: a string with the absolute URI of the type
+ @return: a tuple consisting of the predicate (URI) and the object for the triple to be generated
+ """
+ # 9.1.1. set a new context
+ new_context = context.new_copy(item_type)
+ # 9.1.2, generate the URI for the property name, that will be the predicate
+ # Also update the context
+ # Note that the method also checks, and stores, the possible superproperty/equivalent property values
+ new_context.current_name = predicate = self.generate_predicate_URI(name, new_context)
+ # 9.1.3, generate the property value. The extra flag signals that the value is a new item
+ # Note that 9.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)
+ # Note that the value may be None (e.g, for an <img> element without a @src), in which case nothing
+ # is generated
+ value = self.get_property_value(prop, new_context)
+ return (predicate, value)
+
# Step 1,2: if the subject has to be set, store it in memory
- subject = context.get_memory( item )
- if subject == None :
+ subject = context.get_memory(item)
+
+ if subject is 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() )
+ if item.hasAttribute("itemid") :
+ subject = URIRef(generate_URI(self.base, item.getAttribute("itemid").strip()))
else :
- subject = BNode()
- context.set_memory( item, subject )
+ if item in self.bnodes :
+ subject = self.bnodes[item]
+ else :
+ subject = BNode()
+ self.bnodes[item] = subject
+ 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)) )
+ 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
+ # Step 4, 5 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 :
+ elif context.current_type is not None :
itype = context.current_type
else :
itype = None
- # Step 7, 8, 9: Check the registry for possible keys and set the vocab
+ # Step 6, 7: Check the registry for possible keys and set the vocab
vocab = None
- if itype != None :
+ if itype is not 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 :
+ # The registry has not set the vocabulary; it has to be extracted from the type
+ if vocab is None :
parsed = urlsplit(itype)
if parsed.fragment != "" :
- vocab = urlunsplit( (parsed.scheme,parsed.netloc,parsed.path,parsed.query,"") ) + '#'
+ 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] + '/'
+ vocab = itype.rsplit('/', 1)[0] + '/'
- # Step 9: update vocab in the context
- if vocab != None :
+ # Step 8: update vocab in the context
+ if vocab is not 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.
+ # Step 9: Get the item properties and run a cycle on those
# 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
+ # Steps 9.1.1 to 9.1.3 are done in a separate function
+ (predicate, value) = _get_predicate_object(prop, name, itype)
+ if value is None : continue
+ # 9.1.5, generate the triple
+ self.graph.add((subject, URIRef(predicate), value))
+ # 9.1.6, take care of the possible subProperty/equivalentProperty
+ if name in self.subs and self.subs[name] is not None :
+ for sup in self.subs[name] :
+ self.graph.add((subject, sup, value))
+
+ # Step 10: Almost identical to step 9, except for itemprop-reverse
+ # The only difference is that a Literal value must be ignored
+ for prop in self.get_item_properties(item) :
+ for name in prop.getAttribute("itemprop-reverse").strip().split() :
+ # Steps 9.1.1 to 9.1.3 are done in a separate function
+ (predicate, value) = _get_predicate_object(prop, name, itype)
+ if value is None or isinstance(value, Literal) :
+ continue
+ # 9.1.5, generate the triple
+ self.graph.add((value, URIRef(predicate), subject))
+ # 9.1.6, take care of the possible subProperty/equivalentProperty
+ if name in self.subs and self.subs[name] is not None :
+ for sup in self.subs[name] :
+ self.graph.add((value, sup, subject))
+
+ # Step 11: return the subject to the caller
return subject
- def generate_predicate_URI( self, name, context ) :
+ 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}
+ @type context: L{EvaluationContext}
"""
- if debug: print( "name: %s, %s" % (name,context) )
-
+ def add_to_subs(subpr) :
+ if subpr is not None :
+ if isinstance(subpr,list) :
+ self.subs[name] = []
+ for p in subpr :
+ self.subs[name].append(URIRef(p))
+ else :
+ self.subs[name] = [URIRef(subpr)]
+
# 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 context.current_type is None and context.current_vocabulary is 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)
+ # Extract the possible subproperty/equivalentProperty relations on the fly
+ # see if there are subproperty/equivalentProperty relations
+ if name not in self.subs :
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)) )
+ vocab_mapping = registry[context.current_vocabulary]["properties"][name]
+ for rel in ["subPropertyOf", "equivalentProperty"] :
+ if rel in vocab_mapping :
+ add_to_subs(vocab_mapping[rel])
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
+ # no harm done, no extra vocabulary term
+ self.subs[name] = None
+ else :
+ self.subs[name] = None
+ escaped_name = fragment_escape(name)
+ if context.current_vocabulary[-1] == '#' or context.current_vocabulary[-1] == '/' :
+ return context.current_vocabulary + escaped_name
+ else :
+ return context.current_vocabulary + '#' + escaped_name
- 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
@@ -539,42 +476,53 @@ class MicrodataConversion(Microdata) :
object.
Otherwise, either URIRefs are created for <a>, <img>, etc, elements, or a Literal; the latter
- gets a time-related type for the <time> element.
+ gets a time-related type for the <time> element, and possible numeric types for the @value
+ attribute of the <meter> and <data> elements.
@param node: the DOM Node for which the property values should be generated
@type node: DOM Node
@param context: an instance of an evaluation context
- @type context: L{Evaluation_Context}
+ @type context: L{EvaluationContext}
@return: an RDF resource (URIRef, BNode, or Literal)
"""
URI_attrs = {
+ "a" : "href",
"audio" : "src",
+ "area" : "href",
"embed" : "src",
"iframe" : "src",
"img" : "src",
+ "link" : "href",
+ "object" : "data",
"source" : "src",
"track" : "src",
- "video" : "src",
- "data" : "src",
- "a" : "href",
- "area" : "href",
- "link" : "href",
- "object" : "data"
+ "video" : "src"
}
- lang = get_lang_from_hierarchy( self.document, node )
+ lang = get_lang_from_hierarchy(self.document, node)
if node.hasAttribute("itemscope") :
# THIS IS A RECURSION ENTRY POINT!
- return self.generate_triples( node, context )
+ return self.generate_triples(node, context)
- elif node.tagName in URI_attrs and node.hasAttribute(URI_attrs[node.tagName]) :
- return URIRef( generate_URI( self.base, node.getAttribute(URI_attrs[node.tagName]).strip() ) )
+ elif node.tagName in URI_attrs :
+ if node.hasAttribute(URI_attrs[node.tagName]) :
+ return URIRef(generate_URI(self.base, node.getAttribute(URI_attrs[node.tagName]).strip()))
+ else :
+ return None
elif node.tagName == "meta" and node.hasAttribute("content") :
if lang :
- return Literal( node.getAttribute("content"), lang = lang )
+ return Literal(node.getAttribute("content"), lang = lang)
+ else :
+ return Literal(node.getAttribute("content"))
+
+ elif node.tagName == "time" and node.hasAttribute("datetime") :
+ litval = node.getAttribute("datetime")
+ dtype = get_time_type(litval)
+ if dtype :
+ return Literal(litval, datatype = dtype)
else :
- return Literal( node.getAttribute("content") )
+ return Literal(litval)
elif node.tagName == "meter" or node.tagName == "data" :
if node.hasAttribute("value") :
@@ -582,82 +530,21 @@ class MicrodataConversion(Microdata) :
# check whether the attribute value can be defined as a float or an integer
try :
fval = int(val)
- dt = ns_xsd["integer"]
+ return Literal(val, datatype = ns_xsd["integer"])
except :
- # Well, not an int, try then a integer
+ # Well, not an int, try then a float
try :
fval = float(val)
- dt = ns_xsd["float"]
+ return Literal(val, datatype = ns_xsd["double"])
except :
# Sigh, this is not a valid value, but let it go through as a plain literal nevertheless
- fval = val
- dt = None
- if dt :
- return Literal( val, datatype = dt)
- else :
- return Literal( val )
+ return Literal(val)
else :
- return Literal( "" )
-
- elif node.tagName == "time" and node.hasAttribute("datetime") :
- litval = node.getAttribute("datetime")
- dtype = get_time_type(litval)
- if dtype :
- return Literal( litval, datatype = dtype )
- else :
- return Literal( litval )
+ return Literal("")
else :
if lang :
- return Literal( get_Literal(node), lang = lang )
+ return Literal(get_Literal(node), lang = lang)
else :
- return Literal( get_Literal(node) )
-
- def generate_property_values( self, subject, predicate, objects, context) :
- """
- Generate the property values for a specific subject and predicate. The context should specify whether
- the objects should be added in an RDF list or each triples individually.
-
- @param subject: RDF subject
- @type subject: RDFLib Node (URIRef or blank node)
- @param predicate: RDF predicate
- @type predicate: RDFLib URIRef
- @param objects: RDF objects
- @type objects: list of RDFLib nodes (URIRefs, Blank Nodes, or literals)
- @param context: evaluation context
- @type context: L{Evaluation_Context}
- """
- # generate triples with a list, or a bunch of triples, depending on the context
- # The biggest complication is to find the method...
- method = ValueMethod.unordered
- superproperties = None
-
- # This is necessary because predicate is a URIRef, and I am not sure the comparisons would work well
- # to be tested, in fact...
- pred_key = "%s" % predicate
- for key in registry :
- if predicate.startswith(key) :
- # This the part of the registry corresponding to the predicate's vocabulary
- registry_object = registry[key]
- try :
- if "multipleValues" in registry_object : method = registry_object["multipleValues"]
- # The generic definition can be overwritten for a specific property. The simplest is to rely on a 'try'
- # with the right structure...
- try :
- method = registry_object["properties"][pred_key[len(key):]]["multipleValues"]
- except :
- pass
- except :
- pass
-
- if method == ValueMethod.unordered :
- for object in objects :
- self.graph.add( (subject, predicate, object) )
- else :
- self.graph.add( (subject,predicate,generate_RDF_collection( self.graph, objects )) )
-
-
-
-
-
+ return Literal(get_Literal(node))
diff --git a/rdflib/plugins/parsers/pyMicrodata/registry.py b/rdflib/plugins/parsers/pyMicrodata/registry.py
index 22cec0ac..2e830eed 100644
--- a/rdflib/plugins/parsers/pyMicrodata/registry.py
+++ b/rdflib/plugins/parsers/pyMicrodata/registry.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
"""
-Hardcoded version of the current microdata->RDF registry. There is also a local registry to include some test cases.
-Finally, there is a local dictionary for prefix mapping for the registry items; these are the preferred prefixes
+Hardcoded version of the current microdata->RDF registry.
+There is also a local dictionary for prefix mapping for the registry items; these are the preferred prefixes
for those vocabularies, and are used to make the output nicer.
@organization: U{World Wide Web Consortium<http://www.w3.org>}
@@ -12,124 +12,34 @@ U{W3C® SOFTWARE NOTICE AND LICENSE<href="http://www.w3.org/Consortium/Legal/200
"""
"""
-$Id: registry.py,v 1.5 2012/09/05 16:40:43 ivan Exp $
-$Date: 2012/09/05 16:40:43 $
+$Id: registry.py,v 1.6 2012-12-01 22:46:57 ivan Exp $
+$Date: 2012-12-01 22:46:57 $
"""
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"}
+ "additionalType": {"subPropertyOf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
}
},
- "http://microformats.org/profile/hcard": {
- "propertyURI": "vocabulary",
- "multipleValues": "unordered"
- },
- "http://microformats.org/profile/hcalendar#": {
- "propertyURI": "vocabulary",
- "multipleValues": "unordered",
- "properties": {
- "categories": {"multipleValues": "list"}
- }
- }
+
+ "http://microformats.org/profile/hcard": {}
}
"""
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"
- }
+ "http://microformats.org/profile/hcard#" : "hcard"
}
-"""
-
-registry = []
-myRegistry = []
+registry = []
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)
+ registry = json.loads(_registry)
else :
import simplejson
- registry = simplejson.loads(_registry)
- myRegistry = simplejson.loads(_myRegistry)
-
-for (k,v) in list(myRegistry.items()) : registry[k] = v
+ registry = simplejson.loads(_registry)
diff --git a/rdflib/plugins/parsers/pyMicrodata/utils.py b/rdflib/plugins/parsers/pyMicrodata/utils.py
index 9ac25835..9ee905a4 100644
--- a/rdflib/plugins/parsers/pyMicrodata/utils.py
+++ b/rdflib/plugins/parsers/pyMicrodata/utils.py
@@ -9,41 +9,40 @@ U{W3C® SOFTWARE NOTICE AND LICENSE<href="http://www.w3.org/Consortium/Legal/200
"""
"""
-$Id: utils.py,v 1.7 2012/09/01 15:17:28 ivan Exp $
-$Date: 2012/09/01 15:17:28 $
+$Id: utils.py,v 1.8 2014-02-21 16:26:59 ivan Exp $
+$Date: 2014-02-21 16:26:59 $
"""
-import os, os.path, sys
+import sys, socket
(py_v_major, py_v_minor, py_v_micro, py_v_final, py_v_serial) = sys.version_info
+# The separate W3C branch is necessary for the local security setup at W3C. It is ugly to have this
+# in the code, but I was lazy to make it more generic...
+# With the inclusion of pyMicrodata into RDFLib, this service looses its importance anyway...
if py_v_major >= 3 :
- from urllib.request import Request, urlopen
+ import urllib.request
+ url_opener = urllib.request.build_opener()
+ from urllib.request import Request
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
+ import urllib2
+ url_opener = urllib2.build_opener()
+ from urllib2 import Request
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 ) :
+def is_absolute_URI(uri) :
return urlparse(uri)[0] != ""
#################################################################################
-def fragment_escape( name ) :
+def fragment_escape(name) :
return quote(name, '/~:-.')
#################################################################################
@@ -55,7 +54,7 @@ def generate_URI(base, v) :
@param base: Absolute URI for base
@param v: relative or absolute URI
"""
- if is_absolute_URI( v ) :
+ if is_absolute_URI(v) :
return v
else :
# UGLY!!! There is a bug for a corner case in python version <= 2.5.X
@@ -78,24 +77,7 @@ def generate_URI(base, v) :
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):
+def get_Literal(Pnode) :
"""
Get (recursively) the full text from a DOM Node.
@@ -119,21 +101,21 @@ def get_Literal(Pnode):
#################################################################################
def get_lang(node) :
# we may have lang and xml:lang
- retval = None
+ 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() ) :
+ if not(xmllang is not 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 :
+ if lang is None :
parent = node.parentNode
- if parent != None and parent != document :
+ if parent is not None and parent != document :
return get_lang_from_hierarchy(document, parent)
else :
return get_lang(document)
@@ -174,7 +156,7 @@ _formats = {
],
}
-_dur_times = [ "%HH%MM%SS", "%HH", "%MM", "%SS", "%HH%MM", "%HH%SS", "%MM%SS" ]
+_dur_times = ["%HH%MM%SS", "%HH", "%MM", "%SS", "%HH%MM", "%HH%SS", "%MM%SS"]
def get_time_type(string) :
"""
@@ -223,7 +205,7 @@ def get_time_type(string) :
break
except ValueError :
pass
- if td == True :
+ if td :
# Getting there...
for format in _dur_times :
try :
@@ -240,7 +222,7 @@ def get_time_type(string) :
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,
+ # there is a discrepancy between 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
@@ -278,7 +260,7 @@ class URIOpener :
@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'
+ CONTENT_LOCATION = 'Content-Location'
def __init__(self, name) :
"""
@param name: URL to be opened
@@ -287,14 +269,13 @@ class URIOpener :
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()
+ self.data = url_opener.open(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])
+ self.location = urlparse.urljoin(self.data.geturl(), self.headers[URIOpener.CONTENT_LOCATION])
else :
self.location = name
diff --git a/rdflib/plugins/parsers/structureddata.py b/rdflib/plugins/parsers/structureddata.py
index fb96efda..e4058cd4 100644
--- a/rdflib/plugins/parsers/structureddata.py
+++ b/rdflib/plugins/parsers/structureddata.py
@@ -220,18 +220,10 @@ class MicrodataParser(Parser):
@param graph: target graph for the triples; output graph, in RDFa
spec. parlance
@type graph: RDFLib Graph
- @keyword vocab_expansion: whether the RDFa @vocab attribute should
- also mean vocabulary expansion (see the RDFa 1.1 spec for further
- details)
+ @keyword vocab_expansion: this argument is not used any more, maintained for backward compatibility reasons only
@type vocab_expansion: Boolean
- @keyword vocab_cache: in case vocab expansion is used, whether the
- expansion data (i.e., vocabulary) should be cached locally. This
- requires the ability for the local application to write on the
- local file system
+ @keyword vocab_cache: this argument is not used any more, maintained for backward compatibility reasons only
@type vocab_chache: Boolean
- @keyword rdfOutput: whether Exceptions should be catched and added,
- as triples, to the processor graph, or whether they should be raised.
- @type rdfOutput: Boolean
"""
if html5lib is False:
raise ImportError(
@@ -239,17 +231,12 @@ class MicrodataParser(Parser):
'and Microdata parsers.')
(baseURI, orig_source) = _get_orig_source(source)
- self._process(graph, baseURI, orig_source,
- vocab_expansion=vocab_expansion,
- vocab_cache=vocab_cache)
+ self._process(graph, baseURI, orig_source)
- def _process(self, graph, baseURI, orig_source,
- vocab_expansion=False, vocab_cache=False):
+ def _process(self, graph, baseURI, orig_source):
from .pyMicrodata import pyMicrodata
- processor = pyMicrodata(base=baseURI, vocab_expansion=vocab_expansion,
- vocab_cache=vocab_cache)
- processor.graph_from_source(
- orig_source, graph=graph, rdfOutput=False)
+ processor = pyMicrodata(base=baseURI)
+ processor.graph_from_source(orig_source, graph=graph, rdfOutput=False)
class StructuredDataParser(Parser):
@@ -288,9 +275,6 @@ class StructuredDataParser(Parser):
requires the ability for the local application to write on the
local file system
@type vocab_chache: Boolean
- @keyword rdfOutput: whether Exceptions should be catched and added,
- as triples, to the processor graph, or whether they should be raised.
- @type rdfOutput: Boolean
"""
# Note that the media_type argument is ignored, and is here only to avoid an 'unexpected argument' error.
# This parser works for text/html only anyway...
@@ -301,8 +285,6 @@ class StructuredDataParser(Parser):
rdfa_version=rdfa_version,
vocab_expansion=vocab_expansion,
vocab_cache=vocab_cache)
- MicrodataParser()._process(graph, baseURI, orig_source,
- vocab_expansion=vocab_expansion,
- vocab_cache=vocab_cache)
+ MicrodataParser()._process(graph, baseURI, orig_source)
from .hturtle import HTurtleParser
HTurtleParser()._process(graph, baseURI, orig_source, media_type='text/html')