enp0s1
enp0s1

Reputation: 3

RDF/XML Ontology: Convert into JSON(-LD) Tree in Java

I am trying to process an existing ontology (OWL 2.0) stored in the RDF/XML format created using Protégé to a JSON/JSON-LD tree representation in Java. The goal is to use this processed data in a separate vue.js web application for visualization purposes.

Unfortunately, I am struggling to get this done.

Data I am trying to process:

Here's the ontology I am trying to process (example ontology):

<?xml version="1.0"?>
<rdf:RDF xmlns="urn:absolute:example.com/"
     xml:base="urn:absolute:example.com/"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:owl="http://www.w3.org/2002/07/owl#"
     xmlns:xml="http://www.w3.org/XML/1998/namespace"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
    <owl:Ontology rdf:about="urn:absolute:example.com/"/>



    <!-- 
    ///////////////////////////////////////////////////////////////////////////////////////
    //
    // Classes
    //
    ///////////////////////////////////////////////////////////////////////////////////////
     -->




    <!-- urn:absolute:example.com/#CPU -->

    <owl:Class rdf:about="urn:absolute:example.com/#CPU">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Hardware"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Enduser_Application -->

    <owl:Class rdf:about="urn:absolute:example.com/#Enduser_Application">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Software"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#GPU -->

    <owl:Class rdf:about="urn:absolute:example.com/#GPU">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Hardware"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#HDD -->

    <owl:Class rdf:about="urn:absolute:example.com/#HDD">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Storage"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Hardware -->

    <owl:Class rdf:about="urn:absolute:example.com/#Hardware"/>



    <!-- urn:absolute:example.com/#Keyboard -->

    <owl:Class rdf:about="urn:absolute:example.com/#Keyboard">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Peripherals"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Mainboard -->

    <owl:Class rdf:about="urn:absolute:example.com/#Mainboard">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Hardware"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Monitor -->

    <owl:Class rdf:about="urn:absolute:example.com/#Monitor">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Peripherals"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Mouse -->

    <owl:Class rdf:about="urn:absolute:example.com/#Mouse">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Peripherals"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Operating_System -->

    <owl:Class rdf:about="urn:absolute:example.com/#Operating_System">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Software"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Peripherals -->

    <owl:Class rdf:about="urn:absolute:example.com/#Peripherals">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Hardware"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Printer -->

    <owl:Class rdf:about="urn:absolute:example.com/#Printer">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Peripherals"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#SSD -->

    <owl:Class rdf:about="urn:absolute:example.com/#SSD">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Storage"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Software -->

    <owl:Class rdf:about="urn:absolute:example.com/#Software"/>



    <!-- urn:absolute:example.com/#Storage -->

    <owl:Class rdf:about="urn:absolute:example.com/#Storage">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Hardware"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Video_Game -->

    <owl:Class rdf:about="urn:absolute:example.com/#Video_Game">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Enduser_Application"/>
    </owl:Class>



    <!-- urn:absolute:example.com/#Word_Processor -->

    <owl:Class rdf:about="urn:absolute:example.com/#Word_Processor">
        <rdfs:subClassOf rdf:resource="urn:absolute:example.com/#Enduser_Application"/>
    </owl:Class>
</rdf:RDF>



<!-- Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi -->

Here is the structure I want to turn this ontology into (preferably in JSON or JSON-LD):

Protégé Screenshot (Imgur)

Thing
|-- Hardware
  |-- CPU
  |-- GPU
  |-- Mainboard
  |-- Peripherals
    |-- Keyboard
    |-- Monitor
    |-- Mouse
    |-- Printer
  |-- Storage
    |-- HDD
    |-- SSD
|-- Software
  |-- Enduser_Application
    |-- Video_Game
    |-- Word_Processor
  |-- Operating_System

The ontology is however defining the exact opposite relation between classes with their subclassOf attributes. Thus, things seem to get more difficult.

Previous approaches

I've already tried a few different approaches.

  1. Using Apache Jena

    Model model = ModelFactory.createOntologyModel();
    model.read(ontology, "OWL");
    model.write(new BufferedWriter(f), "JSON-LD");
    

    This seems to work "best" currently. I eventually get a String containing JSON-LD data in a tree representation. The class relationships are inverted, though:

    For instance, the top layer consists of the elements Keyboard, Monitor, Mouse, Printer, and so on. Their respective superclasses are attached as child elements.

If there's a way to reverse the relationships using Apache Jena, that'd be pretty cool. I currently can't think of a possible way though.

  1. Using owlapi

    For some reason owlapi would not work at all for me. It continously failed at parsing my ontology.

  2. Using JSON-LD Framing (using the output from approach 1)

    I noticed that JSON-LD has a so-called 'framing' feature which essentially allows you to re-fit data into a defined skeleton.

    I tinkered around with JSON-LD's @reverse keyword in conjunction with rdfs:subclassOf hoping to essentially have the relationship reversed. However, I can't get that to work either and I am not exactly experienced in JSON-LD. Hence, I am somewhat struggling.

This has led to some sleepless nights for me already. I'd be SO happy if someone knows a solution to this or just can give me hints on how to solve this problem.

Thank you very, very much in advance.

Upvotes: 0

Views: 1723

Answers (1)

Henriette Harmse
Henriette Harmse

Reputation: 4787

I checked and I have indeed been able to load your ontology using the OWL API and save it into JsonLD format. Though, I doubt it will solve your problem as @Ignazio pointed out. In order to print out the tree structure you need access to a reasoner from which you can query subsumption relations.

Here is a code sample loading and saving your ontology and printing it in a tree structure.

private static Logger logger = LoggerFactory
        .getLogger(owl.api.test.StandaloneOWLNamedIndividualRetrievalv5.AppHardwareTest.class);
// Why This Failure marker
private static final Marker WTF_MARKER = MarkerFactory.getMarker("WTF");

static OWLReasoner reasoner;

static void printChildren(NodeSet<OWLClass> owlClasses) {
    for (Node<OWLClass> node : owlClasses) {
        logger.trace(node.getRepresentativeElement().toString());
        if (!node.getRepresentativeElement().isBottomEntity())
            printChildren(reasoner.getSubClasses(node.getRepresentativeElement()));
    }       
}

public static void main(String[] args) {
    try {
        // Setup physical IRI for storing ontology
        Path path = Paths.get(".").toAbsolutePath().normalize();
        IRI loadDocumentIRI = IRI.create("file:" + path.toFile().getAbsolutePath() + "/hardware.owl");
        IRI saveDocumentIRI = IRI.create("file:" + path.toFile().getAbsolutePath() + "/hardwareSave.txt");

        // Initialize
        OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
        OWLOntology ontology = manager.loadOntologyFromOntologyDocument(loadDocumentIRI);

        // Write to JsonLD format
        OWLDocumentFormat ontologyFormat = new RDFJsonLDDocumentFormat();
        manager.saveOntology(ontology, ontologyFormat, saveDocumentIRI);        

        // Print tree structure
        OWLReasonerFactory reasonerFactory = new JFactFactory();
        reasoner = reasonerFactory.createReasoner(ontology);            
        Node<OWLClass> top = reasoner.getTopClassNode();
        logger.trace(top.getRepresentativeElement().toString());
        printChildren(reasoner.getSubClasses(top.getRepresentativeElement()));          
    } catch (Throwable t) {
        logger.error(WTF_MARKER, t.getMessage(), t);
    }
}

I hope it helps. Good luck.

Upvotes: 0

Related Questions