1

Suppose I have some jena query object :

String query = "SELECT * WHERE{ ?s <some_uri> ?o ...etc. }";
Query q = QueryFactory.create(query, Syntax.syntaxARQ);

I would like to use an ElementWalker and add triples to the query like so:

Given a query

SELECT * WHERE {
    ?s ?p ?o;
       ?p2 ?o2.
    ?s2 ?p3 ?o3.
}

I would hope to add a triple s.t. the query looks something like:

    SELECT * WHERE {
    ?s ?p ?o;
       ?p2 ?o2.
 -->?s <some_url> "value". //added
    ?s2 ?p3 ?o3.
}

I know that there are ways to add to the top level (Jena Tutorial), but I'd like to somehow add the triples as I walk through them using an ElementWalker:

ElementWalker.walk(query.getQueryPattern(), new ElementVisitorBase(){

        public void visit(ElementPathBlock el) {

            // when it's a block of triples, add in some triple
            ElementPathBlock elCopy = new ElementPathBlock();
            Iterator<TriplePath> triples = el.patternElts();
            int index = 0;
            int numAdded = 0;
            while (triples.hasNext()) {
                TriplePath t = triples.next();
                if(t.getSubject().equals(/*something*/)){
                    //add triple here, something like:
                    elCopy.addTriple(index+numAdded, /*someTriple*/);
                    numAdded++;
                }
                index++;
            }
            el = elCopy;
        }

        public void visit(ElementSubQuery el) {

            // get the subquery and walk it
            ElementGroup subQP = (ElementGroup) el.getQuery().getQueryPattern();
            ElementWalker.walk(subQP, this);
        }

        public void visit(ElementOptional el) {

            // get optional elements and walk them
            Element optionalQP = el.getOptionalElement();
            ElementWalker.walk(optionalQP, this);
        }
    });

The problem with the code above is that it successfully adds the triple to the ElementPathBlock (el), but the change doesn't perpetuate up through to the query itself. My hope would be to successfully modify the query while visiting this specific ElementPathBlock inside of the query.

Any help appreciated.

Nick Bartlett
  • 4,865
  • 2
  • 24
  • 37

1 Answers1

5

This code uses an walker to add ?d ?d ?d after any triple whose subject is ?d. Since there are multiple triples in the query with the subject ?d, multiple instances of ?d ?d ?d get inserted, and the changes are preserved.

import java.util.ListIterator;

import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.sparql.core.TriplePath;
import com.hp.hpl.jena.sparql.core.Var;
import com.hp.hpl.jena.sparql.syntax.ElementPathBlock;
import com.hp.hpl.jena.sparql.syntax.ElementVisitorBase;
import com.hp.hpl.jena.sparql.syntax.ElementWalker;

public class ElementWalkerExample {
    public static void main(String[] args) {
        final String queryString  = "" +
            "SELECT * WHERE {\n" +
            " ?a ?b ?c1 ;\n" +
            "    ?b ?c2 .\n" +
            " ?d ?e ?f .\n" +
            " ?g ?h ?i .\n" +
            "{ ?p ?q ?r .\n" +
            "  ?d ?e2 ?f2 . }\n" +
            "}";
        final Query query = QueryFactory.create( queryString );
        System.out.println( "== before ==\n"+query );
        ElementWalker.walk( query.getQueryPattern(), 
                new ElementVisitorBase() {
                    @Override
                    public void visit(ElementPathBlock el) {
                        ListIterator<TriplePath> it = el.getPattern().iterator();
                        while ( it.hasNext() ) {
                            final TriplePath tp = it.next();
                            final Var d = Var.alloc( "d" );
                            if ( tp.getSubject().equals( d )) {
                                it.add( new TriplePath( new Triple( d, d, d )));
                            }
                        }
                    }
        });
        System.out.println( "== after ==\n"+query );
    }
}

The output is:

== before ==
SELECT  *
WHERE
  { ?a ?b ?c1 .
    ?a ?b ?c2 .
    ?d ?e ?f .
    ?g ?h ?i
    { ?p ?q ?r .
      ?d ?e2 ?f2
    }
  }

== after ==
SELECT  *
WHERE
  { ?a ?b ?c1 .
    ?a ?b ?c2 .
    ?d ?e ?f .
    ?d ?d ?d .
    ?g ?h ?i
    { ?p ?q ?r .
      ?d ?e2 ?f2 .
      ?d ?d ?d
    }
  }
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • Also, for anyone else reading this, there are more examples of how ElementWalkers can be used in [this answer](http://stackoverflow.com/a/15205946/1281433) (not mine) to another one of [DirectCtrl](http://stackoverflow.com/users/1759514/)'s questions. – Joshua Taylor Jul 24 '13 at 18:07
  • So the main idea here is in the line `ListIterator it = el.getPattern().iterator();`. By using that instead of `Iterator it = el.patternElts();` I can use the provided `it.add(...)` to add in triples. Works well, thanks for the help. – Nick Bartlett Jul 24 '13 at 18:55
  • 1
    @DirectCtrl Right, the ListIterator lets you add in the middle. If this does work for you, feel free to [accept](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) to let other users know that it works! – Joshua Taylor Jul 24 '13 at 19:08