Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blank prefixes in SHACL property paths error out #112

Closed
mucaho opened this issue Apr 15, 2021 · 8 comments
Closed

Blank prefixes in SHACL property paths error out #112

mucaho opened this issue Apr 15, 2021 · 8 comments

Comments

@mucaho
Copy link

mucaho commented Apr 15, 2021

For the following minimum reproducible example:

# data_shapes_file.ttl

@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix : <http://example.com/> .

### DATA

:a :p :b .
:b :p :c .

### SHAPES

:TestShape
    a sh:NodeShape ;
    sh:targetNode :a ;
    sh:rule [
        rdf:type sh:TripleRule ;
        sh:subject sh:this ;
        sh:predicate :q ;
        sh:object [ sh:path [ sh:zeroOrMorePath :p ] ] ;
    ] ;

Running $ ./shaclinfer.sh -datafile data_shapes_file.ttl produces the following exception:

#Exception in thread "main" org.apache.jena.query.QueryParseException: Line 2, column 1: Unresolved prefixed name: :p
        at org.apache.jena.sparql.lang.ParserBase.throwParseException(ParserBase.java:522)
        at org.apache.jena.sparql.lang.ParserBase.resolvePName(ParserBase.java:287)
        at org.apache.jena.sparql.lang.arq.ARQParser.PrefixedName(ARQParser.java:5780)
        at org.apache.jena.sparql.lang.arq.ARQParser.iri(ARQParser.java:5764)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathPrimary(ARQParser.java:3541)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathElt(ARQParser.java:3412)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathEltOrInverse(ARQParser.java:3440)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathSequence(ARQParser.java:3377)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathAlternative(ARQParser.java:3356)
        at org.apache.jena.sparql.lang.arq.ARQParser.Path(ARQParser.java:3349)
        at org.apache.jena.sparql.lang.arq.ARQParser.VerbPath(ARQParser.java:3301)
        at org.apache.jena.sparql.lang.arq.ARQParser.PropertyListPathNotEmpty(ARQParser.java:3231)
        at org.apache.jena.sparql.lang.arq.ARQParser.TriplesSameSubjectPath(ARQParser.java:3180)
        at org.apache.jena.sparql.lang.arq.ARQParser.TriplesBlock(ARQParser.java:2360)
        at org.apache.jena.sparql.lang.arq.ARQParser.GroupGraphPatternSub(ARQParser.java:2278)
        at org.apache.jena.sparql.lang.arq.ARQParser.GroupGraphPattern(ARQParser.java:2240)
        at org.apache.jena.sparql.lang.arq.ARQParser.WhereClause(ARQParser.java:803)
        at org.apache.jena.sparql.lang.arq.ARQParser.AskQuery(ARQParser.java:668)
        at org.apache.jena.sparql.lang.arq.ARQParser.Query(ARQParser.java:39)
        at org.apache.jena.sparql.lang.arq.ARQParser.QueryUnit(ARQParser.java:21)
        at org.apache.jena.sparql.lang.ParserARQ$1.exec(ParserARQ.java:48)
        at org.apache.jena.sparql.lang.ParserARQ.perform(ParserARQ.java:96)
        at org.apache.jena.sparql.lang.ParserARQ.parse$(ParserARQ.java:52)
        at org.apache.jena.sparql.lang.SPARQLParser.parse(SPARQLParser.java:34)
        at org.apache.jena.query.QueryFactory.parse(QueryFactory.java:147)
        at org.topbraid.jenax.util.ARQFactory.doCreateQuery(ARQFactory.java:207)
        at org.topbraid.jenax.util.ARQFactory.createQuery(ARQFactory.java:237)
        at org.topbraid.shacl.arq.SHACLPaths.getJenaPath(SHACLPaths.java:255)
        at org.topbraid.shacl.expr.lib.PathExpression.<init>(PathExpression.java:51)
        at org.topbraid.shacl.expr.NodeExpressionFactory.lambda$static$14(NodeExpressionFactory.java:194)
        at org.topbraid.shacl.expr.NodeExpressionFactory.create(NodeExpressionFactory.java:259)
        at org.topbraid.shacl.rules.TripleRule.createNodeExpression(TripleRule.java:57)
        at org.topbraid.shacl.rules.TripleRule.<init>(TripleRule.java:46)
        at org.topbraid.shacl.rules.TripleRuleLanguage.createRule(TripleRuleLanguage.java:25)
        at org.topbraid.shacl.rules.RuleEngine.lambda$getShapeRules$0(RuleEngine.java:238)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1133)
        at org.topbraid.shacl.rules.RuleEngine.getShapeRules(RuleEngine.java:224)
        at org.topbraid.shacl.rules.RuleEngine.executeShape(RuleEngine.java:145)
        at org.topbraid.shacl.rules.RuleEngine.executeShapes(RuleEngine.java:133)
        at org.topbraid.shacl.rules.RuleEngine.executeAll(RuleEngine.java:93)
        at org.topbraid.shacl.rules.RuleUtil.executeRulesHelper(RuleUtil.java:124)
        at org.topbraid.shacl.rules.RuleUtil.executeRules(RuleUtil.java:63)
        at org.topbraid.shacl.tools.Infer.run(Infer.java:54)
        at org.topbraid.shacl.tools.Infer.main(Infer.java:44)

This seems like a bug, since I would expect the blank prefix to work like in all other constructs.

For reference and as a control test, changing this to a non-blank prefix:

# data_shapes_file.ttl

@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <http://example.com/> .

### DATA

ex:a ex:p ex:b .
ex:b ex:p ex:c .

### SHAPES

ex:TestShape
    a sh:NodeShape ;
    sh:targetNode ex:a ;
    sh:rule [
        rdf:type sh:TripleRule ;
        sh:subject sh:this ;
        sh:predicate ex:q ;
        sh:object [ sh:path [ sh:zeroOrMorePath ex:p ] ] ;
    ] ;

fixes the issue $ ./shaclinfer.sh -datafile data_shapes_file.ttl:

@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

<http://example.com/a>
        <http://example.com/q>  <http://example.com/b> , <http://example.com/a> , <http://example.com/c> .

I am running the latest SHACL API v1.3.2 on x64 linux.

@HolgerKnublauch
Copy link
Collaborator

HolgerKnublauch commented Apr 19, 2021

I believe this is due to standard Jena behavior. RuleUtil will wrap the data graph into a MultiUnion together with the inferred triples. That MultiUnion uses this prefix mapping, which only looks for the empty (default) prefix in the base graph, see the prefix.length() > 0 in PolyadicPrefixMappingImpl in Jena:

@Override public String getNsPrefixURI( String prefix ) 
    {
    PrefixMapping bm = getBaseMapping();
    String s = bm.getNsPrefixURI( prefix );
    if (s == null && prefix.length() > 0)

The philosophical issue behind this is that the default namespace should only apply to the base graph of a MultiUnion. In general, I would strongly discourage the use of default prefixes as some tools or users will mix them up across graphs. As seen above :)

I guess the change that I could make is to add

		unionGraph.setBaseGraph(dataModel.getGraph());

to RuleUtil, right after the upper unionGraph is created (line 96 in my version). Are you able to try this out in your environment to confirm this improves things?

I have run this locally and it seems to parse OK afterwards. As stated on #111 I will put this into our local copy before applying the same change to the open source repo in the future.

@afs
Copy link
Contributor

afs commented Apr 20, 2021

ARQFactory removes "":

@HolgerKnublauch
Copy link
Collaborator

That's correct, but the next line pm.setNsPrefixes(map); does not delete the "" prefix from the underlying PrefixMapping, if that already defines one. The fix mentioned above does resolve the issue for me though, by setting the base graph.

@mucaho
Copy link
Author

mucaho commented Jun 26, 2021

Are you able to try this out in your environment to confirm this improves things?

Thank you, can confirm, after adding the example as a resource file, adapting the RuleExample to use it and after adding the proposed changes to RuleUtil the example seems to pass:

java [...] org.topbraid.shacl.RuleExample
@base          <http://example.org/random> .
@prefix :     <http://example.com/> .
@prefix dash: <http://datashapes.org/dash#> .
@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 sh:   <http://www.w3.org/ns/shacl#> .
@prefix swa:  <http://topbraid.org/swa#> .
@prefix tosh: <http://topbraid.org/tosh#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .

:TestShape  rdf:type   sh:NodeShape ;
        sh:rule        [ rdf:type      sh:TripleRule ;
                         sh:object     [ sh:path  [ sh:zeroOrMorePath  :p ]
                                       ] ;
                         sh:predicate  :q ;
                         sh:subject    sh:this
                       ] ;
        sh:targetNode  :a .

:a      :p      :b ;
        :q      :b , :a , :c .

:b      :p      :c .


Process finished with exit code 0

On current master efc9fcc

@HolgerKnublauch
Copy link
Collaborator

I have put this on master, and noticed it should have been shapesModel, not dataModel. The latter only worked if both graphs were the same.

I believe this closes the ticket.

@rmfranken
Copy link
Contributor

rmfranken commented Nov 7, 2023

I think I have an expansion upon this issue, that may warrant re-opening it:

running on latest version (1.4.2) in windows 10.

Shapes:

@prefix : <https://myprefix.com/someprefix/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:ageshape a sh:NodeShape ;
sh:targetClass :Age ;
sh:property [ 
            sh:maxCount 1 ;
            sh:minCount 1 ;         
            sh:hasValue 24 ;
            sh:path ( :hasQuantity :hasNumber ) ]
            .

data:

@prefix : <https://myprefix.com/someprefix/> .


:someAge a :Age ;
  :hasQuantity [:hasNumber 24] ;
  .

Running the shacl validate command returns an error:

PS shacl-1.4.2\bin> .\shaclvalidate.bat -datafile 'synthea_patients_valid.ttl' -shapesfile 'shacl (1).ttl'
Exception in thread "main" org.apache.jena.query.QueryParseException: Line 2, column 1: Unresolved prefixed name: :hasQuantity
        at org.apache.jena.sparql.lang.QueryParserBase.throwParseException(QueryParserBase.java:578)
        at org.apache.jena.sparql.lang.QueryParserBase.resolvePName(QueryParserBase.java:320)
        at org.apache.jena.sparql.lang.arq.ARQParser.PrefixedName(ARQParser.java:6438)
        at org.apache.jena.sparql.lang.arq.ARQParser.iri(ARQParser.java:6422)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathPrimary(ARQParser.java:3743)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathElt(ARQParser.java:3602)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathEltOrInverse(ARQParser.java:3630)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathSequence(ARQParser.java:3565)
        at org.apache.jena.sparql.lang.arq.ARQParser.PathAlternative(ARQParser.java:3544)
        at org.apache.jena.sparql.lang.arq.ARQParser.Path(ARQParser.java:3538)
        at org.apache.jena.sparql.lang.arq.ARQParser.VerbPath(ARQParser.java:3493)
        at org.apache.jena.sparql.lang.arq.ARQParser.PropertyListPathNotEmpty(ARQParser.java:3418)
        at org.apache.jena.sparql.lang.arq.ARQParser.TriplesSameSubjectPath(ARQParser.java:3365)
        at org.apache.jena.sparql.lang.arq.ARQParser.TriplesBlock(ARQParser.java:2512)
        at org.apache.jena.sparql.lang.arq.ARQParser.GroupGraphPatternSub(ARQParser.java:2425)
        at org.apache.jena.sparql.lang.arq.ARQParser.GroupGraphPattern(ARQParser.java:2387)
        at org.apache.jena.sparql.lang.arq.ARQParser.WhereClause(ARQParser.java:858)
        at org.apache.jena.sparql.lang.arq.ARQParser.AskQuery(ARQParser.java:719)
        at org.apache.jena.sparql.lang.arq.ARQParser.Query(ARQParser.java:43)
        at org.apache.jena.sparql.lang.arq.ARQParser.QueryUnit(ARQParser.java:22)
        at org.apache.jena.sparql.lang.ParserARQ$1.exec(ParserARQ.java:48)
        at org.apache.jena.sparql.lang.ParserARQ.perform(ParserARQ.java:95)
        at org.apache.jena.sparql.lang.ParserARQ.parse$(ParserARQ.java:52)
        at org.apache.jena.sparql.lang.SPARQLParser.parse(SPARQLParser.java:33)
        at org.apache.jena.query.QueryFactory.parse(QueryFactory.java:144)
        at org.topbraid.jenax.util.ARQFactory.doCreateQuery(ARQFactory.java:201)
        at org.topbraid.jenax.util.ARQFactory.createQuery(ARQFactory.java:215)
        at org.topbraid.shacl.arq.SHACLPaths.getJenaPath(SHACLPaths.java:260)
        at org.topbraid.shacl.engine.Shape.<init>(Shape.java:109)
        at org.topbraid.shacl.engine.ShapesGraph.lambda$getShape$1(ShapesGraph.java:201)
        at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1740)
        at org.topbraid.shacl.engine.ShapesGraph.getShape(ShapesGraph.java:201)
        at org.topbraid.shacl.validation.ValidationEngine.validateNodesAgainstShape(ValidationEngine.java:523)
        at org.topbraid.shacl.validation.PropertyConstraintExecutor.executeHelper(PropertyConstraintExecutor.java:60)
        at org.topbraid.shacl.validation.PropertyConstraintExecutor.executeConstraint(PropertyConstraintExecutor.java:47)
        at org.topbraid.shacl.validation.ValidationEngine.validateNodesAgainstConstraint(ValidationEngine.java:629)
        at org.topbraid.shacl.validation.ValidationEngine.validateShapes(ValidationEngine.java:582)
        at org.topbraid.shacl.validation.ValidationEngine.validateAll(ValidationEngine.java:482)
        at org.topbraid.shacl.validation.ValidationUtil.validateModel(ValidationUtil.java:122)
        at org.topbraid.shacl.validation.ValidationUtil.validateModel(ValidationUtil.java:103)
        at org.topbraid.shacl.tools.Validate.run(Validate.java:59)
        at org.topbraid.shacl.tools.Validate.main(Validate.java:48)

I generally try to avoid using the default prefix, but this is not a sustainable solution - given the fact that empty prefix is a valid component of rdf/ttl serialization. If there is no fix, I have to switch to using Jena shacl for some clients which use the empty prefix, which I would love to avoid since I really like this CLI version.

@afs
Copy link
Contributor

afs commented Nov 8, 2023

@rmfranken - your example needs a triple-backtick to box it.

It also means whoever has GH handle 'prefix' doesn't get notifications!

@HolgerKnublauch
Copy link
Collaborator

Sorry for the delay. Fix is on master (hopefully).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants