I am trying to map an XML source to RDF and would like to know how to traverse recursively while keeping track of the parent's attributes each time. In the example shown, I want all Person
nodes to be extracted with the name
of each parent node appended to the current node. Considering all parent names is necessary as the node names may not be unique. (See grandChild1
two times in the example)
Note that I do not know in advance how many levels the nesting can go and hence adding one TriplesMap for each level is not a feasible option.
After having gone through the documentation, examples, and test cases, I am not quite sure if this is even possible.
Following are a simplified sample XML, the RML mapping I created so far, the current RDF output generated using RMLMapper, as well as the RDF output I am expecting.
Data<Root>
<Person>
<name>parent1</name>
<Children>
<Person>
<name>child1</name>
<Person>
<name>grandchild1</name>
<Children>
<Person>
<name>greatgrandchild1</name>
</Person>
</Children>
</Person>
</Person>
<Person>
<name>child2</name>
<Person>
<name>grandchild1</name>
</Person>
</Person>
</Children>
</Person>
</Root>
Mapping
@prefix rml: <http://semweb.mmlab.be/ns/rml#> .
@prefix rr: <http://www.w3.org/ns/r2rml#> .
@prefix ql: <http://semweb.mmlab.be/ns/ql#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix testont: <http://www.example.com/ontology/> .
@prefix : <http://www.example.com/rules/> .
@base <http://www.example.com/instance/> .
:TriplesMapPerson a rr:TriplesMap;
rml:logicalSource [
rml:source "recursion_data.xml";
rml:referenceFormulation ql:XPath;
rml:iterator "//Root/Person"
].
:TriplesMapPerson rr:subjectMap [
rr:template "{name}"
].
:TriplesMapPerson rr:predicateObjectMap [
rr:predicate rdf:type;
rr:object testont:Person
].
:TriplesMapChild a rr:TriplesMap;
rml:logicalSource [
rml:source "recursion_data.xml";
rml:referenceFormulation ql:XPath;
rml:iterator "//Root/Person/Children/Person"
].
:TriplesMapChild rr:subjectMap [
rr:template "{name}_{../../name}"
].
:TriplesMapChild rr:predicateObjectMap [
rr:predicate rdf:type;
rr:object testont:Person
].
Current RDF
<http://www.example.com/instance/parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/child1_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/child2_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
Expected RDF
<http://www.example.com/instance/parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/child1_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/grandchild1_child1_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/greatgrandchild1_grandchild1_child1_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/child2_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
<http://www.example.com/instance/grandchild1_child2_parent1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.com/ontology/Person>.
I appreciate any assistance in resolving this. Thanks in advance!
You can make use of the recursive nature of XPath's
//
operator to iterate over all persons, regardless of depth.Then, in your subject template, you can use XPath's ancestor-or-self axis to get a list of ancestors nodes that have a name, reverse it to get the desired order, and get the name attribute for each node:
Then you can use XPaths string-join function to join the values to get the desired result.
The mapping would then look like
Giving the following result:
Note that for this to work the XPath implementation of your mapping tool needs to support reverse-axis traversal. I ran this example through https://github.com/carml/carml which supports that.
Note also that your xml input example is missing some intermediary
Children
nodes for somePerson
nodes.