From 13a2d43c04035e97ce94e380e9b0399ca2c70f06 Mon Sep 17 00:00:00 2001 From: Jim Balhoff Date: Fri, 20 Oct 2023 19:03:57 -0400 Subject: [PATCH] Ensure longest namespace match is used. Disallow prefixes that are substrings of OBO namespace. --- .../obo2owl/OBOFormatPrefixManager.java | 175 ++++++++++++++++++ .../org/obolibrary/obo2owl/OWLAPIOwl2Obo.java | 2 +- 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 oboformat/src/main/java/org/obolibrary/obo2owl/OBOFormatPrefixManager.java diff --git a/oboformat/src/main/java/org/obolibrary/obo2owl/OBOFormatPrefixManager.java b/oboformat/src/main/java/org/obolibrary/obo2owl/OBOFormatPrefixManager.java new file mode 100644 index 0000000000..fe1065e9e3 --- /dev/null +++ b/oboformat/src/main/java/org/obolibrary/obo2owl/OBOFormatPrefixManager.java @@ -0,0 +1,175 @@ +package org.obolibrary.obo2owl; + +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLRuntimeException; +import org.semanticweb.owlapi.model.PrefixManager; +import org.semanticweb.owlapi.util.StringComparator; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; + +public class OBOFormatPrefixManager implements PrefixManager { + + private final String OBO_NS = "http://purl.obolibrary.org/obo/"; + + @Nonnull + private StringComparator comparator = new StringComparator() { + + final Comparator comparer = Comparator.comparing(s -> -s.length()); + + @Override + public int compare(String o1, String o2) { + return comparer.compare(o1, o2); + } + + }; + + @Nonnull + private final TreeMap nsToPrefix; + @Nonnull + private final TreeMap prefixToNS; + + public OBOFormatPrefixManager(@Nullable PrefixManager pm) { + prefixToNS = new TreeMap<>(comparator); + nsToPrefix = new TreeMap<>(comparator); + if (pm != null) { + copyPrefixesFrom(pm); + } + } + + @Nonnull + @Override + public StringComparator getPrefixComparator() { + return this.comparator; + } + + @Override + public void setPrefixComparator(@Nonnull StringComparator comparator) { + this.comparator = comparator; + } + + @Nullable + @Override + public String getDefaultPrefix() { + return null; + } + + @Override + public boolean containsPrefixMapping(@Nonnull String prefixName) { + return prefixToNS.containsKey(prefixName); + } + + @Nullable + @Override + public String getPrefix(@Nonnull String prefixName) { + return prefixToNS.get(prefixName); + } + + @Nonnull + @Override + public Map getPrefixName2PrefixMap() { + return Collections.unmodifiableMap(prefixToNS); + } + + @Nonnull + @Override + public IRI getIRI(@Nonnull String prefixIRI) { + if (prefixIRI.startsWith("<")) { + return IRI.create(prefixIRI.substring(1, prefixIRI.length() - 1)); + } + int sep = prefixIRI.indexOf(':'); + if (sep == -1) { + if (getDefaultPrefix() != null) { + return IRI.create(getDefaultPrefix() + prefixIRI); + } else { + return IRI.create(prefixIRI); + } + } else { + String prefixName = prefixIRI.substring(0, sep + 1); + if (!containsPrefixMapping(prefixName)) { + throw new OWLRuntimeException( + "Prefix not registered for prefix name: " + prefixName); + } + String prefix = getPrefix(prefixName); + String localName = prefixIRI.substring(sep + 1); + return IRI.create(prefix, localName); + } + } + + @Nullable + @Override + public String getPrefixIRI(@Nonnull IRI iri) { + String iriString = iri.toString(); + Optional> mappingOpt = nsToPrefix.entrySet().stream().filter(e -> iriString.startsWith(e.getKey())).findFirst(); + if (mappingOpt.isPresent()) { + Map.Entry mapping = mappingOpt.get(); + String localId = iriString.substring(mapping.getKey().length()); + return mapping.getValue() + ":" + localId; + } else return null; + } + + @Nullable + @Override + public String getPrefixIRIIgnoreQName(@Nonnull IRI iri) { + return getPrefixIRI(iri); + } + + @Nonnull + @Override + public Set getPrefixNames() { + return prefixToNS.keySet(); + } + + @Override + public void setDefaultPrefix(@Nullable String defaultPrefix) { + } + + @Override + public void setPrefix(@Nonnull String prefixName, @Nonnull String prefix) { + if (!prefixName.isEmpty() && !prefixName.equals(":") && !OBO_NS.startsWith(prefix)) { + System.out.println(prefixName + " ::: " + prefix); + String cleanPrefixName = prefixName; + if (prefixName.endsWith(":")) { + cleanPrefixName = prefixName.substring(0, prefixName.length() - 1); + } + prefixToNS.put(cleanPrefixName, prefix); + nsToPrefix.put(prefix, cleanPrefixName); + } + } + + @Override + public void copyPrefixesFrom(@Nonnull PrefixManager from) { + copyPrefixesFrom(from.getPrefixName2PrefixMap()); + } + + @Override + public void copyPrefixesFrom(@Nonnull Map from) { + for (Map.Entry e : from.entrySet()) { + String prefix = e.getKey(); + if (!prefix.isEmpty()) { + setPrefix(e.getKey(), e.getValue()); + } + } + } + + @Override + public void unregisterNamespace(@Nonnull String namespace) { + List toRemove = new ArrayList<>(); + for (Map.Entry e : prefixToNS.entrySet()) { + if (e.getValue().equals(namespace)) { + toRemove.add(e.getKey()); + } + } + for (String s : toRemove) { + prefixToNS.remove(s); + } + nsToPrefix.remove(namespace); + } + + @Override + public void clear() { + prefixToNS.clear(); + nsToPrefix.clear(); + } +} diff --git a/oboformat/src/main/java/org/obolibrary/obo2owl/OWLAPIOwl2Obo.java b/oboformat/src/main/java/org/obolibrary/obo2owl/OWLAPIOwl2Obo.java index 2695b0805c..88cbcaa9a9 100644 --- a/oboformat/src/main/java/org/obolibrary/obo2owl/OWLAPIOwl2Obo.java +++ b/oboformat/src/main/java/org/obolibrary/obo2owl/OWLAPIOwl2Obo.java @@ -233,7 +233,7 @@ public void setObodoc(@Nonnull OBODoc obodoc) { } public void setPrefixManager(@Nonnull PrefixManager manager) { - this.prefixManager = manager; + this.prefixManager = new OBOFormatPrefixManager(manager); } /**