Graph Serialization (Blank Node labels)

Viewed 78

I'm attempting to do some graph normalization following the URDNA2015 algorithm.

If I'm understanding the spec, blank nodes should have labels like _:c14nX where X is an incrementing counter.

I can produce a graph that has blank nodes with these labels, but when serializing the graph to NTRIPLES these run through NodeFmtLib#encodeBNodeLabel which performs some encoding -- at the very least always prefixes the resulting node with 'B'. For example c14n92 -> Bc14n92 or _:c14n92 -> BX5FX3Ac14n92 due to hex encoding.

My serialization code is very basic currently:

        StringWriter sw = new StringWriter();
        RDFDataMgr.write(sw, normalizedGraph, Lang.NTRIPLES);

What is the suggested way of having finer control over this serialization?

EDIT: One approach I found that works, but I'm not sure if it is the recommended way:

RDFWriterRegistry.register(RDFFormat.NTRIPLES_UTF8, new CustomWriterGraphRIOTFactory());

Then implement a chain of classes that override:

  • WriterGraphRIOTFactory
  • NTriplesWriter
  • StreamRDFLib
  • WriterStreamRDFPlain
  • NodeFormatter

to ultimately get to a place of overriding formatBNode:

public class CustomNodeFormatter extends NodeFormatterNT {
    public CustomNodeFormatter(CharSpace charSpace) {
        super(charSpace);
    }

    @Override
    public void formatBNode(AWriter w, String label) {
        w.print(label);
    }
}
1 Answers

The Jena writers work on graphs and a graph is a set of triple - unordered. As triples can be deleted and re-added, order isn't so easy even in a single threaded program because changes to the graph may reorder hash tables.

If you are doing this from JSON-LD - Jena currently uses jsonld-java - check whether the JSON-LD parsing is in a consistent order and labelling.

If you want to respect the order in syntax in other formats, look at parsing files to a StreamRDF object (- the parser output stream, - as well as having a custom FactoryRDF (which controls the label used for the blank node - you could for example make them 1,2,3 at this point).

RDFParser.create().source(...).factory(FactoryRDF).parse(StreamRDF);

Note when doing it via output without control of the input the order of output may change from run to run as blank nodes get different ids each parser run.

Related