4

Rdflib CONSTRUCT query returns a list of tuples representing a graph. However, template languages usually are most convenient with a tree-like structures of nested mixed dicts and lists (because the structure matches well with tree-like structure of HTML markup). Actually, SELECT is no better in this respect, but denormalized version of the same data.

It's quite easy to come up with some ad hoc transformation, but maybe there is some idiomatic way given the graph and some hints for "pivots", which produces a tree?

For example, if we have a graph, containing Query and ResultVar individuals (with data properties, like labels, etc), then the tree could be a list of Query with ResultVar children:

[
{'name': 'q1', 'uri': '...', 'children': 
  [{'name': 'x', 'value': '1', ... },
   {'name': 'y', 'value': '1', ... },
   ...
  ]},
...
]

For this we may hint the method to use Query - ResultVar order. And the result is easy to use with nested "loops", which generate HTML markup in the template.

I'd not liked to reinvent the wheel, and I guess this kind of problem is not unique, but I have not found any solution.

However, I do not want the ORM approach, as it means having schema in the code, and I do not want to hardwire that.

EDIT: To clarify possible misunderstanding, the Query / ResultVar is just an example. I could use Blog / Comment or Calendar / Event instead.

EDIT2 It seems like what is being sought here is object framing, as used in JSON-LD:

Framing is the process of taking a JSON-LD document, which expresses a graph of information, and applying a specific graph layout (called a Frame).

JSON-LD Framing allows developers to query by example and force a specific tree layout to a JSON-LD document.

So, what is wanted here is some way for framing in rdflib, Python. This document ("JSON-LD: Cycle Breaking and Object Framing") gives a popular explanation of what is being sought by my question, but is there something like that for Python?

Community
  • 1
  • 1
Roman Susi
  • 4,135
  • 2
  • 32
  • 47

2 Answers2

1

What you're asking for can be realized with the SPARQLWrapper2 class. Sadly the docs for it are a bit "complicated" to understand to say the least. But there's a nice example in the overall docs:

from SPARQL import SPARQLWrapper2
queryString = "SELECT ?subj ?o ?opt WHERE { ?subj <http://a.b.c> ?o. OPTIONAL { ?subj <http://d.e.f> ?opt }}"
sparql = SPARQLWrapper2("http://localhost:2020/sparql")
# add a default graph, though that can also be in the query string
sparql.addDefaultGraph("http://www.example.com/data.rdf")
sparql.setQuery(queryString)
try :
    ret = sparql.query()
    print ret.variables  # this is an array consisting of "subj", "o", "opt"
        if (u"subj",u"prop",u"opt") in ret :
               # there is at least one binding covering the optional "opt", too
               bindings = ret[u"subj",u"o",u"opt"]
               # bindings is an array of dictionaries with the full bindings
               for b in bindings :
                       subj = b[u"subj"].value
                       o    = b[u"o"].value
                       opt  = b[u"opt"].value
                       # do something nice with subj, o, and opt
        # another way of accessing to values for a single variable:
        # take all the bindings of the "subj"
        subjbind = ret.getValues(u"subj") # an array of Value instances
        ...
except:
    deal_with_the_exception()

So adapted to your case you could use children = ret.getValues(u'q1').

Jörn Hees
  • 3,338
  • 22
  • 44
  • Seem like you have a typo in the 1st line of code, should be: from SPARQLWrapper import SPARQLWrapper2 – Roman Susi May 16 '15 at 06:01
  • Sorry for misunderstanding your answer (I've deleted my comment). I was unable to run your code and the one from the docs due to syntax errors. And now I revisited it and there is a potential in this approach. I guess, it must be more efficient, because it's lower level. Thank you! – Roman Susi May 16 '15 at 06:36
  • Sorry to unaccept, but I have found now how what I've described in the question is called, and updated the question. – Roman Susi May 22 '15 at 11:27
1

"Object framing", which allows to transform document in the RDF-model via JSON-LD into a tree-form, more suitable for some application scenarios is provided by the pyld library:

https://github.com/digitalbazaar/pyld

The result graph can be serialized to JSON-LD, given so-called context (JSON-LD terminilogy), then, given a frame (one more JSON-LD term, covered in the draft):

jsonld.frame(doc, frame)

will produce a "framed" data structure, actually a tree with a fixed layout, which can be used by application.

For more specific cases, like tree-like GUI generation scenarios, Fresnel Vocabulary is supposed to be "the RDF way". However, How to display RDF data described by Fresnel vocabulary? suggests, LDP (Linked data platform) is the more advanced approach.

Community
  • 1
  • 1
Roman Susi
  • 4,135
  • 2
  • 32
  • 47
  • any idea what the type of `frame` is supposed to be? I keep getting errors like ` ctx = frame.get('@context', {}) AttributeError: 'builtin_function_or_method' object has no attribute 'get'` trying to use a string/URL. When I try to use a json-ld document, I get an error that something must start with `http` or `https`. – Brian Tingle Feb 28 '16 at 17:08
  • 1
    In my case it was a dict (nested) with "@context" key and value for context, and some other entries. – Roman Susi Feb 28 '16 at 17:48
  • it seems *the frame* (represented as dict version of json or a link to a `jsonld` document) acts as a template of sorts for how the output should look http://json-ld.org/playground/#/gist/040f1a6515799ccf4179 – Brian Tingle Feb 28 '16 at 18:28