Search code examples
javardfjenahl7-fhirturtle-rdf

How do I control Jena Turtle output?


I am trying to write a FHIR/RDF model to a Turtle (TTL) output file and validate it against a reference schema using ShEx. I have created a Jena model and am using the RDFDataMgr class to write it out. The problem is that the resulting output does not look like the Turtle output used in the FHIR examples. Specifically, it adds angle brackets where there are none; it does not use the subject-"a"-type syntax that is idiomatic Turtle; most importantly, it fails to validate using the FHIR validation tool. I have read through the Jena docs and not found any more granular controls over the output than what I am using, so I am hoping someone with more depth in the area can point out what I should be doing to get the expected output. It's a bit of long post; thanks for reading.

My code:

Model model = ModelFactory.createDefaultModel();

HashMap<String,String> prefixes = new HashMap<>();
prefixes.put("rdf"   ,"http://www.w3.org/1999/02/22-rdf-syntax-ns#");
prefixes.put("rdfs"  ,"http://www.w3.org/2000/01/rdf-schema#");
prefixes.put("owl"   ,"http://www.w3.org/2002/07/owl#");
prefixes.put("xsd"   ,"http://www.w3.org/2001/XMLSchema#");
prefixes.put("fhir"  ,"http://hl7.org/fhir/");
prefixes.put("loinc" ,"http://loinc.org/rdf#");
prefixes.put("sct"   ,"http://snomed.info/id#");

for (String key : prefixes.keySet())
        model.setNsPrefix(key, prefixes.get(key));

Resource root = model.getResource("fhir:Patient/" + patient.identifier);
root.addProperty(model.createProperty("rdf:type"),"fhir:Patient");
root.addProperty(model.createProperty("fhir:nodeRole"),"fhir:treeRoot");
root.addProperty(model.createProperty("fhir:Resource.id"), patient.identifier);
root.addProperty(
    model.createProperty("fhir:Patient.identifier"),
    model.createResource().addProperty(model.createProperty("fhir:index"), "0")
                .addProperty(
                        model.createProperty("fhir:Identifier.value"),
                        model.createResource()
                                .addProperty(model.createProperty("fhir:index"), "0")
                                .addProperty(model.createProperty("fhir:value"), patient.identifier)));


ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
RDFDataMgr.write(byteArrayOutputStream, model, RDFFormat.TURTLE);
String outputMessageText = new String(byteArrayOutputStream.toByteArray());

My output:

@prefix fhir:  <http://hl7.org/fhir/> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix sct:   <http://snomed.info/id#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix loinc: <http://loinc.org/rdf#> .

<fhir:Patient/6789012345>
    <fhir:Patient.birthDate>   [ <fhir:value>
                      "\"07/01/1970\"^^xsd:date" ] ;
    <fhir:Patient.gender>      [ <fhir:value>
                      "male" ] ;
    <fhir:Patient.identifier>  [ <fhir:Identifier.value>  [ <fhir:index>  "0" ;
                                                                           <fhir:value>  "6789012345"
                                                          ] ;
                                 <fhir:index>             "0"
                               ] ;
    <fhir:Patient.name>        [ <fhir:HumanName.given>  [ <fhir:index>  "0" ;
                                                           <fhir:value>  "Simmons, Henry"
                                                         ] ;
                                 <fhir:index>            "0"
                               ] ;
    <fhir:Resource.id>         "6789012345" ;
    <fhir:nodeRole>            "fhir:treeRoot" ;
    <rdf:type>                 "fhir:Patient" .

And then the sample from the FHIR docs (an excerpt):

@prefix fhir: <http://hl7.org/fhir/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# - resource
<http://hl7.org/fhir/Patient/pat1> a fhir:Patient;
  fhir:nodeRole fhir:treeRoot;
  fhir:Resource.id [ fhir:value "pat1"];
  fhir:Patient.identifier [
     fhir:index 0;
     fhir:Identifier.use [ fhir:value "usual" ];
     fhir:Identifier.type [
       fhir:CodeableConcept.coding [
         fhir:index 0;
         fhir:Coding.system [ fhir:value "http://terminology.hl7.org/CodeSystem/v2-0203" ];
         fhir:Coding.code [ fhir:value "MR" ]
       ]
     ];
     fhir:Identifier.system [ fhir:value "urn:oid:0.1.2.3.4.5.6.7" ];
     fhir:Identifier.value [ fhir:value "654321" ]
  ];

And finally, the ShEx:

<Patient> CLOSED {
a [fhir:Patient];
fhir:nodeRole [fhir:treeRoot]?;
fhir:Resource.id @<id>?;
fhir:Resource.meta @<Meta>?;
fhir:Resource.implicitRules @<uri>?;
fhir:Resource.language @<code>?;
fhir:DomainResource.text @<Narrative>?;
fhir:DomainResource.contained @<Resource>*;
fhir:DomainResource.extension @<Extension>*;
fhir:DomainResource.modifierExtension @<Extension>*;
fhir:Patient.identifier @<Identifier>*;
fhir:Patient.active @<boolean>?;
fhir:Patient.name @<HumanName>*;

Solution

  • It turns out the Jena-idiomatic way to do this is as follows:

    Model model = ModelFactory.createDefaultModel();
    model.setNsPrefix("fhir", "http://hl7.org/fhir/");
    Resource root = model.getResource(model.expandPrefix("fhir:Patient/" + patient.identifier));
    

    Thanks to the poster who provided the correct answer and deleted it an hour later.