SVS
SVS

Reputation: 61

How to convert xsd:dateTime literal into xsd:date in GraphDB?

I am trying to convert xsd:dateTime into xsd:date to be able to FILTER objects only by dates. But by doing following in GraphDB

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?s ?e { 
    VALUES (?start ?end) {("2011-02-02T14:45:14"^^xsd:dateTime "2011-02-04T14:45:13"^^xsd:dateTime)}
    BIND ( xsd:date(?start) AS ?s)
    BIND ( xsd:date(?end) AS ?e)
}

I get the following error

org.eclipse.rdf4j.query.QueryEvaluationException: Unknown function 'http://www.w3.org/2001/XMLSchema#date'

But as one can see here GraphDB Javascript Functions there is a usage of xsd:date function.

Upvotes: 1

Views: 1246

Answers (2)

Damyan Ognyanov
Damyan Ognyanov

Reputation: 786

The documentation from the link about GraphDB Javascript Functions uses an non-existing function xsd:date. For some reason it didn't end in the release.

Some technical notes.

The RDF values passed as arguments to the user defined javascript functions undergo a type conversion. The instances of org.eclipse.rdf4j.model.IRI and org.eclipse.rdf4j.model.BNode are passed "as-is", but the Literals are converted like:

  • if it is an integer datatype e.g. one of (xsd:integer, xsd:long, xsd:int, xsd:byte, xsd:short, xsd:nonPositiveInteger, xsd:negativeInteger, xsd:nonNegativeInteger, xsd:positiveInteger, xsd:unsignedLong, xsd:unsignedInt, xsd:unsignedShort and xsd:unsignedByte) the value passed is a long

  • if it is one of: xsd:decimal, xsd:float or xsd:double the value passed is a double

  • if it is one of: xsd:dateTime, xsd:date, xsd:time, xsd:gYearMonth, xsd:gMonthDay, xsd:gYear, xsd:gMonth or xsd:gDay the value passed is an instance of javax.xml.datatype.XMLGregorianCalendar

  • if it is a duration, e.g. one of: xsd:duration, xsd:dayTimeDuration or xsd:yearMonthDuration the value passed is an instance of javax.xml.datatype.Duration

  • finally, for xsd:boolean is a boolean

  • for anything else, the Literal's label as String

Alternatively, the return value is also converted. If it is an instance of org.eclipse.rdf4j.Value, no conversion is done. Otherwise, conversion to RDF literal depends on its type and also on what is avaliable in RDF4J ValueFactory as createLiteral methods that can handle these, including the XMLGregorianCalendar. So if there is no specific handler, the string value of the result is used to create the Literal.

In the example from the first answer, the result of jsfn:convertDate is of type jdk.nashorn.internal.objects.NativeDate so when the literal of the result is created, the plugin invokes its toString and that lead to results like [Date 2011-02-02T14:45:14.000Z]

Further, the scripting engine in the plugin is restricted to have access only to classes starting with java.lang. (excluding java.lang.Thread), org.eclipse.rdf4j.model. and com.ontotext.trree.sdk.

Having in mind the above notes and restrictions, a javascript function that converts a xsd:dateTime to xsd:date need to set the fields of the calendar value which are related to the time to DatatypeConstants.FIELD_UNDEFINED which is actually Integer.MIN_VALUE and construct a Literal through the RDF4J ValueFactory:

PREFIX jsfn:<http://www.ontotext.com/js#>
INSERT DATA {
    [] jsfn:register '''
    function convertDate(value) {
        value.setTime(java.lang.Integer.MIN_VALUE, java.lang.Integer.MIN_VALUE, java.lang.Integer.MIN_VALUE);
        return org.eclipse.rdf4j.model.impl.SimpleValueFactory.getInstance().createLiteral(value);
    }
'''
}

HTH

Upvotes: 3

Sava Savov
Sava Savov

Reputation: 611

Create javascript function in GraphDB like:

PREFIX jsfn:<http://www.ontotext.com/js#>
INSERT DATA {
    [] jsfn:register '''
    function convertDate(value) {
        return new Date(value);
    }
'''
}

Verify that the function is registered or:

PREFIX jsfn:<http://www.ontotext.com/js#>
SELECT ?s ?o {
    ?s jsfn:enum ?o
}

And then use it as follows:

PREFIX jsfn:<http://www.ontotext.com/js#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?s ?e { 
    VALUES (?start ?end) {("2011-02-02T14:45:14"^^xsd:dateTime "2011-02-04T14:45:13"^^xsd:dateTime)}
    BIND ( jsfn:convertDate(?start) AS ?s)
    BIND ( jsfn:convertDate(?end) AS ?e)
}

Returned result is:

[Date 2011-02-02T14:45:14.000Z]

[Date 2011-02-04T14:45:13.000Z]

Hope this helps.

Upvotes: 1

Related Questions