how to replace the VALUES from SPARQL with the Builtin listContains from the general purpose rule engine - jena

In SPARQL, Data can be directly written in a graph pattern or added to a query using VALUES:
SELECT ...
WHERE {
VALUES ?l {"no" "neg"}
?a delph:hasLemma ?l.
}
In Jena, I found the listContains(?l, ?x) in https://jena.apache.org/documentation/inference/index.html#RULEbuiltins. But how to use it? How to provide a list of values to check if a given object of a triple is in that list?

listContains is not part of SPARQL.
list:member maybe what you are looking for.
https://jena.apache.org/documentation/query/library-propfunc.html
PREFIX list: <http://jena.apache.org/ARQ/list#>
SELECT ...
WHERE {
?a delph:hasLemma ?l.
{ ?l list:member "no" } UNION { ?l list:member "neg" }
}
It is equivalent to
WHERE {
?a delph:hasLemma ?l .
?l list:member ?member
FILTER(?member IN ("no", "neg") )
}
or
WHERE {
?a delph:hasLemma ?l.
VALUES ?member { "no" "neg" }
?l list:member ?member
}

Related

XQuery 3: Conditionally add map entry

Example XQuery (using Saxon-HE, version 9.8.0.6)
xquery version "3.1";
let $xml := <simple>
<hello>Hello World!</hello>
</simple>
return fn:serialize(map{
'greeting': data($xml/hello),
'number': data($xml/number) (: ? how to add this entry only if there is a number ? :)
}, map{'method':'json', 'indent':true()})
Output:
{
"number":null,
"greeting":"Hello World!"
}
Question
How to prevent entries with a null value (in this case 'number')? Or more specifically in this case: how to add the 'number' entry only if it is a number?
Note: I know about map:entry and map:merge. I am looking for a solution without these functions, so "inline" (within the map constructor).
Update
Based on the answer of #joewiz, this is not possible. This is the closest we can get:
xquery version "3.1";
declare namespace map="http://www.w3.org/2005/xpath-functions/map";
let $xml := <simple>
<hello>Hello World!</hello>
</simple>
return fn:serialize(
map:merge((
map:entry('greeting', data($xml/hello)),
let $n := number($xml/number) return if ($n) then map:entry('number', $n) else()
)),
map{'method':'json', 'indent':true()})
If you're doing this often enough to make it worthwile you could do:
declare function f:addConditionally($map, $key, $data) as map(*) {
if (exists($data)) then map:put($map, $key, $data) else $map
};
let $m :=
map{}
=> f:addConditionally('greeting', data($xml/hello))
=> f:addConditionally('number', data($xml/number))
According to the XQuery 3.1 specification on Map Constructors, map constructors consist of map constructor entries, which themselves consist of a map key expression and a map value expression. In other words, map constructor entries are not general expressions and cannot accommodate a conditional expression such as:
map { if ($condition) then "key": "value" else () }
If you need to put anything in a map besides a key-value expression pair, you'll need to abandon the map constructor and fall back on map:merge() and map:entry(). The correct syntax for the above case would be as follows:
map:merge( if ($condition) then map:entry("key", "value") else () )

To order null values in createcritera.list

I have a problem when sorting a list created using createCriteria.
The problem is when I sort according to some a property its value is null , then the whole object is excluded from the list.
(the sort parameter is passed through sorttable column )
Here is a sample of my code.
SomeClass.createCriteria().list {
eq('sth', sth)
if (sort == 'someValue') {
nestedClass1 {
nestedClass2 {
nestedClass3 {
order('name', sortOrder)
} } }
}}
The problem is for instance when nestedCalss1 is null then the whole object is dropped from the list
Association queries like that are inner joins by default, to include nulls you need to use left outer joins, which you can do with createAlias
import org.hibernate.criterion.CriteriaSpecification
SomeClass.createCriteria().list {
eq('sth', sth)
if (sort == 'someValue') {
createAlias("nestedClass1", "nc1", CriteriaSpecification.LEFT_JOIN)
createAlias("nc1.nestedClass2", "nc2", CriteriaSpecification.LEFT_JOIN)
createAlias("nc2.nestedClass3", "nc3", CriteriaSpecification.LEFT_JOIN)
order("nc3.name", sortOrder)
}
}
Here's how you can make the nulls last in the order of the list:
def c = SomeClass.createCriteria()
List instanceList = c.list {
eq('sth', sth)
if (sort == 'someValue') {
createAlias("nestedClass1", "nc1", CriteriaSpecification.LEFT_JOIN)
createAlias("nc1.nestedClass2", "nc2", CriteriaSpecification.LEFT_JOIN)
createAlias("nc2.nestedClass3", "nc3", CriteriaSpecification.LEFT_JOIN)
if(params.order == "asc")
c.addOrder(Order.asc("nc3.name").nulls(org.hibernate.NullPrecedence.LAST))
else
c.addOrder(Order.desc("nc3.name").nulls(org.hibernate.NullPrecedence.LAST))
}
}

How can I see what the default value of a visit is?

Assume I have:
visit(p) {
case ...
default:
println("This should not happen. All elements should be catched. Check: <x>");
};
How can I print out (in this case as x) what could not be matched?
I tried:
x:default:
\x:default:
default:x:
\default:x:
Tx,
Jos
We have a library named Traversal that allows you to get back the context of a match. So, you can do something like this:
import Traversal;
import IO;
void doit() {
m = (1:"one",2:"two",3:"three");
bottom-up visit(m) {
case int n : println("<n> is an int");
default: {
tc = getTraversalContext();
println("Context is: <tc>");
println("<tc[0]> is not an int");
if (str s := tc[0]) {
println("<s> is a string");
}
}
}
}
tc is then a list of all the nodes back to the top of the term -- in this case, it will just be the current value, like "three", and the entire value of map m (or the entire map, which will also be a match for the default case). If you had something structured as a tree, such as terms formed using ADTs or nodes, you would get all the intervening structure from the point of the match back to the top (which would be the entire term).
For some reason, though, default is matching the same term multiple times. I've filed this as bug report https://github.com/cwi-swat/rascal/issues/731 on GitHub.
You could also try this idiom:
visit(x) {
case ...
case ...
case value x: throw "default case should not happen <x>";
}
The value pattern will catch everything but only after the others are tried.

what is a good way to test parsed json maps for equality?

The following code prints:
false
false
true
{{a: b}, {a: b}}
code
import "dart:json" as JSON;
main() {
print(JSON.parse('{ "a" : "b" }') == JSON.parse('{ "a" : "b" }'));
print({ "a" : "b" } == { "a" : "b" });
print({ "a" : "b" }.toString() == { "a" : "b" }.toString());
Set s = new Set();
s.add(JSON.parse('{ "a" : "b" }'));
s.add(JSON.parse('{ "a" : "b" }'));
print(s);
}
I am using json and parsing two equivalent objects, storing them in a Set, hoping they will not be duplicated. This is not the case and it seems to be because the first two lines (unexpectedly?) results in false. What is an efficient way to correctly compare two Map objects assuming each were the result of JSON.parse()?
The recommended way to compare JSON maps or lists, possibly nested, for equality is by using the Equality classes from the following package
import 'package:collection/collection.dart';
E.g.,
Function eq = const DeepCollectionEquality().equals;
var json1 = JSON.parse('{ "a" : 1, "b" : 2 }');
var json2 = JSON.parse('{ "b" : 2, "a" : 1 }');
print(eq(json1, json2)); // => true
For details see this answer which talks about some of the different equality classes: How can I compare Lists for equality in Dart?.
This is a difficult one, because JSON objects are just Lists and Maps of num, String, bool and Null. Testing Maps and Lists on equality is still an issue in Dart, see https://code.google.com/p/dart/issues/detail?id=2217
UPDATE
This answer is not valid anymore, see answer #Patrice_Chalin
This is actually pretty hard, as the == operator on Maps and Lists doesn't really compare keys/values/elements to each other.
Depending on your use case, you may have to write a utility method. I once wrote this quick and dirty function:
bool mapsEqual(Map m1, Map m2) {
Iterable k1 = m1.keys;
Iterable k2 = m2.keys;
// Compare m1 to m2
if(k1.length!=k2.length) return false;
for(dynamic o in k1) {
if(!k2.contains(o)) return false;
if(m1[o] is Map) {
if(!(m2[o] is Map)) return false;
if(!mapsEqual(m1[o], m2[o])) return false;
} else {
if(m1[o] != m2[o]) return false;
}
}
return true;
}
Please note that while it handles nested JSON objects, it will always return false as soon as nested lists are involved. If you want to use this approach, you may need to add code for handling this.
Another approach I once started was to write wrappers for Map and List (implementing Map/List to use it normally) and override operator==, then use JsonParser and JsonListener to parse JSON strings using those wrappers. As I abandoned that pretty soon, I don't have code for it and don't know if it really would have worked, but it could be worth a try.
The matcher library, used from unittest, will do this.

findAll() method in Grails not behaving properly when using "and" and "or" clauses

Why the "and" and "or" clauses don't work inside the findAll() method in grails?
For instance, this code:
Student.findAll {
and {
name == "A"
name ==~ "%A"
}
}.collect { it.name }
will generate the list:
['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ']
which is wrong. It should have generated nothing. None of the records match the condition having the exact name “A” and an ending “A”. The string shown is listing ALL the records in my Student table.
It gets a little bit worse. This code:
Student.findAll {
or {
name == "A"
name ==~ "%A"
}
}.collect { it.name }
generates the same list:
['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ']
when in reality should have returned just the record “AA”.
Is there something wrong with this code?
Thanks!
Use regular boolean operators in the criteria, e.g.:
Student.findAll {
name == "A" && name ==~ "%A"
}.collect { it.name }
Student.findAll {
name == "A" || name ==~ "%A"
}.collect { it.name }

Resources