Search code examples
javahashmapsparqlrdfturtle-rdf

Converting Java HashMap to turtle triples


I am trying to construct :subject :${key} :${value} turtle triples in Java from a HashMap.

I am currently doing this with a string builder iterating through the HashMap but this is not very elegant and is quite slow.

Is there a better way to do this? Thank you!

Here is the code where object is a Map :


object.forEach((k, v) -> body.append(" :").append(k).append(“ :object \"").append(v).append("\" . ")) ;

return body.toString();

Solution

  • I'd use an RDF library for this, rather than just gluing strings together, as it gives you better assurances that your end result will be syntactically correct. For example, using Eclipse RDF4J you could do this by first turning your Map into an RDF model object, and then just using the Rio parser/writer to serialize to Turtle format.

    Assuming your map of strings is something like this:

        Map<String, String> map = new HashMap<>();
        map.put("property1", "value 1");
        map.put("property2", "value 2");
    

    You can use a ModelBuilder to first create an RDF model out of your Map, for example like this:

        ModelBuilder mb = new ModelBuilder();
        // set a default namespace
        mb.setNamespace("", "http://example.org/");
        // set the subject of our statements
        mb.subject(":subject1");
    
        // convert the map to statements about the set subject
        map.forEach((key, value) -> mb.add(":" + key, value));
    
        Model model = mb.build();
    

    Then you can use an RDF writer to convert the model to Turtle RDF syntax, like so (using a different OutputStream than System.out if you need it as a file or as a String object in Java, of course):

        Rio.write(model, System.out, RDFFormat.TURTLE);
    

    Output looks like this:

        @prefix : <http://example.org/> .
        @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
    
        :subject1 :property1 "value 1";
                  :property2 "value 2" .
    

    Update as you can see, the output contains a namespace definition for the xsd namespace. This is added automatically by the ModelBuilder because we are using literal values ("value 1" and "value 2"), which are of type xsd:string. However this datatype is the default for literals in RDF, so it's not really necessary to spell it out (which is why in the output it doesn't say "value 1"^^xsd:string, but just "value 1"). In other words the ModelBuilder is a bit over-zealous here, trying to be helpful.

    There's no harm in having the namespace declaration in your file even if it's not used, but if you really prefer not to have it present, you can remove it by adapting the code slightly, adding the following line after the line where you build the Model object:

     model.removeNamespace("xsd");
    

    I've also logged a bug report with RDF4J to fix this behaviour in the ModelBuilder. See https://github.com/eclipse/rdf4j/issues/2260.

    (disclosure: I am one of RDF4J's developers)