[SHACL-API] Scrolling through an rdf:List

31 views
Skip to first unread message

Angelo Frozza

unread,
Feb 27, 2020, 8:44:35 AM2/27/20
to TopBraid Suite Users
Hi,

I'm creating a function to test the minimum number of elements in an rdf:List. I am using the SHACL-API to run this function.

I can't use sh:minCount or sh:maxCount because they disregard the existence of duplicate elements in the rdf:List, and in my case study, I can have more than one element with the same value in the rdf:List.

The function code is:
function myMinOccur ($this) {
// Defines an array for the return
var results = [];
// Defines the the IRI of the target node
var propertyName = TermFactory.namedNode("http://www.example.org#coordinates");  
var rest = TermFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");  
var nil = TermFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");   

        // Finds the object defined by the target node
var propertyObject = $data.find($this, propertyName, null) ;

// Navigate the target node graph
        for (var t = propertyObject.next(); t; t = propertyObject.next()) {
// Each instance is a Javascript object
var node = t.object;
var head = node;
var lenght = 0;
// This loop runs thorugh the list and 
// counts how many elements are in the list.
for ( ; node !== nil; ) {
                   lenght++;
                   var next = $data.find(node,rest,null).next();
                   if (!next || next == node) { node = nil; } 
                      else {node = next;} 
        }
// If the list lenght < 2 ($minSize), then it is an outlier.
if (length < 2 ) {
results.push({
value : head 
});
}
}
return results;
}


I have two problems/doubts in this code:
a) the inner loop is apparently looping, that is, it cannot find the end of the list.
b) How do I pass the value of ex:minSize to the function?

The problem in (a) was discussed, but with no solution, here:

I tested the function with the rdflib.js and rdflib-graph.js libraries found at (https://github.com/TopQuadrant/shacl-js) and it worked perfectly.
However, in this test, the loop mentioned in (a) is replaced by length = node.elements.length, which is not supported by the SHACL-API.

Attached are the shape graph and data graph files used in the tests.

Best regards,

Angelo
Case_1-DataGraph.ttl
Case_1-ShapeGraph.ttl

Ralph TQ [Gmail]

unread,
Feb 27, 2020, 8:55:15 AM2/27/20
to topbrai...@googlegroups.com
Angelo

Just a first glance. I noticed a spelling mistake: lenght++;

Ralph Hodgson, @ralphtq
CTO, TopQuadrant, @TopQuadrant

On Feb 27, 2020, at 8:44 AM, Angelo Frozza <fro...@gmail.com> wrote:


--
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/topbraid-users/6af577ee-0a59-43c9-8e65-7136d0a7ae51%40googlegroups.com.
<Case_1-DataGraph.ttl>
<Case_1-ShapeGraph.ttl>

Angelo Frozza

unread,
Feb 27, 2020, 9:04:32 AM2/27/20
to TopBraid Suite Users
Ralph,

True, there was this error.
Thanks.

I already corrected it in the online version of the function.
But the problem of infinite looping continues.

Hugs,

Angelo
Angelo

To unsubscribe from this group and stop receiving emails from it, send an email to topbrai...@googlegroups.com.

Holger Knublauch

unread,
Feb 27, 2020, 8:04:51 PM2/27/20
to topbrai...@googlegroups.com

Hi Angelo,

apologies but this type of very detailed question goes beyond what we can afford to answer for TBC-FE and API users. I hope you understand the commercial pressures.

Having said this I believe a problem is the !== comparison in

var nil = TermFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"
);   
...
for ( ; node !== nil; ) {
    length++;
    var next = $data.find(node,rest,null).next();
    if (!next || next == node) { 
        node = nil; 
    } 
    else {
        node = next;
    } 
}


because the rdf:nil instance delivered by the $data.find is another JS object. Compare by URIs instead.

To pass in ex:minSize, just declare it as

function myMinOccur ($this, $minSize)

and the engine should bind that variable automatically.

Holger

To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/topbraid-users/9a059d2d-c29c-40c7-a4e4-7b3ab9ddf266%40googlegroups.com.

Angelo Frozza

unread,
Feb 28, 2020, 11:46:07 AM2/28/20
to TopBraid Suite Users
Hi Holger,
Thanks again for the answers, it has been of great help.
I understand the commercial pressures.
But, here I found the best answers, since there is a lack of material on SHACL.

I believe that I finally got to the solution to my problem.

- I rewrote the comparison using the URI, as you indicated:
 for (; node.value! == "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil";) {...}

- $minSize must be declared with sh:parameter in the shape.
I did this and created a ConstraintComponent, removing the restriction from nodeShape.

I leave here my test files, in case anyone else needs it.
The final code of the function is this:
 function myMinOccur ($this, $minSize) {

   
// Defines an array for the return
   
var results = [];

   
// Defines the the IRIs of the target node

   
var propertyName = TermFactory.namedNode("http://www.example.org#coordinates");  
   
var rest = TermFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");  
   
var nil = TermFactory.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");  


   
// Finds the object defined by the target node
   
var propertyObject = $data.find($this, propertyName, null) ;


   
// Navigate the target node graph
   
for (var t = propertyObject.next(); t; t = propertyObject.next()) {
       
// Each instance is a Javascript object
       
var node = t.object;
       
var head = node;

       
var length = 0;

       
// This loop runs thorugh the list and
       
// counts how many elements are in the list.

       
for ( ; node.value !== "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"; ) {

            length
++;
           
var next = $data.find(node,rest,null).next();

            node
= next ? next.object : nil; // Get object if triple
       
}
       
// If the list length < 2 ($minSize), then it is an outlier.
       
if (length < $minSize.lex ) {

          results
.push({
          value
: head
       
});
     
}
   
}
 
return results;
}

And the result of the validation was:
[ a            sh:ValidationReport ;
  sh
:conforms  false ;
  sh
:result    [ a                             sh:ValidationResult ;
                 sh
:focusNode                  ex:MyExample_04 ;
                 sh
:resultMessage              "Value does not have shape ex:PointShape" ;
                 sh
:resultPath                 ex:p_name_3 ;
                 sh
:resultSeverity             sh:Violation ;
                 sh
:sourceConstraintComponent  sh:NodeConstraintComponent ;
                 sh
:sourceShape                []  ;
                 sh
:value                      ex:point_4
               
] ;

  sh
:result    [ a                             sh:ValidationResult ;
                 sh
:focusNode                  ex:point_4 ;
                 sh
:resultMessage              "Verify minOccur in coordinates!!!" ;
                 sh
:resultPath                 ex:coordinates ;   # Have only one element in rdf:list
                 sh
:resultSeverity             sh:Violation ;
                 sh
:sourceConstraintComponent  ex:MinOccurConstraintComponent ;
                 sh
:sourceShape                []  ;
                 sh
:value                      []  
               
]
] .



Hugs,

Angelo

Case_1-DataGraph.ttl
Case_1-ShapeGraph.ttl

Holger Knublauch

unread,
Feb 29, 2020, 7:48:23 PM2/29/20
to topbrai...@googlegroups.com

Thanks for sharing this solution.

Holger

--
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages