from rdflib import RDF from rdflib.syntax.serializers import Serializer from rdflib.Graph import Graph from rdflib import URIRef, Literal, BNode from rdflib.util import first, uniq, more_than from rdflib.syntax.xml_names import split_uri from rdflib.syntax.serializers.XMLWriter import XMLWriter from rdflib.syntax.serializers.RDFaSerializer import StorelessNamespaceManager XMLLANG = "http://www.w3.org/XML/1998/namespacelang" class RDFaDocumentSerializer(Serializer): def __init__(self, store): """ I serialize RDF graphs in RDFaDocument format. Output is a fragment with implied XHTML default namespace suitable for including in XHTML documents. """ super(RDFaDocumentSerializer, self).__init__(store) def serialize(self, stream, base=None, encoding=None): self.__serialized = {} base = self.base encoding = self.encoding store = self.store namespaces = {} prefixes = {} possible = uniq(store.predicates()) for predicate in possible: prefix, namespace, local = store.namespace_manager.compute_qname(predicate) # XHTML is the implied default in output fragment, must rename any # supplied default if prefix is '': prefix = u'default1' namespaces[namespace] = prefix prefixes[prefix] = namespace # The XHTML NS does not have a trailing hash but this needs to for split_uri # XHTML is always the (assumed) default namespace, so never included in # output fragment xhtml = u"http://www.w3.org/1999/xhtml#" self.about = xhtml+u'about' self.property = xhtml+u'property' self.rel = xhtml+u'rel' self.href= xhtml+u'href' self.ul = xhtml+u'ul' self.li = xhtml+u'li' self.a = xhtml+u'a' namespaces[xhtml] = u'' namespaces["http://www.w3.org/1999/02/22-rdf-syntax-ns#"] = "rdf" prefixes["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" self.nm = nm = StorelessNamespaceManager(namespaces) self.writer = writer = XMLWriter(stream, nm, encoding) writer.push(self.ul) writer.namespaces(prefixes.iteritems()) for subject in uniq(store.subjects()): writer.push(self.li) writer.attribute(self.about, self.curie(subject)) for t in store.triples((subject, None, None)): writer.push(self.li) if isinstance(t[2], Literal): writer.attribute(self.property, t[1]) writer.text(t[2]) else: writer.attribute(self.rel, t[1]) writer.attribute(self.href, self.curie(t[2])) writer.pop(self.li) writer.pop(self.li) # # Write out subjects that can not be inline # for subject in store.subjects(): # if (None, None, subject) in store: # if (subject, None, subject) in store: # self.subject(subject, 1) # else: # self.subject(subject, 1) # # # write out anything that has not yet been reached # for subject in store.subjects(): # self.subject(subject, 1) # for s, p, o in store: # writer.push(li) # writer.attribute(about, self.curie(s)) # if isinstance(o, Literal): # if o.language: # writer.attribute(XMLLANG, o.language) # if o.datatype: # writer.attribute(RDF.datatype, o.datatype) # writer.attribute(property,self.curie(p)) # writer.text(o) # else: # if not isinstance(o,BNode): # writer.push(a) # writer.attribute(rel, self.curie(p)) # writer.attribute(href, self.relativize(o)) # writer.text(self.curie(p)) # writer.pop(a) # else: # writer.attribute(rel, self.curie(p)) # writer.attribute(href, self.curie(o)) # writer.text(self.curie(p)) # writer.pop(li) writer.pop(self.ul) def subject(self, subject, depth=1): store = self.store writer = self.writer if not subject in self.__serialized: self.__serialized[subject] = 1 writer.push(self.li) if isinstance(subject, BNode): if more_than(store.triples((None, None, subject)), 1): writer.attribute(self.about, self.curie(subject)) else: writer.attribute(self.about, self.curie(subject)) if (subject, None, None) in store: for predicate, object in store.predicate_objects(subject): #if not (predicate==RDF.type and object==type): self.predicate(predicate, object, depth+1) #print 'sNN' writer.pop(self.li) def predicate(self, predicate, object, depth=1): writer = self.writer store = self.store writer.attribute(self.property, self.curie(predicate)) if isinstance(object, Literal): if object.language: writer.attribute(XMLLANG, object.language) if object.datatype: writer.attribute(RDF.datatype, object.datatype) writer.text(object) elif object in self.__serialized or not (object, None, None) in store: if isinstance(object, BNode): if more_than(store.triples((None, None, object)), 1): writer.attribute(self.content, self.curie(object)) else: writer.attribute(self.href, self.relativize(object)) else: items = [] for item in store.items(object): # add a strict option to items? if isinstance(item, Literal): items = None # can not serialize list with literal values in them with rdf/xml else: items.append(item) if first(store.objects(object, RDF.first)): # may not have type RDF.List collection = object self.__serialized[object] = 1 # TODO: warn that any assertions on object other than # RDF.first and RDF.rest are ignored... including RDF.List writer.attribute(RDF.parseType, "Collection") while collection: item = first(store.objects(collection, RDF.first)) if item: self.subject(item) collection = first(store.objects(collection, RDF.rest)) self.__serialized[collection] = 1 else: self.subject(object, depth+1) def curie(self, uriref): if (isinstance(uriref,BNode)): return '[_:'+uriref+']' return self.nm.qname(uriref)