/** * Answer a list of the named hierarchy roots of a given {@link OntModel}. This will be similar to * the results of {@link OntModel#listHierarchyRootClasses()}, with the added constraint that * every member of the returned iterator will be a named class, not an anonymous class expression. * The named root classes are calculated from the root classes, by recursively replacing every * anonymous class with its direct sub-classes. Thus it can be seen that the values in the list * consists of the shallowest fringe of named classes in the hierarchy. * * @param m An ontology model * @return A list of classes whose members are the named root classes of the class hierarchy in * <code>m</code> */ public static List<OntClass> namedHierarchyRoots(OntModel m) { List<OntClass> nhr = new ArrayList<OntClass>(); // named roots List<OntClass> ahr = new ArrayList<OntClass>(); // anon roots // do the initial partition of the root classes partitionByNamed(m.listHierarchyRootClasses(), nhr, ahr); // now push the fringe down until we have only named classes while (!ahr.isEmpty()) { OntClass c = ahr.remove(0); partitionByNamed(c.listSubClasses(true), nhr, ahr); } return nhr; }
/** * Answer the shortest path from the <code>start</code> resource to the <code>end</code> RDF node, * such that every step on the path is accepted by the given filter. A path is a {@link List} of * RDF {@link Statement}s. The subject of the first statement in the list is <code>start</code>, * and the object of the last statement in the list is <code>end</code>. * * <p>The <code>onPath</code> argument is a {@link Filter}, which accepts a statement and returns * true if the statement should be considered to be on the path. To search for an unconstrained * path, pass {@link Filter#any} as an argument. To search for a path whose predicates match a * fixed restricted set of property names, pass an instance of {@link PredicatesFilter}. * * <p>If there is more than one path of minimal length from <code>start</code> to <code>end</code> * , this method returns an arbitrary one. The algorithm is blind breadth-first search, with loop * detection. * * @param m The model in which we are seeking a path * @param start The starting resource * @param end The end, or goal, node * @param onPath A filter which determines whether a given statement can be considered part of the * path * @return A path, consisting of a list of statements whose first subject is <code>start</code>, * and whose last object is <code>end</code>, or null if no such path exists. */ public static Path findShortestPath( Model m, Resource start, RDFNode end, Filter<Statement> onPath) { List<Path> bfs = new LinkedList<Path>(); Set<Resource> seen = new HashSet<Resource>(); // initialise the paths for (Iterator<Statement> i = m.listStatements(start, null, (RDFNode) null).filterKeep(onPath); i.hasNext(); ) { bfs.add(new Path().append(i.next())); } // search Path solution = null; while (solution == null && !bfs.isEmpty()) { Path candidate = bfs.remove(0); if (candidate.hasTerminus(end)) { solution = candidate; } else { Resource terminus = candidate.getTerminalResource(); if (terminus != null) { seen.add(terminus); // breadth-first expansion for (Iterator<Statement> i = terminus.listProperties().filterKeep(onPath); i.hasNext(); ) { Statement link = i.next(); // no looping allowed, so we skip this link if it takes us to a node we've seen if (!seen.contains(link.getObject())) { bfs.add(candidate.append(link)); } } } } } return solution; }