package org.aksw.jena_sparql_api.utils; import org.apache.jena.rdf.model.*; import org.apache.jena.vocabulary.RDFS; import org.aksw.commons.collections.MultiMaps; import org.aksw.commons.util.strings.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.*; /** * @author Claus Stadler */ public class ModelUtils { /** * Extracts a mapping childClass -> parentClass from a given Model. * You can use TransitiveClosure.transitiveClosure for "inferring" the whole hierarchy. * * @param model * @return */ public static Map<Resource, Set<Resource>> extractDirectSuperClassMap(Model model) { Map<Resource, Set<Resource>> result = new HashMap<Resource, Set<Resource>>(); StmtIterator it = model.listStatements(null, RDFS.subClassOf, (RDFNode)null); while (it.hasNext()) { Statement stmt = it.next(); // Skip "invalid" triples if(!(stmt.getObject() instanceof Resource)) continue; MultiMaps.put(result, stmt.getSubject(), (Resource)stmt.getObject()); } it.close(); return result; } private static Logger logger = LoggerFactory.getLogger(ModelUtils.class); /** * * @param model * @param resource * @return */ public static Model filterBySubject(Model model, Resource resource) { Iterator<Statement> it = model.listStatements(resource, (Property)null, (RDFNode)null); Model result = ModelFactory.createDefaultModel(); result.setNsPrefixes(model.getNsPrefixMap()); while(it.hasNext()) { result.add(it.next()); } return result; } public static Model combine(Collection<Model> models) { Model result = ModelFactory.createDefaultModel(); for(Model model : models) { result.add(model); } return result; } public static Model read(InputStream in, String lang) throws IOException { return read(ModelFactory.createDefaultModel(), in, lang); } /* public static void main(String[] args) throws IOException { read(new File("test.nt")); } */ /** * FIXME Extend to Uris * * @param file * @return * @throws Exception */ public static Model read(File file) throws Exception { Collection<String> langs = null; // Auto detect language by file name extension String fileName = file.getPath().toLowerCase(); for(Map.Entry<String, String> entry : Constants.extensionToJenaFormat.entrySet()) { if(fileName.endsWith(entry.getKey().toLowerCase())) { langs = Collections.singleton(entry.getValue()); break; } } if(langs == null) { langs = new HashSet<String>(Constants.extensionToJenaFormat.values()); } String logMessage = "Parsing file '" + fileName + "' with languages " + langs + ": "; Model result = null; for(String lang : langs) { FileInputStream in = new FileInputStream(file); try { result = read(in, lang); logMessage += " Success (" + lang + ")"; break; } catch(Exception e) { //FIXME: Extend this method to return a mapping of language to exception if(langs.size() == 1) { throw e; } } finally { if(in != null) in.close(); } } if(result == null) { logMessage += " Failed. "; } logger.debug(logMessage); if(result == null) { throw new IOException("Unsupported file format"); } return result; } public static Model read(File file, String lang) throws IOException { return read(new FileInputStream(file), lang); } public static Model read(Model model, InputStream in, String lang) throws IOException { try { model.read(in, null, lang); } finally { in.close(); } return model; } public static Model read(Model model, File file, String lang) throws IOException { return read(model, new FileInputStream(file), lang); } public static Model write(Model model, File file) throws IOException { Map.Entry<String, String> extToLang = StringUtils.getMatchBySuffix(file.getPath(), Constants.extensionToJenaFormat); String lang = (extToLang == null) ? null : extToLang.getValue(); return write(model, file, lang); } public static Model write(Model model, File file, String lang) throws IOException { FileOutputStream out = new FileOutputStream(file); model.write(out, lang); out.close(); return model; } public static String toString(Model model) { return toString(model, "N3"); } public static String toString(Model model, RDFWriter writer) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); /* OutputStreamWriter osw; try { osw = new OutputStreamWriter(baos, "UTF8"); } catch (Exception e) { throw new RuntimeException(e); } writer.write(Model, osw, ""); */ writer.write(model, baos, ""); return baos.toString(); } public static String toString(Model model, String format) { if(model == null) return "null"; RDFWriter writer = model.getWriter(format); return toString(model, writer); } /** * An efficient method for separating a URI into namespace and prefix, * given a set of arbitrary namespace prefixes. * Note: This method is mainly intended for a nice representation, * as a decomposition with arbitrary prefixes may not work with cerain RDF * serializations. * * (e.g. <http://ex.org/this/is/a/test> with prefix p:<http://ex.org/this> * becomes p:is/a/test) * * * @param uri * @param prefixMap * @return */ public static String[] decompose(String uri, NavigableMap<String, String> prefixMap) { String prefix = ""; String name = uri; //NavigableMap<String, String> candidates = prefixMap.headMap(uri, false).descendingMap(); //Map.Entry<String, String> candidate = candidates.firstEntry(); Map.Entry<String, String> candidate = StringUtils.longestPrefixLookup(uri, prefixMap); if(candidate != null && uri.startsWith(candidate.getKey())) { String candidateNs = candidate.getKey(); String candidatePrefix = candidate.getValue(); int splitIdx = candidateNs.length(); prefix = candidatePrefix; name = uri.substring(splitIdx); } return new String[]{prefix, name}; } public static String prettyUri(String uri, NavigableMap<String, String> prefixMap) { String[] tmp = decompose(uri, prefixMap); String result = (tmp[0].isEmpty()) ? StringUtils.urlDecode(tmp[1]) : tmp[0] + ":" + StringUtils.urlDecode(tmp[1]); return result; } }