/******************************************************************************* | |
* Copyright (c) 2009, 2012 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
* Sean Muir (JKM Software) - package loading, snippet generation | |
* David A Carlson (XMLmodeling.com) - various helper methods | |
* Christian W. Damus - flexible, pluggable instance initializers (artf3272) | |
* Rama Ramakrishnan - Added loadAs() convenience method for forcing to load | |
* with a predefined document type | |
* | |
*******************************************************************************/ | |
package org.eclipse.mdht.uml.cda.util; | |
import java.io.InputStream; | |
import java.io.OutputStream; | |
import java.io.Writer; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Queue; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
import javax.xml.XMLConstants; | |
import javax.xml.namespace.NamespaceContext; | |
import javax.xml.namespace.QName; | |
import javax.xml.parsers.DocumentBuilder; | |
import javax.xml.parsers.DocumentBuilderFactory; | |
import javax.xml.transform.dom.DOMSource; | |
import javax.xml.transform.stream.StreamSource; | |
import javax.xml.validation.Schema; | |
import javax.xml.validation.SchemaFactory; | |
import javax.xml.validation.Validator; | |
import javax.xml.xpath.XPath; | |
import javax.xml.xpath.XPathConstants; | |
import javax.xml.xpath.XPathExpression; | |
import javax.xml.xpath.XPathFactory; | |
import org.eclipse.emf.common.util.BasicDiagnostic; | |
import org.eclipse.emf.common.util.BasicEList; | |
import org.eclipse.emf.common.util.Diagnostic; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.EMap; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.emf.ecore.EAttribute; | |
import org.eclipse.emf.ecore.EClass; | |
import org.eclipse.emf.ecore.EDataType; | |
import org.eclipse.emf.ecore.EFactory; | |
import org.eclipse.emf.ecore.ENamedElement; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.EPackage; | |
import org.eclipse.emf.ecore.EReference; | |
import org.eclipse.emf.ecore.EStructuralFeature; | |
import org.eclipse.emf.ecore.ETypedElement; | |
import org.eclipse.emf.ecore.EcoreFactory; | |
import org.eclipse.emf.ecore.EcorePackage; | |
import org.eclipse.emf.ecore.resource.ResourceSet; | |
import org.eclipse.emf.ecore.resource.URIConverter; | |
import org.eclipse.emf.ecore.util.Diagnostician; | |
import org.eclipse.emf.ecore.util.EcoreUtil; | |
import org.eclipse.emf.ecore.util.ExtendedMetaData; | |
import org.eclipse.emf.ecore.util.FeatureMap; | |
import org.eclipse.emf.ecore.util.FeatureMapUtil; | |
import org.eclipse.emf.ecore.xmi.DOMHandler; | |
import org.eclipse.emf.ecore.xmi.DOMHelper; | |
import org.eclipse.emf.ecore.xmi.XMLResource; | |
import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl; | |
import org.eclipse.emf.ecore.xml.type.AnyType; | |
import org.eclipse.mdht.emf.runtime.resource.DOMDocumentHandlerImpl; | |
import org.eclipse.mdht.emf.runtime.resource.FleXMLResource; | |
import org.eclipse.mdht.emf.runtime.resource.FleXMLResourceSet; | |
import org.eclipse.mdht.emf.runtime.resource.XSITypeProvider; | |
import org.eclipse.mdht.emf.runtime.util.Initializer; | |
import org.eclipse.mdht.uml.cda.Act; | |
import org.eclipse.mdht.uml.cda.CDAFactory; | |
import org.eclipse.mdht.uml.cda.CDAPackage; | |
import org.eclipse.mdht.uml.cda.CDAPlugin; | |
import org.eclipse.mdht.uml.cda.ClinicalDocument; | |
import org.eclipse.mdht.uml.cda.ClinicalStatement; | |
import org.eclipse.mdht.uml.cda.Component2; | |
import org.eclipse.mdht.uml.cda.Component3; | |
import org.eclipse.mdht.uml.cda.Component4; | |
import org.eclipse.mdht.uml.cda.Component5; | |
import org.eclipse.mdht.uml.cda.DocumentRoot; | |
import org.eclipse.mdht.uml.cda.Encounter; | |
import org.eclipse.mdht.uml.cda.Entry; | |
import org.eclipse.mdht.uml.cda.EntryRelationship; | |
import org.eclipse.mdht.uml.cda.Observation; | |
import org.eclipse.mdht.uml.cda.ObservationMedia; | |
import org.eclipse.mdht.uml.cda.Organizer; | |
import org.eclipse.mdht.uml.cda.Procedure; | |
import org.eclipse.mdht.uml.cda.RegionOfInterest; | |
import org.eclipse.mdht.uml.cda.Section; | |
import org.eclipse.mdht.uml.cda.StructuredBody; | |
import org.eclipse.mdht.uml.cda.SubstanceAdministration; | |
import org.eclipse.mdht.uml.cda.Supply; | |
import org.eclipse.mdht.uml.cda.internal.resource.CDAResource; | |
import org.eclipse.mdht.uml.cda.internal.resource.CDAResourceFactoryImpl; | |
import org.eclipse.mdht.uml.cda.internal.resource.CDAXSITypeProvider; | |
import org.eclipse.mdht.uml.hl7.datatypes.II; | |
import org.eclipse.mdht.uml.hl7.datatypes.util.DatatypesUtil.ValidationStatistics; | |
import org.eclipse.mdht.uml.hl7.rim.InfrastructureRoot; | |
import org.eclipse.mdht.uml.hl7.vocab.x_ActRelationshipEntry; | |
import org.eclipse.mdht.uml.hl7.vocab.x_ActRelationshipEntryRelationship; | |
import org.eclipse.ocl.ecore.Constraint; | |
import org.eclipse.ocl.ecore.OCL; | |
import org.eclipse.ocl.ecore.OCLExpression; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Node; | |
import org.w3c.dom.NodeList; | |
import org.xml.sax.ErrorHandler; | |
import org.xml.sax.InputSource; | |
import org.xml.sax.SAXException; | |
import org.xml.sax.SAXParseException; | |
public class CDAUtil { | |
public static boolean ignoreBadValues = true; | |
public static final String CDA_ANNOTATION_SOURCE = "http://www.openhealthtools.org/mdht/uml/cda/annotation"; | |
private static final Pattern COMPONENT_PATTERN = Pattern.compile("(^[A-Za-z0-9]+)(\\[([1-9]+[0-9]*)\\])?"); | |
static { | |
// configure the CDA resource implementation | |
CDAResourceFactoryImpl.init(); | |
} | |
/** | |
* List of all template classes derived from ClinicalDocument. | |
*/ | |
public static Map<String, EClass> getAllDocumentClasses() { | |
Map<String, EClass> result; | |
XSITypeProvider provider = XSITypeProvider.Registry.INSTANCE.getXSITypeProvider(CDAPackage.eINSTANCE); | |
if (provider instanceof CDAXSITypeProvider) { | |
result = Collections.unmodifiableMap(((CDAXSITypeProvider) provider).getAllDocumentClasses()); | |
} else { | |
result = Collections.emptyMap(); | |
} | |
return result; | |
} | |
/** | |
* If not null, use this EClass as the document root in loader. | |
* | |
* @deprecated Use resource sets created by the {@link #createResourceSet(EClass)} or {@link #createResourceSet(String)} API to force a particular document class in resource loading | |
*/ | |
@Deprecated | |
public static EClass getDocumentClass() { | |
EClass result = null; | |
XSITypeProvider provider = XSITypeProvider.Registry.INSTANCE.getXSITypeProvider(CDAPackage.eINSTANCE); | |
if (provider instanceof CDAXSITypeProvider) { | |
result = ((CDAXSITypeProvider) provider).getDocumentClass(); | |
} | |
return result; | |
} | |
/** | |
* EClass to use as the document root, or set to null for default behavior of | |
* discovering EClass based on templateId. | |
* | |
* @deprecated Use the {@link #createResourceSet(EClass)} API, instead, to create a resource set configured to load documents of the given type | |
*/ | |
@Deprecated | |
public static void setDocumentClass(EClass eClass) { | |
XSITypeProvider.Registry.INSTANCE.registerXSITypeProvider(CDAPackage.eINSTANCE, new CDAXSITypeProvider(eClass)); | |
} | |
/** | |
* Model qualified name (e.g. ccd::ContinuityOfCareDocument) of the EClass to use | |
* as the document root, or set to null for default behavior of | |
* discovering EClass based on templateId. | |
* | |
* @deprecated Use the {@link #createResourceSet(String)} API, instead, to create a resource set configured to load documents of the given type | |
*/ | |
@Deprecated | |
public static void setDocumentClassQName(String documentClassQName) { | |
XSITypeProvider.Registry.INSTANCE.registerXSITypeProvider( | |
CDAPackage.eINSTANCE, new CDAXSITypeProvider(documentClassQName)); | |
} | |
/** | |
* Creates a new resource set for loading CDA-based XML documents. | |
* | |
* @return the resource set | |
* | |
* @see #createResourceSet(EClass) | |
* @see #createResourceSet(String) | |
*/ | |
public static FleXMLResourceSet createResourceSet() { | |
return FleXMLResourceSet.Factory.INSTANCE.createResourceSet().setDefaultResourceFactory( | |
CDAResource.Factory.INSTANCE); | |
} | |
/** | |
* Creates a new resource set for loading CDA-based XML documents of a specified {@link EClass} type. | |
* | |
* @param documentClass my forced document class, or {@code null} to discover the document class by template ID | |
* | |
* @return the resource set | |
*/ | |
public static FleXMLResourceSet createResourceSet(EClass eClass) { | |
FleXMLResourceSet result = FleXMLResourceSet.Factory.INSTANCE.createResourceSet().setDefaultResourceFactory( | |
CDAResource.Factory.INSTANCE); | |
result.getXSITypeProviderRegistry().registerXSITypeProvider( | |
CDAPackage.eINSTANCE, new CDAXSITypeProvider(eClass)); | |
return result; | |
} | |
/** | |
* Creates a new resource set for loading CDA-based XML documents of a specified document class type. | |
* | |
* @param documentClassQName my forced document class's qualified name, or {@code null} to discover the document class by template ID | |
* | |
* @return the resource set | |
*/ | |
public static FleXMLResourceSet createResourceSet(String documentClassQName) { | |
FleXMLResourceSet result = FleXMLResourceSet.Factory.INSTANCE.createResourceSet().setDefaultResourceFactory( | |
CDAResource.Factory.INSTANCE); | |
result.getXSITypeProviderRegistry().registerXSITypeProvider( | |
CDAPackage.eINSTANCE, new CDAXSITypeProvider(documentClassQName)); | |
return result; | |
} | |
public static ClinicalDocument load(InputStream in) throws Exception { | |
return load(in, (ValidationHandler) null); | |
} | |
public static ClinicalDocument load(InputSource is) throws Exception { | |
return load(is, (ValidationHandler) null); | |
} | |
public static ClinicalDocument load(Document document) throws Exception { | |
return load(document, (ValidationHandler) null); | |
} | |
public static ClinicalDocument load(InputStream in, final ValidationHandler handler) throws Exception { | |
return load(CDAUtil.createResourceSet((EClass) null), generateURI(), in, handler); | |
} | |
public static ClinicalDocument load(ResourceSet resourceSet, URI uri, InputStream in, | |
final ValidationHandler handler) throws Exception { | |
XMLResource resource = (XMLResource) resourceSet.createResource(uri); | |
Map<Object, Object> options = createOptimizedLoadOptions(); | |
if (handler != null) { | |
// perform XML schema validation BEFORE load for base standard compliance (complete) | |
options.put(FleXMLResource.OPTION_DOM_DOCUMENT_HANDLER, new DOMDocumentHandlerImpl() { | |
@Override | |
public void aboutToLoadDOM(Document document) { | |
performSchemaValidation(document, handler); | |
} | |
}); | |
} | |
resource.load(in, options); | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
ClinicalDocument clinicalDocument = root.getClinicalDocument(); | |
if (handler != null) { | |
// perform EMF validation AFTER load for base standard compliance (subset) + IG-specific compliance | |
performEMFValidation(clinicalDocument, handler); | |
} | |
return clinicalDocument; | |
} | |
public static ClinicalDocument load(InputSource is, final ValidationHandler handler) throws Exception { | |
return load(CDAUtil.createResourceSet((EClass) null), generateURI(), is, handler); | |
} | |
public static ClinicalDocument load(ResourceSet resourceSet, URI uri, InputSource is, | |
final ValidationHandler handler) throws Exception { | |
XMLResource resource = (XMLResource) resourceSet.createResource(uri); | |
Map<Object, Object> options = createOptimizedLoadOptions(); | |
if (handler != null) { | |
// perform XML schema validation BEFORE load for base standard compliance (complete) | |
options.put(FleXMLResource.OPTION_DOM_DOCUMENT_HANDLER, new DOMDocumentHandlerImpl() { | |
@Override | |
public void aboutToLoadDOM(Document document) { | |
performSchemaValidation(document, handler); | |
} | |
}); | |
} | |
resource.load(is, options); | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
ClinicalDocument clinicalDocument = root.getClinicalDocument(); | |
if (handler != null) { | |
// perform EMF validation AFTER load for base standard compliance (subset) + IG-specific compliance | |
performEMFValidation(clinicalDocument, handler); | |
} | |
return clinicalDocument; | |
} | |
public static ClinicalDocument load(Document document, final ValidationHandler handler) throws Exception { | |
return load(CDAUtil.createResourceSet((EClass) null), generateURI(), document, handler); | |
} | |
public static ClinicalDocument load(ResourceSet resourceSet, URI uri, Document document, | |
final ValidationHandler handler) throws Exception { | |
XMLResource resource = (XMLResource) resourceSet.createResource(uri); | |
Map<Object, Object> options = createOptimizedLoadOptions(); | |
if (handler != null) { | |
// perform XML schema validation BEFORE load for base standard compliance (complete) | |
options.put(FleXMLResource.OPTION_DOM_DOCUMENT_HANDLER, new DOMDocumentHandlerImpl() { | |
@Override | |
public void aboutToLoadDOM(Document document) { | |
performSchemaValidation(document, handler); | |
} | |
}); | |
} | |
resource.load(document, options); | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
ClinicalDocument clinicalDocument = root.getClinicalDocument(); | |
if (handler != null) { | |
// perform EMF validation AFTER load for base standard compliance (subset) + IG-specific compliance | |
performEMFValidation(clinicalDocument, handler); | |
} | |
return clinicalDocument; | |
} | |
public static ClinicalDocument load(URI uri, final ValidationHandler handler) throws Exception { | |
return load(CDAUtil.createResourceSet((EClass) null), uri, handler); | |
} | |
public static ClinicalDocument load(URI uri) throws Exception { | |
return load(CDAUtil.createResourceSet((EClass) null), uri, (ValidationHandler) null); | |
} | |
/** | |
* Convenience load method for loading a CDA document as a specific type | |
* | |
* @param in | |
* @param docTypeEClass | |
* @return | |
* @throws Exception | |
*/ | |
public static ClinicalDocument loadAs(InputStream in, EClass docTypeEClass) throws Exception { | |
return load(CDAUtil.createResourceSet(docTypeEClass), generateURI(), in, (ValidationHandler) null); | |
} | |
/** | |
* Convenience load method for loading a CDA document as a specific type | |
* | |
* @param in | |
* @param docTypeEClass | |
* @param handler | |
* @return | |
* @throws Exception | |
*/ | |
public static ClinicalDocument loadAs(InputStream in, EClass docTypeEClass, final ValidationHandler handler) | |
throws Exception { | |
return load(CDAUtil.createResourceSet(docTypeEClass), generateURI(), in, handler); | |
} | |
private static int uriCounter = 0; | |
public static URI generateURI() { | |
URI uri = URI.createURI("http:///resource" + uriCounter + ".xml"); | |
uriCounter++; | |
return uri; | |
} | |
private static Map<Object, Object> createOptimizedLoadOptions() { | |
Map<Object, Object> options = new java.util.HashMap<Object, Object>(); | |
options.put(XMLResource.OPTION_USE_PARSER_POOL, new XMLParserPoolImpl()); | |
options.put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, Boolean.TRUE); | |
options.put(XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP, new HashMap<Object, Object>()); | |
options.put(URIConverter.OPTION_TIMEOUT, 500); | |
return options; | |
} | |
public static ClinicalDocument load(ResourceSet resourceSet, URI uri, final ValidationHandler handler) | |
throws Exception { | |
XMLResource resource = (XMLResource) resourceSet.createResource(uri); | |
Map<Object, Object> options = createOptimizedLoadOptions(); | |
if (handler != null) { | |
// perform XML schema validation BEFORE load for base standard compliance (complete) | |
options.put(FleXMLResource.OPTION_DOM_DOCUMENT_HANDLER, new DOMDocumentHandlerImpl() { | |
@Override | |
public void aboutToLoadDOM(Document document) { | |
performSchemaValidation(document, handler); | |
} | |
}); | |
} | |
resource.load(options); | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
ClinicalDocument clinicalDocument = root.getClinicalDocument(); | |
if (handler != null) { | |
// perform EMF validation AFTER load for base standard compliance (subset) + IG-specific compliance | |
performEMFValidation(clinicalDocument, handler); | |
} | |
return clinicalDocument; | |
} | |
/** | |
* @deprecated Use the {@link #load(ResourceSet, URI, LoadHandler)} API, instead. | |
*/ | |
@Deprecated | |
public static ClinicalDocument load(InputStream in, LoadHandler handler) throws Exception { | |
DocumentBuilder builder = newDocumentBuilder(); | |
Document doc = builder.parse(in); | |
return load(doc, handler); | |
} | |
/** | |
* @deprecated Use the {@link #load(ResourceSet, URI, LoadHandler)} API, instead. | |
*/ | |
@Deprecated | |
public static ClinicalDocument load(InputSource is, LoadHandler handler) throws Exception { | |
DocumentBuilder builder = newDocumentBuilder(); | |
Document doc = builder.parse(is); | |
return load(doc, handler); | |
} | |
/** | |
* @deprecated Use the {@link #load(ResourceSet, URI, LoadHandler)} API, instead. | |
*/ | |
@Deprecated | |
public static ClinicalDocument load(Document doc, LoadHandler handler) throws Exception { | |
XMLResource resource = (XMLResource) createResourceSet().createResource(URI.createURI(CDAPackage.eNS_URI)); | |
resource.load(doc, null); | |
if (handler != null) { | |
processResource(resource, handler); | |
} | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
return root.getClinicalDocument(); | |
} | |
public static ClinicalDocument load(ResourceSet resourceSet, URI uri, LoadHandler handler) throws Exception { | |
XMLResource resource = (XMLResource) resourceSet.createResource(uri); | |
resource.load(null); | |
if (handler != null) { | |
processResource(resource, handler); | |
} | |
DocumentRoot root = (DocumentRoot) resource.getContents().get(0); | |
return root.getClinicalDocument(); | |
} | |
private static DocumentBuilder newDocumentBuilder() throws Exception { | |
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | |
factory.setNamespaceAware(true); | |
return factory.newDocumentBuilder(); | |
} | |
private static void processResource(XMLResource resource, LoadHandler handler) { | |
Map<EObject, AnyType> extMap = resource.getEObjectToExtensionMap(); | |
for (EObject key : extMap.keySet()) { | |
AnyType value = extMap.get(key); | |
handleUnknownData(key, value, handler); | |
} | |
} | |
private static void handleUnknownData(EObject object, AnyType unknownData, LoadHandler handler) { | |
handleUnknownFeatures(object, unknownData.getMixed(), handler); | |
handleUnknownFeatures(object, unknownData.getAnyAttribute(), handler); | |
} | |
private static void handleUnknownFeatures(EObject owner, FeatureMap featureMap, LoadHandler handler) { | |
Iterator<FeatureMap.Entry> iterator = featureMap.iterator(); | |
while (iterator.hasNext()) { | |
FeatureMap.Entry entry = iterator.next(); | |
EStructuralFeature feature = entry.getEStructuralFeature(); | |
if (handler.handleUnknownFeature(owner, feature, entry.getValue())) { | |
iterator.remove(); | |
} | |
} | |
} | |
public interface LoadHandler { | |
public boolean handleUnknownFeature(EObject owner, EStructuralFeature feature, Object value); | |
} | |
public static void save(ClinicalDocument clinicalDocument, OutputStream out) throws Exception { | |
save(clinicalDocument, out, true); | |
} | |
public static void save(ClinicalDocument clinicalDocument, OutputStream out, boolean defaults) throws Exception { | |
XMLResource resource = prepare(clinicalDocument, defaults); | |
resource.save(out, null); | |
} | |
public static void save(ClinicalDocument clinicalDocument, Writer writer) throws Exception { | |
save(clinicalDocument, writer, true); | |
} | |
public static void save(ClinicalDocument clinicalDocument, Writer writer, boolean defaults) throws Exception { | |
XMLResource resource = prepare(clinicalDocument, defaults); | |
resource.save(writer, null); | |
} | |
public static Document save(ClinicalDocument clinicalDocument, DOMHandler handler) throws Exception { | |
XMLResource resource = prepare(clinicalDocument, true); | |
return resource.save(newDocumentBuilder().newDocument(), null, handler); | |
} | |
private static XMLResource prepare(ClinicalDocument clinicalDocument, boolean defaults) { | |
if (defaults) { | |
handleDefaults(clinicalDocument); | |
} | |
XMLResource resource = (XMLResource) clinicalDocument.eResource(); | |
if (resource == null) { | |
resource = (XMLResource) createResourceSet().createResource(URI.createURI(CDAPackage.eNS_URI)); | |
DocumentRoot root = CDAFactory.eINSTANCE.createDocumentRoot(); | |
root.setClinicalDocument(clinicalDocument); | |
root.getXMLNSPrefixMap().put("", CDAPackage.eNS_URI); | |
root.getXSISchemaLocation().put(CDAPackage.eNS_URI, SCHEMA_NAME); | |
resource.getContents().add(root); | |
} else { | |
DocumentRoot root = (DocumentRoot) clinicalDocument.eContainer(); | |
List<String> keys = new ArrayList<String>(); | |
for (Map.Entry<String, String> entry : root.getXMLNSPrefixMap().entrySet()) { | |
if (EPackage.Registry.INSTANCE.keySet().contains(entry.getValue())) { | |
keys.add(entry.getKey()); | |
} | |
} | |
for (String key : keys) { | |
root.getXMLNSPrefixMap().removeKey(key); | |
} | |
root.getXMLNSPrefixMap().put("", CDAPackage.eNS_URI); | |
} | |
return resource; | |
} | |
public static void saveSnippet(EObject snippet, OutputStream out) throws Exception { | |
saveSnippet(snippet, out, true); | |
} | |
public static void saveSnippet(EObject snippet, OutputStream out, boolean defaults) throws Exception { | |
XMLResource resource = prepare(snippet, defaults); | |
resource.save(out, snippetOptions()); | |
} | |
public static void saveSnippet(InfrastructureRoot snippet, Writer writer) throws Exception { | |
XMLResource resource = prepare(snippet, true); | |
resource.save(writer, snippetOptions()); | |
} | |
private static Map<String, Object> snippetOptions() { | |
Map<String, Object> options = new HashMap<String, Object>(); | |
options.put(XMLResource.OPTION_ENCODING, "UTF8"); | |
options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.FALSE); | |
options.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE); | |
options.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE); | |
options.put(XMLResource.OPTION_USE_FILE_BUFFER, Boolean.TRUE); | |
return options; | |
} | |
/** | |
* Creates a document root instance and adds the cda snippet to be streamed | |
* | |
* @param cdaSnippet | |
* @param defaults | |
* @return | |
*/ | |
@SuppressWarnings({ "unchecked", "rawtypes" }) | |
private static XMLResource prepare(EObject cdaSnippet, boolean defaults) { | |
XMLResource resource = (XMLResource) createResourceSet().createResource(URI.createURI(CDAPackage.eNS_URI)); | |
EClass documentRootEClass = EcoreFactory.eINSTANCE.createEClass(); | |
documentRootEClass.setName("DocumentRoot"); | |
ExtendedMetaData.INSTANCE.setName(documentRootEClass, ""); | |
ExtendedMetaData.INSTANCE.setContentKind(documentRootEClass, ExtendedMetaData.MIXED_CONTENT); | |
EAttribute mixed = EcoreFactory.eINSTANCE.createEAttribute(); | |
mixed.setName("mixed"); | |
mixed.setEType(EcorePackage.eINSTANCE.getEFeatureMapEntry()); | |
mixed.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); | |
ExtendedMetaData.INSTANCE.setName(mixed, ":mixed"); | |
ExtendedMetaData.INSTANCE.setFeatureKind(mixed, ExtendedMetaData.ELEMENT_WILDCARD_FEATURE); | |
documentRootEClass.getEStructuralFeatures().add(mixed); | |
EReference xmlnsPrefixMap = EcoreFactory.eINSTANCE.createEReference(); | |
xmlnsPrefixMap.setName("xMLNSPrefixMap"); | |
xmlnsPrefixMap.setEType(EcorePackage.eINSTANCE.getEStringToStringMapEntry()); | |
xmlnsPrefixMap.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); | |
xmlnsPrefixMap.setContainment(true); | |
xmlnsPrefixMap.setTransient(true); | |
ExtendedMetaData.INSTANCE.setName(xmlnsPrefixMap, "xmlns:prefix"); | |
ExtendedMetaData.INSTANCE.setFeatureKind(xmlnsPrefixMap, ExtendedMetaData.ATTRIBUTE_FEATURE); | |
documentRootEClass.getEStructuralFeatures().add(xmlnsPrefixMap); | |
EReference xsiSchemaLocation = EcoreFactory.eINSTANCE.createEReference(); | |
xsiSchemaLocation.setName("xSISchemaLocation"); | |
xsiSchemaLocation.setEType(EcorePackage.eINSTANCE.getEStringToStringMapEntry()); | |
xsiSchemaLocation.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); | |
xsiSchemaLocation.setContainment(true); | |
xsiSchemaLocation.setTransient(true); | |
ExtendedMetaData.INSTANCE.setName(xsiSchemaLocation, "xsi:schemaLocation"); | |
ExtendedMetaData.INSTANCE.setFeatureKind(xsiSchemaLocation, ExtendedMetaData.ATTRIBUTE_FEATURE); | |
documentRootEClass.getEStructuralFeatures().add(xsiSchemaLocation); | |
EReference snippetReference = EcoreFactory.eINSTANCE.createEReference(); | |
String snippetName = cdaSnippet.eClass().getName(); | |
for (EClass eClass : cdaSnippet.eClass().getEAllSuperTypes()) { | |
if (CDAPackage.eINSTANCE.getNsURI().equals(eClass.getEPackage().getNsURI()) && | |
!"ClinicalStatement".equals(eClass.getName())) { | |
snippetName = eClass.getName(); | |
break; | |
} | |
} | |
snippetReference.setName(snippetName.toLowerCase()); | |
snippetReference.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); | |
snippetReference.setContainment(true); | |
snippetReference.setEType(cdaSnippet.eClass()); | |
documentRootEClass.getEStructuralFeatures().add(snippetReference); | |
EPackage documentRootPackage = EcoreFactory.eINSTANCE.createEPackage(); | |
documentRootPackage.setName(CDAPackage.eNAME); | |
documentRootPackage.setNsPrefix(CDAPackage.eNS_PREFIX); | |
documentRootPackage.setNsURI(CDAPackage.eNS_URI); | |
documentRootPackage.getEClassifiers().add(documentRootEClass); | |
EFactory documentRootFactoryInstance = documentRootPackage.getEFactoryInstance(); | |
EObject documentRootInstance = documentRootFactoryInstance.create(documentRootEClass); | |
((EMap<String, String>) documentRootInstance.eGet(xmlnsPrefixMap)).put("", CDAPackage.eNS_URI); | |
((EMap<String, String>) documentRootInstance.eGet(xsiSchemaLocation)).put(CDAPackage.eNS_URI, SCHEMA_NAME); | |
((List) documentRootInstance.eGet(snippetReference)).add(cdaSnippet); | |
resource.getContents().add(documentRootInstance); | |
return resource; | |
} | |
// iterative breadth-first traversal using queue | |
@SuppressWarnings("unchecked") | |
private static void handleDefaults(EObject root) { | |
Queue<EObject> queue = new LinkedList<EObject>(); | |
queue.add(root); // root | |
while (!queue.isEmpty()) { | |
EObject eObject = queue.remove(); | |
EClass eClass = eObject.eClass(); | |
for (EAttribute attribute : eClass.getEAllAttributes()) { // visit | |
if (!eObject.eIsSet(attribute) && attribute.getLowerBound() > 0 && | |
attribute.getDefaultValueLiteral() != null) { | |
if (attribute.isMany()) { | |
List<Object> list = (List<Object>) eObject.eGet(attribute); | |
list.add(attribute.getDefaultValue()); | |
} else { | |
eObject.eSet(attribute, attribute.getDefaultValue()); | |
} | |
} | |
} | |
for (EReference reference : eClass.getEAllReferences()) { // process successors | |
Object value = eObject.eGet(reference); | |
if (value != null) { | |
if (reference.isMany()) { | |
queue.addAll((List<EObject>) value); | |
} else { | |
queue.add((EObject) value); | |
} | |
} | |
} | |
} | |
} | |
public static boolean validate(ClinicalDocument clinicalDocument) { | |
return validate(clinicalDocument, null); | |
} | |
public static boolean validate(ClinicalDocument clinicalDocument, ValidationHandler handler) { | |
return validate(clinicalDocument, handler, true); | |
} | |
public static boolean validate(ClinicalDocument clinicalDocument, ValidationHandler handler, boolean defaults) { | |
if (defaults) { | |
handleDefaults(clinicalDocument); | |
} | |
if (clinicalDocument.eResource() != null) { | |
// process diagnostics that were produced during EMF deserialization | |
processDiagnostic(EcoreUtil.computeDiagnostic(clinicalDocument.eResource(), true), handler); | |
} | |
Map<String, Object> context = new HashMap<String, Object>(); | |
if (handler != null && handler.isCaptureValidationStatistics()) { | |
ValidationStatistics counter = new ValidationStatistics(); | |
handler.setValidationStatistics(counter); | |
context.put(ValidationStatistics.class.getCanonicalName(), handler.getValidationStatistics()); | |
} | |
Diagnostic diagnostic = Diagnostician.INSTANCE.validate(clinicalDocument, context); | |
if (handler != null) { | |
processDiagnostic(diagnostic, handler); | |
} | |
return diagnostic.getSeverity() != Diagnostic.ERROR; | |
} | |
public static void performSchemaValidation(ClinicalDocument clinicalDocument, ValidationHandler handler) { | |
try { | |
Document document = CDAUtil.save(clinicalDocument, (DOMHandler) null); | |
performSchemaValidation(document, handler); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* @author seanmuir | |
* | |
*/ | |
public static interface SchemaLoader { | |
Schema getSchema(); | |
}; | |
/** | |
* @author seanmuir | |
* | |
*/ | |
public static class ClassPathSchemaLoader implements SchemaLoader { | |
Schema schema = null; | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.mdht.uml.cda.util.CDAUtil.SchemaLoader#getSchema() | |
*/ | |
@Override | |
public Schema getSchema() { | |
if (schema == null) { | |
try { | |
String schemaLocation = System.getProperty(SCHEMA_LOCATION_PROPERTY); | |
if (schemaLocation == null) { | |
schemaLocation = CDAPlugin.INSTANCE.getString(SCHEMA_PROPERTY); | |
} | |
if (schemaLocation == null) { | |
schemaLocation = SCHEMA_NAME; | |
} | |
// Look for the schema location using class path | |
URL url = CDAUtil.class.getClassLoader().getResource(schemaLocation); | |
if (url == null) { | |
// If null, prefix with "../" to account when running within eclipse environment, the class path does not include | |
// the root directory of the project - just the bin and selected folders | |
url = CDAUtil.class.getClassLoader().getResource("../" + schemaLocation); | |
} | |
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); | |
if (url == null) { | |
throw new RuntimeException("Unable to load CDA Schema " + schemaLocation); | |
} | |
schema = factory.newSchema(new StreamSource(url.toExternalForm())); | |
} catch (SAXException e) { | |
e.printStackTrace(); | |
} | |
} | |
return schema; | |
} | |
}; | |
public static String SCHEMA_LOCATION_PROPERTY = "org.mdht.cda.schema"; | |
public static String SCHEMA_LOADER = "org.mdht.cda.schemaloader"; | |
public static String SCHEMA_NAME = "infrastructure/cda/CDA_SDTC.xsd"; | |
private static String SCHEMA_PROPERTY = "cdaSchema"; | |
private static SchemaLoader schemaLoader = null; | |
private static SchemaLoader getScheamLoader() { | |
if (schemaLoader == null) { | |
String schemaLoaderProperty = System.getProperty(SCHEMA_LOADER); | |
if (schemaLoaderProperty == null) { | |
schemaLoader = new ClassPathSchemaLoader(); | |
} else { | |
try { | |
Class<?> classDefinition = Class.forName(schemaLoaderProperty); | |
schemaLoader = (SchemaLoader) classDefinition.newInstance(); | |
} catch (Exception e) { | |
System.err.println("Unable to create schema loader " + schemaLoaderProperty + " using default"); | |
} finally { | |
schemaLoader = new ClassPathSchemaLoader(); | |
} | |
} | |
} | |
return schemaLoader; | |
} | |
public static void performSchemaValidation(Document document, ValidationHandler handler) { | |
try { | |
Schema schema = getScheamLoader().getSchema(); // factory.newSchema(new StreamSource(url.toExternalForm())); | |
Validator validator = schema.newValidator(); | |
validator.setErrorHandler(new SchemaValidationHandler(handler)); | |
validator.validate(new DOMSource(document)); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void performEMFValidation(Document document, ValidationHandler handler) { | |
try { | |
ClinicalDocument clinicalDocument = CDAUtil.load(document); | |
performEMFValidation(clinicalDocument, handler); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
public static void performEMFValidation(ClinicalDocument clinicalDocument, ValidationHandler handler) { | |
validate(clinicalDocument, handler); | |
} | |
public static class SchemaValidationHandler implements ErrorHandler { | |
private ValidationHandler handler = null; | |
public SchemaValidationHandler(ValidationHandler handler) { | |
this.handler = handler; | |
} | |
public void error(SAXParseException exception) throws SAXException { | |
handler.handleError(createDiagnostic(Diagnostic.ERROR, exception)); | |
} | |
public void fatalError(SAXParseException exception) throws SAXException { | |
} | |
public void warning(SAXParseException exception) throws SAXException { | |
handler.handleWarning(createDiagnostic(Diagnostic.WARNING, exception)); | |
} | |
private Diagnostic createDiagnostic(int severity, SAXParseException exception) { | |
return new BasicDiagnostic( | |
severity, "javax.xml.validation.Validator", 0, exception.getMessage(), new Object[] { exception }); | |
} | |
} | |
// iterative breadth-first traversal of diagnostic tree using queue | |
private static void processDiagnostic(Diagnostic diagnostic, ValidationHandler handler) { | |
Queue<Diagnostic> queue = new LinkedList<Diagnostic>(); | |
queue.add(diagnostic); // root | |
while (!queue.isEmpty()) { | |
Diagnostic d = queue.remove(); | |
if (shouldHandle(d)) { | |
handleDiagnostic(d, handler); // visit | |
} | |
for (Diagnostic childDiagnostic : d.getChildren()) { // process successors | |
queue.add(childDiagnostic); | |
} | |
} | |
} | |
private static boolean shouldHandle(Diagnostic diagnostic) { | |
// filter out diagnostics with no message or with root diagnostic message | |
if (diagnostic.getMessage() == null || diagnostic.getMessage().startsWith("Diagnosis of")) { | |
return false; | |
} | |
return true; | |
} | |
private static void handleDiagnostic(Diagnostic diagnostic, ValidationHandler handler) { | |
switch (diagnostic.getSeverity()) { | |
case Diagnostic.ERROR: | |
handler.handleError(diagnostic); | |
break; | |
case Diagnostic.WARNING: | |
handler.handleWarning(diagnostic); | |
break; | |
case Diagnostic.INFO: | |
handler.handleInfo(diagnostic); | |
break; | |
} | |
} | |
public interface ValidationHandler { | |
public void handleError(Diagnostic diagnostic); | |
public void handleWarning(Diagnostic diagnostic); | |
public void handleInfo(Diagnostic diagnostic); | |
public boolean isCaptureValidationStatistics(); | |
public ValidationStatistics getValidationStatistics(); | |
public void setValidationStatistics(ValidationStatistics validationStatistics); | |
} | |
// walk up the containment tree until we reach the ClinicalDocument or we run out of containers | |
public static ClinicalDocument getClinicalDocument(EObject object) { | |
while (object != null && !(object instanceof ClinicalDocument)) { | |
object = object.eContainer(); | |
} | |
return (ClinicalDocument) object; | |
} | |
// walk up the containment tree until we reach a Section or we run out of containers | |
public static Section getSection(EObject object) { | |
while (object != null && !(object instanceof Section)) { | |
object = object.eContainer(); | |
} | |
return (Section) object; | |
} | |
/** | |
* | |
* @param source | |
* a Clinical Statement | |
* @param typeCode | |
* If typeCode is null, then all relationships are matched. | |
* @param targetClass | |
* EClass of relationship target. If null, then all target types are returned. | |
* @return list of Clinical Statements | |
*/ | |
public static EList<ClinicalStatement> getEntryRelationshipTargets(ClinicalStatement source, | |
x_ActRelationshipEntryRelationship typeCode, EClass targetClass) { | |
List<ClinicalStatement> targets = new ArrayList<ClinicalStatement>(); | |
// test children | |
for (EntryRelationship rel : CDAUtil.getEntryRelationships(source)) { | |
boolean typeCodeMatch = typeCode == null | |
? true | |
: typeCode.equals(rel.getTypeCode()); | |
ClinicalStatement target = CDAUtil.getClinicalStatement(rel); | |
if (target != null && isReference(target)) { | |
// resolve 'id' referenced elements | |
ClinicalStatement element = resolveReference(target); | |
if (element != null) { | |
target = element; | |
} | |
} | |
if ((Boolean.FALSE == rel.getInversionInd() || null == rel.getInversionInd()) && typeCodeMatch && | |
target != null && (targetClass == null || targetClass.isSuperTypeOf(target.eClass()))) { | |
targets.add(target); | |
} | |
} | |
// test container with inversionInd="true" | |
if (source.eContainer() instanceof EntryRelationship) { | |
EntryRelationship rel = (EntryRelationship) source.eContainer(); | |
boolean typeCodeMatch = typeCode == null | |
? true | |
: typeCode.equals(rel.getTypeCode()); | |
if (Boolean.TRUE == rel.getInversionInd() && typeCodeMatch && | |
rel.eContainer() instanceof ClinicalStatement && | |
(targetClass == null || targetClass.isSuperTypeOf(rel.eContainer().eClass()))) { | |
targets.add((ClinicalStatement) rel.eContainer()); | |
} | |
} | |
return new BasicEList.UnmodifiableEList<ClinicalStatement>(targets.size(), targets.toArray()); | |
} | |
/** | |
* | |
* @param source | |
* a Section | |
* @param typeCode | |
* If typeCode is null, then all relationships are matched. | |
* @param targetClass | |
* EClass of relationship target. If null, then all target types are returned. | |
* @return list of Clinical Statements | |
*/ | |
public static EList<ClinicalStatement> getEntryTargets(Section source, x_ActRelationshipEntry typeCode, | |
EClass targetClass) { | |
List<ClinicalStatement> targets = new ArrayList<ClinicalStatement>(); | |
// test children | |
for (Entry rel : source.getEntries()) { | |
boolean typeCodeMatch = typeCode == null | |
? true | |
: typeCode.equals(rel.getTypeCode()); | |
ClinicalStatement target = CDAUtil.getClinicalStatement(rel); | |
if (target != null && isReference(target)) { | |
// resolve 'id' referenced elements | |
ClinicalStatement element = resolveReference(target); | |
if (element != null) { | |
target = element; | |
} | |
} | |
if (typeCodeMatch && target != null && | |
(targetClass == null || targetClass.isSuperTypeOf(target.eClass()))) { | |
targets.add(target); | |
} | |
} | |
return new BasicEList.UnmodifiableEList<ClinicalStatement>(targets.size(), targets.toArray()); | |
} | |
/** | |
* A CDA element may be reference if it has an 'id' child, but no 'templateId'. | |
*/ | |
public static boolean isReference(EObject element) { | |
EObject id = getChildElement(element, "id"); | |
EObject templateId = getChildElement(element, "templateId"); | |
return templateId == null && id instanceof II && ((II) id).getRoot() != null; | |
} | |
@SuppressWarnings("unchecked") | |
private static EObject getChildElement(EObject eObject, String name) { | |
Object result = null; | |
EStructuralFeature feature = eObject.eClass().getEStructuralFeature(name); | |
if (feature != null) { | |
if (feature.isMany()) { | |
List<Object> list = (List<Object>) eObject.eGet(feature); | |
if (list.size() > 0) { | |
result = list.get(0); | |
} | |
} else { | |
result = eObject.eGet(feature); | |
} | |
} | |
return (result instanceof EObject) | |
? (EObject) result | |
: null; | |
} | |
private static class ReferenceFilter<T extends EObject> implements Filter<T> { | |
private II id; | |
public ReferenceFilter(II id) { | |
this.id = id; | |
} | |
public boolean accept(T item) { | |
EObject itemId = getChildElement(item, "id"); | |
EObject templateId = getChildElement(item, "templateId"); | |
if (itemId instanceof II && templateId != null && id.equals(itemId)) { | |
return true; | |
} | |
return false; | |
} | |
} | |
/** | |
* Return the referenced element, or null if 'element' argument is not a reference | |
* or referenced id is not found. | |
*/ | |
public static EObject resolveReference(EObject element) { | |
if (!isReference(element)) { | |
return null; | |
} | |
final II id = (II) getChildElement(element, "id"); | |
EObject target = null; | |
ClinicalDocument clinicalDocument = getClinicalDocument(element); | |
if (clinicalDocument != null) { | |
Query query = new Query(clinicalDocument); | |
target = query.getEObject(EObject.class, new ReferenceFilter<EObject>(id)); | |
} | |
return target; | |
} | |
/** | |
* Return the referenced clinical statement, or null if 'element' argument is not a reference | |
* or referenced id is not found. | |
*/ | |
public static ClinicalStatement resolveReference(ClinicalStatement element) { | |
if (!isReference(element)) { | |
return null; | |
} | |
final II id = (II) getChildElement(element, "id"); | |
ClinicalStatement target = null; | |
ClinicalDocument clinicalDocument = getClinicalDocument(element); | |
if (clinicalDocument != null) { | |
Query query = new Query(clinicalDocument); | |
target = query.getClinicalStatement(ClinicalStatement.class, new ReferenceFilter<ClinicalStatement>(id)); | |
} | |
return target; | |
} | |
// initializer processing to populate runtime instance | |
public static void init(EObject eObject) { | |
final Initializer.Registry reg = Initializer.Util.getRegistry(eObject); | |
// for backwards compatibility, make sure that the annotation-based initializer is used for old packages | |
AnnotationBasedInitializer.ensureCompatibility(eObject.eClass(), reg); | |
init(eObject, reg); | |
} | |
// initializer processing to populate runtime instance | |
public static EObject init(EObject eObject, Initializer.Registry initializerRegistry) { | |
EObject result = eObject; | |
for (Initializer<? super EObject> next : initializerRegistry.getInitializers(eObject.eClass())) { | |
result = next.initialize(eObject); | |
} | |
return result; | |
} | |
public static void init(EObject eObject, Map<String, String> details) { | |
List<String> created = new ArrayList<String>(); | |
for (String key : details.keySet()) { | |
try { | |
String path = key.replace(".", "/"); | |
if (path.contains("/")) { | |
String s = path.substring(0, path.lastIndexOf("/")); | |
if (!created.contains(s)) { | |
create(eObject, s); | |
created.add(s); | |
} | |
} | |
set(eObject, path, details.get(key)); | |
} catch (Exception e) { | |
} | |
} | |
} | |
// BEGIN: Path Expression Support | |
public static <T> T create(EObject root, String path) { | |
return create(root, path, null); | |
} | |
@SuppressWarnings("unchecked") | |
public static <T> T create(EObject root, String path, EClass eClass) { | |
EObject current = root; | |
String[] components = path.split("/"); | |
int currentIndex = 0; | |
for (String component : components) { | |
EStructuralFeature feature = current.eClass().getEStructuralFeature(component); | |
if (feature instanceof EReference) { | |
EObject eObject = null; | |
Object value = current.eGet(feature); | |
if (value == null || feature.isMany()) { | |
EClass type = (EClass) feature.getEType(); | |
if (currentIndex == components.length - 1 && eClass != null && type.isSuperTypeOf(eClass)) { | |
eObject = EcoreUtil.create(eClass); | |
} else { | |
eObject = EcoreUtil.create(type); | |
} | |
if (feature.isMany()) { | |
List<EObject> list = (List<EObject>) value; | |
list.add(eObject); | |
} else { | |
current.eSet(feature, eObject); | |
} | |
} else { | |
eObject = (EObject) value; | |
} | |
current = eObject; | |
} | |
currentIndex++; | |
} | |
return (T) current; | |
} | |
@SuppressWarnings("unchecked") | |
public static void set(EObject root, String path, Object value) { | |
String last = path.substring(path.lastIndexOf("/") + 1); | |
EObject target = path.equals(last) | |
? root | |
: (EObject) get(root, path.substring(0, path.lastIndexOf("/"))); | |
if (target != null) { | |
String name = null; | |
Integer index = null; | |
Matcher matcher = COMPONENT_PATTERN.matcher(last); | |
if (matcher.matches()) { | |
name = matcher.group(1); | |
if (matcher.group(3) != null) { | |
index = Integer.valueOf(matcher.group(3)) - 1; | |
} | |
EStructuralFeature feature = target.eClass().getEStructuralFeature(name); | |
if (feature != null && value != null) { | |
if (FeatureMapUtil.isFeatureMap(feature) && value instanceof String) { | |
FeatureMap featureMap = (FeatureMap) target.eGet(feature); | |
FeatureMapUtil.addText(featureMap, (String) value); | |
} else { | |
if (feature instanceof EAttribute) { | |
EDataType type = (EDataType) feature.getEType(); | |
if (value instanceof String && !type.isInstance(value)) { | |
value = EcoreUtil.createFromString(type, (String) value); | |
} | |
} | |
if (feature.isMany()) { | |
List<Object> list = (List<Object>) target.eGet(feature); | |
if (index != null) { | |
if (index >= 0 && index < list.size()) { | |
list.set(index, value); | |
} | |
} else { | |
list.add(value); | |
} | |
} else { | |
target.eSet(feature, value); | |
} | |
} | |
} | |
} | |
} | |
} | |
@SuppressWarnings("unchecked") | |
public static <T> T get(EObject root, String path) { | |
Object result = null; | |
EObject current = root; | |
String[] components = path.split("/"); | |
for (String component : components) { | |
if (current != null) { | |
String name = null; | |
Integer index = null; | |
Matcher matcher = COMPONENT_PATTERN.matcher(component); | |
if (matcher.matches()) { | |
name = matcher.group(1); | |
if (matcher.group(3) != null) { | |
index = Integer.valueOf(matcher.group(3)) - 1; | |
} | |
EStructuralFeature feature = current.eClass().getEStructuralFeature(name); | |
if (feature != null) { | |
if (feature.isMany()) { | |
List<Object> list = (List<Object>) current.eGet(feature); | |
if (index == null) { | |
index = list.size() - 1; | |
} | |
result = (index >= 0 && index < list.size()) | |
? list.get(index) | |
: null; | |
} else { | |
result = current.eGet(feature); | |
} | |
if (feature instanceof EReference) { | |
current = (EObject) result; | |
} | |
} else { | |
result = current = null; | |
} | |
} | |
} | |
} | |
return (T) result; | |
} | |
public static boolean isSet(EObject root, String path) { | |
return get(root, path) != null; | |
} | |
@SuppressWarnings("unchecked") | |
public static void unset(EObject root, String path) { | |
String last = path.substring(path.lastIndexOf("/") + 1); | |
EObject target = path.equals(last) | |
? root | |
: (EObject) get(root, path.substring(0, path.lastIndexOf("/"))); | |
if (target != null) { | |
String name = null; | |
Integer index = null; | |
Matcher matcher = COMPONENT_PATTERN.matcher(last); | |
if (matcher.matches()) { | |
name = matcher.group(1); | |
if (matcher.group(3) != null) { | |
index = Integer.valueOf(matcher.group(3)) - 1; | |
} | |
EStructuralFeature feature = target.eClass().getEStructuralFeature(name); | |
if (feature != null) { | |
if (feature.isMany() && index != null) { | |
List<Object> list = (List<Object>) target.eGet(feature); | |
if (index >= 0 && index < list.size()) { | |
list.remove(index); | |
} | |
} else { | |
target.eUnset(feature); | |
} | |
} | |
} | |
} | |
} | |
// END: Path Expression Support | |
// BEGIN: OCL Support | |
private static final OCL ocl = OCL.newInstance(); | |
public static Object query(EObject eObject, String body) throws Exception { | |
OCL.Helper helper = ocl.createOCLHelper(); | |
helper.setContext(eObject.eClass()); | |
OCLExpression expression = helper.createQuery(body); | |
OCL.Query query = ocl.createQuery(expression); | |
return query.evaluate(eObject); | |
} | |
public static boolean check(EObject eObject, String body) throws Exception { | |
OCL.Helper helper = ocl.createOCLHelper(); | |
helper.setContext(eObject.eClass()); | |
Constraint constraint = helper.createInvariant(body); | |
OCL.Query query = ocl.createQuery(constraint); | |
return query.check(eObject); | |
} | |
// END: OCL Support | |
// BEGIN: Experimental Query/Filter operations | |
public interface Filter<T> { | |
public boolean accept(T item); | |
} | |
public static class OCLFilter<T extends EObject> implements Filter<T> { | |
protected String body = null; | |
public OCLFilter(String body) { | |
this.body = body; | |
} | |
public boolean accept(T item) { | |
boolean result = false; | |
try { | |
result = check(item, body); | |
} catch (Exception e) { | |
} | |
return result; | |
} | |
} | |
public static class Query { | |
private ClinicalDocument clinicalDocument = null; | |
private List<Section> allSections = null; | |
private List<ClinicalStatement> allClinicalStatements = null; | |
private List<EObject> allEObjects = null; | |
public Query(ClinicalDocument clinicalDocument) { | |
this.clinicalDocument = clinicalDocument; | |
} | |
// get first section that conforms to clazz and is accepted by filter | |
public <T extends Section> T getSection(Class<T> clazz, Filter<T> filter) { | |
List<T> sections = getSections(clazz, filter); | |
return !sections.isEmpty() | |
? sections.get(0) | |
: null; | |
} | |
// get first section that conforms to clazz | |
public <T extends Section> T getSection(Class<T> clazz) { | |
List<T> sections = getSections(clazz); | |
return !sections.isEmpty() | |
? sections.get(0) | |
: null; | |
} | |
// get sections that conform to clazz and are accepted by filter | |
public <T extends Section> List<T> getSections(Class<T> clazz, Filter<T> filter) { | |
List<T> sections = new ArrayList<T>(); | |
for (T section : getSections(clazz)) { | |
if (filter.accept(section)) { | |
sections.add(section); | |
} | |
} | |
return sections; | |
} | |
// get sections that conform to clazz | |
public <T extends Section> List<T> getSections(Class<T> clazz) { | |
List<T> sections = new ArrayList<T>(); | |
for (Section section : getAllSections()) { | |
if (clazz.isInstance(section)) { | |
sections.add(clazz.cast(section)); | |
} | |
} | |
return sections; | |
} | |
// get all sections in the document (closure) | |
public List<Section> getAllSections() { | |
if (allSections == null) { | |
allSections = CDAUtil.getAllSections(clinicalDocument); | |
} | |
return allSections; | |
} | |
// get first clinical statement that conform to clazz and is accepted by filter | |
public <T extends ClinicalStatement> T getClinicalStatement(Class<T> clazz, Filter<T> filter) { | |
List<T> clinicalStatements = getClinicalStatements(clazz, filter); | |
return !clinicalStatements.isEmpty() | |
? clinicalStatements.get(0) | |
: null; | |
} | |
// get first clinical statement that conform to clazz | |
public <T extends ClinicalStatement> T getClinicalStatement(Class<T> clazz) { | |
List<T> clinicalStatements = getClinicalStatements(clazz); | |
return !clinicalStatements.isEmpty() | |
? clinicalStatements.get(0) | |
: null; | |
} | |
// get clinical statements that conform to clazz and are accepted by filter | |
public <T extends ClinicalStatement> List<T> getClinicalStatements(Class<T> clazz, Filter<T> filter) { | |
List<T> clinicalStatements = new ArrayList<T>(); | |
for (T clinicalStatement : getClinicalStatements(clazz)) { | |
if (filter.accept(clinicalStatement)) { | |
clinicalStatements.add(clinicalStatement); | |
} | |
} | |
return clinicalStatements; | |
} | |
// get clinical statements that conform to clazz | |
public <T extends ClinicalStatement> List<T> getClinicalStatements(Class<T> clazz) { | |
List<T> clinicalStatements = new ArrayList<T>(); | |
for (EObject clinicalStatement : getAllClinicalStatements()) { | |
if (clazz.isInstance(clinicalStatement)) { | |
clinicalStatements.add(clazz.cast(clinicalStatement)); | |
} | |
} | |
return clinicalStatements; | |
} | |
// get all clinical statements in the document (closure) | |
public List<ClinicalStatement> getAllClinicalStatements() { | |
if (allClinicalStatements == null) { | |
allClinicalStatements = CDAUtil.getAllClinicalStatements(clinicalDocument); | |
} | |
return allClinicalStatements; | |
} | |
// get first object that conforms to clazz and is accepted by filter | |
public <T extends EObject> T getEObject(Class<T> clazz, Filter<T> filter) { | |
List<T> eObjects = getEObjects(clazz, filter); | |
return !eObjects.isEmpty() | |
? eObjects.get(0) | |
: null; | |
} | |
// get first object that conforms to clazz | |
public <T extends EObject> T getEObject(Class<T> clazz) { | |
List<T> eObjects = getEObjects(clazz); | |
return !eObjects.isEmpty() | |
? eObjects.get(0) | |
: null; | |
} | |
// get objects that conform to clazz and are accepted by filter | |
public <T extends EObject> List<T> getEObjects(Class<T> clazz, Filter<T> filter) { | |
List<T> eObjects = new ArrayList<T>(); | |
for (T eObject : getEObjects(clazz)) { | |
if (filter.accept(eObject)) { | |
eObjects.add(eObject); | |
} | |
} | |
return eObjects; | |
} | |
// get objects that conform to clazz | |
public <T extends EObject> List<T> getEObjects(Class<T> clazz) { | |
List<T> eObjects = new ArrayList<T>(); | |
for (EObject eObject : getAllEObjects()) { | |
if (clazz.isInstance(eObject)) { | |
eObjects.add(clazz.cast(eObject)); | |
} | |
} | |
return eObjects; | |
} | |
// get all objects in the document (closure) | |
public List<EObject> getAllEObjects() { | |
if (allEObjects == null) { | |
allEObjects = CDAUtil.getAllEObjects(clinicalDocument); | |
} | |
return allEObjects; | |
} | |
} | |
// get first section that conforms to clazz and is accepted by filter | |
public static <T extends Section> T getSection(ClinicalDocument clinicalDocument, Class<T> clazz, | |
Filter<T> filter) { | |
List<T> sections = getSections(clinicalDocument, clazz, filter); | |
return !sections.isEmpty() | |
? sections.get(0) | |
: null; | |
} | |
// get first section that conforms to clazz | |
public static <T extends Section> T getSection(ClinicalDocument clinicalDocument, Class<T> clazz) { | |
List<T> sections = getSections(clinicalDocument, clazz); | |
return !sections.isEmpty() | |
? sections.get(0) | |
: null; | |
} | |
// get sections that conform to clazz and are accepted by filter | |
public static <T extends Section> List<T> getSections(ClinicalDocument clinicalDocument, Class<T> clazz, | |
Filter<T> filter) { | |
List<T> sections = new ArrayList<T>(); | |
for (T section : getSections(clinicalDocument, clazz)) { | |
if (filter.accept(section)) { | |
sections.add(section); | |
} | |
} | |
return sections; | |
} | |
// get sections that conform to clazz | |
public static <T extends Section> List<T> getSections(ClinicalDocument clinicalDocument, Class<T> clazz) { | |
List<T> sections = new ArrayList<T>(); | |
for (Section section : getAllSections(clinicalDocument)) { | |
if (clazz.isInstance(section)) { | |
sections.add(clazz.cast(section)); | |
} | |
} | |
return sections; | |
} | |
// get all sections in the document (closure) | |
public static List<Section> getAllSections(ClinicalDocument clinicalDocument) { | |
List<Section> allSections = new ArrayList<Section>(); | |
Component2 component2 = clinicalDocument.getComponent(); | |
if (component2 != null) { | |
StructuredBody structuredBody = component2.getStructuredBody(); | |
if (structuredBody != null) { | |
for (Component3 component3 : structuredBody.getComponents()) { | |
Section section = component3.getSection(); | |
if (section != null) { | |
allSections.addAll(getSections(section)); | |
} | |
} | |
} | |
} | |
return allSections; | |
} | |
// get all nested sections in the section (closure) | |
public static List<Section> getAllSections(Section section) { | |
return getSections(section); | |
} | |
// iterative breadth-first traversal using queue | |
private static List<Section> getSections(Section section) { | |
List<Section> sections = new ArrayList<Section>(); | |
Queue<Section> queue = new LinkedList<Section>(); | |
queue.add(section); // root | |
while (!queue.isEmpty()) { | |
Section sect = queue.remove(); | |
sections.add(sect); // visit | |
for (Component5 component : sect.getComponents()) { // process successors | |
Section child = component.getSection(); | |
if (child != null) { | |
queue.add(child); | |
} | |
} | |
} | |
return sections; | |
} | |
// get first clinical statement that conforms to clazz and is accepted by filter | |
public static <T extends ClinicalStatement> T getClinicalStatement(ClinicalDocument clinicalDocument, | |
Class<T> clazz, Filter<T> filter) { | |
List<T> clinicalStatements = getClinicalStatements(clinicalDocument, clazz, filter); | |
return !clinicalStatements.isEmpty() | |
? clinicalStatements.get(0) | |
: null; | |
} | |
// get first clinical statement that conforms to clazz | |
public static <T extends ClinicalStatement> T getClinicalStatement(ClinicalDocument clinicalDocument, | |
Class<T> clazz) { | |
List<T> clinicalStatements = getClinicalStatements(clinicalDocument, clazz); | |
return !clinicalStatements.isEmpty() | |
? clinicalStatements.get(0) | |
: null; | |
} | |
// get clinical statements that conform to clazz and are accepted by filter | |
public static <T extends ClinicalStatement> List<T> getClinicalStatements(ClinicalDocument clinicalDocument, | |
Class<T> clazz, Filter<T> filter) { | |
List<T> clinicalStatements = new ArrayList<T>(); | |
for (T clinicalStatement : getClinicalStatements(clinicalDocument, clazz)) { | |
if (filter.accept(clinicalStatement)) { | |
clinicalStatements.add(clinicalStatement); | |
} | |
} | |
return clinicalStatements; | |
} | |
// get clinical statements that conform to clazz | |
public static <T extends ClinicalStatement> List<T> getClinicalStatements(ClinicalDocument clinicalDocument, | |
Class<T> clazz) { | |
List<T> clinicalStatements = new ArrayList<T>(); | |
for (EObject clinicalStatement : getAllClinicalStatements(clinicalDocument)) { | |
if (clazz.isInstance(clinicalStatement)) { | |
clinicalStatements.add(clazz.cast(clinicalStatement)); | |
} | |
} | |
return clinicalStatements; | |
} | |
// get all clinical statements in the document (closure) | |
public static List<ClinicalStatement> getAllClinicalStatements(ClinicalDocument clinicalDocument) { | |
List<ClinicalStatement> allClinicalStatements = new ArrayList<ClinicalStatement>(); | |
for (Section section : getAllSections(clinicalDocument)) { | |
allClinicalStatements.addAll(getClinicalStatements(section)); | |
} | |
return allClinicalStatements; | |
} | |
private static List<ClinicalStatement> getClinicalStatements(Section section) { | |
List<ClinicalStatement> clinicalStatements = new ArrayList<ClinicalStatement>(); | |
for (Entry entry : section.getEntries()) { | |
ClinicalStatement clinicalStatement = getClinicalStatement(entry); | |
if (clinicalStatement != null) { | |
clinicalStatements.addAll(getClinicalStatements(clinicalStatement)); | |
} | |
} | |
return clinicalStatements; | |
} | |
// iterative breadth-first traversal using queue | |
private static List<ClinicalStatement> getClinicalStatements(ClinicalStatement clinicalStatement) { | |
List<ClinicalStatement> clinicalStatements = new ArrayList<ClinicalStatement>(); | |
Queue<ClinicalStatement> queue = new LinkedList<ClinicalStatement>(); | |
queue.add(clinicalStatement); // root | |
while (!queue.isEmpty()) { | |
ClinicalStatement stmt = queue.remove(); | |
clinicalStatements.add(stmt); // visit | |
if (stmt instanceof Organizer) { | |
Organizer organizer = (Organizer) stmt; | |
for (Component4 component : organizer.getComponents()) { // process successors | |
ClinicalStatement child = getClinicalStatement(component); | |
if (child != null) { | |
queue.add(child); | |
} | |
} | |
} else { | |
for (EntryRelationship entryRelationship : getEntryRelationships(stmt)) { // process successors | |
ClinicalStatement child = getClinicalStatement(entryRelationship); | |
if (child != null) { | |
queue.add(child); | |
} | |
} | |
} | |
} | |
return clinicalStatements; | |
} | |
private static List<EntryRelationship> getEntryRelationships(ClinicalStatement clinicalStatement) { | |
if (clinicalStatement instanceof Act) { | |
return ((Act) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof Encounter) { | |
return ((Encounter) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof Observation) { | |
return ((Observation) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof ObservationMedia) { | |
return ((ObservationMedia) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof Procedure) { | |
return ((Procedure) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof RegionOfInterest) { | |
return ((RegionOfInterest) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof SubstanceAdministration) { | |
return ((SubstanceAdministration) clinicalStatement).getEntryRelationships(); | |
} | |
if (clinicalStatement instanceof Supply) { | |
return ((Supply) clinicalStatement).getEntryRelationships(); | |
} | |
return Collections.<EntryRelationship> emptyList(); | |
} | |
private static ClinicalStatement getClinicalStatement(Entry entry) { | |
if (entry.getAct() != null) { | |
return entry.getAct(); | |
} | |
if (entry.getEncounter() != null) { | |
return entry.getEncounter(); | |
} | |
if (entry.getObservation() != null) { | |
return entry.getObservation(); | |
} | |
if (entry.getObservationMedia() != null) { | |
return entry.getObservationMedia(); | |
} | |
if (entry.getOrganizer() != null) { | |
return entry.getOrganizer(); | |
} | |
if (entry.getProcedure() != null) { | |
return entry.getProcedure(); | |
} | |
if (entry.getRegionOfInterest() != null) { | |
return entry.getRegionOfInterest(); | |
} | |
if (entry.getSubstanceAdministration() != null) { | |
return entry.getSubstanceAdministration(); | |
} | |
if (entry.getSupply() != null) { | |
return entry.getSupply(); | |
} | |
return null; | |
} | |
private static ClinicalStatement getClinicalStatement(EntryRelationship entryRelationship) { | |
if (entryRelationship.getAct() != null) { | |
return entryRelationship.getAct(); | |
} | |
if (entryRelationship.getEncounter() != null) { | |
return entryRelationship.getEncounter(); | |
} | |
if (entryRelationship.getObservation() != null) { | |
return entryRelationship.getObservation(); | |
} | |
if (entryRelationship.getObservationMedia() != null) { | |
return entryRelationship.getObservationMedia(); | |
} | |
if (entryRelationship.getOrganizer() != null) { | |
return entryRelationship.getOrganizer(); | |
} | |
if (entryRelationship.getProcedure() != null) { | |
return entryRelationship.getProcedure(); | |
} | |
if (entryRelationship.getRegionOfInterest() != null) { | |
return entryRelationship.getRegionOfInterest(); | |
} | |
if (entryRelationship.getSubstanceAdministration() != null) { | |
return entryRelationship.getSubstanceAdministration(); | |
} | |
if (entryRelationship.getSupply() != null) { | |
return entryRelationship.getSupply(); | |
} | |
return null; | |
} | |
private static ClinicalStatement getClinicalStatement(Component4 component) { | |
if (component.getAct() != null) { | |
return component.getAct(); | |
} | |
if (component.getEncounter() != null) { | |
return component.getEncounter(); | |
} | |
if (component.getObservation() != null) { | |
return component.getObservation(); | |
} | |
if (component.getObservationMedia() != null) { | |
return component.getObservationMedia(); | |
} | |
if (component.getOrganizer() != null) { | |
return component.getOrganizer(); | |
} | |
if (component.getProcedure() != null) { | |
return component.getProcedure(); | |
} | |
if (component.getRegionOfInterest() != null) { | |
return component.getRegionOfInterest(); | |
} | |
if (component.getSubstanceAdministration() != null) { | |
return component.getSubstanceAdministration(); | |
} | |
if (component.getSupply() != null) { | |
return component.getSupply(); | |
} | |
return null; | |
} | |
// get first object that conforms to clazz and is accepted by filter | |
public static <T extends EObject> T getEObject(ClinicalDocument clinicalDocument, Class<T> clazz, | |
Filter<T> filter) { | |
List<T> eObjects = getEObjects(clinicalDocument, clazz, filter); | |
return !eObjects.isEmpty() | |
? eObjects.get(0) | |
: null; | |
} | |
// get first object that conforms to clazz | |
public static <T extends EObject> T getEObject(ClinicalDocument clinicalDocument, Class<T> clazz) { | |
List<T> eObjects = getEObjects(clinicalDocument, clazz); | |
return !eObjects.isEmpty() | |
? eObjects.get(0) | |
: null; | |
} | |
// get objects that conform to clazz and are accepted by filter | |
public static <T extends EObject> List<T> getEObjects(ClinicalDocument clinicalDocument, Class<T> clazz, | |
Filter<T> filter) { | |
List<T> eObjects = new ArrayList<T>(); | |
for (T eObject : getEObjects(clinicalDocument, clazz)) { | |
if (filter.accept(eObject)) { | |
eObjects.add(eObject); | |
} | |
} | |
return eObjects; | |
} | |
// get objects that conform to clazz | |
public static <T extends EObject> List<T> getEObjects(ClinicalDocument clinicalDocument, Class<T> clazz) { | |
List<T> eObjects = new ArrayList<T>(); | |
for (EObject eObject : getAllEObjects(clinicalDocument)) { | |
if (clazz.isInstance(eObject)) { | |
eObjects.add(clazz.cast(eObject)); | |
} | |
} | |
return eObjects; | |
} | |
// get all objects in the document (closure) | |
// iterative breadth-first traversal using queue | |
public static List<EObject> getAllEObjects(ClinicalDocument clinicalDocument) { | |
List<EObject> allEObjects = new ArrayList<EObject>(); | |
Queue<EObject> queue = new LinkedList<EObject>(); | |
queue.add(clinicalDocument); // root | |
while (!queue.isEmpty()) { | |
EObject eObject = queue.remove(); | |
allEObjects.add(eObject); // visit | |
for (EObject child : eObject.eContents()) { // process successors | |
queue.add(child); | |
} | |
} | |
return allEObjects; | |
} | |
// END: Experimental Query/Filter operations | |
// BEGIN: CDA XPath Support | |
public static Map<ClinicalDocument, CDAXPath> CACHE = new HashMap<ClinicalDocument, CDAXPath>(); | |
// factory method to create CDAXPath instances using cache | |
public static CDAXPath createCDAXPath(ClinicalDocument clinicalDocument) { | |
CDAXPath xpath = CACHE.get(clinicalDocument); | |
if (xpath == null) { | |
try { | |
xpath = new CDAXPath(clinicalDocument); | |
CACHE.put(clinicalDocument, xpath); | |
} catch (Exception e) { | |
} | |
} | |
return xpath; | |
} | |
public static class CDAXPath { | |
private ClinicalDocument clinicalDocument = null; | |
private Document document = null; | |
private DocumentRoot documentRoot = null; | |
private Map<Node, Object> nodeToObject = null; | |
private Map<Object, Node> objectToNode = null; | |
private XPath xpath = null; | |
public CDAXPath(ClinicalDocument clinicalDocument) throws Exception { | |
this.clinicalDocument = clinicalDocument; | |
nodeToObject = new HashMap<Node, Object>(); | |
objectToNode = new HashMap<Object, Node>(); | |
document = CDAUtil.save(clinicalDocument, new DOMHandler() { | |
public DOMHelper getDOMHelper() { | |
return null; | |
} | |
public void recordValues(Node node, EObject container, EStructuralFeature feature, Object value) { | |
if (value != null) { | |
nodeToObject.put(node, value); | |
objectToNode.put(value, node); | |
} | |
} | |
}); | |
documentRoot = (DocumentRoot) clinicalDocument.eContainer(); | |
nodeToObject.put(document, documentRoot); | |
objectToNode.put(documentRoot, document); | |
xpath = XPathFactory.newInstance().newXPath(); | |
xpath.setNamespaceContext(new NamespaceContext() { | |
public String getNamespaceURI(String prefix) { | |
if ("cda".equals(prefix)) { | |
return "urn:hl7-org:v3"; | |
} else if ("sdtc".equals(prefix)) { | |
return "urn:hl7-org:sdtc"; | |
} else if ("xsi".equals(prefix)) { | |
return "http://www.w3.org/2001/XMLSchema-instance"; | |
} | |
return null; | |
} | |
public String getPrefix(String namespaceURI) { | |
if ("urn:hl7-org:v3".equals(namespaceURI)) { | |
return "cda"; | |
} else if ("urn:hl7-org:sdtc".equals(namespaceURI)) { | |
return "sdtc"; | |
} else if ("http://www.w3.org/2001/XMLSchema-instance".equals(namespaceURI)) { | |
return "xsi"; | |
} | |
return null; | |
} | |
public Iterator<String> getPrefixes(String namespaceURI) { | |
return null; | |
} | |
}); | |
} | |
public Object evaluate(Node item, String expr, QName returnType) throws Exception { | |
XPathExpression expression = xpath.compile(expr); | |
return expression.evaluate(item, returnType); | |
} | |
public <T> T evaluate(Object item, String expr, Class<T> clazz) throws Exception { | |
QName returnType = null; | |
if (clazz.equals(Double.class)) { | |
returnType = XPathConstants.NUMBER; | |
} else if (clazz.equals(String.class)) { | |
returnType = XPathConstants.STRING; | |
} else if (clazz.equals(Boolean.class)) { | |
returnType = XPathConstants.BOOLEAN; | |
} else if (clazz.equals(NodeList.class)) { | |
returnType = XPathConstants.NODESET; | |
} else if (clazz.equals(Node.class)) { | |
returnType = XPathConstants.NODE; | |
} | |
return returnType != null | |
? clazz.cast(evaluate(getNode(item), expr, returnType)) | |
: null; | |
} | |
public <T> T evaluate(String expr, Class<T> clazz) throws Exception { | |
return evaluate(documentRoot, expr, clazz); | |
} | |
public Object evaluate(String expr, QName returnType) throws Exception { | |
return evaluate(document, expr, returnType); | |
} | |
public ClinicalDocument getClinicalDocument() { | |
return clinicalDocument; | |
} | |
public Document getDocument() { | |
return document; | |
} | |
public DocumentRoot getDocumentRoot() { | |
return documentRoot; | |
} | |
public Node getNode(Object object) { | |
return objectToNode.get(object); | |
} | |
public Object getObject(Node node) { | |
return nodeToObject.get(node); | |
} | |
public List<Node> selectNodes(Node item, String expr) throws Exception { | |
List<Node> result = new ArrayList<Node>(); | |
NodeList nodeList = (NodeList) evaluate(item, expr, XPathConstants.NODESET); | |
if (nodeList != null) { | |
for (int i = 0; i < nodeList.getLength(); i++) { | |
result.add(nodeList.item(i)); | |
} | |
} | |
return result; | |
} | |
public <T extends EObject> List<T> selectNodes(Object item, String expr, Class<T> clazz) throws Exception { | |
List<T> result = new ArrayList<T>(); | |
for (Node node : selectNodes(getNode(item), expr)) { | |
Object object = getObject(node); | |
if (clazz.isInstance(object)) { | |
result.add(clazz.cast(object)); | |
} | |
} | |
return result; | |
} | |
public List<Node> selectNodes(String expr) throws Exception { | |
return selectNodes(document, expr); | |
} | |
public <T extends EObject> List<T> selectNodes(String expr, Class<T> clazz) throws Exception { | |
return selectNodes(documentRoot, expr, clazz); | |
} | |
public Node selectSingleNode(Node item, String expr) throws Exception { | |
List<Node> result = selectNodes(item, expr); | |
return !result.isEmpty() | |
? result.get(0) | |
: null; | |
} | |
public <T extends EObject> T selectSingleNode(Object item, String expr, Class<T> clazz) throws Exception { | |
List<T> result = selectNodes(item, expr, clazz); | |
return !result.isEmpty() | |
? result.get(0) | |
: null; | |
} | |
public Node selectSingleNode(String expr) throws Exception { | |
return selectSingleNode(document, expr); | |
} | |
public <T extends EObject> T selectSingleNode(String expr, Class<T> clazz) throws Exception { | |
return selectSingleNode(documentRoot, expr, clazz); | |
} | |
} | |
// END: CDA XPath Support | |
public static String getPath(EObject eObject) { | |
String path = ""; | |
while (eObject != null && !(eObject instanceof DocumentRoot)) { | |
EStructuralFeature feature = eObject.eContainingFeature(); | |
EObject container = eObject.eContainer(); | |
Object value = container.eGet(feature); | |
if (feature.isMany()) { | |
List<?> list = (List<?>) value; | |
int index = list.indexOf(eObject) + 1; | |
if (index > 1) { | |
path = "/" + getName(feature) + "[" + index + "]" + path; | |
} else { | |
path = "/" + getName(feature) + path; | |
} | |
} else { | |
path = "/" + getName(feature) + path; | |
} | |
eObject = eObject.eContainer(); | |
} | |
return path; | |
} | |
public static String getDomainPath(EObject eObject) { | |
String path = ""; | |
String featurePath = ""; | |
while (eObject != null && !(eObject instanceof DocumentRoot)) { | |
EStructuralFeature feature = eObject.eContainingFeature(); | |
path = eObject.eClass().getName() + "." + path; | |
featurePath = getName(feature) + "." + featurePath; | |
if (eObject instanceof ClinicalStatement) { | |
break; | |
} | |
eObject = eObject.eContainer(); | |
} | |
return featurePath + "(" + path + ")"; | |
} | |
public static String getName(ENamedElement eNamedElement) { | |
String result = EcoreUtil.getAnnotation(eNamedElement, ExtendedMetaData.ANNOTATION_URI, "name"); | |
if (result != null) { | |
return result; | |
} | |
return eNamedElement.getName(); | |
} | |
public static String getDomainName(ENamedElement eNamedElement) { | |
return eNamedElement.eContainer().eClass().getName() + "." + eNamedElement.getName(); | |
} | |
public static void loadPackages() { | |
CDAPackageLoader.loadPackages(); | |
} | |
public static void loadPackages(String location) { | |
CDAPackageLoader.loadPackages(location); | |
} | |
} |