/* * This file is part of the OWL API. * * The contents of this file are subject to the LGPL License, Version 3.0. * * Copyright (C) 2011, The University of Manchester * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * * Alternatively, the contents of this file may be used under the terms of the Apache License, Version 2.0 * in which case, the provisions of the Apache License Version 2.0 are applicable instead of those above. * * Copyright 2011, University of Manchester * * 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. */ package org.coode.owlapi.obo12.parser; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; import org.semanticweb.owlapi.model.AddAxiom; import org.semanticweb.owlapi.model.AddOntologyAnnotation; import org.semanticweb.owlapi.model.HasIRI; import org.semanticweb.owlapi.model.IRI; import org.semanticweb.owlapi.model.OWLAnnotation; import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom; import org.semanticweb.owlapi.model.OWLAnnotationProperty; import org.semanticweb.owlapi.model.OWLAxiom; import org.semanticweb.owlapi.model.OWLClass; import org.semanticweb.owlapi.model.OWLClassExpression; import org.semanticweb.owlapi.model.OWLDataFactory; import org.semanticweb.owlapi.model.OWLEntity; import org.semanticweb.owlapi.model.OWLLiteral; import org.semanticweb.owlapi.model.OWLObjectProperty; import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.model.OWLOntologyChange; import org.semanticweb.owlapi.model.OWLOntologyManager; import org.semanticweb.owlapi.util.CollectionFactory; /** * Author: Matthew Horridge<br> * The University Of Manchester<br> * Bio-Health Informatics Group<br> * Date: 10-Jan-2007<br> * <br> * <p/> * Concrete implementations of this interface allow specific behaviour for processing specific tag * value pairs in an OBO file to be specified. * <p> * <h3>Tag-Value Pairs (From the OBO 1.4 Guide)</h3> * <p/> * Tag-value pairs consist of a tag name, an unescaped colon, the tag value, and a newline: * <p/> * <tag>: <value> {<trailing modifiers>} ! <comment> The tag name is always * a string. The value is always a string, but the value string may require special parsing * depending on the tag with which it is associated. * <p/> * In general, tag-value pairs occur on a single line. Multi-line values are possible using escape * characters (see escape characters). * <p/> * In general, each stanza type expects a particular set of pre-defined tags. However, a stanza may * contain any tag. If a parser does not recognize a tag name for a particular stanza, no error will * be generated. This allows new experimental tags to be added without breaking existing parsers. * See handling unrecognized tags for specifics. * <p/> * <h3>Trailing Modifiers</h3> * <p/> * Any tag-value pair may be followed by a trailing modifier. Trailing modifiers have been * introduced into the OBO 1.2 Specification to allow the graceful addition of new features to * existing tags. * <p/> * A trailing modifier has the following structure: * <p/> * {<name>=<value>, <name=value>, <name=value>} That is, trailing modifiers * are lists of name-value pairs. * <p/> * Parser implementations may choose to decode and/or round-trip these trailing modifiers. However, * this is not required. A parser may choose to ignore or strip away trailing modifiers. * <p/> * For this reason, trailing modifiers should only include information that is optional or * experimental. * <p/> * Trailing modifiers may also occur within dbxref definitions (see dbxref formatting). * <p/> * </p> */ interface TagValueHandler { /** * Gets the name of the tag handled by this tag value handler * * @return The name of the tag */ String getTagName(); /** * Handles a tag. This is called by the OBOConsumer during parsing to handle tags that match the * value returned by the {@link #getTagName()} method. * * @param currentId The id of the current frame. * @param value The value of the tag * @param qualifierBlock qualifier block * @param comment The hidden comment. This is made up of any characters between ! and the end of * line. */ void handle(String currentId, String value, String qualifierBlock, String comment); } abstract class AbstractTagValueHandler implements TagValueHandler { private final String tag; private final OBOConsumer consumer; public AbstractTagValueHandler(String tag, OBOConsumer consumer) { this.tag = tag; this.consumer = consumer; } @Override public String getTagName() { return tag; } public OWLOntologyManager getOWLOntologyManager() { return consumer.getOWLOntologyManager(); } public OWLOntology getOntology() { return consumer.getOntology(); } public void applyChange(OWLOntologyChange change) { consumer.getOWLOntologyManager().applyChange(change); } public OBOConsumer getConsumer() { return consumer; } public OWLDataFactory getDataFactory() { return consumer.getOWLOntologyManager().getOWLDataFactory(); } public IRI getTagIRI(OBOVocabulary vocabulary) { return consumer.getIRIFromTagName(vocabulary.getName()); } /** * Gets an IRI for a tag name. This is a helper method, which ultimately calls * {@link OBOConsumer#getIRIFromTagName(String)}. * * @param tagName The tag name. * @return The IRI corresponding to the tag name. */ public IRI getTagIRI(String tagName) { return consumer.getIRIFromTagName(tagName); } public IRI getIRIFromOBOId(String id) { return consumer.getIRIFromOBOId(id); } /** * Gets an {@link OWLAnnotation} for a tag value pair. * * @param tagName The tag name. * @param value The tag value. Note that the tag value is un-escaped and stripped of double * quotes if they exist. * @return An {@link OWLAnnotation} that is formed by converting the tagName to an IRI and then * to an {@link OWLAnnotationProperty} and the value to an {@link OWLLiteral}. */ public OWLAnnotation getAnnotationForTagValuePair(String tagName, String value) { IRI tagIRI = getTagIRI(tagName); OWLDataFactory df = getDataFactory(); OWLAnnotationProperty annotationProperty = df.getOWLAnnotationProperty(tagIRI); String unescapedString = getUnquotedString(value); OWLLiteral annotationValue = df.getOWLLiteral(unescapedString); return df.getOWLAnnotation(annotationProperty, annotationValue); } public OWLClass getClassFromId(String s) { return getDataFactory().getOWLClass(getIRIFromOBOId(s)); } public OWLClass getCurrentClass() { return getDataFactory().getOWLClass(getIRIFromOBOId(consumer.getCurrentId())); } protected OWLClass getOWLClass(String id) { return getDataFactory().getOWLClass(getIRIFromOBOId(id)); } protected OWLObjectProperty getOWLObjectProperty(String id) { return getDataFactory().getOWLObjectProperty(getIRIFromOBOId(id)); } protected String getUnquotedString(String value) { String unquotedString; if (value.startsWith("\"") && value.endsWith("\"")) { unquotedString = value.substring(1, value.length() - 1); } else { unquotedString = value; } return unquotedString; } protected OWLClassExpression getOWLClassOrRestriction(String termList) { String[] strings = termList.split(" "); if (strings.length == 1) { return getDataFactory().getOWLClass(getIRIFromOBOId(strings[0])); } String id0 = strings[0]; String id1 = strings[1]; IRI propertyIRI = getConsumer().getRelationIRIFromSymbolicIdOrOBOId(id0); OWLObjectProperty prop = getDataFactory().getOWLObjectProperty(propertyIRI); OWLClass filler = getDataFactory().getOWLClass(getIRIFromOBOId(id1)); return getDataFactory().getOWLObjectSomeValuesFrom(prop, filler); } protected OWLLiteral getBooleanConstant(boolean b) { return getDataFactory().getOWLLiteral(b); } protected void addAnnotation(String id, String uriID, OWLLiteral value) { IRI subject = getIRIFromOBOId(id); OWLAnnotationProperty annotationProperty = getDataFactory().getOWLAnnotationProperty(getIRIFromOBOId(uriID)); OWLAxiom ax = getDataFactory().getOWLAnnotationAssertionAxiom(annotationProperty, subject, value); applyChange(new AddAxiom(getOntology(), ax)); } } class AltIdTagValueHandler extends AbstractTagValueHandler { public AltIdTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.ALT_ID.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { HasIRI subject = getConsumer().getCurrentEntity(); OWLAnnotationProperty property = getDataFactory().getOWLAnnotationProperty(OBOVocabulary.ALT_ID); IRI object = getIRIFromOBOId(value); OWLAnnotationAssertionAxiom ax = getDataFactory().getOWLAnnotationAssertionAxiom(property, subject.getIRI(), object); applyChange(new AddAxiom(getOntology(), ax)); } } class AsymmetricHandler extends AbstractTagValueHandler { public AsymmetricHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_ASYMMETRIC.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (Boolean.parseBoolean(value)) { OWLObjectProperty prop = getOWLObjectProperty(currentId); OWLAxiom ax = getDataFactory().getOWLAsymmetricObjectPropertyAxiom(prop); applyChange(new AddAxiom(getOntology(), ax)); } else { addAnnotation(currentId, OBOVocabulary.IS_ASYMMETRIC.getName(), getBooleanConstant(false)); } } } class DataVersionTagValueHandler extends AbstractTagValueHandler { public DataVersionTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.DATA_VERSION.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { getConsumer().setDataVersionTagValue(value); } } /** * Author: Matthew Horridge<br> * The University Of Manchester<br> * Information Management Group<br> * Date: 01-Sep-2008<br> * <br> * <p/> * OBO Namespaces are NOT like XML Namespaces. They are NOT used to form abbreviations for IRIs. The * description below, taken from the OBOEdit manual, explains their provenance. * <p/> * <h3>OBO Namespaces and Ontology Name (OBO Syntax and Semantics Document: Section 4.3)</h3> * <p/> * Note that OBO namespaces are not the same as OWL namespaces - the analog of OWL namespaces are * OBO ID spaces. OBO namespaces are semantics-free properties of a frame that allow partitioning of * an ontology into sub-ontologies. For example, the GO is partitioned into 3 ontologies (3 OBO * namespaces, 1 OWL namespace). * <p/> * Every frame must have exactly one namespace. However, these do not need to be explicitly * assigned. After parsing an OBO Document, any frame without a namespace is assigned the * default-namespace, from the OBO Document header. If this is not specified, the Parser assigns a * namespace arbitrarily. It is recommended this is equivalent to the URL or file path from which * the document was retrieved. * <p/> * Every OBODoc should have an "ontology" tag specified in the header. If this is not specified, * then the parser should supply a default value. This value should be derived from the URL of the * source of the ontology (typically using http or file schemes). * <p/> * <p/> * <p/> * <p/> * <h3>OBO Namespaces (From the OBOEdit Manual)</h3> * <p/> * Namespaces * <p/> * OBO files are designed to be easily merged and separated. Most tools that use OBO files can load * many OBO files at once. If several ontologies have been loaded together and saved into a single * file, it would be impossible to know which terms came from which file unless the origin of each * term is indicated somehow. Namespaces are used to solve this problem by indicating a "logical * ontology" to which every term, relation, instance OR relationship belongs, i.e., each entity is * tagged with a Namespace that indicates which ontology it is part of. * <p/> * Namespaces are user-definable. Every ontology object belongs to a single namespace. When terms * from many ontologies have been loaded together, namespaces are used to break the merged ontology * back into separate files. */ class DefaultNamespaceTagValueHandler extends AbstractTagValueHandler { public DefaultNamespaceTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.DEFAULT_NAMESPACE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { // Just register the namespace with the consumer and add it as an // annotation to the ontology getConsumer().setDefaultNamespaceTagValue(value); // Add an annotation to the ontology OWLAnnotation annotation = getAnnotationForTagValuePair( OBOVocabulary.DEFAULT_NAMESPACE.getName(), value); applyChange(new AddOntologyAnnotation(getOntology(), annotation)); } } class DefTagValueHandler extends AbstractTagValueHandler { private static final Pattern PATTERN = Pattern.compile("\"([^\"]*)\"\\s*(\\[([^\\]]*)\\])?\\s*"); private static final int QUOTED_STRING_CONTENT_GROUP = 1; private static final int XREF_GROUP = 3; public DefTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.DEF.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { Matcher matcher = PATTERN.matcher(value); OWLDataFactory df = getDataFactory(); String annotationValue; Set<OWLAnnotation> xrefAnnotations = Collections.emptySet(); if (matcher.matches()) { annotationValue = matcher.group(QUOTED_STRING_CONTENT_GROUP); xrefAnnotations = getXRefAnnotations(matcher); } else { annotationValue = getUnquotedString(value); } IRI propertyIRI = getTagIRI(getTagName()); OWLAnnotationProperty property = df.getOWLAnnotationProperty(propertyIRI); OWLEntity currentEntity = getConsumer().getCurrentEntity(); OWLLiteral literal = df.getOWLLiteral(annotationValue); OWLAnnotationAssertionAxiom ax = df.getOWLAnnotationAssertionAxiom(property, currentEntity.getIRI(), literal, xrefAnnotations); applyChange(new AddAxiom(getOntology(), ax)); } private Set<OWLAnnotation> getXRefAnnotations(Matcher matcher) { Set<OWLAnnotation> annotations = new HashSet<>(); String xrefs = matcher.group(XREF_GROUP); if (xrefs != null) { for (String xrefValue : xrefs.split(",")) { annotations.add(getConsumer().parseXRef(xrefValue)); } } return annotations; } } class DisjointFromHandler extends AbstractTagValueHandler { public DisjointFromHandler(OBOConsumer consumer) { super("disjoint_from", consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { OWLAxiom ax = getDataFactory().getOWLDisjointClassesAxiom( CollectionFactory.createSet(getCurrentClass(), getOWLClass(value))); applyChange(new AddAxiom(getOntology(), ax)); } } class DomainHandler extends AbstractTagValueHandler { public DomainHandler(OBOConsumer consumer) { super(OBOVocabulary.DOMAIN.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { OWLObjectProperty prop = getOWLObjectProperty(getConsumer().getCurrentId()); OWLClass cls = getOWLClass(value); applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLObjectPropertyDomainAxiom(prop, cls))); } } class IDSpaceTagValueHandler extends AbstractTagValueHandler { private static final Pattern PATTERN = Pattern.compile("([^\\s]*)\\s+([^\\s]*)"); private static final int ID_PREFIX_GROUP = 1; private static final int IRI_PREFIX_GROUP = 2; public IDSpaceTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.ID_SPACE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { Matcher matcher = PATTERN.matcher(value); if (matcher.matches()) { String idPrefix = matcher.group(ID_PREFIX_GROUP); String iriPrefix = matcher.group(IRI_PREFIX_GROUP); getConsumer().registerIdSpace(idPrefix, iriPrefix); } } } class IDTagValueHandler extends AbstractTagValueHandler { public IDTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.ID.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { getConsumer().setCurrentId(value); OWLEntity entity = getConsumer().getCurrentEntity(); applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLDeclarationAxiom(entity))); } } class IntersectionOfHandler extends AbstractTagValueHandler { public IntersectionOfHandler(OBOConsumer consumer) { super("intersection_of", consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { getConsumer().addIntersectionOfOperand(getOWLClassOrRestriction(value)); } } class InverseHandler extends AbstractTagValueHandler { public InverseHandler(OBOConsumer consumer) { super(OBOVocabulary.INVERSE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { OWLAxiom ax = getDataFactory().getOWLInverseObjectPropertiesAxiom( getOWLObjectProperty(currentId), getOWLObjectProperty(value)); applyChange(new AddAxiom(getOntology(), ax)); } } class IsATagValueHandler extends AbstractTagValueHandler { public IsATagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_A.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (getConsumer().isTerm()) { // We simply add a subclass axiom applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLSubClassOfAxiom( getClassFromId(currentId), getClassFromId(value)))); } else if (getConsumer().isTypedef()) { // We simply add a sub property axiom applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLSubObjectPropertyOfAxiom( getOWLObjectProperty(currentId), getOWLObjectProperty(value)))); } } } class IsObsoleteTagValueHandler extends AbstractTagValueHandler { public IsObsoleteTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_OBSOLETE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { OWLDataFactory df = getDataFactory(); OWLAnnotationProperty deprecatedProperty = df.getOWLDeprecated(); OWLLiteral annotationValue = df.getOWLLiteral(true); IRI subject = getIRIFromOBOId(currentId); OWLAnnotationAssertionAxiom ax = df.getOWLAnnotationAssertionAxiom(deprecatedProperty, subject, annotationValue); applyChange(new AddAxiom(getOntology(), ax)); } } class NameTagValueHandler extends AbstractTagValueHandler { public NameTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.NAME.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { // This is an annotation - but add as a label OWLEntity ent; if (getConsumer().isTerm()) { ent = getDataFactory().getOWLClass(getIRIFromOBOId(currentId)); } else if (getConsumer().isTypedef()) { ent = getDataFactory().getOWLObjectProperty(getIRIFromOBOId(currentId)); } else { ent = getDataFactory().getOWLNamedIndividual(getIRIFromOBOId(currentId)); } OWLAxiom ax = getDataFactory().getOWLAnnotationAssertionAxiom(ent.getIRI(), getDataFactory().getRDFSLabel(value)); applyChange(new AddAxiom(getOntology(), ax)); } } class OntologyTagValueHandler extends AbstractTagValueHandler { public OntologyTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.ONTOLOGY.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { getConsumer().setOntologyTagValue(value); } } class PartOfTagValueHandler extends AbstractTagValueHandler { public PartOfTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.RELATIONSHIP.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { int index = value.indexOf(' '); String propLocalName = value.substring(0, index); String val = value.substring(index + 1, value.length()); OWLDataFactory df = getDataFactory(); OWLObjectProperty prop = df.getOWLObjectProperty(getIRIFromOBOId(propLocalName)); OWLClass filler = getClassFromId(val); OWLClassExpression desc = df.getOWLObjectSomeValuesFrom(prop, filler); OWLAxiom ax = df.getOWLSubClassOfAxiom(getCurrentClass(), desc); applyChange(new AddAxiom(getOntology(), ax)); } } class RawFrameHandler implements OBOParserHandler { @Nullable private String currentFrameType = ""; private final List<OBOTagValuePair> currentTagValuePairs = new ArrayList<>(); @Nullable private OBOFrame headerFrame; private final List<OBOFrame> typeDefFrames = new ArrayList<>(); private final List<OBOFrame> nonTypeDefFrames = new ArrayList<>(); @Override public void startHeader() { currentTagValuePairs.clear(); } @Override public void endHeader() { headerFrame = new OBOFrame(currentTagValuePairs); } @Override public void startFrame(@Nullable String frameType) { currentFrameType = frameType; currentTagValuePairs.clear(); } @Override public void endFrame() { storeCurrentFrame(); } private OBOFrame storeCurrentFrame() { OBOFrame frame = new OBOFrame(currentFrameType, currentTagValuePairs); if (frame.isTypeDefFrame()) { typeDefFrames.add(frame); } else { nonTypeDefFrames.add(frame); } return frame; } @Override public void handleTagValue(String tag, String value, String qualifierBlock, String comment) { OBOTagValuePair tvp = new OBOTagValuePair(tag, value, qualifierBlock, comment); currentTagValuePairs.add(tvp); } /** * @return the header frame */ @Nullable public OBOFrame getHeaderFrame() { return headerFrame; } /** * @return the typedef frames */ public List<OBOFrame> getTypeDefFrames() { return typeDefFrames; } /** * @return the non typedef frames */ public List<OBOFrame> getNonTypeDefFrames() { return nonTypeDefFrames; } } class ReflexiveHandler extends AbstractTagValueHandler { public ReflexiveHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_REFLEXIVE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (Boolean.parseBoolean(value)) { OWLObjectProperty prop = getOWLObjectProperty(currentId); OWLAxiom ax = getDataFactory().getOWLReflexiveObjectPropertyAxiom(prop); applyChange(new AddAxiom(getOntology(), ax)); } else { addAnnotation(currentId, OBOVocabulary.IS_REFLEXIVE.getName(), getBooleanConstant(false)); } } } class RelationshipTagValueHandler extends AbstractTagValueHandler { private final Pattern tagValuePattern = Pattern.compile("([^\\s]*)\\s*([^\\s]*)\\s*(\\{([^\\}]*)\\})?"); public RelationshipTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.RELATIONSHIP.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { Matcher matcher = tagValuePattern.matcher(value); if (matcher.matches()) { IRI propIRI = getConsumer().getRelationIRIFromSymbolicIdOrOBOId(matcher.group(1)); IRI fillerIRI = getIRIFromOBOId(matcher.group(2)); OWLObjectProperty prop = getDataFactory().getOWLObjectProperty(propIRI); OWLClass filler = getDataFactory().getOWLClass(fillerIRI); OWLClassExpression restriction = getDataFactory().getOWLObjectSomeValuesFrom(prop, filler); OWLClass subCls = getDataFactory().getOWLClass(getIRIFromOBOId(currentId)); applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLSubClassOfAxiom(subCls, restriction))); applyChange(new AddAxiom(getOntology(), getDataFactory().getOWLDeclarationAxiom(prop))); } } } class SymmetricTagValueHandler extends AbstractTagValueHandler { public SymmetricTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_SYMMETRIC.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (Boolean.parseBoolean(value)) { OWLObjectProperty prop = getOWLObjectProperty(currentId); OWLAxiom ax = getDataFactory().getOWLSymmetricObjectPropertyAxiom(prop); applyChange(new AddAxiom(getOntology(), ax)); } else { addAnnotation(currentId, OBOVocabulary.IS_SYMMETRIC.getName(), getBooleanConstant(false)); } } } class SynonymTagValueHandler extends AbstractTagValueHandler { private static final String TAG_NAME = OBOVocabulary.SYNONYM.toString(); // synonym: "synonym" (EXACT|BROAD|NARROW|RELATED) TYPE? XRefList private static final Pattern VALUEPATTERN = Pattern .compile("\"([^\"]*)\"\\s*([^\\s]*)\\s*([^\\[\\s]+)?\\s*\\[([^\\]]*)\\]"); private static final int VALUE_GROUP = 1; private static final int SCOPE_GROUP = 2; private static final int SYNONYM_TYPE_GROUP = 3; private static final int XREF_GROUP = 4; public static final IRI SYNONYM_TYPE_IRI = OBOVocabulary.SYNONYM_TYPE.getIRI(); public static final IRI XREF_IRI = OBOVocabulary.XREF.getIRI(); public SynonymTagValueHandler(OBOConsumer consumer) { super(TAG_NAME, consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { Matcher matcher = VALUEPATTERN.matcher(value); if (matcher.matches()) { OWLDataFactory df = getDataFactory(); OWLAnnotationProperty property = getSynonymAnnotationProperty(matcher); Set<OWLAnnotation> annotations = new HashSet<>(); annotations.addAll(getSynonymTypeAnnotations(matcher)); annotations.addAll(getXRefAnnotations(matcher)); OWLEntity subject = getConsumer().getCurrentEntity(); String synonym = matcher.group(VALUE_GROUP); OWLLiteral synonymLiteral = df.getOWLLiteral(synonym); OWLAnnotationAssertionAxiom annoAssertion = df.getOWLAnnotationAssertionAxiom(property, subject.getIRI(), synonymLiteral, annotations); applyChange(new AddAxiom(getOntology(), annoAssertion)); } } private Set<OWLAnnotation> getSynonymTypeAnnotations(Matcher matcher) { if (matcher.group(SYNONYM_TYPE_GROUP) != null) { OWLAnnotation typeAnnotation = getSynonymTypeAnnotation(matcher); return Collections.singleton(typeAnnotation); } else { return Collections.emptySet(); } } private Set<OWLAnnotation> getXRefAnnotations(Matcher matcher) { Set<OWLAnnotation> annotations = new HashSet<>(); String xrefs = matcher.group(XREF_GROUP); if (xrefs != null) { StringTokenizer tokenizer = new StringTokenizer(xrefs, ","); while (tokenizer.hasMoreTokens()) { String xref = tokenizer.nextToken(); OWLAnnotation xrefAnnotation = getConsumer().parseXRef(xref); annotations.add(xrefAnnotation); } } return annotations; } private OWLAnnotationProperty getSynonymAnnotationProperty(Matcher matcher) { String synonymScope = matcher.group(SCOPE_GROUP); IRI annotationPropertyIRI; if (SynonymScope.BROAD.name().equals(synonymScope)) { annotationPropertyIRI = getTagIRI(OBOVocabulary.BROAD_SYNONYM); } else if (SynonymScope.EXACT.name().equals(synonymScope)) { annotationPropertyIRI = getTagIRI(OBOVocabulary.EXACT_SYNONYM); } else if (SynonymScope.NARROW.name().equals(synonymScope)) { annotationPropertyIRI = getTagIRI(OBOVocabulary.NARROW_SYNONYM); } else if (SynonymScope.RELATED.name().equals(synonymScope)) { annotationPropertyIRI = getTagIRI(OBOVocabulary.RELATED_SYNONYM); } else { annotationPropertyIRI = getTagIRI(OBOVocabulary.SYNONYM); } return getDataFactory().getOWLAnnotationProperty(annotationPropertyIRI); } private OWLAnnotation getSynonymTypeAnnotation(Matcher matcher) { OWLDataFactory df = getDataFactory(); String synonymType = matcher.group(SYNONYM_TYPE_GROUP); return df.getOWLAnnotation(df.getOWLAnnotationProperty(SYNONYM_TYPE_IRI), df.getOWLLiteral(synonymType)); } } class SynonymTypeDefTagHandler extends AbstractTagValueHandler { private static final Pattern PATTERN = Pattern.compile("([^\\s]*)\\s+\"([^\"]*)\"(\\s*([^\\s]*)\\s*)?"); private static final int ID_GROUP = 1; private static final int NAME_GROUP = 2; public SynonymTypeDefTagHandler(OBOConsumer consumer) { super(OBOVocabulary.SYNONYM_TYPE_DEF.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { Matcher matcher = PATTERN.matcher(value); if (matcher.matches()) { String id = matcher.group(ID_GROUP); IRI annotationPropertyIRI = getIRIFromOBOId(id); String name = matcher.group(NAME_GROUP); OWLDataFactory df = getDataFactory(); OWLAnnotationProperty annotationProperty = df.getOWLAnnotationProperty(annotationPropertyIRI); applyChange(new AddAxiom(getOntology(), df.getOWLDeclarationAxiom(annotationProperty))); IRI subsetdefIRI = getTagIRI(OBOVocabulary.SUBSETDEF.getName()); OWLAnnotationProperty subsetdefAnnotationProperty = df.getOWLAnnotationProperty(subsetdefIRI); applyChange(new AddAxiom(getOntology(), df.getOWLSubAnnotationPropertyOfAxiom( annotationProperty, subsetdefAnnotationProperty))); applyChange(new AddAxiom(getOntology(), df.getOWLAnnotationAssertionAxiom( annotationPropertyIRI, df.getRDFSLabel(name)))); } else { OWLAnnotation annotation = getAnnotationForTagValuePair( OBOVocabulary.SYNONYM_TYPE_DEF.getName(), value); applyChange(new AddOntologyAnnotation(getOntology(), annotation)); } // ID QuotedString [Scope] // 18th April 2012 // AnnotationProperty(T(ID)) // SubAnnotationPropertyOf(T(ID) T(subsetdef)) // AnnotationAssertion(T(name) T(ID) ID) // AnnotationAssertion(T(hasScope) T(ID) Scope) } } class TransitiveOverHandler extends AbstractTagValueHandler { public TransitiveOverHandler(OBOConsumer consumer) { super("is_transitive_over", consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { OWLObjectProperty first = getOWLObjectProperty(currentId); OWLObjectProperty second = getOWLObjectProperty(value); List<OWLObjectProperty> chain = new ArrayList<>(); chain.add(first); chain.add(second); OWLAxiom ax = getDataFactory().getOWLSubPropertyChainOfAxiom(chain, first); applyChange(new AddAxiom(getOntology(), ax)); } } class TransitiveTagValueHandler extends AbstractTagValueHandler { public TransitiveTagValueHandler(OBOConsumer consumer) { super(OBOVocabulary.IS_TRANSITIVE.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (Boolean.parseBoolean(value)) { OWLObjectProperty prop = getDataFactory().getOWLObjectProperty(getIRIFromOBOId(currentId)); OWLAxiom ax = getDataFactory().getOWLTransitiveObjectPropertyAxiom(prop); applyChange(new AddAxiom(getOntology(), ax)); } } } class UnionOfHandler extends AbstractTagValueHandler { public UnionOfHandler(OBOConsumer consumer) { super("union_of", consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { getConsumer().addUnionOfOperand(getOWLClassOrRestriction(value)); } } class XRefTagHandler extends AbstractTagValueHandler { public XRefTagHandler(OBOConsumer consumer) { super(OBOVocabulary.XREF.getName(), consumer); } @Override public void handle(String currentId, String value, String qualifierBlock, String comment) { if (currentId == null) { return; } OWLAnnotation xrefAnnotation = getConsumer().parseXRef(value); IRI subject = getIRIFromOBOId(currentId); OWLAnnotationAssertionAxiom ax = getDataFactory().getOWLAnnotationAssertionAxiom( xrefAnnotation.getProperty(), subject, xrefAnnotation.getValue()); applyChange(new AddAxiom(getOntology(), ax)); if (getConsumer().isTypedef() && xrefAnnotation.getValue().isIRI()) { IRI xrefIRI = (IRI) xrefAnnotation.getValue(); String typedefId = getConsumer().getCurrentId(); getConsumer().addSymbolicIdMapping(typedefId, xrefIRI); } } }