001/** 002 * Copyright (C) 2007 - 2016, Jens Lehmann 003 * 004 * This file is part of DL-Learner. 005 * 006 * DL-Learner is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation; either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * DL-Learner is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.dllearner.algorithms.qtl.datastructures.impl; 020 021import javax.xml.bind.DatatypeConverter; 022import java.io.PrintWriter; 023import java.util.*; 024import java.util.Map.Entry; 025import java.util.regex.Pattern; 026 027import com.google.common.collect.Sets; 028import org.apache.jena.datatypes.BaseDatatype; 029import org.apache.jena.datatypes.RDFDatatype; 030import org.apache.jena.datatypes.xsd.XSDDatatype; 031import org.apache.jena.graph.Node; 032import org.apache.jena.graph.NodeFactory; 033import org.apache.jena.graph.Triple; 034import org.apache.jena.query.Query; 035import org.apache.jena.query.QueryFactory; 036import org.apache.jena.query.Syntax; 037import org.apache.jena.rdf.model.Literal; 038import org.apache.jena.sparql.core.TriplePath; 039import org.apache.jena.sparql.syntax.ElementGroup; 040import org.apache.jena.sparql.syntax.ElementPathBlock; 041import org.apache.jena.sparql.syntax.ElementTriplesBlock; 042import org.apache.jena.sparql.syntax.ElementVisitorBase; 043import org.apache.jena.vocabulary.OWL; 044import org.apache.jena.vocabulary.RDF; 045import org.apache.jena.vocabulary.RDFS; 046import org.dllearner.algorithms.qtl.datastructures.NodeRenderer; 047import org.dllearner.algorithms.qtl.datastructures.QueryTree; 048import org.dllearner.algorithms.qtl.datastructures.rendering.Edge; 049import org.dllearner.algorithms.qtl.datastructures.rendering.Vertex; 050import org.dllearner.algorithms.qtl.filters.Filters; 051import org.dllearner.utilities.PrefixCCMap; 052import org.jgrapht.Graph; 053import org.json.JSONArray; 054import org.json.JSONException; 055import org.json.JSONObject; 056import org.semanticweb.owlapi.model.*; 057import org.semanticweb.owlapi.vocab.OWL2Datatype; 058import org.semanticweb.owlapi.vocab.OWLFacet; 059import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl; 060 061/** 062 * 063 * @author Lorenz Bühmann 064 * 065 */ 066public class QueryTreeImpl<N> implements QueryTree<N>{ 067 068 public enum NodeType{ 069 RESOURCE, LITERAL, BLANK, VARIABLE 070 } 071 072 public enum LiteralNodeSubsumptionStrategy { 073 DATATYPE, 074 INTERVAL, 075 MIN, 076 MAX, 077 ENUMERATION, 078 OFF 079 } 080 081 public enum LiteralNodeConversionStrategy{ 082 /** 083 * Literals in form of an enumeration, e.g. {3, 4, 10} 084 */ 085 DATA_ONE_OF, 086 /** 087 * Literals as an interval on the datatype, e.g. [>= 5 <=10] 088 */ 089 MIN_MAX, 090 /** 091 * Literals as datatype, e.g. xsd:integer 092 */ 093 DATATYPE, 094 095 MIN, 096 097 MAX, 098 } 099 100 private N userObject; 101 102 private QueryTreeImpl<N> parent; 103 104 private List<QueryTreeImpl<N>> children; 105 106 private Map<QueryTree<N>, Object> child2EdgeMap; 107 private Map<String, List<QueryTree<N>>> edge2ChildrenMap; 108 109 private NodeRenderer<N> toStringRenderer; 110 111 private boolean tagged = false; 112 113 private int cnt; 114 115 private int id; 116 117 private boolean isLiteralNode = false; 118 private boolean isResourceNode = false; 119 private boolean isBlankNode = false; 120 121 private Set<Literal> literals = new HashSet<>(); 122 123 private NodeType nodeType; 124 125 public QueryTreeImpl(N userObject) { 126 this.userObject = userObject; 127 children = new ArrayList<>(); 128 child2EdgeMap = new HashMap<>(); 129 edge2ChildrenMap = new HashMap<>(); 130 toStringRenderer = new NodeRenderer<N>() { 131 @Override 132 public String render(QueryTree<N> object) { 133 String label = object.toString() + "(" + object.getId() + ")"; 134 if(object.isLiteralNode()){ 135// if(object.getLiterals().size() == 1){ 136// label += object.getLiterals().iterator().next(); 137// } else if(object.getLiterals().size() > 1){ 138// label += "Values: " + object.getLiterals(); 139// } 140 if(!object.getLiterals().isEmpty()){ 141 label += "Values: " + object.getLiterals(); 142 } 143 } 144// label += object.isResourceNode() + "," + object.isLiteralNode(); 145 return label; 146 } 147 }; 148// if(isVarNode() && !getUserObject().equals("?")){ 149// System.out.println(getUserObject()); 150// System.out.println("ERROR1"); 151//// System.exit(0); 152// } 153 } 154 155 public QueryTreeImpl(N userObject, NodeType nodeType) { 156 this(userObject, nodeType, 0); 157 } 158 159 public QueryTreeImpl(N userObject, NodeType nodeType, int id) { 160 this.userObject = userObject; 161 this.nodeType = nodeType; 162 this.id = id; 163 children = new ArrayList<>(); 164 child2EdgeMap = new HashMap<>(); 165 edge2ChildrenMap = new HashMap<>(); 166 toStringRenderer = new NodeRenderer<N>() { 167 @Override 168 public String render(QueryTree<N> object) { 169 String label = object.toString() + "(" + object.getId() + ")"; 170 if(object.isLiteralNode()){ 171// if(object.getLiterals().size() == 1){ 172// label += object.getLiterals().iterator().next(); 173// } else if(object.getLiterals().size() > 1){ 174// label += "Values: " + object.getLiterals(); 175// } 176 if(!object.getLiterals().isEmpty()){ 177 label += "Values: " + object.getLiterals(); 178 } 179 } 180// label += object.isResourceNode() + "," + object.isLiteralNode(); 181 return label; 182 } 183 }; 184 if(nodeType == NodeType.RESOURCE){ 185 isResourceNode = true; 186 } else if(nodeType == NodeType.LITERAL){ 187 isLiteralNode = true; 188 } 189// if(isVarNode() && !getUserObject().equals("?")){ 190// System.out.println(getUserObject()); 191// System.out.println("ERROR2"); 192// System.exit(0); 193// } 194 } 195 196 public QueryTreeImpl(QueryTree<N> tree){ 197 this(tree.getUserObject(), tree.getNodeType()); 198 199// this.userObject = tree.getUserObject(); 200// children = new ArrayList<QueryTreeImpl<N>>(); 201// child2EdgeMap = new HashMap<QueryTree<N>, Object>(); 202// edge2ChildrenMap = new HashMap<String, List<QueryTree<N>>>(); 203// toStringRenderer = new NodeRenderer<N>() { 204// public String render(QueryTree<N> object) { 205// String label = object.toString() + "(" + object.getId() + ")"; 206// if(object.isLiteralNode()){ 207//// if(object.getLiterals().size() == 1){ 208//// label += object.getLiterals().iterator().next(); 209//// } else if(object.getLiterals().size() > 1){ 210//// label += "Values: " + object.getLiterals(); 211//// } 212// if(!object.getLiterals().isEmpty()){ 213// label += "Values: " + object.getLiterals(); 214// } 215// } 216//// label += object.isResourceNode() + "," + object.isLiteralNode(); 217// return label; 218// } 219// }; 220 221 setId(tree.getId()); 222 QueryTreeImpl<N> subTree; 223 for(QueryTree<N> child : tree.getChildren()){ 224 subTree = new QueryTreeImpl<>(child); 225 subTree.setId(child.getId()); 226 subTree.setIsLiteralNode(child.isLiteralNode()); 227 subTree.setIsResourceNode(child.isResourceNode()); 228 subTree.addLiterals(child.getLiterals()); 229 addChild(subTree, tree.getEdge(child)); 230 } 231 232 setIsResourceNode(tree.isResourceNode()); 233 setIsLiteralNode(tree.isLiteralNode()); 234 addLiterals(tree.getLiterals()); 235 } 236 237 @Override 238 public boolean sameType(QueryTree<N> tree){ 239 return (isResourceNode && tree.isResourceNode()) || 240 (isVarNode() && tree.isVarNode()) || 241 (isLiteralNode && tree.isLiteralNode()); 242 } 243 244 @Override 245 public N getUserObject() { 246 return userObject; 247 } 248 249 @Override 250 public void setUserObject(N userObject) { 251 this.userObject = userObject; 252 } 253 254 @Override 255 public void setId(int id) { 256 this.id = id; 257 } 258 259 @Override 260 public int getId() { 261 return id; 262 } 263 264 @Override 265 public NodeType getNodeType() { 266 return nodeType; 267 } 268 269 @Override 270 public boolean isEmpty(){ 271 return this.children.isEmpty(); 272 } 273 274 @Override 275 public QueryTree<N> getNodeById(int nodeId){ 276 QueryTree<N> node = null; 277 if(this.id == nodeId){ 278 node = this; 279 } else { 280 for(QueryTree<N> child : children){ 281 node = child.getNodeById(nodeId); 282 if(node != null){ 283 return node; 284 } 285 } 286 } 287 return node; 288 } 289 290 @Override 291 public boolean isLiteralNode() { 292 return isLiteralNode; 293 } 294 295 @Override 296 public void setIsLiteralNode(boolean isLiteralNode) { 297 this.isLiteralNode = isLiteralNode; 298 } 299 300 public void setIsBlankNode(boolean isBlankNode) { 301 this.isBlankNode = isBlankNode; 302 } 303 304 public boolean isBlankNode() { 305 return isBlankNode; 306 } 307 308 @Override 309 public boolean isResourceNode() { 310 return isResourceNode; 311 } 312 313 @Override 314 public void setIsResourceNode(boolean isResourceNode) { 315 this.isResourceNode = isResourceNode; 316 } 317 318 @Override 319 public boolean isVarNode() { 320 return !isLiteralNode && !isResourceNode; 321 } 322 323 @Override 324 public void setVarNode(boolean isVarNode) { 325 isLiteralNode = false; 326 isResourceNode = false; 327 } 328 329 public void setParent(QueryTreeImpl<N> parent) { 330 if (this.parent != null) { 331 this.parent.children.remove(this); 332 } 333 this.parent = parent; 334 this.parent.children.add(this); 335 } 336 337 /* (non-Javadoc) 338 * @see org.dllearner.algorithms.qtl.datastructures.QueryTree#setParent(org.dllearner.algorithms.qtl.datastructures.QueryTree) 339 */ 340 @Override 341 public void setParent(QueryTree<N> parent) { 342 setParent((QueryTreeImpl<N>)parent); 343 } 344 345 @Override 346 public void addChild(QueryTreeImpl<N> child) { 347 children.add(child); 348 child.parent = this; 349 } 350 351 public void addChild(QueryTree<N> child) { 352 children.add((QueryTreeImpl<N>) child); 353 child.setParent(this); 354 } 355 356 /* (non-Javadoc) 357 * @see org.dllearner.algorithms.qtl.datastructures.QueryTree#addChild(org.dllearner.algorithms.qtl.datastructures.QueryTree, java.lang.Object) 358 */ 359 @Override 360 public void addChild(QueryTree<N> child, Object edge) { 361 addChild((QueryTreeImpl<N>)child, edge); 362 } 363 364 @Override 365 public void addChild(QueryTreeImpl<N> child, int position) { 366 children.add(position, child); 367 child.parent = this; 368 } 369 370 @Override 371 public void addChild(QueryTreeImpl<N> child, Object edge) { 372 addChild(child); 373 child2EdgeMap.put(child, edge); 374 375 List<QueryTree<N>> children = edge2ChildrenMap.get(edge); 376 if(children == null){ 377 children = new ArrayList<>(); 378 edge2ChildrenMap.put((String)edge, children); 379 } 380 children.add(child); 381 } 382 383 @Override 384 public void addChild(QueryTreeImpl<N> child, Object edge, int position) { 385 addChild(child, position); 386 child2EdgeMap.put(child, edge); 387 388 List<QueryTree<N>> children = edge2ChildrenMap.get(edge); 389 if(children == null){ 390 children = new ArrayList<>(); 391 edge2ChildrenMap.put((String)edge, children); 392 } 393 children.add(child); 394 395 } 396 397 @Override 398 public int removeChild(QueryTreeImpl<N> child) { 399 int pos = children.indexOf(child); 400 children.remove(child); 401 edge2ChildrenMap.get(child2EdgeMap.get(child)).remove(child); 402 child.parent = null; 403 return pos; 404 } 405 406 public void removeChildren(Set<QueryTreeImpl<N>> children) { 407 for(QueryTreeImpl<N> child : children){ 408 this.children.remove(child); 409 child.parent = null; 410 } 411 } 412 413 /** 414 * Removes all children connected by the given edge. 415 */ 416 @Override 417 public void removeChildren(Object edge) { 418 List<QueryTree<N>> children = edge2ChildrenMap.remove(edge); 419 if(children != null){ 420 this.children.removeAll(children); 421 } 422// List<QueryTree<N>> list = edge2ChildrenMap.get("http://dl-learner.org/carcinogenesis#hasAtom"); 423// List<QueryTree<N>> newList = new ArrayList<QueryTree<N>>(); 424// for (int i = 0; i < Math.min(list.size(), 11); i++) { 425// QueryTreeImpl<N> keep = (QueryTreeImpl<N>) list.get(i); 426// newList.add(keep); 427// } 428// list.clear(); 429// list.addAll(newList); 430// this.children.clear(); 431// this.children = new ArrayList<QueryTreeImpl<N>>(); 432// this.children.addAll((Collection<? extends QueryTreeImpl<N>>) list); 433// edge2ChildrenMap.clear(); 434// edge2ChildrenMap.put("http://dl-learner.org/carcinogenesis#hasAtom", list); 435 } 436 437 @Override 438 public Object getEdge(QueryTree<N> child) { 439 return child2EdgeMap.get(child); 440 } 441 442 @Override 443 public Set<Object> getEdges(){ 444 return new TreeSet<>(child2EdgeMap.values()); 445 } 446 447 @Override 448 public void sortChildren(Comparator<QueryTree<N>> comparator) { 449 Collections.sort(children, comparator); 450 } 451 452 public void clearChildren() { 453 for (QueryTreeImpl<N> child : new ArrayList<>(children)) { 454 removeChild(child); 455 } 456 } 457 458 @Override 459 public QueryTree<N> getParent() { 460 return parent; 461 } 462 463 @Override 464 public List<QueryTree<N>> getChildren() { 465 return new ArrayList<>(children); 466 } 467 468 @Override 469 public List<QueryTree<N>> getChildren(Object edge) { 470// List<QueryTree<N>> children = new ArrayList<QueryTree<N>>(); 471// for(Entry<QueryTree<N>, Object> entry : child2EdgeMap.entrySet()){ 472// if(entry.getValue().equals(edge)){ 473// children.add(entry.getKey()); 474// } 475// } 476// return children; 477 List<QueryTree<N>> children = edge2ChildrenMap.get(edge); 478 if(children == null){ 479 children = new ArrayList<>(); 480 } 481 return new ArrayList<>(children); 482 } 483 484 @Override 485 public int getChildCount() { 486 return children.size(); 487 } 488 489 @Override 490 public boolean isRoot() { 491 return parent == null; 492 } 493 494 @Override 495 public boolean isLeaf() { 496 return children.isEmpty(); 497 } 498 499 @Override 500 public boolean isSubsumedBy(QueryTree<N> tree) { 501// System.out.println("++++++++++++++++++++++++++++"); 502// System.out.println(tree + "-" + this.userObject); 503// System.out.println(tree.isResourceNode() + "," + tree.isLiteralNode() + "---" + this.isResourceNode + "," + this.isLiteralNode); 504// if(tree.getParent() != null && getParent() != null) 505// System.out.println(tree.getParent().getEdge(tree) + "#" + getParent().getEdge(this)); 506// System.out.println(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject)); 507 if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){ 508 return false; 509 } 510 if(isResourceNode() && tree.isResourceNode() && this.userObject.equals(tree.getUserObject())){ 511 return true; 512 } 513 Object edge; 514 for(QueryTree<N> child : tree.getChildren()){ 515 boolean isSubsumed = false; 516 edge = tree.getEdge(child); 517 for(QueryTree<N> child2 : this.getChildren(edge)){ 518 if(child2.isSubsumedBy(child)){ 519 isSubsumed = true; 520 break; 521 } 522 } 523 if(!isSubsumed){ 524// System.err.println(child.getParent() + "--" + child.getParent().getEdge(child) + "-->" + child); 525// System.err.println(child.getStringRepresentation(true)); 526 return false; 527 } 528 } 529 return true; 530// return isSubsumedBy(tree, LiteralNodeSubsumptionStrategy.OFF); 531 } 532 533 @Override 534 public boolean isSubsumedBy(QueryTree<N> tree, LiteralNodeSubsumptionStrategy strategy) { 535// System.out.println("++++++++++++++++++++++++++++"); 536// System.out.println(tree + "-" + this.userObject); 537// System.out.println(tree.isResourceNode() + "," + tree.isLiteralNode() + "---" + this.isResourceNode + "," + this.isLiteralNode); 538// if(tree.getParent() != null && getParent() != null) 539// System.out.println(tree.getParent().getEdge(tree) + "#" + getParent().getEdge(this)); 540// System.out.println(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject)); 541 542 if(tree.isResourceNode() && this.isResourceNode){ 543 if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){ 544 return false; 545 } 546 } else if(tree.isLiteralNode() && this.isLiteralNode){ 547 if(!tree.getUserObject().equals(this.userObject)){ 548 if(strategy == LiteralNodeSubsumptionStrategy.OFF){ 549 return tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject); 550 } else { 551 // rdf:PlainLiteral 552 if(tree.getDatatype() == null && this.getDatatype() == null) { 553 return true; 554 } 555 if(tree.getLiterals().isEmpty()) { 556 return true; 557 } 558 return subsumes(tree.getLiterals(), this.getLiterals(), strategy); 559 } 560 } 561 } else if(!tree.isVarNode() && this.isVarNode()){ 562 return false; 563 } else if(tree.isVarNode() && this.isLiteralNode()) { 564 return true; 565 } else if(tree.isResourceNode() && this.isLiteralNode || tree.isLiteralNode() && this.isResourceNode){//node type mismatch 566 return false; 567 } 568 Object edge; 569 for(QueryTree<N> child : tree.getChildren()){ 570 boolean isSubsumed = false; 571 edge = tree.getEdge(child); 572 for(QueryTree<N> child2 : this.getChildren(edge)){ 573 if(child2.isSubsumedBy(child, strategy)){ 574 isSubsumed = true; 575 break; 576 } 577 } 578 if(!isSubsumed){ 579// System.err.println("not covered: " + QueryTreeUtils.printPathToRoot(child, tree)); 580 return false; 581 } 582 } 583 return true; 584 } 585 586 private boolean subsumes(Set<Literal> subsumer, Set<Literal> subsumee, LiteralNodeSubsumptionStrategy strategy){ 587 if(subsumer.isEmpty() || subsumee.isEmpty()){ 588 return false; 589 } 590 if(strategy == LiteralNodeSubsumptionStrategy.DATATYPE){ 591 //check if both datatypes are the same 592 RDFDatatype subsumerDatatype = getDatatype(subsumer); 593 RDFDatatype subsumeeDatatype = getDatatype(subsumee); 594 595// if(subsumerDatatype == null && subsumeeDatatype == null) { 596// return true; 597// } 598 599 if(subsumerDatatype == null || subsumeeDatatype == null) { 600 return false; 601 } 602 603 return subsumerDatatype.equals(subsumeeDatatype); 604 } else if(strategy == LiteralNodeSubsumptionStrategy.ENUMERATION){ 605 return subsumer.containsAll(subsumee); 606 } else { 607 //check if both datatypes are the same 608 RDFDatatype subsumerDatatype = getDatatype(subsumer); 609 RDFDatatype subsumeeDatatype = getDatatype(subsumee); 610 611 if(subsumerDatatype == null || subsumeeDatatype == null) { 612 return false; 613 } 614 615 if(!subsumerDatatype.equals(subsumeeDatatype)){ 616 return false; 617 } 618 619 //avoid boolean datatypes for interval check as there are only 2 possible values 620 if(subsumerDatatype.equals(XSDDatatype.XSDboolean)){ 621 return true; 622 } 623 624 if(strategy == LiteralNodeSubsumptionStrategy.INTERVAL){ 625 //check if subsumee interval is contained in subsumer interval 626 Literal subsumerMin = getMin(subsumer); 627 Literal subsumerMax = getMax(subsumer); 628 629 Literal subsumeeMin = getMin(subsumee); 630 Literal subsumeeMax = getMax(subsumee); 631 632 boolean leftMoreGeneral = isLessOrEqual(subsumerMin, subsumeeMin); 633 boolean rightMoreGeneral = isGreaterOrEqual(subsumerMax, subsumeeMax); 634 635 if(!(leftMoreGeneral && rightMoreGeneral)){ 636 // System.out.println("[" + subsumeeMin + "," + subsumeeMax + "] not in interval " + "[" + subsumerMin + "," + subsumerMax + "]"); 637 return false; 638 } 639 } else if(strategy == LiteralNodeSubsumptionStrategy.MIN){ 640 641 //check if subsumee min is greater than subsumer min 642 Literal subsumerMin = getMin(subsumer); 643 Literal subsumeeMin = getMin(subsumee); 644 645 return isGreaterOrEqual(subsumeeMin, subsumerMin); 646 } else if(strategy == LiteralNodeSubsumptionStrategy.MAX){ 647 648 //check if subsumee min is greater than subsumer min 649 Literal subsumerMax = getMax(subsumer); 650 Literal subsumeeMax = getMax(subsumee); 651 652 return isGreaterOrEqual(subsumerMax, subsumeeMax); 653 } 654 } 655 return true; 656 } 657 658 /** 659 * Returns the datatype of the literals. Throws exception if there are multiple datatypes. 660 * @param literals 661 */ 662 private RDFDatatype getDatatype(Set<Literal> literals){ 663 RDFDatatype datatype = literals.iterator().next().getDatatype(); 664 return datatype; 665 } 666 667 /** 668 * Checks if all literals have the same datatype. 669 * @param literals 670 * @return 671 */ 672 private boolean sameDatatype(Set<Literal> literals){ 673 Iterator<Literal> iterator = literals.iterator(); 674 RDFDatatype datatype = iterator.next().getDatatype(); 675 while(iterator.hasNext()){ 676 if(!iterator.next().getDatatype().equals(datatype)){ 677 return false; 678 } 679 } 680 return true; 681 } 682 683 @Override 684 public boolean isSubsumedBy(QueryTree<N> tree, boolean stopAfterError) { 685 if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){ 686 return false; 687 } 688 689 Object edge; 690 for(QueryTree<N> child : tree.getChildren()){ 691 boolean isSubsumed = false; 692 edge = tree.getEdge(child); 693 for(QueryTree<N> child2 : this.getChildren(edge)){ 694 if(child2.isSubsumedBy(child, true)){ 695 isSubsumed = true; 696 break; 697 } 698 } 699 if(!isSubsumed){ 700 child.tag(); 701 return false; 702 } 703 } 704 return true; 705 } 706 707 @Override 708 public void tag(){ 709 tagged = true; 710 } 711 712 @Override 713 public boolean isTagged(){ 714 return tagged; 715 } 716 717 @Override 718 public QueryTree<N> getRoot() { 719 if (parent == null) { 720 return this; 721 } 722 return parent.getRoot(); 723 } 724 725 @Override 726 public List<QueryTree<N>> getLeafs(){ 727 List<QueryTree<N>> leafs = new LinkedList<>(); 728 if(isLeaf()){ 729 leafs.add(this); 730 } else { 731 for(QueryTree<N> child : children){ 732 leafs.addAll(child.getLeafs()); 733 } 734 } 735 return leafs; 736 } 737 738 @Override 739 public List<QueryTree<N>> getPathToRoot() { 740 List<QueryTree<N>> path = new ArrayList<>(); 741 path.add(0, this); 742 QueryTree<N> par = parent; 743 while (par != null) { 744 path.add(0, par); 745 par = par.getParent(); 746 } 747 return path; 748 } 749 750 751 752 @Override 753 public List<N> getUserObjectPathToRoot() { 754 List<N> path = new ArrayList<>(); 755 path.add(0, this.getUserObject()); 756 QueryTree<N> par = parent; 757 while (par != null) { 758 path.add(0, par.getUserObject()); 759 par = par.getParent(); 760 } 761 return path; 762 } 763 764 @Override 765 public List<QueryTree<N>> getChildrenClosure() { 766 List<QueryTree<N>> children = new ArrayList<>(); 767 getChildrenClosure(this, children); 768 return children; 769 } 770 771 private void getChildrenClosure(QueryTree<N> tree, List<QueryTree<N>> bin) { 772 bin.add(tree); 773 for (QueryTree<N> child : tree.getChildren()) { 774 getChildrenClosure(child, bin); 775 } 776 } 777 778 @Override 779 public Set<N> getUserObjectClosure() { 780 Set<N> objects = new HashSet<>(); 781 getUserObjectClosure(this, objects); 782 return objects; 783 } 784 785 @Override 786 public int getTriplePatternCount(){ 787 return countTriplePattern(this); 788 } 789 790 private int countTriplePattern(QueryTree<N> tree){ 791 int cnt = 0; 792 Object object; 793 if(!tree.isLeaf()){ 794 for(QueryTree<N> child : tree.getChildren()){ 795 object = child.getUserObject(); 796 boolean objectIsResource = !object.equals("?"); 797 cnt++; 798 if(!objectIsResource){ 799 cnt+=countTriplePattern(child); 800 } 801 } 802 } 803 return cnt; 804 } 805 806 public QueryTree<N> getSPARQLQueryTree(){ 807 return createSPARQLQueryTree(this); 808 } 809 810 private QueryTree<N> createSPARQLQueryTree(QueryTree<N> tree){ 811 QueryTree<N> copy = new QueryTreeImpl<>(tree.getUserObject()); 812 if(tree.getUserObject().equals("?")){ 813 for(QueryTree<N> child : tree.getChildren()){ 814 copy.addChild((QueryTreeImpl<N>) createSPARQLQueryTree(child), tree.getEdge(child)); 815 } 816 } 817// for(QueryTree<N> child : tree.getChildren()){ 818// if(child.getUserObject().equals("?")){ 819// copy.addChild((QueryTreeImpl<N>) createSPARQLQueryTree(child), tree.getEdge(child)); 820// } else { 821// copy.addChild((QueryTreeImpl<N>) child, tree.getEdge(child)); 822// } 823// 824// } 825 826 return copy; 827 } 828 829 private void getUserObjectClosure(QueryTree<N> tree, Set<N> bin) { 830 bin.add(tree.getUserObject()); 831 for (QueryTree<N> child : tree.getChildren()) { 832 getUserObjectClosure(child, bin); 833 } 834 } 835 836 @Override 837 public String getStringRepresentation(){ 838 return getStringRepresentation(false); 839 } 840 841 /** 842 * Prints the query tree and shows children of resources only if enabled. 843 * @param stopIfChildIsResourceNode whether to stop if child is resource 844 * @return the query tree string 845 */ 846 @Override 847 public String getStringRepresentation(boolean stopIfChildIsResourceNode){ 848 int depth = getPathToRoot().size(); 849 StringBuilder sb = new StringBuilder(); 850 if(isRoot()){ 851 sb.append("TREE\n\n"); 852 } 853 String ren = toStringRenderer.render(this); 854 ren = ren.replace("\n", "\n" + sb); 855 sb.append(ren); 856 sb.append("\n"); 857 if(isRoot() || !isResourceNode || (isResourceNode && !stopIfChildIsResourceNode)){ 858 for (QueryTree<N> child : getChildren()) { 859 for (int i = 0; i < depth; i++) { 860 sb.append("\t"); 861 } 862 Object edge = getEdge(child); 863 if (edge != null) { 864 sb.append(" "); 865 sb.append(edge); 866 sb.append(" ---> "); 867 } 868 sb.append(child.getStringRepresentation(stopIfChildIsResourceNode)); 869 } 870 } 871 return sb.toString(); 872 } 873 874 public String getStringRepresentation(int indent){ 875 int depth = getPathToRoot().size(); 876 StringBuilder sb = new StringBuilder(); 877 for (int i = 0; i < depth + indent; i++) { 878 sb.append("\t"); 879 } 880 String ren = toStringRenderer.render(this); 881 ren = ren.replace("\n", "\n" + sb); 882 sb.append(ren); 883 sb.append("\n"); 884 for (QueryTree<N> child : getChildren()) { 885 Object edge = getEdge(child); 886 if (edge != null) { 887 sb.append("--- "); 888 sb.append(edge); 889 sb.append(" ---\n"); 890 } 891 sb.append(((QueryTreeImpl<N>)child).getStringRepresentation(indent)); 892 } 893 return sb.toString(); 894 } 895 896 @Override 897 public void dump() { 898 dump(new PrintWriter(System.out), 0); 899 } 900 901 @Override 902 public void dump(PrintWriter writer) { 903 dump(writer, 0); 904 } 905 906 @Override 907 public void dump(PrintWriter writer, int indent) { 908 int depth = getPathToRoot().size(); 909 StringBuilder sb = new StringBuilder(); 910 for (int i = 0; i < depth + indent; i++) { 911 sb.append("\t"); 912 } 913 writer.print(sb.toString()); 914 String ren = toStringRenderer.render(this); 915 ren = ren.replace("\n", "\n" + sb); 916 writer.println(ren); 917 for (QueryTree<N> child : getChildren()) { 918 Object edge = getEdge(child); 919 boolean meaningful = !edge.equals(RDF.type.getURI()) || meaningful(child); 920 if (meaningful) { 921 writer.print(sb.toString()); 922 writer.print("--- "); 923 writer.print(edge); 924 writer.print(" ---\n"); 925 926 // recursive call 927 child.dump(writer, indent); 928 } 929 } 930 writer.flush(); 931// int depth = getPathToRoot().size(); 932// StringBuilder sb = new StringBuilder(); 933// for (int i = 0; i < depth + indent; i++) { 934// sb.append("\t"); 935// } 936// writer.print(sb.toString()); 937// String ren = toStringRenderer.render(this); 938// ren = ren.replace("\n", "\n" + sb); 939// writer.println(ren); 940// for (QueryTree<N> child : getChildren()) { 941// Object edge = getEdge(child); 942// if (edge != null) { 943// writer.print(sb.toString()); 944// writer.print("--- "); 945// writer.print(edge); 946// writer.print(" ---\n"); 947// } 948// child.dump(writer, indent); 949// } 950// writer.flush(); 951 } 952 953 private boolean meaningful(QueryTree<N> tree){ 954 if(tree.isResourceNode() || tree.isLiteralNode()){ 955 return true; 956 } else { 957 for (QueryTree<N> child : tree.getChildren()) { 958 Object edge = tree.getEdge(child); 959 if(!edge.equals(RDFS.subClassOf.getURI())){ 960 return true; 961 } else if(child.isResourceNode()){ 962 return true; 963 } else if(meaningful(child)){ 964 return true; 965 } 966 } 967 } 968 return false; 969 } 970 971 @Override 972 public List<N> fillDepthFirst() { 973 List<N> results = new ArrayList<>(); 974 fillDepthFirst(this, results); 975 return results; 976 } 977 978 private void fillDepthFirst(QueryTree<N> tree, List<N> bin) { 979 bin.add(tree.getUserObject()); 980 for (QueryTree<N> child : tree.getChildren()) { 981 fillDepthFirst(child, bin); 982 } 983 } 984 985 public void replace(QueryTreeImpl<N> tree) { 986 parent.children.remove(this); 987 parent.children.add(tree); 988 parent = null; 989 tree.children.clear(); 990 tree.children.addAll(children); 991 children.clear(); 992 } 993 994 public String toString() { 995 if (userObject != null) { 996 return userObject.toString(); 997 } else { 998 return ""; 999 } 1000 } 1001 1002 public int getSize() { 1003 return getUserObjectClosure().size(); 1004 } 1005 1006 @Override 1007 public int getMaxDepth() { 1008 return getMaxDepth(this); 1009 } 1010 1011 private int getMaxDepth(QueryTree<N> tree) { 1012 int maxChildDepth = tree.getPathToRoot().size(); 1013 for (QueryTree<N> child : tree.getChildren()) { 1014 int childDepth = getMaxDepth(child); 1015 if(childDepth > maxChildDepth) { 1016 maxChildDepth = childDepth; 1017 } 1018 } 1019 return maxChildDepth; 1020 } 1021 1022 @Override 1023 public Object clone() throws CloneNotSupportedException { 1024 QueryTreeImpl<N> copy = new QueryTreeImpl<>(this.userObject, this.nodeType); 1025 copy.setIsResourceNode(isResourceNode); 1026 copy.setIsLiteralNode(isLiteralNode); 1027 for(QueryTreeImpl<N> child : children){ 1028 copy.addChild((QueryTreeImpl<N>)child.clone(), getEdge(child)); 1029 } 1030 1031 return copy; 1032 } 1033 1034// @Override 1035// public boolean equals(Object obj) { 1036// if(obj == this){ 1037// return true; 1038// } 1039// if(!(obj instanceof QueryTreeImpl<?>)){ 1040// return false; 1041// } 1042// QueryTreeImpl<N> other = (QueryTreeImpl<N>)obj; 1043// if(!this.userObject.equals(other.getUserObject())){ 1044// return false; 1045// } 1046// Object edge; 1047// for(QueryTreeImpl<N> child : this.children){ 1048// boolean existsEqualChild = false; 1049// edge = child2EdgeMap.get(child); 1050// for(QueryTree<N> child2 : other.getChildren(edge)){ 1051// if(child.equals(child2)){ 1052// existsEqualChild = true; 1053// break; 1054// } 1055// } 1056// if(!existsEqualChild){ 1057// return false; 1058// } 1059// } 1060// return true; 1061// } 1062 1063 @Override 1064 public boolean isSameTreeAs(QueryTree<N> tree){ 1065 if(!this.userObject.equals(tree.getUserObject())){ 1066 return false; 1067 } 1068 Object edge; 1069 for(QueryTreeImpl<N> child : this.children){ 1070 boolean existsEqualChild = false; 1071 edge = child2EdgeMap.get(child); 1072 for(QueryTree<N> child2 : tree.getChildren(edge)){ 1073 if(child.isSameTreeAs(child2)){ 1074 existsEqualChild = true; 1075 break; 1076 } 1077 } 1078 if(!existsEqualChild){ 1079 return false; 1080 } 1081 } 1082 return true; 1083 } 1084 1085 @Override 1086 public Query toSPARQLQuery() { 1087 return QueryFactory.create(toSPARQLQueryString(), Syntax.syntaxARQ); 1088 } 1089 1090 @Override 1091 public String toSPARQLQueryString() { 1092 if(children.isEmpty()){ 1093 return "SELECT ?x0 WHERE {?x0 ?y ?z.}"; 1094 } 1095 cnt = 0; 1096 StringBuilder sb = new StringBuilder(); 1097 sb.append("SELECT DISTINCT ?x0 WHERE {\n"); 1098 List<String> filters = new ArrayList<>(); 1099 buildSPARQLQueryString(this, sb, true, false, filters); 1100 for(String filter : filters){ 1101 sb.append(filter).append("\n"); 1102 } 1103 sb.append("}"); 1104 return sb.toString(); 1105 } 1106 1107 @Override 1108 public String toSPARQLQueryString(boolean filterMeaninglessProperties, boolean useNumericalFilters) { 1109 return toSPARQLQueryString(filterMeaninglessProperties, useNumericalFilters, Collections.<String, String>emptyMap()); 1110 } 1111 1112 @Override 1113 public String toSPARQLQueryString(boolean filterMeaninglessProperties, boolean useNumericalFilters, Map<String, String> prefixMap) { 1114 if(children.isEmpty()){ 1115 return "SELECT ?x0 WHERE {?x0 ?y ?z.}"; 1116 } 1117 cnt = 0; 1118 StringBuilder sb = new StringBuilder(); 1119 List<String> filters = new ArrayList<>(); 1120 sb.append("SELECT DISTINCT ?x0 WHERE {\n"); 1121 buildSPARQLQueryString(this, sb, filterMeaninglessProperties, useNumericalFilters, filters); 1122 for(String filter : filters){ 1123 sb.append(filter).append("\n"); 1124 } 1125 sb.append("}"); 1126 Query query = QueryFactory.create(sb.toString(), Syntax.syntaxSPARQL_11); 1127 1128 //get the used resources in the query 1129 Set<String> usedResources = getUsedResources(query); 1130 1131 //add a prefix for each used namespace 1132 for (Entry<String, String> entry : prefixMap.entrySet()) { 1133 String prefix = entry.getKey(); 1134 String namespace = entry.getValue(); 1135 for (String res : usedResources) { 1136 if(res.startsWith(namespace)){ 1137 query.setPrefix(prefix, namespace); 1138 break; 1139 } 1140 } 1141 } 1142 return query.toString(); 1143 } 1144 1145 private Set<String> getUsedResources(Query query) { 1146 final Set<String> resources = Sets.newHashSet(); 1147 query.getQueryPattern().visit(new ElementVisitorBase() { 1148 @Override 1149 public void visit(ElementGroup el) { 1150 el.getElements().get(0).visit(this); 1151 } 1152 1153 @Override 1154 public void visit(ElementPathBlock el) { 1155 for (Iterator<TriplePath> it = el.patternElts(); it.hasNext();) { 1156 Triple t = it.next().asTriple(); 1157 if (t.getSubject().isURI()) { 1158 resources.add(t.getSubject().getURI()); 1159 } 1160 if (t.getPredicate().isURI()) { 1161 resources.add(t.getPredicate().getURI()); 1162 } 1163 if (t.getObject().isURI()) { 1164 resources.add(t.getObject().getURI()); 1165 } 1166 } 1167 } 1168 1169 @Override 1170 public void visit(ElementTriplesBlock el) { 1171 for (Iterator<Triple> it = el.patternElts(); it.hasNext();) { 1172 Triple t = it.next(); 1173 if (t.getSubject().isURI()) { 1174 resources.add(t.getSubject().getURI()); 1175 } 1176 if (t.getPredicate().isURI()) { 1177 resources.add(t.getPredicate().getURI()); 1178 } 1179 if (t.getObject().isURI()) { 1180 resources.add(t.getObject().getURI()); 1181 } 1182 } 1183 } 1184 }); 1185 return resources; 1186 } 1187 1188 private void buildSPARQLQueryString(QueryTree<N> tree, StringBuilder sb, boolean filterMeaninglessProperties, boolean useNumericalFilters, List<String> filters){ 1189 Object subject = null; 1190 if(tree.getUserObject().equals("?")){ 1191 subject = "?x" + cnt++; 1192 if(useNumericalFilters){ 1193 if(tree.isLiteralNode() && !tree.getLiterals().isEmpty()){ 1194 filters.add(getFilter(subject.toString(), tree.getLiterals())); 1195 } 1196 } 1197 } else { 1198 subject = "<" + tree.getUserObject() + ">"; 1199 } 1200 Object predicate; 1201 Object object; 1202 if(!tree.isLeaf()){ 1203 for(QueryTree<N> child : tree.getChildren()){ 1204 predicate = tree.getEdge(child); 1205 if(filterMeaninglessProperties){ 1206 if(Filters.getAllFilterProperties().contains(predicate.toString())){ 1207 continue; 1208 } 1209 } 1210 object = child.getUserObject(); 1211 boolean objectIsResource = !object.equals("?"); 1212 if(!objectIsResource){ 1213 object = "?x" + cnt; 1214 } else if(((String)object).startsWith("http://")){ 1215 object = "<" + object + ">"; 1216 } 1217 if(child.isLiteralNode() && object.toString().contains("\n")) { 1218 object = "\"\"" + object + "\"\""; 1219 } 1220 sb.append(subject).append(" <").append(predicate).append("> ").append(object).append(".\n"); 1221 if(!objectIsResource){ 1222 buildSPARQLQueryString(child, sb, filterMeaninglessProperties, useNumericalFilters, filters); 1223 } 1224 } 1225 } 1226 } 1227 1228 private void buildSPARQLQueryStringPretty(QueryTree<N> tree, StringBuilder sb, boolean filterMeaninglessProperties, boolean useNumericalFilters, List<String> filters){ 1229 Object subject = null; 1230 if(tree.getUserObject().equals("?")){ 1231 subject = "?x" + cnt++; 1232 if(useNumericalFilters){ 1233 if(tree.isLiteralNode() && !tree.getLiterals().isEmpty()){ 1234 filters.add(getFilter(subject.toString(), tree.getLiterals())); 1235 } 1236 } 1237 } else { 1238 subject = "<" + tree.getUserObject() + ">"; 1239 } 1240 boolean first = true; 1241 Object predicate; 1242 Object object; 1243 if(!tree.isLeaf()){ 1244 for(Iterator<QueryTree<N>> iter = tree.getChildren().iterator(); iter.hasNext();){ 1245 QueryTree<N> child = iter.next(); 1246 //get the predicate 1247 predicate = tree.getEdge(child); 1248 if(filterMeaninglessProperties){ 1249 if(Filters.getAllFilterProperties().contains(predicate.toString())){ 1250 continue; 1251 } 1252 } 1253 //get the object 1254 object = child.getUserObject(); 1255 boolean objectIsResource = !object.equals("?"); 1256 if(!objectIsResource){ 1257 object = "?x" + cnt; 1258 } else if(((String)object).startsWith("http://")){ 1259 object = "<" + object + ">"; 1260 } 1261 //attach the triple pattern 1262 if(first){ 1263 sb.append(subject).append(" <").append(predicate).append("> ").append(object); 1264 if(iter.hasNext() && (objectIsResource || child.isLeaf())){ 1265 sb.append(";"); 1266 } else { 1267 sb.append("."); 1268 } 1269 sb.append("\n"); 1270 first = false; 1271 } else { 1272 sb.append(" <").append(predicate).append("> ").append(object); 1273 if(iter.hasNext() && (objectIsResource || child.isLeaf())){ 1274 sb.append(";"); 1275 } else { 1276 sb.append("."); 1277 } 1278 sb.append("\n"); 1279 } 1280 1281 //recursive call if object is not a resource or literal 1282 if(!child.isResourceNode() && !child.isLeaf()){ 1283 buildSPARQLQueryString(child, sb, filterMeaninglessProperties, useNumericalFilters, filters); 1284 if(child.isVarNode()){ 1285 first = true; 1286 } 1287 } 1288 } 1289 } 1290 } 1291 1292 private String getFilter(String varName, Set<Literal> literals){ 1293 String filter = "FILTER("; 1294 1295 Literal min = getMin(literals); 1296 filter += varName + ">=\"" + min.getLexicalForm() + "\"^^<" + min.getDatatypeURI() + ">"; 1297 1298 filter += " && "; 1299 1300 Literal max = getMax(literals); 1301 filter += varName + "<=\"" + max.getLexicalForm() + "\"^^<" + min.getDatatypeURI() + ">"; 1302 1303 filter += ")"; 1304 return filter; 1305 } 1306 1307 private boolean isLessOrEqual(Literal l1, Literal l2){ 1308 if((l1.getDatatype() == XSDDatatype.XSDinteger || l1.getDatatype() == XSDDatatype.XSDint) && 1309 (l2.getDatatype() == XSDDatatype.XSDinteger || l2.getDatatype() == XSDDatatype.XSDint)){ 1310 return (l1.getInt() <= l2.getInt()); 1311 } else if((l1.getDatatype() == XSDDatatype.XSDdouble || l1.getDatatype() == XSDDatatype.XSDdecimal) && 1312 (l2.getDatatype() == XSDDatatype.XSDdouble || l2.getDatatype() == XSDDatatype.XSDdecimal)){ 1313 return l1.getDouble() <= l2.getDouble(); 1314 } else if(l1.getDatatype() == XSDDatatype.XSDfloat && l2.getDatatype() == XSDDatatype.XSDfloat){ 1315 return l1.getFloat() <= l2.getFloat(); 1316 } else if(l1.getDatatype() == XSDDatatype.XSDdate && l2.getDatatype() == XSDDatatype.XSDdate){ 1317 Calendar date1 = DatatypeConverter.parseDate(l1.getLexicalForm()); 1318 Calendar date2 = DatatypeConverter.parseDate(l2.getLexicalForm()); 1319 int comp = date1.compareTo(date2); 1320 return comp <= 0; 1321 } 1322 return false; 1323 } 1324 1325 private boolean isGreaterOrEqual(Literal l1, Literal l2){ 1326 if((l1.getDatatype() == XSDDatatype.XSDinteger || l1.getDatatype() == XSDDatatype.XSDint) && 1327 (l2.getDatatype() == XSDDatatype.XSDinteger || l2.getDatatype() == XSDDatatype.XSDint)){ 1328 return (l1.getInt() >= l2.getInt()); 1329 } else if((l1.getDatatype() == XSDDatatype.XSDdouble || l1.getDatatype() == XSDDatatype.XSDdecimal) && 1330 (l2.getDatatype() == XSDDatatype.XSDdouble || l2.getDatatype() == XSDDatatype.XSDdecimal)){ 1331 return l1.getDouble() >= l2.getDouble(); 1332 } else if(l1.getDatatype() == XSDDatatype.XSDfloat && l2.getDatatype() == XSDDatatype.XSDfloat){ 1333 return l1.getFloat() >= l2.getFloat(); 1334 } else if(l1.getDatatype() == XSDDatatype.XSDdate && l2.getDatatype() == XSDDatatype.XSDdate){ 1335 Calendar date1 = DatatypeConverter.parseDate(l1.getLexicalForm()); 1336 Calendar date2 = DatatypeConverter.parseDate(l2.getLexicalForm()); 1337 int comp = date1.compareTo(date2); 1338 return comp >= 0; 1339 } 1340 return false; 1341 } 1342 1343 private Literal getMin(Set<Literal> literals){ 1344 Iterator<Literal> iter = literals.iterator(); 1345 Literal min = iter.next(); 1346 Literal l; 1347 while(iter.hasNext()){ 1348 l = iter.next(); 1349 if(l.getDatatype() == XSDDatatype.XSDinteger || l.getDatatype() == XSDDatatype.XSDint){ 1350 min = (l.getInt() < min.getInt()) ? l : min; 1351 } else if(l.getDatatype() == XSDDatatype.XSDdouble || l.getDatatype() == XSDDatatype.XSDdecimal){ 1352 min = (l.getDouble() < min.getDouble()) ? l : min; 1353 } else if(l.getDatatype() == XSDDatatype.XSDfloat){ 1354 min = (l.getFloat() < min.getFloat()) ? l : min; 1355 } else if(l.getDatatype() == XSDDatatype.XSDdate){ 1356 min = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(min.getLexicalForm())) == -1) ? l : min; 1357 } else if(l.getDatatype() == XSDDatatype.XSDgYear){ 1358 min = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(min.getLexicalForm())) == -1) ? l : min; 1359 } 1360 } 1361 return min; 1362 } 1363 1364 private Literal getMax(Set<Literal> literals){ 1365 Iterator<Literal> iter = literals.iterator(); 1366 Literal max = iter.next(); 1367 Literal l; 1368 while(iter.hasNext()){ 1369 l = iter.next(); 1370 if(l.getDatatype() == XSDDatatype.XSDinteger || l.getDatatype() == XSDDatatype.XSDint){ 1371 max = (l.getInt() > max.getInt()) ? l : max; 1372 } else if(l.getDatatype() == XSDDatatype.XSDdouble || l.getDatatype() == XSDDatatype.XSDdecimal){ 1373 max = (l.getDouble() > max.getDouble()) ? l : max; 1374 } else if(l.getDatatype() == XSDDatatype.XSDfloat){ 1375 max = (l.getFloat() > max.getFloat()) ? l : max; 1376 } else if(l.getDatatype() == XSDDatatype.XSDdate){ 1377 max = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(max.getLexicalForm())) == 1) ? l : max; 1378 } else if(l.getDatatype() == XSDDatatype.XSDgYear){ 1379 max = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(max.getLexicalForm())) == 1) ? l : max; 1380 } 1381 } 1382 return max; 1383 } 1384 1385 @Override 1386 public Query toQuery(){ 1387 Query query = QueryFactory.make(); 1388 query.setQuerySelectType(); 1389 query.addResultVar(NodeFactory.createVariable("x0")); 1390 query.setDistinct(true); 1391 query.setPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); 1392 query.setPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); 1393 query.setPrefix("yago", "http://dbpedia.org/class/yago/"); 1394 query.setPrefix("cyc", "http://sw.opencyc.org/2008/06/10/concept/"); 1395 query.setPrefix("owl", "http://www.w3.org/2002/07/owl#"); 1396 query.setPrefix("dbp", "http://dbpedia.org/property/"); 1397 query.setPrefix("dbo", "http://dbpedia.org/ontology/"); 1398 query.setPrefix("dbr", "http://dbpedia.org/resource/"); 1399 query.setPrefix("dc", "http://purl.org/dc/terms/"); 1400 ElementGroup whereClause = new ElementGroup(); 1401 ElementTriplesBlock triples = new ElementTriplesBlock(); 1402 for(Triple t : buildTriples(this)){ 1403 triples.addTriple(t); 1404 } 1405 whereClause.addElement(triples); 1406 1407 query.setQueryPattern(whereClause); 1408 return query; 1409 } 1410 1411 private List<Triple> buildTriples(QueryTree<N> tree){ 1412 List<Triple> triples = new ArrayList<>(); 1413 Pattern pattern = Pattern.compile("^^", Pattern.LITERAL); 1414 1415 Node subject = tree.getUserObject().equals("?") ? NodeFactory.createVariable("x" + tree.getId()) : NodeFactory.createURI((String) tree.getUserObject()); 1416 Node predicate = null; 1417 Node object = null; 1418 1419 String objectLabel = null; 1420 for(QueryTree<N> child : tree.getChildren()){ 1421 predicate = NodeFactory.createURI((String) tree.getEdge(child)); 1422 objectLabel = (String) child.getUserObject(); 1423 if(objectLabel.equals("?")){ 1424 object = NodeFactory.createVariable("x" + child.getId()); 1425 } else if(objectLabel.startsWith("http:")){ 1426 object = NodeFactory.createURI(objectLabel); 1427 } else { 1428// System.out.println(objectLabel); 1429 String[] split = objectLabel.split("@"); 1430// System.out.println(Arrays.toString(split)); 1431 if(split.length == 2){ 1432 object = NodeFactory.createLiteral(split[0], split[1], null); 1433 } else { 1434 1435 split = pattern.split(objectLabel); 1436 if(split.length == 2){ 1437 object = NodeFactory.createLiteral(split[0], null, new BaseDatatype(split[1])); 1438 } else { 1439 object = NodeFactory.createLiteral(objectLabel); 1440 } 1441 } 1442 1443 } 1444 triples.add(new Triple(subject, predicate, object)); 1445 if(!child.isLeaf() && child.isVarNode()){ 1446 triples.addAll(buildTriples(child)); 1447 } 1448 } 1449 return triples; 1450 } 1451 1452 public void addLiteral(Literal l){ 1453 literals.add(l); 1454 } 1455 1456 @Override 1457 public Set<Literal> getLiterals() { 1458 return literals; 1459 } 1460 1461 public void addLiterals(Collection<Literal> literals) { 1462 this.literals.addAll(literals); 1463 } 1464 1465 @Override 1466 public RDFDatatype getDatatype(){ 1467 if(isLiteralNode){ 1468 if(!literals.isEmpty()){ 1469 return literals.iterator().next().getDatatype(); 1470 } else { 1471 return null; 1472 } 1473 } else { 1474 throw new UnsupportedOperationException("Node ist not a literal"); 1475 } 1476 } 1477 1478 /** 1479 * Converts the query tree in a corresponding OWL class expression. Literal nodes 1480 * are transformed into existential restrictions. 1481 */ 1482 @Override 1483 public OWLClassExpression asOWLClassExpression(){ 1484 return asOWLClassExpression(LiteralNodeConversionStrategy.DATATYPE); 1485 } 1486 1487 /** 1488 * Converts the query tree in a corresponding OWL class expression. Literal nodes 1489 * are transformed following the given strategy. 1490 */ 1491 @Override 1492 public OWLClassExpression asOWLClassExpression(LiteralNodeConversionStrategy literalNodeConversionStrategy){ 1493 OWLDataFactory df = new OWLDataFactoryImpl(); 1494 QueryTree<N> root = getRoot(); 1495 Set<OWLClassExpression> classExpressions = buildOWLClassExpressions(df, root, literalNodeConversionStrategy); 1496 if(classExpressions.size() == 1){ 1497 return classExpressions.iterator().next(); 1498 } else { 1499 return df.getOWLObjectIntersectionOf(classExpressions); 1500 } 1501 } 1502 1503 private Set<OWLClassExpression> buildOWLClassExpressions(OWLDataFactory df, QueryTree<N> tree, LiteralNodeConversionStrategy literalNodeConversionStrategy){ 1504 1505 List<QueryTree<N>> children = tree.getChildren(); 1506 1507 // if tree has no children return owl:Thing 1508 if(children.isEmpty()) { 1509 return Collections.<OWLClassExpression>singleton(df.getOWLThing()); 1510 } 1511 1512 // process children 1513 Set<OWLClassExpression> classExpressions = new HashSet<>(); 1514 for(QueryTree<N> child : children){ 1515 String childLabel = (String) child.getUserObject(); 1516 String predicateString = (String) tree.getEdge(child); 1517 if(predicateString.equals(RDF.type.getURI()) || predicateString.equals(RDFS.subClassOf.getURI())){//A 1518 if(child.isVarNode()){ 1519 classExpressions.addAll(buildOWLClassExpressions(df, child, literalNodeConversionStrategy)); 1520 } else { 1521 if(!childLabel.equals(OWL.Thing.getURI())){//avoid trivial owl:Thing statements 1522 classExpressions.add(df.getOWLClass(IRI.create(childLabel))); 1523 } 1524 } 1525 } else { 1526 if(child.isLiteralNode()){ 1527 OWLDataProperty p = df.getOWLDataProperty(IRI.create((String) tree.getEdge(child))); 1528 if(childLabel.equals("?")){//p some int 1529 Set<Literal> literals = child.getLiterals(); 1530 OWLDataRange dataRange = null; 1531 if(literals.isEmpty()){//happens if there are heterogeneous datatypes 1532 String datatypeURI = OWL2Datatype.RDFS_LITERAL.getIRI().toString(); 1533 dataRange = df.getOWLDatatype(IRI.create(datatypeURI)); 1534 } else { 1535 if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.DATATYPE){ 1536 Literal lit = literals.iterator().next(); 1537 RDFDatatype datatype = lit.getDatatype(); 1538 String datatypeURI; 1539 if(datatype == null){ 1540 datatypeURI = OWL2Datatype.RDF_PLAIN_LITERAL.getIRI().toString(); 1541 } else { 1542 datatypeURI = datatype.getURI(); 1543 } 1544 dataRange = df.getOWLDatatype(IRI.create(datatypeURI)); 1545 } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.DATA_ONE_OF){ 1546 dataRange = asDataOneOf(df, literals); 1547 } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MIN_MAX){ 1548 dataRange = asFacet(df, literals); 1549 } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MIN){ 1550 dataRange = asMinFacet(df, literals); 1551 } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MAX){ 1552 dataRange = asMaxFacet(df, literals); 1553 } 1554 } 1555 classExpressions.add(df.getOWLDataSomeValuesFrom(p, dataRange)); 1556 } else {//p value 1.2 1557 Set<Literal> literals = child.getLiterals(); 1558 Literal lit = literals.iterator().next(); 1559 OWLLiteral owlLiteral = asOWLLiteral(df, lit); 1560 classExpressions.add(df.getOWLDataHasValue(p, owlLiteral)); 1561 } 1562 } else { 1563 OWLObjectProperty p = df.getOWLObjectProperty(IRI.create((String) tree.getEdge(child))); 1564 OWLClassExpression filler; 1565 if(child.isVarNode()){//p some C 1566// System.out.println(child + ":" + child.isVarNode() + ":" + child.isResourceNode()); 1567 Set<OWLClassExpression> fillerClassExpressions = buildOWLClassExpressions(df, child, literalNodeConversionStrategy); 1568 if(fillerClassExpressions.isEmpty()){ 1569 filler = df.getOWLThing(); 1570 } else if(fillerClassExpressions.size() == 1){ 1571 filler = fillerClassExpressions.iterator().next(); 1572 } else { 1573 filler = df.getOWLObjectIntersectionOf(fillerClassExpressions); 1574 } 1575 classExpressions.add(df.getOWLObjectSomeValuesFrom(p, filler)); 1576 } else {//p value {a} 1577 classExpressions.add(df.getOWLObjectHasValue(p, df.getOWLNamedIndividual(IRI.create(childLabel)))); 1578 } 1579 } 1580 } 1581 } 1582 return classExpressions; 1583 } 1584 1585 private OWLDataRange asFacet(OWLDataFactory df, Set<Literal> literals){ 1586 //return Boolean datatype because it doesn't make sense to return a facet of Boolean values 1587 if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){ 1588 return df.getBooleanOWLDatatype(); 1589 } 1590 Literal min = getMin(literals); 1591 Literal max = getMax(literals); 1592 1593 OWLFacetRestriction minRestriction = df.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, asOWLLiteral(df, min)); 1594 OWLFacetRestriction maxRestriction = df.getOWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, asOWLLiteral(df, max)); 1595 1596 return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), minRestriction, maxRestriction); 1597 } 1598 1599 private OWLDataRange asMinFacet(OWLDataFactory df, Set<Literal> literals){ 1600 //return Boolean datatype because it doesn't make sense to return a facet of Boolean values 1601 if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){ 1602 return df.getBooleanOWLDatatype(); 1603 } 1604 Literal min = getMin(literals); 1605 1606 OWLFacetRestriction minRestriction = df.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, asOWLLiteral(df, min)); 1607 1608 return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), minRestriction); 1609 } 1610 1611 private OWLDataRange asMaxFacet(OWLDataFactory df, Set<Literal> literals){ 1612 //return Boolean datatype because it doesn't make sense to return a facet of Boolean values 1613 if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){ 1614 return df.getBooleanOWLDatatype(); 1615 } 1616 Literal max = getMax(literals); 1617 1618 OWLFacetRestriction maxRestriction = df.getOWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, asOWLLiteral(df, max)); 1619 1620 return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), maxRestriction); 1621 } 1622 1623 private OWLDataRange asDataOneOf(OWLDataFactory df, Set<Literal> literals){ 1624 //return Boolean datatype because it doesn't make sense to return a enumeration of Boolean values 1625 if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){ 1626 return df.getBooleanOWLDatatype(); 1627 } 1628 return df.getOWLDataOneOf(asOWLLiterals(df, literals)); 1629 } 1630 1631 private Set<OWLLiteral> asOWLLiterals(OWLDataFactory df, Set<Literal> literals){ 1632 Set<OWLLiteral> owlLiterals = new HashSet<>(literals.size()); 1633 for (Literal literal : literals) { 1634 owlLiterals.add(asOWLLiteral(df, literal)); 1635 } 1636 return owlLiterals; 1637 } 1638 1639 private OWLLiteral asOWLLiteral(OWLDataFactory df, Literal literal){ 1640 OWLLiteral owlLiteral; 1641 if(literal.getDatatypeURI() == null){ 1642 owlLiteral = df.getOWLLiteral(literal.getLexicalForm(), literal.getLanguage()); 1643 } else { 1644 owlLiteral = df.getOWLLiteral(literal.getLexicalForm(), df.getOWLDatatype(IRI.create(literal.getDatatypeURI()))); 1645 } 1646 return owlLiteral; 1647 } 1648 1649 private OWLDatatype getOWLDatatype(OWLDataFactory df, Set<Literal> literals){ 1650 return df.getOWLDatatype(IRI.create(literals.iterator().next().getDatatypeURI())); 1651 } 1652 1653 private void buildGraph(Graph<Vertex, Edge> graph, QueryTree<N> tree){ 1654 PrefixCCMap prefixes = PrefixCCMap.getInstance(); 1655 List<QueryTree<N>> children = tree.getChildren(); 1656 Vertex parent = new Vertex(tree.getId(), prefixed(prefixes, tree.getUserObject().toString())); 1657 graph.addVertex(parent); 1658 for (QueryTree<N> child : children) { 1659 Vertex childVertex = new Vertex(child.getId(), prefixed(prefixes, child.getUserObject().toString())); 1660 graph.addVertex(childVertex); 1661 Edge edge = new Edge(Long.parseLong(parent.getId() + "0" + childVertex.getId()), prefixed(prefixes, tree.getEdge(child).toString())); 1662 graph.addEdge(parent, childVertex, edge); 1663 buildGraph(graph, child); 1664 } 1665 } 1666 1667 public String asJSON(){ 1668 1669 PrefixCCMap prefixes = PrefixCCMap.getInstance(); 1670 JSONObject json = null; 1671 try { 1672 json = buildJSON(this, prefixes); 1673 JSONArray array = new JSONArray(); 1674 buildJSON2(array, this, prefixes); 1675 System.out.println(array); 1676 } catch (JSONException e) { 1677 e.printStackTrace(); 1678 } 1679 1680 1681 return json.toString(); 1682 } 1683 1684 private JSONObject buildJSON(QueryTree<N> tree, PrefixCCMap prefixes) throws JSONException{ 1685 JSONObject json = new JSONObject(); 1686 json.put("name", prefixed(prefixes, tree.getUserObject().toString())); 1687 JSONArray children = new JSONArray(); 1688 for (QueryTree<N> child : tree.getChildren()) { 1689 children.put(buildJSON(child, prefixes)); 1690 } 1691 json.put("children", children); 1692 return json; 1693 } 1694 1695 private void buildJSON2(JSONArray array, QueryTree<N> tree, PrefixCCMap prefixes) throws JSONException{ 1696 for (QueryTree<N> child : tree.getChildren()) { 1697 JSONObject json = new JSONObject(); 1698 json.put("source", tree.getId()); 1699 json.put("target", child.getId()); 1700 json.put("type", prefixed(prefixes, tree.getEdge(child).toString())); 1701 array.put(json); 1702 buildJSON2(array, child, prefixes); 1703 } 1704 } 1705 1706 private String prefixed(Map<String, String> prefixes, String uri){ 1707 if(uri.startsWith("http://")){ 1708 for (Entry<String, String> entry : prefixes.entrySet()) { 1709 String prefix = entry.getKey(); 1710 String ns = entry.getValue(); 1711 if(uri.startsWith(ns)){ 1712 return uri.replace(ns, prefix + ":"); 1713 } 1714 } 1715 } 1716 return uri; 1717 } 1718}