/// <summary> /// Parse the XML for a term /// </summary> /// <param name="xmlReader"></param> /// <param name="ontologyEntries"></param> /// <param name="mostRecentTerm"></param> /// <param name="classIdentifier">Identifier from the owl:Class term</param> /// <returns>Term name</returns> private string ParseTerm(XmlReader xmlReader, ICollection <OwlEntry> ontologyEntries, string mostRecentTerm, string classIdentifier = "") { try { var identifier = classIdentifier; var name = string.Empty; var definition = string.Empty; var comment = string.Empty; var parentTerms = new Dictionary <string, OwlEntry.eParentType>(); var synonyms = new List <string>(); var insideEquivalentClass = false; var insideIntersectionOf = false; var insideSubClassOf = false; var relationshipType = string.Empty; var termParsed = false; var startingDepth = xmlReader.Depth; while (xmlReader.Read()) { switch (xmlReader.NodeType) { case XmlNodeType.Element: // Start element switch (xmlReader.Name) { case "owl:Class": if (insideIntersectionOf || insideEquivalentClass || insideSubClassOf) { break; } if (!string.IsNullOrWhiteSpace(classIdentifier)) { OnWarningEvent("Nested owl:Class terms; this is unexpected. See term: " + classIdentifier); } else if (string.IsNullOrEmpty(name)) { OnWarningEvent("Nested owl:Class terms; this is unexpected. Most recent term: " + mostRecentTerm); } else { OnWarningEvent("Nested owl:Class terms; this is unexpected. See term: " + name); } break; case "owl:intersectionOf": insideIntersectionOf = true; break; case "owl:equivalentClass": insideEquivalentClass = true; break; case "rdfs:label": name = xmlReader.ReadInnerXml(); break; case "rdfs:subClassOf": insideSubClassOf = true; relationshipType = "part_of"; // Look for property rdf:resource if (xmlReader.HasAttributes) { var parentURL = xmlReader.GetAttribute("rdf:resource"); if (GetItemFromURL(parentURL, out var parentTermId)) { AddParentTerm(parentTerms, "is_a", parentTermId, identifier); } } else { // The subclass may have a restriction, e.g. // <rdfs:subClassOf> // <owl:Restriction> // <owl:onProperty rdf:resource="http://purl.obolibrary.org/obo/bto#part_of"/> // <owl:someValuesFrom rdf:resource="http://purl.obolibrary.org/obo/BTO_0000439"/> // </owl:Restriction> // </rdfs:subClassOf> // // We'll check for this when looking for element owl:someValuesFrom } break; case "owl:onProperty": if (insideSubClassOf && xmlReader.HasAttributes) { var parentURL = xmlReader.GetAttribute("rdf:resource"); if (GetItemFromURL(parentURL, out var relationshipTypeText)) { var poundIndex = relationshipTypeText.IndexOf("#", StringComparison.Ordinal); if (poundIndex >= 0) { relationshipType = relationshipTypeText.Substring(poundIndex + 1); } else { relationshipType = relationshipTypeText; } } } break; case "owl:someValuesFrom": if (insideSubClassOf && xmlReader.HasAttributes) { var parentURL = xmlReader.GetAttribute("rdf:resource"); if (GetItemFromURL(parentURL, out var parentTermId)) { AddParentTerm(parentTerms, relationshipType, parentTermId, identifier); } } break; case "oboInOwl:id": identifier = xmlReader.ReadInnerXml(); break; case "oboInOwl:hasOBONamespace": // Could parse out the name space break; case "oboInOwl:hasRelatedSynonym": var synonym = xmlReader.ReadInnerXml(); synonyms.Add(synonym); break; case "obo:IAO_0000115": definition = xmlReader.ReadInnerXml(); break; case "rdfs:comment": comment = xmlReader.ReadInnerXml(); break; } break; case XmlNodeType.EndElement: switch (xmlReader.Name) { case "rdfs:subClassOf": insideSubClassOf = false; break; case "owl:intersectionOf": insideIntersectionOf = false; break; case "owl:equivalentClass": insideEquivalentClass = true; break; } if (xmlReader.Depth == startingDepth) { termParsed = true; } break; case XmlNodeType.Text: // Important text should have already been skipped break; } if (termParsed) { break; } } var ontologyEntry = new OwlEntry(identifier, name) { Definition = definition, Comment = comment }; foreach (var parentEntry in parentTerms) { ontologyEntry.AddParentTerm(parentEntry.Key, parentEntry.Value); } foreach (var synonym in synonyms) { ontologyEntry.AddSynonym(synonym); } ontologyEntries.Add(ontologyEntry); return(name); } catch (Exception ex) { throw new Exception("Exception in ParseTerm: " + ex.Message, ex); } }