Roy Tang

Programmer, engineer, scientist, critic, gamer, dreamer, and kid-at-heart.

Blog Notes Photos Links Archives About

This is a follow-up to my question here: https://stackoverflow.com/questions/47449002/marklogic-template-driven-extraction-and-triples-dealing-with-array-nodes/47459250#47459250

So let’s say I have a number of documents structured like this:

declareUpdate();

xdmp.documentInsert(
       '/test/tde.json',
       {
         content: {
           name:'Joe Parent',
           children: [
             {
               name: 'Bob Child'
             },
             {
               name: 'Sue Child'
             },
             {
               name: 'Guy Child'
             }
           ]
         }
       },
       {permissions : xdmp.defaultPermissions(),
        collections : ['test']})

I want to define a template that would extract triples from these documents defining sibling relationships between the children. For the above example, I would want to extract the following triples (the relationship is two-way):

Bob Child sibling-of Sue Child
Bob Child sibling-of Guy Child
Sue Child sibling-of Bob Child
Sue Child sibling-of Guy Child
Guy Child sibling-of Bob Child
Guy Child sibling-of Sue Child

How can i set up my template to accomplish this?

Thanks!

Comments

I converted JSON to XML, wrote XSLT transformation to get XML triples. Later XML can be transformed back to JSON if needed.

XSLT transformation:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:json="http://marklogic.com/xdmp/json/basic" xmlns:sem="http://marklogic.com/semantics" exclude-result-prefixes="json">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="json:content">
 <sem:triples xmlns:sem="http://marklogic.com/semantics">
  <xsl:apply-templates select="json:children"/>
 </sem:triples>
</xsl:template>
<xsl:template match="json:children">
 <xsl:for-each select="json:json">
  <xsl:variable name="subjectName">
   <xsl:value-of select="json:name/text()"/>
  </xsl:variable>
 <xsl:for-each select="following-sibling::* | preceding-sibling::* ">
  <sem:triple>
   <sem:subject>
    <xsl:value-of select="$subjectName"/>
   </sem:subject>
   <sem:predicate>sibling-of</sem:predicate>
   <sem:object><xsl:value-of select="json:name/text()"/></sem:object>
  </sem:triple>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

XQuery code that converts JSON to XML and makes transformation:

xquery version "1.0-ml";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
declare namespace sem = "http://marklogic.com/semantics";
declare variable $j := '{"content": {"name": "Joe Parent","children": [{"name": "Bob Child"}, {"name": "Sue Child"}, {"name": "Guy Child"}]}}';
let $doc := json:transform-from-json($j),
$xslt := doc("myTemplates.xsl"),
$result :=  xdmp:xslt-eval($xslt,$doc),
$config := json:config("custom"),
$_ := map:put($config, "whitespace", "ignore"),
$_ := map:put($config, "array-element-names", ("triple")),
$_ := map:put($config, "element-namespace","http://marklogic.com/semantics")
return json:transform-to-json($result, $config)

I don’t know of a way to do that, but it seems like any “sibling-of” relationship is equivalent to two “child-of” relationships. Could you do something like this instead?

{
  ?x is-parent-of ?a-child . 
  ?x is-parent-of ?b-child. 
  ?a-child != ?b-child
}

Or if you’re in a position to use inference rules, you can build a rule that defines “sibling-of” like that. Then although the template doesn’t generate “sibling-of” directly, the triples are still tied to the ingested document in the same way as they would be, by virtue of the template generating the “is-parent-of” triples.