/******************************************************************************* * Copyright 2012 University of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This code was developed by the Information Integration Group as part * of the Karma project at the Information Sciences Institute of the * University of Southern California. For more information, publications, * and related projects, please see: http://www.isi.edu/integration ******************************************************************************/ package edu.isi.karma.er.helper; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Stack; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.isi.karma.kr2rml.Predicate; import edu.isi.karma.kr2rml.PredicateObjectMap; import edu.isi.karma.kr2rml.RefObjectMap; import edu.isi.karma.kr2rml.mapping.R2RMLMapping; import edu.isi.karma.kr2rml.planning.TriplesMap; /** * @author shri * */ public class SPARQLGeneratorUtil { private static Logger logger = LoggerFactory.getLogger(SPARQLGeneratorUtil.class); private StringBuffer select_params; private HashMap<String, String> prefix_list; private int var_count; private HashMap<String, ParentMapingInfo> ParentMapingInfoList; private class ParentMapingInfo { public TriplesMap parent; public Predicate predicate; public ParentMapingInfo(TriplesMap triple, Predicate predicate) { this.parent = triple; this.predicate = predicate; } } private String generate_sparql(TriplesMap node, String node_symbol, String graph) { ArrayList<Object> queue = new ArrayList<>(); queue.add(node); StringBuffer query = new StringBuffer(); this.var_count = 1; this.prefix_list = new HashMap<>(); this.select_params = new StringBuffer(); HashMap<TriplesMap, String> markedTriples = new HashMap<>(); this.ParentMapingInfoList = new HashMap<>(); HashMap<Predicate, String> predicateList = new HashMap<>(); // using a BFS approach, we traverse the tree from the root node and add triples/predicates to the queue while(!queue.isEmpty()) { Object currentObj = queue.remove(0); // if this is a tripleMap, then add all its RefObjects to the queue // for the predicates, add only the ones that satisfy the criteria of being <...hasValue> if (currentObj instanceof TriplesMap) { String var = "x"+var_count; TriplesMap triple = (TriplesMap)currentObj; boolean foundHasValue = false; List<PredicateObjectMap> predicates = triple.getPredicateObjectMaps(); for (PredicateObjectMap p_map : predicates) { // if there are tripleMaps linked to the current tripleMap, then // we need to save their relation/linkage between them if(p_map.getObject().hasRefObjectMap()) { RefObjectMap objMap = p_map.getObject().getRefObjectMap(); queue.add(objMap.getParentTriplesMap()); logger.info(triple.getSubject().getId() + " ---> " + objMap.getParentTriplesMap().getSubject().getId()); // maintain a list of mapping properties between triples ParentMapingInfoList.put(objMap.getParentTriplesMap().getSubject().getId(), new ParentMapingInfo(triple, p_map.getPredicate())); } else if(!foundHasValue) { if(p_map.getPredicate().getTemplate().toString().equalsIgnoreCase("<http://www.opengis.net/gml/hasValue>")) { queue.add(p_map.getPredicate()); predicateList.put(p_map.getPredicate(), var); foundHasValue = true; } } } // if this triple is marked to be included in the query, // we add it to the markedTriples list and add to the query string // for its class type Eg. // Prefix pref1: <.../.../Input> // x2 a pref1: if (foundHasValue) { markedTriples.put(triple, var); String rdfsTypes = triple.getSubject().getRdfsType().get(0).toString(); this.prefix_list.put(rdfsTypes, "pref"+var_count); query.append(" ?"+var + " a pref"+var_count+": ."); // if the parent of this triple is also marked for the query // then we add the relation to between triples to the query. Eg. // TriplesMap parentTriple = parent.get(triple.getSubject().getId()); ParentMapingInfo parentTriple = ParentMapingInfoList.get(triple.getSubject().getId()); if( parentTriple != null && markedTriples.containsKey(parentTriple.parent)) { String predicate = parentTriple.predicate.getTemplate().toString(); // PredicateObjectMap parentPredicate = getPredicateBetweenTriples(triple, parentTriple); if(predicate != null) { query.append(" ?" + markedTriples.get(parentTriple.parent) + " " + predicate + " ?"+var + " . "); } else { logger.error("predicate is null from parent : " + triple.getSubject().getRdfsType().toString()); } } } var_count++; } // if it is a predicate Object, create a variable in in the query string else if (currentObj instanceof Predicate) { Predicate predicate = (Predicate)currentObj; query.append(" ?" + predicateList.get(predicate) + " " + predicate.getTemplate() + " ?z"+ var_count + " . "); select_params.append(" ?z" + var_count); var_count++; } // if this is a RefObject add the Child Triple to the queue else if (currentObj instanceof RefObjectMap) { RefObjectMap refObj = (RefObjectMap)currentObj; TriplesMap t = refObj.getParentTriplesMap(); queue.add(t); } } // generate the query from the list of prefix and the param lists Iterator<String> itr = this.prefix_list.keySet().iterator(); StringBuffer sQuery = new StringBuffer(); while(itr.hasNext()) { String key = itr.next(); sQuery.append(" PREFIX ").append(this.prefix_list.get(key)).append(": ").append(key); } if(graph == null || graph.isEmpty()) { sQuery.append(" select ").append(select_params).append(" where { ").append(query.toString()).append(" } "); } else { sQuery.append(" select ").append(select_params).append(" where { GRAPH <").append(graph) .append("> { ").append(query.toString()).append(" } }"); } logger.info("Genreated Query : " + sQuery); return sQuery.toString(); } public String get_query(R2RMLMapping r2rmlMap, String graph) { List<TriplesMap> triples = r2rmlMap.getTriplesMapList(); TriplesMap root_node = null; // get the root node first for (TriplesMap row : triples) { if (row.getSubject().isSteinerTreeRootNode() ) { root_node = row; break; } } return generate_sparql(root_node, "x"+var_count, graph); } public String get_query(TriplesMap root, ArrayList<HashMap<String, String>> columns) { return get_query(root, columns, false); } /** * @author shri * This method will genereate a sparql query to select the list of columns (in the order they are provided) * * @param root This object of TriplesMap is the root from which this method begins to fetch columns * @param columns This ArrayList<String> has the list of columns to be fetched. These columns are identifyed by their complete URL as defined in the ontology. <br /> * For example: <http://isi.edu/integration/karma/ontologies/model/accelerometer#AccelerometerReading>. Now there may exists many instance of a class in within the same ontology. * */ public String get_query(TriplesMap root, ArrayList<HashMap<String, String>> columns, boolean distinct_query) { ArrayList<Object> queue = new ArrayList<>(); queue.add(root); StringBuffer query = new StringBuffer(); this.var_count = 1; this.prefix_list = new HashMap<>(); this.select_params = new StringBuffer(); // ArrayList<String> select_param = new ArrayList<String>(); HashMap<TriplesMap, String> markedTriples = new HashMap<>(); ArrayList<String> visited_columns = new ArrayList<>(); this.ParentMapingInfoList = new HashMap<>(); // save the column predicate url and the column name to be dislayed HashMap<Predicate, String> predicateList = new HashMap<>(); HashMap<String, String> columnList = new HashMap<>(); if(columns != null && !columns.isEmpty()) { // for (String k : columns) { // int index = 0; // if(k.indexOf("#") > 0) { // index = k.lastIndexOf('#')+1; // } else if(k.indexOf("/") > 0) { // index = k.lastIndexOf('/')+1; // } // columnList.put(k, k.substring(index, k.length())); // } for(HashMap<String, String> col : columns) { columnList.put(col.get("name"), col.get("url")); } } // using a BFS approach, we traverse the tree from the root node and add triples/predicates to the queue while(!queue.isEmpty()) { Object currentObj = queue.remove(0); // if this is a tripleMap, then add all its RefObjects to the queue // for the predicates, add only the ones that satisfy the criteria of being <...hasValue> if (currentObj instanceof TriplesMap) { String var = "x"+var_count; TriplesMap triple = (TriplesMap)currentObj; boolean foundHasValue = false; List<PredicateObjectMap> predicates = triple.getPredicateObjectMaps(); for (PredicateObjectMap p_map : predicates) { if(p_map.getObject().hasRefObjectMap()) { RefObjectMap objMap = p_map.getObject().getRefObjectMap(); queue.add(objMap.getParentTriplesMap()); logger.info(triple.getSubject().getId() + " ---> " + objMap.getParentTriplesMap().getSubject().getId()); // maintain a list of mapping properties between triples ParentMapingInfoList.put(objMap.getParentTriplesMap().getSubject().getId(), new ParentMapingInfo(triple, p_map.getPredicate())); } else { queue.add(p_map.getPredicate()); predicateList.put(p_map.getPredicate(), var); foundHasValue = true; } } // if this triple is marked to be included in the query, // we add it to the markedTriples list and add to the query string // for its class type Eg. // Prefix pref1: <.../.../Input> // x2 a pref1: if (foundHasValue) { markedTriples.put(triple, var); String rdfsTypes = triple.getSubject().getRdfsType().get(0).toString(); this.prefix_list.put("pref"+var_count, rdfsTypes); query.append(" ?"+var + " a pref"+var_count+": ."); // if the parent of this triple is also marked for the query // then we add the relation to between triples to the query. Eg. // TriplesMap parentTriple = parent.get(triple.getSubject().getId()); ParentMapingInfo parentTriple = ParentMapingInfoList.get(triple.getSubject().getId()); // from the current node, keep poping out till we reach the last node in the // parent map to see if any of the parents are connected if(parentTriple != null) { String sq = checkParentMarked(triple, markedTriples, var); if (sq.length() > 1) { query.append(sq); } } // if( parentTriple != null && markedTriples.containsKey(parentTriple.parent)) { // String predicate = parentTriple.predicate.getTemplate().toString(); //// PredicateObjectMap parentPredicate = getPredicateBetweenTriples(triple, parentTriple); // if(predicate != null) { // query.append(" ?" + markedTriples.get(parentTriple.parent) + " " + // predicate + " ?"+var + " . "); // } else { // System.out.println("predicate is null from parent : " + triple.getSubject().getRdfsType().toString()); // } // } } var_count++; } // if it is a predicate Object, create a variable in in the query string else if (currentObj instanceof Predicate) { Predicate predicate = (Predicate)currentObj; String k = predicate.getTemplate().toString(); k = k.replace('<', ' ').replace('>', ' ').trim(); if(columns != null && !columns.isEmpty()) { // if(columnList.containsKey(k)) { if(columnList.containsValue(k)) { Iterator<String> itr = columnList.keySet().iterator(); while(itr.hasNext()) { String cName = itr.next(); if(columnList.get(cName).equals(k) && !visited_columns.contains(cName)) { // get the column name from the end of this url - either the last '/' or the '#' query.append(" ?" + predicateList.get(predicate)) .append(" ") .append(predicate.getTemplate()) .append(" ?") .append(cName + " . "); //columnList.remove(cName); visited_columns.add(cName); var_count++; break; } } // get the column name from the end of this url - either the last '/' or the '#' // query.append(" ?" + predicateList.get(predicate)) // .append(" ") // .append(predicate.getTemplate()) // .append(" ?") // .append(columnList.get(k) + " . "); // var_count++; } else { logger.info("ColumnList does not contain : " + k + " " + currentObj); } } else { int index = 0; if(k.indexOf("#") > 0) { index = k.lastIndexOf('#')+1; } else if(k.indexOf("/") > 0) { index = k.lastIndexOf('/')+1; } query.append(" ?" + predicateList.get(predicate)) .append(" ") .append(predicate.getTemplate()) .append(" ?").append(k.substring(index, k.length())) .append(" ."); var_count++; } } // if this is a RefObject add the Child Triple to the queue else if (currentObj instanceof RefObjectMap) { RefObjectMap refObj = (RefObjectMap)currentObj; TriplesMap t = refObj.getParentTriplesMap(); queue.add(t); } } // append the list of prefixes Iterator<String> itr = this.prefix_list.keySet().iterator(); StringBuffer sQuery = new StringBuffer(); while(itr.hasNext()) { String key = itr.next(); sQuery.append(" PREFIX ").append(key).append(": ").append(this.prefix_list.get(key)); } // append the columns to be selected in the order they are specified sQuery.append(" select "); if(distinct_query) { sQuery.append(" distinct "); } for (HashMap<String, String> s : columns) { sQuery.append(" ?"+s.get("name")); } sQuery.append(" where { ").append(query.toString()).append(" } "); logger.info("Generated Query : " + sQuery); return sQuery.toString(); } private String checkParentMarked(TriplesMap triple, HashMap<TriplesMap, String> markedTriples, String var1) { Stack<String> stk = new Stack<>(); ParentMapingInfo parentTriple = this.ParentMapingInfoList.get(triple.getSubject().getId()); boolean markedParent = false; int count = 1; String previous = var1; while(parentTriple!=null) { String predicate = parentTriple.predicate.getTemplate().toString(); if(markedTriples.get(parentTriple.parent) == null) { markedTriples.put(parentTriple.parent, "Z"+count); String rdfsTypes = parentTriple.parent.getSubject().getRdfsType().get(0).toString(); this.prefix_list.put("pref"+"Z"+count, rdfsTypes); stk.push(" ?Z"+count + " a pref"+"Z"+count+": ."); stk.push(" ?" + markedTriples.get(parentTriple.parent) + " " + predicate + " ?"+previous + " . "); } else { stk.push(" ?" + markedTriples.get(parentTriple.parent) + " " + predicate + " ?"+previous + " . "); markedParent = true; break; } previous = markedTriples.get(parentTriple.parent); parentTriple = this.ParentMapingInfoList.get(parentTriple.parent.getSubject().getId()); if(parentTriple == null) { break; } var1 = markedTriples.get(parentTriple.parent); // if(markedTriples.containsKey(parentTriple.parent)) { // markedParent = true; // stk.push(" ?" + markedTriples.get(parentTriple.parent) + " " + // predicate + " ?"+var1 + " . "); // break; // } } if (markedParent) { return StringUtils.join(stk," "); } return ""; } }