Search code examples
python-3.xrdflibturtle-rdf

Nested triples with units on value in rdflib - > turtle file


I'm currently making a turtle file. I have to relate values/units based on qudt.org Based on example data shown below:

data = {    "objectid_l1": "Bridge_1",
            "defid_l1": "Bridge",
            "objectid_l2": "Deck_1",
            "defid_l2": "Deck",
            "variable": "height",
            "value": "50.0",
            "unit": "M",
}

i made the following code, but the output is not what i want:

from rdflib.namespace import RDF
from rdflib import URIRef, BNode, Literal, Namespace, Graph

EX = Namespace('https://example.com/id/') 
UNIT = Namespace('http://qudt.org/2.1/vocab/unit/')
BS = Namespace('https://w3id.org/def/basicsemantics-owl#')

for i in data:
        if i['objectid_l1'] != None:
                g.add((
                    EX[i['objectid_l1']],
                    RDF.type,
                    EX[i['defid_l1']]
                ))
                g.add((
                    EX[i['objectid_l1']],
                    BS['hasPart'],
                    EX[i['objectid_l2']]
                ))
                g.add((
                    EX[i['objectid_l1']],
                    EX[i['variable']],
                    EX[i['value']]
                ))
                g.add((
                    EX[i['variable']],
                    BS['unit'],
                    UNIT[i['unit']]
                ))

output:

ex:Bridge_1
  a ex:Bridge ;
  bs:hasPart ex:Deck_1 ;
  ex:height 50.0 .

50.0 bs:unit unit:M .

As output i want that the units indent, the desired output is as follows:

ex:Bridge_1
  a ex:Bridge ;
  bs:hasPart ex:Deck_1 ;
  ex:height [
      rdf:value 50.0 ;
      bs:unit unit:M ;
    ];

Solution

  • There is a few things missing in your code to achieve what you want :

    • you need to explicitely create the blank node you show in the expected output, using rdflib BNode, then use it as subject of the triples setting the height value and the unit
    • you have to specify that the height value (50.0) is a litteral value.
    from rdflib.namespace import RDF, XSD, NamespaceManager
    from rdflib import BNode, Literal, Namespace, Graph
    
    EX = Namespace('https://example.com/id/') 
    UNIT = Namespace('http://qudt.org/2.1/vocab/unit/')
    BS = Namespace('https://w3id.org/def/basicsemantics-owl#')
    
    g = Graph()
    g.namespace_manager = NamespaceManager(Graph())
    g.namespace_manager.bind('unit', UNIT)
    g.namespace_manager.bind('bs', BS)
    g.namespace_manager.bind('ex', EX)
    
    i = {
        "objectid_l1": "Bridge_1",
        "defid_l1": "Bridge",
        "objectid_l2": "Deck_1",
        "defid_l2": "Deck",
        "variable": "height",
        "value": "50.0",
        "unit": "M",
    }
    
    if i['objectid_l1'] != None:
        g.add((EX[i['objectid_l1']], RDF.type, EX[i['defid_l1']]))
        g.add((EX[i['objectid_l1']], BS['hasPart'], EX[i['objectid_l2']]))
    
        bnode = BNode()
        g.add((bnode, RDF.value, Literal(i['value'])))
        g.add((bnode, BS['unit'], UNIT[i['unit']]))
        g.add((EX[i['objectid_l1']], EX[i['variable']], bnode))
    
    g.serialize('test.ttl', format='ttl')
    
    

    Should output as expected :

    ex:Bridge_1 a ex:Bridge ;
        bs:hasPart ex:Deck_1 ;
        ex:height [ rdf:value "50.0" ;
                bs:unit unit:M ] .