/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.jena.sparql.util.graph; import java.util.Collection ; import java.util.Iterator ; import java.util.SortedMap ; import java.util.TreeMap ; import java.util.function.Predicate; import java.util.regex.Matcher ; import java.util.regex.Pattern ; import org.apache.jena.atlas.logging.Log ; import org.apache.jena.graph.Graph ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.sparql.expr.Expr ; import org.apache.jena.util.iterator.ExtendedIterator ; import org.apache.jena.vocabulary.RDF ; import org.apache.jena.vocabulary.RDFS ; public class GraphContainerUtils { private static final Node RDFtype = RDF.type.asNode() ; private static final Node BAG = RDF.Bag.asNode() ; private static final Node ALT = RDF.Alt.asNode() ; private static final Node SEQ = RDF.Seq.asNode() ; private static final String membershipPattern$ = RDF.getURI()+"_(\\d+)" ; private static final Pattern membershipPattern = Pattern.compile(membershipPattern$) ; private static final int NOT_FOUND = -9999 ; public static Collection<Node> containerMembers(Graph graph, Node container) { return containerMembers(graph, container, null) ; } public static Collection<Node> containerMembers(Graph graph, Node container, Node containerType) { if ( ! isContainer(graph, container, containerType) ) return null ; ExtendedIterator<Triple> iter = graph.find(container, Node.ANY, Node.ANY) ; SortedMap<Integer, Node> triples = new TreeMap<>(order) ; try { for ( ; iter.hasNext() ; ) { Triple t = iter.next() ; int index = getIndex(t) ; if ( index == NOT_FOUND ) continue ; // Insert triples.put(new Integer(index), t.getObject()) ; } } finally { iter.close() ; } return triples.values() ; } // List x = new ArrayList() ; // try { // for ( ; iter.hasNext() ; ) // { // // Sort triples in a sorted set. // // Then extract. // Triple t = (Triple)iter.next() ; // String p = t.getPredicate().getURI() ; // // if ( p.matches(membershipPattern) ) // x.add(t.getObject()) ; // } // } finally { iter.close() ; } // return x ; // } public static boolean isContainerMember(Graph graph, Node container, Node containerType, Node member) { return countContainerMember(graph, container, containerType, member, true) != 0 ; } public static int countContainerMember(Graph graph, Node container, Node containerType, Node member) { return countContainerMember(graph, container, containerType, member, false) ; } private static Node RDFSmember = RDFS.member.asNode() ; private static Predicate<Triple> filterRDFSmember = new Predicate<Triple>() { @Override public boolean test(Triple triple) { Node p = triple.getPredicate() ; if ( ! triple.getPredicate().isURI() ) return false ; if (RDFSmember.equals(p) ) return true ; String u = triple.getPredicate().getURI() ; return membershipPattern.matcher(u).matches() ; } } ; /** Calculate graph.find(?, rdfs:member, ?) */ public static Iterator<Triple> rdfsMember(Graph graph, Node s, Node o) { ExtendedIterator<Triple> iter = graph.find(s, Node.ANY, o) ; return iter.filterKeep(filterRDFSmember) ; } private static int countContainerMember(Graph graph, Node container, Node containerType, Node member, boolean stopEarly) { if ( graph == null ) { Log.warn(GraphContainerUtils.class, "containerMember called with null graph") ; return 0 ; } if ( container == null ) { Log.warn(GraphContainerUtils.class, "containerMember called with null list") ; return 0 ; } if ( member == null ) { Log.warn(GraphContainerUtils.class, "containerMember called with null member") ; return 0 ; } if ( ! isContainer(graph, container, containerType) ) return 0 ; int count = 0 ; ExtendedIterator<Triple> iter = graph.find(container, Node.ANY, member) ; try { for ( ; iter.hasNext() ; ) { Triple t = iter.next() ; Node p = t.getPredicate() ; String u = p.getURI() ; if ( membershipPattern.matcher(u).matches() ) { count ++ ; if ( stopEarly ) return count ; } } } finally { iter.close() ; } return count ; } // public static boolean isContainer(Graph graph, Node container) // { return isContainer(graph, container, null) ; } public static boolean isContainer(Graph graph, Node container, Node containerType) { // if ( container.isLiteral() ) // return false ; if ( containerType == null ) return isContainer(graph, container, BAG) || isContainer(graph, container, ALT) || isContainer(graph, container, SEQ) ; return graph.contains(container, RDFtype, containerType) ; } private static int getIndex(Triple triple) { String u = triple.getPredicate().getURI() ; // Must be _nnn. Matcher m = membershipPattern.matcher(u); if ( ! m.find() ) return NOT_FOUND ; String index = m.group(1) ; return Integer.parseInt(index) ; } static ContainerOrder order = new ContainerOrder() ; static private class ContainerOrder implements java.util.Comparator<Integer> { @Override public int compare(Integer i1, Integer i2) { int index1 = i1.intValue() ; int index2 = i2.intValue() ; if ( index1 < index2 ) return Expr.CMP_LESS ; if ( index1 > index2 ) return Expr.CMP_GREATER ; return Expr.CMP_EQUAL ; } } }