From 22b3727729e3405189da9607a7ec2a727b84eb5f Mon Sep 17 00:00:00 2001 From: "jelmer.terwal" Date: Thu, 24 Dec 2020 09:31:03 +0100 Subject: [PATCH 01/36] Fix CVEs by updating guava and jakarta json module --- build.gradle | 2 +- tools/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8e1f17b78..cd02fed94 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ subprojects { compile "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jacksonVersion}" - compile 'com.google.guava:guava:29.0-jre' + compile 'com.google.guava:guava:30.1-jre' compile "org.reflections:reflections:${reflectionsVersion}" compile 'com.esotericsoftware:kryo-shaded:4.0.2' //for easy and relatively fast object cloning diff --git a/tools/build.gradle b/tools/build.gradle index 22d6e003a..83b0a8c26 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -15,5 +15,5 @@ dependencies { testCompile project(':referencemodels') compile 'org.leadpony.justify:justify:2.1.0' - compile 'org.glassfish:jakarta.json:1.1.5:module' + compile 'org.glassfish:jakarta.json:1.1.6:module' } \ No newline at end of file From 4597cd37945f516b4f71dacb9dfcb33be8c66612 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Sun, 3 Jan 2021 23:40:55 +0100 Subject: [PATCH 02/36] First parts of an OPT14 parser --- opt14/build.gradle | 43 + .../archie/opt14/DefaultValueConverter.java | 5 + .../archie/opt14/DefinitionConverter.java | 108 + .../archie/opt14/DescriptionConverter.java | 32 + .../archie/opt14/DomainTypeConverter.java | 9 + .../nedap/archie/opt14/IntervalConverter.java | 55 + .../nedap/archie/opt14/Opt14Converter.java | 17 + .../archie/opt14/PrimitiveConverter.java | 87 + .../archie/opt14/TerminologyConverter.java | 27 + opt14/src/main/schemas/xjc/Archetype.xsd | 394 +++ opt14/src/main/schemas/xjc/BaseTypes.xsd | 594 ++++ .../src/main/schemas/xjc/CharacterMapping.xsd | 13 + opt14/src/main/schemas/xjc/Composition.xsd | 36 + .../main/schemas/xjc/CompositionTemplate.xsd | 489 ++++ opt14/src/main/schemas/xjc/Content.xsd | 132 + opt14/src/main/schemas/xjc/Extract.xsd | 142 + opt14/src/main/schemas/xjc/OpenehrProfile.xsd | 94 + opt14/src/main/schemas/xjc/Resource.xsd | 63 + opt14/src/main/schemas/xjc/Structure.xsd | 151 + opt14/src/main/schemas/xjc/Template.xsd | 164 ++ opt14/src/main/schemas/xjc/Version.xsd | 41 + .../com/nedap/archie/opt14/ConverterTest.java | 46 + .../openEHR-EHR-ACTION.procedure.v1.4.1.adls | 2459 +++++++++++++++++ ...EHR-COMPOSITION.health_summary.v1.0.1.adls | 242 ++ ...EHR-EHR-SECTION.procedures_rcp.v1.0.0.adls | 56 + opt14/src/test/resources/procedure_list.opt | 2183 +++++++++++++++ settings.gradle | 1 + 27 files changed, 7683 insertions(+) create mode 100644 opt14/build.gradle create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java create mode 100644 opt14/src/main/schemas/xjc/Archetype.xsd create mode 100644 opt14/src/main/schemas/xjc/BaseTypes.xsd create mode 100644 opt14/src/main/schemas/xjc/CharacterMapping.xsd create mode 100644 opt14/src/main/schemas/xjc/Composition.xsd create mode 100644 opt14/src/main/schemas/xjc/CompositionTemplate.xsd create mode 100644 opt14/src/main/schemas/xjc/Content.xsd create mode 100644 opt14/src/main/schemas/xjc/Extract.xsd create mode 100644 opt14/src/main/schemas/xjc/OpenehrProfile.xsd create mode 100644 opt14/src/main/schemas/xjc/Resource.xsd create mode 100644 opt14/src/main/schemas/xjc/Structure.xsd create mode 100644 opt14/src/main/schemas/xjc/Template.xsd create mode 100644 opt14/src/main/schemas/xjc/Version.xsd create mode 100644 opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls create mode 100644 opt14/src/test/resources/procedure_list.opt diff --git a/opt14/build.gradle b/opt14/build.gradle new file mode 100644 index 000000000..a53b6148f --- /dev/null +++ b/opt14/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.github.edeandrea.xjc-generation' version '1.5' +} + +description = "OPT 1.4 parser and converter to ADL 2" + +ext { + jaxbVersion = '2.3.1' +} + +dependencies { + compile project(':grammars') + compile project(':base') + compile project(':aom') + compile project(':bmm') + compile project(':path-queries') + compile project(':utils') + compile project(':tools') + testCompile project(':openehr-rm') + testCompile project(':archie-utils') + testCompile project(':i18n') + testCompile project(':test-rm') + testCompile project(':referencemodels') + + + xjc "javax.xml.bind:jaxb-api:$jaxbVersion" + xjc "org.glassfish.jaxb:jaxb-runtime:$jaxbVersion" + xjc "org.glassfish.jaxb:jaxb-xjc:$jaxbVersion" +} + +xjcGeneration { + defaultAdditionalXjcOptions = ['encoding': 'UTF-8'] + defaultBindingFile = null //file 'src/main/resources//xjc/xjc.xjb.xml' + + schemas { + opt14 { + schemaFile = 'Template.xsd' + javaPackageName = 'com.nedap.archie.opt14' + } + + } +} + diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java new file mode 100644 index 000000000..440406d57 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -0,0 +1,5 @@ +package com.nedap.archie.opt14; + +public class DefaultValueConverter { + //TODO: default values +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java new file mode 100644 index 000000000..1ad4ee9c5 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -0,0 +1,108 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.ArchetypeSlot; +import com.nedap.archie.aom.CArchetypeRoot; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; + +import static com.nedap.archie.opt14.IntervalConverter.convertCardinality; +import static com.nedap.archie.opt14.IntervalConverter.convertMultiplicity; +import static com.nedap.archie.opt14.PrimitiveConverter.convertPrimitive; + +public class DefinitionConverter { + + private OPERATIONALTEMPLATE opt14; + private Template template; + + public void convert(Template template, OPERATIONALTEMPLATE opt14) { + this.opt14 = opt14; + this.template = template; + CARCHETYPEROOT definition = opt14.getDefinition(); + template.setTerminology(TerminologyConverter.createTerminology(opt14, definition)); + template.setDefinition(convert(definition)); + } + + private CComplexObject convert(CCOMPLEXOBJECT cComplexObject14) { + CComplexObject cComplexObject = new CComplexObject(); + cComplexObject.setNodeId(cComplexObject14.getNodeId()); + cComplexObject.setRmTypeName(cComplexObject14.getRmTypeName()); + cComplexObject.setOccurrences(IntervalConverter.convertMultiplicity(cComplexObject14.getOccurrences())); + + for (CATTRIBUTE attribute14 : cComplexObject14.getAttributes()) { + cComplexObject.addAttribute(convert(attribute14)); + } + return cComplexObject; + } + + private CAttribute convert(CATTRIBUTE attribute14) { + CAttribute attribute = new CAttribute(); + attribute.setRmAttributeName(attribute14.getRmAttributeName()); + attribute.setExistence(convertMultiplicity(attribute14.getExistence())); + if(attribute14 instanceof CMULTIPLEATTRIBUTE) { + CMULTIPLEATTRIBUTE attr14Multiple = (CMULTIPLEATTRIBUTE) attribute14; + attribute.setCardinality(convertCardinality(attr14Multiple.getCardinality())); + attribute.setMultiple(true); + } else if (attribute14 instanceof CSINGLEATTRIBUTE) { + //ok no one cares about this class + attribute.setMultiple(false); + } + for(COBJECT cobject14:attribute14.getChildren()) { + CObject cObject = convert(cobject14); + if(cObject != null) { + attribute.addChild(cObject); + } + } + return attribute; + } + + private CObject convert(COBJECT cobject14) { + if(cobject14 instanceof CARCHETYPEROOT) { + return convertRoot((CARCHETYPEROOT) cobject14); + } else if (cobject14 instanceof CCOMPLEXOBJECT) { + return convert((CCOMPLEXOBJECT) cobject14); + } else if (cobject14 instanceof ARCHETYPESLOT) { + return convertSlot((ARCHETYPESLOT) cobject14); + } else if (cobject14 instanceof CPRIMITIVEOBJECT) { + return convertPrimitive((CPRIMITIVEOBJECT) cobject14); + } else if (cobject14 instanceof CDOMAINTYPE) { + return DomainTypeConverter.convertDomainType((CDOMAINTYPE) cobject14); + } + throw new IllegalArgumentException("unknown COBJECT subtype: " + cobject14.getClass()); + } + + + + private CObject convertSlot(ARCHETYPESLOT cobject14) { + ArchetypeSlot archetypeSlot = new ArchetypeSlot(); + archetypeSlot.setNodeId(cobject14.getNodeId()); + archetypeSlot.setRmTypeName(cobject14.getRmTypeName()); + + archetypeSlot.setOccurrences(IntervalConverter.convertMultiplicity(cobject14.getOccurrences())); + //TODO: assertions for include/exclude, should be straightforward + return archetypeSlot; + } + + private CObject convertRoot(CARCHETYPEROOT cRoot14) { + + TemplateOverlay overlay = new TemplateOverlay(); + overlay.setArchetypeId(new ArchetypeHRID(cRoot14.getArchetypeId().getValue())); + overlay.getArchetypeId().setConceptId(overlay.getArchetypeId().getConceptId() + "ovl-1"); + overlay.setParentArchetypeId(cRoot14.getArchetypeId().getValue()); + overlay.setDefinition(convert(cRoot14)); + overlay.setTerminology(TerminologyConverter.createTerminology(opt14, cRoot14)); + template.addTemplateOverlay(overlay); + + CArchetypeRoot root = new CArchetypeRoot(); + root.setArchetypeRef(overlay.getArchetypeId().getFullId()); + root.setNodeId(cRoot14.getNodeId()); + root.setOccurrences(IntervalConverter.convertMultiplicity(cRoot14.getOccurrences())); + root.setRmTypeName(cRoot14.getRmTypeName()); + return root; + } + + +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java new file mode 100644 index 000000000..5453cab16 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -0,0 +1,32 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.ResourceDescription; +import com.nedap.archie.aom.Template; +import com.nedap.archie.base.terminology.TerminologyCode; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class DescriptionConverter { + + public static void convert(Template template, OPERATIONALTEMPLATE opt14) { + RESOURCEDESCRIPTION description14 = opt14.getDescription(); + ResourceDescription description = new ResourceDescription(); + description.setLifecycleState(TerminologyCode.createFromString("openehr", null, description14.lifecycleState)); + Map author = new LinkedHashMap<>(); + if(description14.getOriginalAuthor() != null) { + for(StringDictionaryItem item:description14.getOriginalAuthor()) { + author.put(item.getId(), item.getValue()); + } + } + description.setOriginalAuthor(author); + template.setDescription(description); + + template.setOriginalLanguage( + TerminologyCode.createFromString( + opt14.getLanguage().getTerminologyId().getValue(), + null, + opt14.getLanguage().getCodeString())); + //TODO: implement me further + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java new file mode 100644 index 000000000..4a80456b9 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -0,0 +1,9 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.CObject; + +public class DomainTypeConverter { + public static CObject convertDomainType(CDOMAINTYPE cobject14) { + return null; + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java new file mode 100644 index 000000000..554102180 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java @@ -0,0 +1,55 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.base.Cardinality; +import com.nedap.archie.base.Interval; +import com.nedap.archie.base.MultiplicityInterval; + +public class IntervalConverter { + + public static Cardinality convertCardinality(CARDINALITY cardinality14) { + if(cardinality14 == null) { + return null; + } + Cardinality result = new Cardinality(); + result.setInterval(convertMultiplicity(cardinality14.getInterval())); + result.setOrdered(cardinality14.isIsOrdered()); + result.setUnique(cardinality14.isIsUnique()); + return result; + } + + public static MultiplicityInterval convertMultiplicity(IntervalOfInteger existence) { + if(existence == null) { + return null; + } + return new MultiplicityInterval( + existence.getLower(), + existence.isLowerIncluded() == null ? true : existence.isLowerIncluded(), + existence.isLowerUnbounded(), + existence.getUpper(), + existence.isUpperIncluded() == null ? true : existence.isUpperIncluded(), + existence.isUpperUnbounded()); + } + + public static com.nedap.archie.base.Interval convertInterval(IntervalOfInteger range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval( + range.getLower() == null ? null : range.getLower().longValue() , + range.getUpper() == null ? null : range.getUpper().longValue() , + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + + public static com.nedap.archie.base.Interval convertInterval(IntervalOfReal range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval( + range.getLower() == null ? null : range.getLower().doubleValue() , + range.getUpper() == null ? null : range.getUpper().doubleValue() , + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java new file mode 100644 index 000000000..53153e323 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -0,0 +1,17 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.Template; + +public class Opt14Converter { + + public Template convert(OPERATIONALTEMPLATE opt14) { + Template template = new Template(); + template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); + DescriptionConverter.convert(template, opt14); + + new DefinitionConverter().convert(template, opt14); + return template; + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java new file mode 100644 index 000000000..075c94b2f --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java @@ -0,0 +1,87 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.primitives.CBoolean; +import com.nedap.archie.aom.primitives.CInteger; +import com.nedap.archie.aom.primitives.CReal; +import com.nedap.archie.aom.primitives.CString; + +import static com.nedap.archie.opt14.IntervalConverter.convertInterval; + +public class PrimitiveConverter { + + public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { + CPRIMITIVE primitive14 = cobject14.getItem(); + if(primitive14 instanceof CINTEGER) { + CINTEGER cinteger14 = (CINTEGER) primitive14; + CInteger cInteger = new CInteger(); + if(cinteger14.getList() != null) { + for(Integer integer:cinteger14.getList()) { + cInteger.addConstraint(new com.nedap.archie.base.Interval(integer.longValue(), integer.longValue())); + } + } + if(cinteger14.getRange() != null) { + cInteger.addConstraint(convertInterval(cinteger14.getRange())); + } + if(cinteger14.getAssumedValue() != null) { + cInteger.setAssumedValue(cinteger14.getAssumedValue().longValue()); + } + return cInteger; + } else if (primitive14 instanceof CREAL) { + CREAL cinteger14 = (CREAL) primitive14; + CReal cInteger = new CReal(); + if(cinteger14.getList() != null) { + for(Float integer:cinteger14.getList()) { + cInteger.addConstraint(new com.nedap.archie.base.Interval(integer.doubleValue(), integer.doubleValue())); + } + } + if(cinteger14.getRange() != null) { + cInteger.addConstraint(convertInterval(cinteger14.getRange())); + } + if(cinteger14.getAssumedValue() != null) { + cInteger.setAssumedValue(cinteger14.getAssumedValue().doubleValue()); + } + return cInteger; + } else if (primitive14 instanceof CBOOLEAN) { + CBOOLEAN cboolean14 = (CBOOLEAN) primitive14; + CBoolean cBoolean = new CBoolean(); + if(cboolean14.isFalseValid()) { + cBoolean.addConstraint(false); + } + if(cboolean14.isTrueValid()) { + cBoolean.addConstraint(true); + } + if(cboolean14.isAssumedValue() != null) { + cBoolean.setAssumedValue(cboolean14.isAssumedValue()); + } + } else if (primitive14 instanceof CSTRING) { + CSTRING cstring14 = (CSTRING) primitive14; + CString cString = new CString(); + if(cstring14.getList() != null) { + cString.getConstraint().addAll(cstring14.getList()); + } + if(cstring14.getPattern() != null) { + cString.getConstraint().add("/" + cstring14.getPattern() + "/"); + } + if(cstring14.isListOpen() != null) { + //TODO. Just return null? + } + cString.setAssumedValue(cstring14.getAssumedValue()); + return cString; + } else if (primitive14 instanceof CDATE) { + return null; + } else if (primitive14 instanceof CDATETIME) { + return null; + } else if (primitive14 instanceof CTIME) { + return null; + } else if (primitive14 instanceof CDURATION) { + return null; + } + throw new IllegalArgumentException("Uknoown primitive type found"); + + + + + } + +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java new file mode 100644 index 000000000..be1df9fe6 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java @@ -0,0 +1,27 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.terminology.ArchetypeTerm; +import com.nedap.archie.aom.terminology.ArchetypeTerminology; + +import java.util.LinkedHashMap; + +public class TerminologyConverter { + + public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, CARCHETYPEROOT definition) { + ArchetypeTerminology terminology = new ArchetypeTerminology(); + String language = opt14.getLanguage().getCodeString(); + LinkedHashMap terms = new LinkedHashMap<>(); + terminology.getTermDefinitions().put(language, terms); + for(ARCHETYPETERM term14:definition.getTermDefinitions()) { + ArchetypeTerm term = new ArchetypeTerm(); + term.setCode(term14.getCode()); + for(StringDictionaryItem item:term14.getItems()) { + term.put(item.getId(), item.getId()); + } + terms.put(term14.getCode(), term); + } + //TODO: term bindings + return terminology; + } +} diff --git a/opt14/src/main/schemas/xjc/Archetype.xsd b/opt14/src/main/schemas/xjc/Archetype.xsd new file mode 100644 index 000000000..cbeddf394 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Archetype.xsd @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/BaseTypes.xsd b/opt14/src/main/schemas/xjc/BaseTypes.xsd new file mode 100644 index 000000000..3fc959837 --- /dev/null +++ b/opt14/src/main/schemas/xjc/BaseTypes.xsd @@ -0,0 +1,594 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/CharacterMapping.xsd b/opt14/src/main/schemas/xjc/CharacterMapping.xsd new file mode 100644 index 000000000..f63868e3f --- /dev/null +++ b/opt14/src/main/schemas/xjc/CharacterMapping.xsd @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/opt14/src/main/schemas/xjc/Composition.xsd b/opt14/src/main/schemas/xjc/Composition.xsd new file mode 100644 index 000000000..71ba5ef71 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Composition.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/CompositionTemplate.xsd b/opt14/src/main/schemas/xjc/CompositionTemplate.xsd new file mode 100644 index 000000000..f9a86aeb2 --- /dev/null +++ b/opt14/src/main/schemas/xjc/CompositionTemplate.xsd @@ -0,0 +1,489 @@ + + + + + + openEHR schema base types for the default values + DEFAULT_VALUE <== is a ==> DEFAULT_DV_BOOLEAN == has a ==> DV_BOOLEAN + + use AOM constraint objects for the DV constraints + + + + + + + + + + 1. Is authored Resource + 2. Uid [1..1]: Add UID which is a GUID (fulfils AuthoredResource req for optional ID) + 3. TemplateId [1..1]: id now called TemplateId (fulfils AuthoredResource req for ID) + 4. Name [1..1]: Has logical name + + + + + + + + + + + + + 1. Remove 'from_template' is not needed + 2. Otherwise is same. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + termQueryId discussion + ====================== + termQueryId --> TSU - terminology subset URI + eg. terminology://Snomed?language=en-GB&subset=AllBacteria + TSU should be (subsetName{terminologyId+queryName})?language=en-GB&terminologyVersion=2007.1 + eg. TSU = Snomed_BloodPhenotype?langauge=en-GB&terminologyVersion=2007.1 + + the combination of terminology name and term subset query name is like a GUID + to refer to a particular term query in the OTS query register + therefore the TSU should be something like: + Snomed[version=2007.1, langauge=en-GB]/BloodPhenotype + + limitTolist, includedValues, excludedValues discussion + ====================================================== + When the included/excluded values include values no longer returned by the TSU + these are simply ignored, so only the intersection of TSU-return terms and includedTerms + are considered for inclusion. Similarly the terms excluded by excludedValues which + are not present in the TSU-return terms are ingored. + + LimitToList is relevant for free text (functions as list_open on C_STRING) + LimitToList is relevant for MOST ext coded text (functions as list_open on C_CODE_REFERENCE) + LimitToList not relevant for internally coded text (where archetype has restricted + codes to internally-defined list; could include list of ext codes in AC binding). + + Included values - + - relevant to include free text values (much as in list in C_STRING) + - relevant to include ext coded text values (might need includedCodes property on a + C_CODE_REFERENCE) + + Excluded values - + - relevant to remove internal term codes + - relevant to remove terms from external term subset + - relevant to remove included text values in embedded templates + - relevant to remove terms from external term subsets in embedded templates + + AllowTerminologyLookup moved out and into form definition. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/opt14/src/main/schemas/xjc/Content.xsd b/opt14/src/main/schemas/xjc/Content.xsd new file mode 100644 index 000000000..a88e9b6c0 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Content.xsd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Extract.xsd b/opt14/src/main/schemas/xjc/Extract.xsd new file mode 100644 index 000000000..ede0020ef --- /dev/null +++ b/opt14/src/main/schemas/xjc/Extract.xsd @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/OpenehrProfile.xsd b/opt14/src/main/schemas/xjc/OpenehrProfile.xsd new file mode 100644 index 000000000..efa28ac8f --- /dev/null +++ b/opt14/src/main/schemas/xjc/OpenehrProfile.xsd @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Resource.xsd b/opt14/src/main/schemas/xjc/Resource.xsd new file mode 100644 index 000000000..f60733a1e --- /dev/null +++ b/opt14/src/main/schemas/xjc/Resource.xsd @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Structure.xsd b/opt14/src/main/schemas/xjc/Structure.xsd new file mode 100644 index 000000000..717560989 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Structure.xsd @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Template.xsd b/opt14/src/main/schemas/xjc/Template.xsd new file mode 100644 index 000000000..95cd28974 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Template.xsd @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Version.xsd b/opt14/src/main/schemas/xjc/Version.xsd new file mode 100644 index 000000000..da5d5c7af --- /dev/null +++ b/opt14/src/main/schemas/xjc/Version.xsd @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java new file mode 100644 index 000000000..1c4c0342b --- /dev/null +++ b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java @@ -0,0 +1,46 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.adlparser.ADLParser; +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.Template; +import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; +import org.junit.Test; +import org.openehr.referencemodels.BuiltinReferenceModels; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Unmarshaller; +import java.io.IOException; +import java.io.InputStream; + +public class ConverterTest { + + @Test + public void procedureList() throws Exception { + InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); + repository.addArchetype(parseAdl2("openEHR-EHR-ACTION.procedure.v1.4.1.adls")); + repository.addArchetype(parseAdl2("openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls")); + repository.addArchetype(parseAdl2("openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls")); + + + JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + try(InputStream stream = getClass().getResourceAsStream("/procedure_list.opt")) { + OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); + Template template = new Opt14Converter().convert(opt14); + System.out.println(ADLArchetypeSerializer.serialize(template)); + } + } + + public Archetype parseAdl2(String resource) throws IOException { + try(InputStream stream = getClass().getResourceAsStream("/adl2/" + resource)) { + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + Archetype archetype = adlParser.parse(stream); + if(adlParser.getErrors().hasErrors()) { + throw new RuntimeException(adlParser.getErrors().toString()); + } + return archetype; + } + } +} diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls b/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls new file mode 100644 index 000000000..81be01cf4 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls @@ -0,0 +1,2459 @@ +archetype (adl_version=2.0.6; rm_release=1.0.4; generated; uid=82e79f18-76b9-4b5c-a930-1115eecbc4b7; build_uid=b4858e75-fcfe-43ab-8854-88e8e38e42f9) + openEHR-EHR-ACTION.procedure.v1.4.1 + +language + original_language = <[ISO_639-1::en]> + translations = < + ["de"] = < + language = <[ISO_639-1::de]> + author = < + ["name"] = <"Kim Sommer, Natalia Strauch"> + ["organisation"] = <"MHH, Medizinische Hochschule Hannover"> + ["email"] = <"sommer.kimkatrin@mh-hannover.de, Strauch.Natalia@mh-hannover.de"> + > + > + ["ru"] = < + language = <[ISO_639-1::ru]> + author = < + ["name"] = <"Art Latyp; Латыпов Артур"> + ["organisation"] = <"RusBITech; РусБИТех, Москва"> + > + accreditation = <"hmm"> + > + ["nb"] = < + language = <[ISO_639-1::nb]> + author = < + ["name"] = <"John Tore Valand / Silje Ljosland Bakke"> + ["organisation"] = <"Helse Bergen HF / Nasjonal IKT HF"> + > + > + ["pt-br"] = < + language = <[ISO_639-1::pt-br]> + author = < + ["name"] = <"Osmeire Chamelette Sanzovo"> + ["organisation"] = <"Hospital Sírio Libanês"> + ["email"] = <"osmeire.acsanzovo@hsl.org.br"> + > + > + ["ar-sy"] = < + language = <[ISO_639-1::ar-sy]> + author = < + ["name"] = <"Mona Saleh"> + > + > + ["sl"] = < + language = <[ISO_639-1::sl]> + author = < + ["name"] = <"Uroš Rajkovič, Biljana Prinčič"> + ["organisation"] = <"Slovenia"> + > + > + ["es"] = < + language = <[ISO_639-1::es]> + author = < + ["name"] = <"Pablo Pazos"> + ["organisation"] = <"CaboLabs"> + ["email"] = <"pablo.pazos@cabolabs.com"> + ["pablo.pazos@cabolabs.com"] = <"pablo.pazos@cabolabs.com"> + > + accreditation = <"Computer Engineer"> + > + > + +description + original_author = < + ["name"] = <"Heather Leslie"> + ["organisation"] = <"Ocean Informatics, Australia"> + ["email"] = <"heather.leslie@oceaninformatics.com"> + ["date"] = <"2007-03-12"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Morten Aas, Oslo Universitetssykehus, Norway", "Tomas Alme, DIPS, Norway", "Vebjørn Arntzen, Oslo University Hospital, Norway", "Koray Atalag, University of Auckland, New Zealand", "Silje Ljosland Bakke, Helse Vest IKT AS, Norway (openEHR Editor)", "Kari Beate Engseth, Finnmarkssykehuset HF + Klinikk Kirkenes, Norway", "Maria Beate Nupen, Oslo Universitetssykehus, Norway", "Lars Bitsch-Larsen, Haukeland University hospital, Norway", "Fredrik Borchsenius, Oslo universitetssykehus, Norway", "Diego Bosca, VeraTech for Health, Spain", "Rong Chen, Cambio Healthcare Systems, Sweden", "Stephen Chu, NEHTA, Australia (Editor)", "Lisbeth Dahlhaug, Helse Midt - Norge IT, Norway", "David Evans, Queensland Health, Australia", "Shahla Foozonkhah, Iran ministry of health and education, Iran", "Einar Fosse, National Centre for Integrated Care and Telemedicine, Norway", "Sebastian Garde, Ocean Informatics, Germany", "Jacquie Garton-Smith, Royal Perth Hospital and DoHWA, Australia", "Bente Gjelsvik, Helse Bergen, Norway", "Andrew Goodchild, NEHTA, Australia", "Heather Grain, Llewelyn Grain Informatics, Australia", "Megan Hawkins, Mater Health Services, Australia", "Sam Heard, Ocean Informatics, Australia", "Kristian Heldal, Telemark Hospital Trust, Norway", "Andreas Hering, Helse Bergen HF, Haukeland universitetssjukehus, Norway", "Anca Heyd, DIPS ASA, Norway", "Hilde Hollås, DIPS ASA, Norway", "Lars Ivar Mehlum, Helse Bergen HF, Norway", "Lars Karlsen, DIPS ASA, Norway", "Lars Morgan Karlsen, DIPS ASA, Norway", "Mary Kelaher, NEHTA, Australia", "Shinji Kobayashi, Kyoto University, Japan", "Sabine Leh, Haukeland University Hospital, Department of Pathology, Norway", "Heather Leslie, Atomica Informatics, Australia (openEHR Editor)", "Hugh Leslie, Ocean Informatics, Australia", "Hallvard Lærum, Norwegian Directorate of e-health, Norway", "Mike Martyn, The Hobart Anaesthetic Group, Australia", "Ian McNicoll, freshEHR Clinical Informatics, United Kingdom (openEHR Editor)", "Chris Mitchell, RACGP, Australia", "Stewart Morrison, NEHTA, Australia", "Bjoern Naess, DIPS ASA, Norway", "Bjørn Næss, DIPS ASA, Norway", "Andrej Orel, Marand d.o.o., Slovenia", "Michael Osborne, Mater Health Services, Australia", "Anne Pauline Anderssen, Helse Nord RHF, Norway", "Chris Pearce, Melbourne East GP Network, Australia", "Rune Pedersen, Universitetssykehuset i Nord Norge, Norway", "Jussara Rotzsch, Hospital Alemão Oswaldo Cruz, Brazil", "Peter Scott, Australia", "Elizabeth Stanick, Hobart Anaesthetic Group, Australia", "Norwegian Review Summary, Nasjonal IKT HF, Norway", "Line Sørensen, Helse Bergen, Norway", "John Taylor, NEHTA, Australia", "Micaela Thierley, Helse Bergen, Norway", "Rowan Thomas, St. Vincent's Hospital Melbourne, Australia", "Line Thomassen, Helse Bergen, Norway", "John Tore Valand, Haukeland Universitetssjukehus, Norway (Nasjonal IKT redaktør)", "Richard Townley-O'Neill, NEHTA, Australia", "Ørjan Vermeer, Haukeland Universitetssjukehus, Kvinneklinikken, Norway", "Ivar Yrke, DIPS AS, Norway"> + lifecycle_state = <"published"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/."> + other_details = < + ["current_contact"] = <"Heather Leslie, Atomica Informatics, heather.leslie@atomicainformatics.com"> + ["MD5-CAM-1.0.1"] = <"108CD01BE8E751B5AA89279E73962671"> + > + details = < + ["de"] = < + language = <[ISO_639-1::de]> + purpose = <"Zur Erfassung von Informationen über die erforderlichen Aktivitäten zum Ausführen einer Prozedur. Dazu zählen die Planung, Terminierung, Durchführung, Unterbrechung, Stornierung, Dokumentation und Beendigung."> + keywords = <"Prozedur", "Vorgehen", "Verfahren", "Intervention", "Eingriff", "chirurgisch", "medizinisch", "klinisch", "therapeutisch", "Diagnostik", "diagnostisch", "heilen", "Behandlung", "Bewertung", "Untersuchung", "Früherkennung", "Screening", "palliativ", "Therapie", "Operation"> + use = <"Verwenden Sie diesen Archetypen zur Erfassung von Informationen über die erforderlichen Aktivitäten zum Ausführen einer Prozedur, einschließlich Planung, Terminierung, Durchführung, Unterbrechung, Stornierung, Dokumentation und Beendigung. Dies geschieht durch die Darstellung von Daten zu bestimmten Aktivitäten durch die \"Pathway\"-Verlaufsschritte. + + Der Anwendungsbereich dieses Archetyps umfasst Aktivitäten für eine breite Palette von klinischen Prozeduren, die für evaluative, ermittelnde, vorsorgliche, diagnostische, kurative, therapeutische oder palliative Zwecke durchgeführt werden. Die Beispiele reichen von relativ einfachen Aktivitäten wie dem Legen einer intravenösen Kanüle bis hin zu komplexen chirurgischen Eingriffen. + + Zusätzliche strukturierte und detaillierte Informationen über die Prozedur können bei Bedarf mit Hilfe von zweckmäßigen Archetypen erfasst werden, die in den Slot \"Details zur Prozedur\" eingefügt werden. + + Zeitpläne, die sich auf eine Prozedur beziehen, können auf zwei Arten verwaltet werden: + - Unter Verwendung des Referenzmodells - die Zeit für die Ausführung eines beliebigen \"Pathway\"-Verlaufsschrittes verwendet das Attribut ACTION Zeit für jeden Schritt. + - Archetypische Datenelemente: + --- das Datenelement \"Geplantes Datum/Uhrzeit\" soll die genaue Zeit erfassen, zu der die Prozedur geplant ist. Hinweis: Das entsprechende Attribut ACTION Zeit für den geplanten \"Pathway\"-Verlaufsschritt erfasst die Zeit, zu der die Prozedur in einem System geplant wurde, nicht das vorgesehene Datum/Uhrzeit, zu der die Prozedur ausgeführt werden soll; und + --- das \"Enddatum/-uhrzeit\" soll die genaue Zeit erfassen, zu der die Prozedur beendet wurde. Damit können die komplexen Vorgänge mit mehreren Komponenten dokumentiert werden. Hinweis: Das entsprechende Attribut ACTION Zeit in dem Element \"Prozedur durchgeführt\", dokumentiert den Beginn der einzelnen durchgeführten Komponenten. Das Datenelement \"Enddatum/-uhrzeit\" erfasst das Datum/die Uhrzeit der letzten aktiven Komponente der Prozedur. Dadurch kann die volle Dauer der aktiven Prozedur berechnet werden. + + Im Rahmen eines Operationsberichts wird dieser Archetyp nur verwendet, um zu erfassen, was während der Operation durchgeführt wurde. Eigenständige Archetypen werden verwendet, um die anderen erforderlichen Komponenten des Operationsberichts zu erfassen, einschließlich der Entnahme von Gewebeproben, der Verwendung von Bildkontrolle, der OP-Befunde, postoperativer Anweisungen und Plänen für die Nachsorge. + + Im Rahmen einer Problemliste oder Zusammenfassung kann dieser Archetyp verwendet werden, um durchgeführte Prozeduren darzustellen. Der Archetyp EVALUATION.Problem/Diagnose wird verwendet, um die Probleme und Diagnosen des Patienten darzustellen. + + In der Praxis werden viele Prozeduren (z.B. in der ambulanten Versorgung) einmalig durchgeführt und nicht im Voraus angeordnet. Angaben zur Prozedur werden im Datenelement \"Prozedur beendet\" hinzugefügt. In einigen Fällen wird eine wiederkehrende Prozedur angeordnet. In diesen Fällen werden jeweils Daten mit dem Element \"Prozedur durchgeführt\" erfasst, so dass die Instruktion im aktiven Zustand verbleibt. Wenn das letzte Ereignis erfasst wird, wird die Aktion \"Prozedur beendet\" dokumentiert. Dies zeigt an, dass sich diese Prozedur nun im abgeschlossenen Zustand befindet. + + In anderen Fällen, wie z.B. in der Sekundärversorgung, kann es eine formelle Anordnung für eine Prozedur mit einem entsprechenden INSTRUCTION-Archetyp geben. Dieser ACTION-Archetyp kann dann verwendet werden, um den Workflow aufzuzeichnen, wann und wie der Auftrag ausgeführt wurde. + + Die Erfassung von Informationen mit diesem ACTION-Archetyp zeigt an, dass tatsächlich eine Art von Aktivität stattgefunden hat; dies ist in der Regel die Prozedur selbst, kann aber auch ein fehlgeschlagener Versuch oder eine andere Aktivität, wie das Verschieben der Prozedur, sein. Wenn es eine formale Anordnung für die Prozedur gibt, wird der Status dieser Anordnung durch das \"Pathway\" Element, für das Daten erfasst werden, dargestellt. Mit diesem Archetyp kann beispielsweise der Fortschritt einer gastroskopischen Anordnung durch separate Einträge in den \"Pathway\" Elementen erfasst werden: + - Erfassung des geplante Startdatum/-zeit für die Gastroskopie (Prozedur geplant (zeitlich)); und + - Dokumentation, dass das Gastroskopieverfahren abgeschlossen ist, einschließlich zusätzlicher Angaben zur Prozedur (Prozedur beendet). + + Bitte beachten Sie, dass es im openEHR-Referenzmodell ein Attribut \"Zeit\" gibt, das dazu dient, das Datum und die Uhrzeit zu erfassen, zu der jeder Verlaufsschritt der Aktion ausgeführt wurde. Dies ist das Attribut, mit dem der Beginn der Prozedur (mit dem Schritt \"Prozedur durchgeführt\") oder die Zeit, zu der die Prozedur abgebrochen wurde (mit dem Schritt \"Prozedur abgebrochen\"), erfasst wird."> + misuse = <"Nicht zur Erfassung von Angaben zur Anästhesie - verwenden Sie dazu einen separaten ACTION-Archetyp. + + Nicht zur Erfassung von Angaben über bildgebende Untersuchungen - verwenden Sie dazu den Archetypen ACTION.imaging_exam. + + Nicht zur Erfassung von Angaben über Laboruntersuchungen - verwenden Sie dazu den Archetypen ACTION.laboratory_test. + + Nicht zur Erfassung von Angaben über erbrachte Ausbildungen/Schulungen - verwenden Sie dazu den Archetypen ACTION.health_education. + + Nicht zur Erfassung von Angaben über administrative Aktivitäten - verwenden Sie zu diesem Zweck spezifische ADMIN-Archetypen. + + Nicht zu verwenden, um Angaben über zusammenhängende Aktivitäten zu erfassen. Beispiele für zusammenhängende Aktivitäten sind: der Einsatz von Gefrierschnitten, die während einer Operation durchgeführt werden; Medikamente, die im Rahmen der Prozedur verabreicht werden oder der Einsatz von Bildkontrolle während der Prozedur. Verwenden Sie zu diesem Zweck eigenständige und spezifische ACTION-Archetypen innerhalb des Templates. + + Nicht zur Erfassung eines vollständigen Berichts über eine OP- oder eine Prozedur - verwenden Sie ein Template, in der dieser Archetyp nur eine Komponente des Gesamtberichts darstellt."> + > + ["ru"] = < + language = <[ISO_639-1::ru]> + purpose = <"Для записи сведений об проведенной процедуре"> + keywords = <"процедура, выполнение", ...> + use = <"Используется для записи подробной информации о процедуре, выполненной пациенту. + Информация о действиях, связанных с выполнением процедуры, таких как анестезия или применение лекарств, долдно быть записано в отдельных архетипах типа ДЕЙСТВИЕ"> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + ["nb"] = < + language = <[ISO_639-1::nb]> + purpose = <"For å registrere informasjon om aktiviteter som må gjennomføres for å utføre en klinisk prosedyre, inkludert planlegging, fastsetting av tidspunkt, utførelse, utsettelse, kansellering, dokumentering og fullføring."> + keywords = <"prosedyre", "intervensjon", "kirurgisk", "medisinsk", "klinisk", "terapeutisk", "diagnostisk", "behandling", "kur", "evaluering", "undersøkelse", "screening", "palliativ", "terapi", "prognostisk"> + use = <"Brukes til å registrere nødvendig informasjon om aktiviteter i gjennomføringen av en klinisk prosedyre. Dette inkluderer planlegging, fastsetting av tidspunkt, utførelse, utsettelse, avlysning, dokumentering og fullføring. Dette gjøres ved å registrere data knyttet til spesifikke aktiviteter som definert i arketypens prosesstrinn (Engelsk: \"Pathway careflow steps\"). + + Arketypen dekker aktiviteter for et bredt spekter av kliniske prosedyrer utført i evaluerende, undersøkende, diagnostisk, kurativ, terapeutisk eller palliativ hensikt. Eksempler strekker seg fra relativt enkle aktiviteter som innlegging av et intravenøst kateter, til komplekse kirurgiske operasjoner. + + Strukturert og detaljert tilleggsinformasjon om prosedyren kan registreres ved bruk av spesifikke CLUSTER-arketyper satt inn i \"Prosedyredetaljer\"-SLOTet der dette kreves. + + Tidsberegning relatert til en prosedyre kan håndteres på en av to måter: + -Ved å benytte referansemodellen: Tiden for gjennomføring av et prosesstrinn vil benytte \"time\"-attributtet som ligger implisitt i en ACTION-arketype, for hvert enkelt prosesstrinn. + -Dataelementer i arketypen: + ---Dataelementet \"Planlagt dato/tid\" skal brukes for å registrere nøyaktig tidspunkt prosedyren er planlagt. Merk: Det korresponderende \"time\"-attributtet for prosesstrinnet \"Fastsatt tidspunkt for prosedyre\" registrerer tidspunktet da prosedyren ble planlagt, ikke dato/tid for når prosedyren er planlagt gjennomført. + --- \"Endelig dato/tid\" skal registrere nøyaktig tidspunkt for da prosedyren ble avsluttet. Den kan brukes for å dokumentere komplekse prosedyrer med mange komponenter. Merk: Det korresponderende \"time\"-attributtet for prosesstrinnet \"Prosedyre iverksatt\" dokumenterer tidspunkt for hver gang en komponent er gjennomført eller påbegynt. Dataelementet \"Endelig dato/tid\" registrerer dato/tid for det siste aktive komponenten av prosedyren. Dette åpner for mulighet for utregning av den totale varigheten av den aktive prosedyren. + + Ved bruk i en operasjonsrapport skal arketypen bare benyttes for å registrere hva som ble utført under prosedyren. Egne arketyper vil bli benyttet for å registrere andre komponenter av operasjonsrapporten, dette inkluderer biopsitakning, bildediagnostisk veiledning, funn under operasjonen, postoperative instruksjoner og videre planer for oppfølging. + + I en problemliste eller i et problemsammendrag kan denne arketypen benyttes for å gi en oversikt over hvilke prosedyrer som er utført. Arketypen EVALUATION.problem_diagnosis vil benyttes for å gi en oversikt over pasientens problemer og diagnoser. + + I praksis vil mange prosedyrer (f.eks. i primærhelsetjenesten) utføres én gang, og ikke bestilles i forkant. Detaljene om prosedyren vil da registreres for det aktuelle prosesstrinnet. I noen tilfeller vil en gjentagende prosedyre bli rekvirert, og i en slik situasjon registreres prosesstrinnet \"Prosedyre utført\" i hvert enkelt tilfelle, og instruksjonen forblir i en aktiv tilstand. Når den siste prosedyren i serien er registrert settes prosesstrinnet \"Prosedyre avsluttet\" for å avslutte forordningen. + + I andre situasjoner, for eksempel i spesialisthelsetjenesten, kan det foreligge en formell rekvisisjon for en prosedyre hvor en motsvarende INSTRUCTION-arketype er benyttet. Denne ACTION-arketypen benyttes da for å registrere arbeidsflyt og når og hvordan prosedyren ble utført. + + Registrering av informasjon i denne ACTION-arketypen indikerer at en eller annen type aktivitet faktisk er utført; dette vil vanligvis være prosedyren i seg selv, men kan også være et mislykket forsøk eller en annen aktivitet som f.eks. en utsettelse av prosedyren. Finnes det en formell henvisning til en prosedyre, er henvisningens status representert i det prosesstrinnet hvor data er registrert. For eksempel vil gjennomføringen av en gastroskopi lagret i denne arketypen kunne registreres som flere påfølgende oppføringer innen et fremdriftsnotat, en oppføring for hvert prosesstrinn: + + - registrert planlagt Start dato/tid for gastroskopien (\"Prosedyre planlagt\") + - registrert at gastroskopiprosedyren er fullført, inkludert informasjon om prosedyredetaljene (\"Prosedyre avsluttet\"). + + Legg merke til at det i openEHR referansemodellen er et attributt \"time\" som er tenkt brukt til å registrere dato og tid for når hvert enkelt prosesstrinn i ACTION-arketypen ble utført. Denne attributten skal brukes til å registre da prosedyren startet (ved prosesstrinnet \"Prosedyre iverksatt\"), eller tidspunktet da prosedyren ble avbrutt (ved prosesstrinnet \"Prosedyre avbrutt\")."> + misuse = <"Benyttes ikke til å registrere detaljer om administrasjon av legemidler - bruk ACTION.medication til dette formålet. + + Benyttes ikke til å registrere detaljer om bildediagnostiske undersøkelser - bruk ACTION.imaging_exam til dette formålet. + + Benyttes ikke til å registrere detaljer om laboratorieundersøkelser - bruk ACTION.laboratory_test til dette formålet. + + Benyttes ikke til å registrere detaljer om pasientopplæring - bruk ACTION.health_education til dette formålet. + + Benyttes ikke til å registrere detaljer om administrative aktiviteter - bruk spesifikke ADMIN-arketyper til dette formålet. + + Benyttes ikke til registrering om relaterte aktiviteter som bruk av frysesnitt tatt under en operasjon, legemidler gitt som del av prosedyren, eller når bildeveiledning er brukt under prosedyren. Bruk separate og spesifikke ACTION-arketyper innen samme templat til dette formålet. + + Benyttes ikke for å registrere en hel operasjon eller prosedyrerapport - bruk en templat der denne arketypen er kun en komponent av den fullstendige rapporten."> + copyright = <"© openEHR Foundation"> + > + ["pt-br"] = < + language = <[ISO_639-1::pt-br]> + purpose = <"Para registrar os detalhes sobre um procedimento realizado, incluindo o planejamento, programação , execução, suspensão , cancelamento , documentação e conclusão."> + keywords = <"procedimento", "intervenção", "cirúrgico", "médico", "clínico", "terapêutico", "diagnóstico", "cura", "tratamento", "evolução", "investigação", "paliativo", "terapia"> + use = <"Use para registrar informações sobre as atividades necessárias para realizar um procedimento , incluindo o planejamento, programação , execução, suspensão , cancelamento , documentação e conclusão. Isto é feito através do registro de dados de atividades específicas , conforme definido neste arquétipo . + + O escopo deste arquétipo abrange as atividades para uma ampla gama de procedimentos clínicos realizados para avaliação, investigação , triagem , diagnóstico , curativo, terapêutico ou fins paliativos. Os exemplos vão desde as atividades relativamente simples, tais como a inserção de uma cânula intravenosa , através de operações cirúrgicas complexas . + + Informações adicionais estruturadas e detalhadas sobre o procedimento podem ser capturadas utilizando arquétipos específicos de uso inserido no slot 'Detalhe do Procedimento', onde for necessário. + + Tempos relacionados a um procedimento podem ser gerenciados de uma de duas maneiras: + - Usando o modelo de referência - o prazo para realização de qualquer passo/caminho usará o atributo tempo de ação para cada etapa. + - Elementos de dados arquetipados: + --- Elemento de dados \"data / hora agendada\" destina-se a registrar o tempo exato em que o procedimento é planejado. Nota: o atributo de tempo de ação correspondente para o passo via Programado irá registrar o tempo que o procedimento foi programado em um sistema, não a data / hora pretendida em que o procedimento se destina a ser realizado; e + --- O 'data final / hora' destina-se a registrar o tempo exato em que o processo foi encerrado. Ele pode ser usado para documentar os procedimentos complexos com componentes múltiplos. Nota: o atributo de tempo de ação correspondente para o \"procedimento realizado\" irá documentar o tempo de cada componente realizada foi iniciada. Este elemento de dados 'Data / hora Final' registrará a data / hora do último componente ativo do procedimento. Isto irá permitir uma duração total do processo ativo a ser calculado. + + Dentro do contexto de um Relatório de Cirurgia, esse arquétipo será usado para gravar apenas o que foi feito durante o procedimento. Arquétipos separados serão utilizados para gravar os outros componentes necessários, incluindo a coleta de amostras de tecidos, utilização de imagens intraoperatórias, achados cirúrgicos, instruções pós-operatória e planos de acompanhamento. + + Dentro do contexto de uma lista de problemas ou resumo, este arquétipo pode ser usado ​​para representar os procedimentos que têm sido realizados. O EVALUATION.problem_diagnosis será usado para representar os problemas do paciente e diagnósticos. + + Na prática, muitos procedimentos (por exemplo, um atendimento ambulatorial) ocorrerá uma vez e não será planejado com antecedência. Os detalhes sobre o procedimento serão adicionados ao passo/caminho, «Processo concluído\". Em alguns casos um procedimento recorrente será ordenado, e nesta situação os dados do \"procedimento realizado\" será gravado em cada ocasião, deixando a instrução no estado ativo. Quando a última ocorrência é registrada do \"Procedimento concluído\" a ação é registrada mostrando que essa ordem está agora no estado concluído. + + Em outras situações, tais como atenção secundária, pode haver uma ordem formal de um procedimento usando um arquétipo instrução correspondente. Este arquétipo ação pode então ser usado para registrar o fluxo de trabalho de quando e como a ordem foi executada. + + Gravando informações utilizando esse arquétipo AÇÃO indica que algum tipo de atividade realmente ocorreu; este será geralmente o procedimento em si, mas pode ser uma tentativa fracassada ou outra atividade, como o adiamento do procedimento. Se existe uma ordem formal para o procedimento, o estado desta ordem é representado pelo passo Pathway contra a qual os dados são gravados. Por exemplo, usando esse arquétipo do estado progredindo de uma ordem Gastroscopia podem ser registrados através de entradas separadas no progresso EHR observado um passo a cada 'Caminho': + - Registrar o início de data / hora programada para a gastroscopia (Procedimento programado); e + - Gravar que o procedimento foi concluído gastroscopia, incluindo informações sobre os detalhes de procedimento (processo encerrado). + + Por favor, note que no Modelo de Referência openEHR há um atributo 'Time', que se destina a registrar a data e hora em que foi realizada a cada passo via da ação. Este é o atributo a ser usado para registar o início do procedimento (usando o \"procedimento realizado 'passo via), ou o tempo que o procedimento foi abortada (usando o\" procedimento abortado' passo via)"> + misuse = <"Não deve ser usado para gravar detalhes sobre o anestésico - usar um arquétipo ação separada para esse fim. + + Não deve ser usado para registrar detalhes sobre as investigações de imagem - use ACTION.imaging_exam para esta finalidade. + + Não deve ser usado para gravar detalhes sobre investigações laboratoriais - ACTION.laboratory_test usar para essa finalidade. + + Não deve ser usado para gravar detalhes sobre educação entregues - ACTION.health_education usar para essa finalidade. + + Não deve ser usado para registrar detalhes sobre as atividades administrativas - usar arquétipos ADMIN específicos para esta finalidade. + + Não deve ser usado para gravar detalhes sobre as atividades relacionadas, tais como medicação administrada como parte do processo ou quando utilização de imagens para visualização é utilizado durante o procedimento - usar arquétipos ação separados e específicos dentro do mesmo modelo para este fim. + + Não deve ser usado para gravar uma operação ou procedimento relatório conjunto - usar um modelo em que esse arquétipo é apenas um componente do relatório completo."> + copyright = <"© openEHR Foundation"> + > + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record information about the activities required to carry out a procedure, including the planning, scheduling, performance, suspension, cancellation, documentation and completion."> + keywords = <"procedure", "intervention", "surgical", "medical", "clinical", "therapeutic", "diagnostic", "cure", "treatment", "evaluation", "investigation", "screening", "palliative", "therapy"> + use = <"Use to record information about the activities required to carry out a procedure, including the planning, scheduling, performance, suspension, cancellation, documentation and completion. This is done by the recording of data against specific activities, as defined by the 'Pathway' careflow steps in this archetype. + + The scope of this archetype encompasses activities for a broad range of clinical procedures performed for evaluative, investigative, screening, diagnostic, curative, therapeutic or palliative purposes. Examples range from the relatively simple activities, such as insertion of an intravenous cannula, through to complex surgical operations. + + Additional structured and detailed information about the procedure can be captured using purpose-specific archetypes inserted into the 'Procedure detail' slot, where required. + + Timings related to a procedure can be managed in one of two ways: + - Using the reference model - the time for performance of any pathway step will use the ACTION time attribute for each step. + - Archetyped data elements: + --- the 'Scheduled date/time' data element is intended to record the precise time when the procedure is planned. Note: the corresponding ACTION time attribute for the Scheduled pathway step will record the time that the procedure was scheduled into a system, not the intended date/time on which the procedure is intended to be carried out; and + --- the 'Final end date/time' is intended to record the precise time when the procedure was ended. It can be used to document the complex procedures with multiple components. Note: the corresponding ACTION time attribute for the 'Procedure performed' will document the time each component performed was commenced. This 'Final end date/time' data element will record the date/time of the final active component of the procedure. This will enable a full duration of the active procedure to be calculated. + + Within the context of an Operation Report, this archetype will be used to record only what was done during the procedure. Separate archetypes will be used to record the other required components of the Operation Report, including the taking of tissue specimen samples, use of imaging guidance, operation findings, post-operative instructions and plans for follow up. + + Within the context of a Problem list or summary, this archetype may be used to represent procedures that have been performed. The EVALUATION.problem_diagnosis will be used to represent the patient's problems and diagnoses. + + In practice, many procedures (for example, in ambulatory care) will occur once and not be ordered in advance. The details about the procedure will be added against the pathway step, 'Procedure completed'. In some cases a recurring procedure will be ordered, and in this situation data against the 'Procedure performed' step will be recorded on each occasion, leaving the instruction in the active state. When the last occurrence is recorded the 'Procedure completed' action is recorded showing that this order is now in the completed state. + + In other situations, such as secondary care, there may be a formal order for a procedure using a corresponding INSTRUCTION archetype. This ACTION archetype can then be used to record the workflow of when and how the order has been carried out. + + Recording information using this ACTION archetype indicates that some sort of activity has actually occurred; this will usually be the procedure itself but may be a failed attempt or another activity such as postponing the procedure. If there is a formal order for the procedure, the state of this order is represented by the Pathway step against which the data is recorded. For example, using this archetype the progressing state of a Gastroscopy order may be recorded through separate entries in the EHR progress notes at each 'Pathway' step: + - record the scheduled Start date/time for the gastroscopy (Procedure scheduled); and + - record that the gastroscopy procedure has been completed, including information about the procedure details (Procedure completed). + + Please note that in the openEHR Reference Model there is a 'Time' attribute, which is intended to record the date and time at which each pathway step of the Action was performed. This is the attribute to use to record the start of the procedure (using the 'Procedure performed' pathway step) or the time that the procedure was aborted (using the 'Procedure aborted' pathway step)."> + misuse = <"Not to be used to record details about the anaesthetic - use a separate ACTION archetype for this purpose. + + Not to be used to record details about imaging investigations - use ACTION.imaging_exam for this purpose. + + Not to be used to record details about laboratory investigations - use ACTION.laboratory_test for this purpose. + + Not to be used to record details about education delivered - use ACTION.health_education for this purpose. + + Not to be used to record details about administrative activities - use specific ADMIN archetypes for this purpose. + + Not to be used to record details about related activities such as the use of frozen sections taken during an operation, medication administered as part of the procedure or when imaging guidance is used during the procedure - use separate and specific ACTION archetypes within the same template for this purpose . + + Not to be used to record a whole operation or procedure report - use a template in which this archetype is only one component of the full report."> + copyright = <"© openEHR Foundation"> + > + ["ar-sy"] = < + language = <[ISO_639-1::ar-sy]> + purpose = <"لتسجيل تفاصيل حول إجراء طبي تم بالفعل إجراؤه"> + keywords = <"الإجراء الطبي", ...> + use = <"لتسجيل معلومات تفصيلية حول إجراء طبي تم تنفيذه على شخص ما. و ينبغي تسجيل المعلومات حول النشاطات المتعلقة بالنشاطات المتعلقة بالإجراء الطبي, مثل التخدير أو إعطاء الأدوية في نماذج (فعل) منفردة."> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + ["sl"] = < + language = <[ISO_639-1::sl]> + purpose = <"Za beleženje podrobnosti o izvedeni aktivnosti"> + keywords = <"aktivnosti", "postopek"> + use = <"Za beleženje podrobnosto o izvedeni aktivnosti, ki zadeva posameznega pacienta/subjekt"> + misuse = <"Podrobnosti o aktivnostih povezani z opisano kativnostjo, kot npr. dajanje zdravil, se zabeleži v arhetipih tipa ACTION"> + copyright = <"© openEHR Foundation"> + > + ["es"] = < + language = <[ISO_639-1::es]> + purpose = <"Para registrar información sobre las actividades requeridas para ejecutar un procedimiento, incluyendo planificación, coordinación, ejecución, suspensión, cancelación, documentación y finalización."> + keywords = <"procedimiento", "intervención", "terapia", "cirugía", "diagnóstico", "evaluación", "curación", "tratamiento"> + use = <"Se utiliza para registrar información sobre las actividades requeridas para llevar a cabo un procedimiento, incluyendo planificación, coordinación, ejecución, suspensión, cancelación, documentación y finalización. Esto se hace mediante el registro de los datos sobre actividades específicas, según la definición de los pasos de la vía clínica definida en el arquetipo. + + El alcance de este arquetipo abarca actividades para una amplia gama de procedimientos clínicos realizados para la evaluación, investigación, detección, diagnóstico, + curativos, terapéuticos o fines paliativos. Los ejemplos van desde las actividades relativamente simples, como la inserción de una cánula intravenosa, hasta operaciones quirúrgicas complejas."> + misuse = <"No utilizar para registrar detalles acerca de la anestesia, para eso utilizar un arquetipo de ACTION separado. + No utilizar para registrar detalles acerca de estudios por imágenes, para eso utilizar el arquetipo ACTION.imaging_exam. + No utilizar para registrar detalles acerca de estudios de laboratorio, para eso utilizar el arquetipo ACTION.laboratory_test. + No utilizar para registrar detalles acerca de educación brindada, para eso utilizar el arquetipo ACTION.health_education. + No utilizar para registrar detalles acerca de actividades administrativas, para eso utilizar un arquetipo ADMIN separado. + No utilizar para registrar detalles acerca de actividades relacionadas, como medicación administrada durante el procedimiento, o sobre imágenes que se utilizaron como guía durante el procedimiento, para esto utilizar arquetipos de ACTION separados, dentro de la misma plantilla. + No utilizar para registrar detalles acerca del informe de la operación, para eso se debe utilizar una plantilla donde este arquetipo sea parte de la misma."> + > + > + +definition + ACTION[id1] matches { -- Procedure + ism_transition matches { + ISM_TRANSITION[id9089] matches { + current_state matches { + DV_CODED_TEXT[id9090] matches { + defining_code matches {[at9126]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9091] matches { + defining_code matches {[at5]} + } + } + } + ISM_TRANSITION[id35] matches { -- X - Procedure planned + current_state matches { + DV_CODED_TEXT[id9127] matches { + defining_code matches {[at9000]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9128] matches { + defining_code matches {[at35]} + } + } + } + ISM_TRANSITION[id8] matches { -- Procedure request sent + current_state matches { + DV_CODED_TEXT[id9129] matches { + defining_code matches {[at9126]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9130] matches { + defining_code matches {[at8]} + } + } + } + ISM_TRANSITION[id36] matches { -- X - Procedure request sent + current_state matches { + DV_CODED_TEXT[id9093] matches { + defining_code matches {[at9000]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9094] matches { + defining_code matches {[at36]} + } + } + } + ISM_TRANSITION[id39] matches { -- Procedure postponed + current_state matches { + DV_CODED_TEXT[id9095] matches { + defining_code matches {[at9001]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9096] matches { + defining_code matches {[at39]} + } + } + } + ISM_TRANSITION[id40] matches { -- Procedure cancelled + current_state matches { + DV_CODED_TEXT[id9097] matches { + defining_code matches {[at9002]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9098] matches { + defining_code matches {[at40]} + } + } + } + ISM_TRANSITION[id37] matches { -- Procedure scheduled + current_state matches { + DV_CODED_TEXT[id9099] matches { + defining_code matches {[at9003]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9100] matches { + defining_code matches {[at37]} + } + } + } + ISM_TRANSITION[id69] matches { -- Procedure commenced + current_state matches { + DV_CODED_TEXT[id9124] matches { + defining_code matches {[at9004]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9125] matches { + defining_code matches {[at69]} + } + } + } + ISM_TRANSITION[id48] matches { -- Procedure performed + current_state matches { + DV_CODED_TEXT[id9101] matches { + defining_code matches {[at9004]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9102] matches { + defining_code matches {[at48]} + } + } + } + ISM_TRANSITION[id41] matches { -- Procedure suspended + current_state matches { + DV_CODED_TEXT[id9103] matches { + defining_code matches {[at9005]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9104] matches { + defining_code matches {[at41]} + } + } + } + ISM_TRANSITION[id42] matches { -- Procedure aborted + current_state matches { + DV_CODED_TEXT[id9105] matches { + defining_code matches {[at9006]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9106] matches { + defining_code matches {[at42]} + } + } + } + ISM_TRANSITION[id44] matches { -- Procedure completed + current_state matches { + DV_CODED_TEXT[id9107] matches { + defining_code matches {[at9007]} + } + } + careflow_step matches { + DV_CODED_TEXT[id9108] matches { + defining_code matches {[at44]} + } + } + } + } + description matches { + ITEM_TREE[id9000] matches { + items cardinality matches {1..*; unordered} matches { + ELEMENT[id3] matches { -- Procedure name + value matches { + DV_TEXT[id9044] + } + } + ELEMENT[id50] occurrences matches {0..1} matches { -- Description + value matches { + DV_TEXT[id9047] + } + } + ELEMENT[id71] matches { -- Indication + value matches { + DV_TEXT[id9131] + } + } + ELEMENT[id66] matches { -- Method + value matches { + DV_TEXT[id9117] + } + } + ELEMENT[id59] occurrences matches {0..1} matches { -- Urgency + value matches { + DV_TEXT[id9118] + } + } + ELEMENT[id64] matches { -- Body site + value matches { + DV_TEXT[id9119] + } + } + allow_archetype CLUSTER[id4] matches { -- Procedure detail + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.device(-[a-zA-Z0-9_]+)*\.v1|openEHR-EHR-CLUSTER\.anatomical_location(-[a-zA-Z0-9_]+)*\.v1|openEHR-EHR-CLUSTER\.anatomical_location_circle(-[a-zA-Z0-9_]+)*\.v1|openEHR-EHR-CLUSTER\.anatomical_location_relative(-[a-zA-Z0-9_]+)*\.v2/} + } + ELEMENT[id49] matches { -- Outcome + value matches { + DV_TEXT[id9051] + } + } + ELEMENT[id70] matches { -- Procedural difficulty + value matches { + DV_TEXT[id9126] + } + } + ELEMENT[id7] matches { -- Complication + value matches { + DV_TEXT[id9054] + } + } + ELEMENT[id67] occurrences matches {0..1} matches { -- Scheduled date/time + value matches { + DV_DATE_TIME[id9120] + } + } + ELEMENT[id61] occurrences matches {0..1} matches { -- Final end date/time + value matches { + DV_DATE_TIME[id9121] + } + } + ELEMENT[id62] occurrences matches {0..1} matches { -- Total duration + value matches { + DV_DURATION[id9122] matches { + value matches {|>=PT0S|} + } + } + } + allow_archetype CLUSTER[id63] matches { -- Multimedia + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.media_capture(-[a-zA-Z0-9_]+)*\.v1/} + } + ELEMENT[id68] occurrences matches {0..1} matches { -- Procedure type + value matches { + DV_TEXT[id9123] + } + } + ELEMENT[id15] matches { -- Reason + value matches { + DV_TEXT[id9045] + } + } + ELEMENT[id6] occurrences matches {0..1} matches { -- Comment + value matches { + DV_TEXT[id9055] + } + } + } + } + } + protocol matches { + ITEM_TREE[id54] matches { -- Tree + items cardinality matches {0..*; unordered} matches { + ELEMENT[id55] occurrences matches {0..1} matches { -- Requestor order identifier + value matches { + DV_TEXT[id9057] + DV_IDENTIFIER[id9115] + } + } + allow_archetype CLUSTER[id56] occurrences matches {0..1} matches { -- Requestor + include + archetype_id/value matches {/.*/} + } + ELEMENT[id57] occurrences matches {0..1} matches { -- Receiver order identifier + value matches { + DV_TEXT[id9058] + DV_IDENTIFIER[id9116] + } + } + allow_archetype CLUSTER[id58] matches { -- Receiver + include + archetype_id/value matches {/.*/} + } + allow_archetype CLUSTER[id65] matches { -- Extension + include + archetype_id/value matches {/.*/} + } + } + } + } + } + +terminology + term_definitions = < + ["de"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"Indikation"> + description = <"Der klinische oder prozessbezogene Grund für die Prozedur."> + > + ["id70"] = < + text = <"Schwierigkeiten bei der Durchführung der Prozedur"> + description = <"Schwierigkeiten oder Probleme, die während der Durchführung der Prozedur aufgetreten sind."> + > + ["id69"] = < + text = <"Prozedur begonnen"> + description = <"Die Prozedur, oder eine Subprozedur in einem mehrstufigen Vorgehen, wurde begonnen."> + > + ["at69"] = < + text = <"Prozedur begonnen"> + description = <"Die Prozedur, oder eine Subprozedur in einem mehrstufigen Vorgehen, wurde begonnen."> + > + ["id68"] = < + text = <"Art der Prozedur"> + description = <"Die Art der Prozedur."> + > + ["id67"] = < + text = <"Geplantes Datum/Uhrzeit"> + description = <"Das Datum und/oder die Uhrzeit für die die Prozedur angesetzt ist."> + > + ["id66"] = < + text = <"Methode"> + description = <"Identifizierung der spezifischen Prozedurmethode oder -technik."> + > + ["id65"] = < + text = <"Erweiterung"> + description = <"Zusätzliche Informationen, die erforderlich sind, um lokale Inhalte zu erfassen oder mit anderen Referenzmodellen/Formalismen abzugleichen."> + > + ["id64"] = < + text = <"Körperstelle"> + description = <"Anatomische Lokalisation, an der die Prozedur durchgeführt wird."> + > + ["id63"] = < + text = <"Multimedia"> + description = <"Multimediale Darstellung der durchgeführten Prozedur."> + > + ["id62"] = < + text = <"Gesamtdauer"> + description = <"Die Gesamtdauer der Prozedur - diese kann sich aus der aktiven Phase und der Phase, in der die Prozedur unterbrochen wurde, ergeben."> + > + ["id61"] = < + text = <"Enddatum/-uhrzeit"> + description = <"Das Datum und/oder die Uhrzeit, an dem die gesamte Prozedur, oder die letzte Komponente einer mehrstufigen Prozedur, beendet wurde."> + > + ["id59"] = < + text = <"Dringlichkeit"> + description = <"Dringlichkeit der Prozedur."> + > + ["id58"] = < + text = <"Empfänger"> + description = <"Angaben über den Gesundheitsdienstleister oder die Organisation, die die Leistungsanforderung erhält."> + > + ["id57"] = < + text = <"Auftragskennung des Empfängers"> + description = <"Die ID, die dem Auftrag von dem Gesundheitsdienstleister oder der Organisation, die die Leistungsanforderung erhält, zugewiesen wurde. Dies wird auch als \"Filler Order Identifier\" bezeichnet."> + > + ["id56"] = < + text = <"Antragsteller"> + description = <"Angaben über den Gesundheitsdienstleister oder die Organisation, die die Leistung anfordert."> + > + ["id55"] = < + text = <"Auftragskennung des Antragstellers"> + description = <"Die lokale ID, die dem Auftrag vom Gesundheitsdienstleister oder der Organisation, die die Leistung anfordert, zugewiesen wurde."> + > + ["id54"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"Beschreibung"> + description = <"Beschreibung der Prozedur, angepasst an den \"Pathway\"-Verlaufsschritt."> + > + ["id49"] = < + text = <"Ausgang"> + description = <"Ausgang der durchgeführten Prozedur."> + > + ["id48"] = < + text = <"Prozedur durchgeführt"> + description = <"Die Prozedur, oder eine Subprozedur in einem mehrstufigen Vorgehen, wurde durchgeführt."> + > + ["at48"] = < + text = <"Prozedur durchgeführt"> + description = <"Die Prozedur, oder eine Subprozedur in einem mehrstufigen Vorgehen, wurde durchgeführt."> + > + ["id44"] = < + text = <"Prozedur beendet"> + description = <"Die Prozedur wurde durchgeführt und alle damit verbundenen klinischen Aktivitäten wurden beendet."> + > + ["at44"] = < + text = <"Prozedur beendet"> + description = <"Die Prozedur wurde durchgeführt und alle damit verbundenen klinischen Aktivitäten wurden beendet."> + > + ["id42"] = < + text = <"Prozedur abgebrochen"> + description = <"Die Prozedur wurde abgebrochen."> + > + ["at42"] = < + text = <"Prozedur abgebrochen"> + description = <"Die Prozedur wurde abgebrochen."> + > + ["id41"] = < + text = <"Prozedur unterbrochen"> + description = <"Die Prozedur wurde unterbrochen."> + > + ["at41"] = < + text = <"Prozedur unterbrochen"> + description = <"Die Prozedur wurde unterbrochen."> + > + ["id40"] = < + text = <"Prozedur storniert"> + description = <"Die geplante Prozedur wurde vor Beginn storniert."> + > + ["at40"] = < + text = <"Prozedur storniert"> + description = <"Die geplante Prozedur wurde vor Beginn storniert."> + > + ["id39"] = < + text = <"Prozedur verschoben"> + description = <"Die Prozedur wurde verschoben."> + > + ["at39"] = < + text = <"Prozedur verschoben"> + description = <"Die Prozedur wurde verschoben."> + > + ["id37"] = < + text = <"geplanter Termin der Prozedur"> + description = <"Ein Termin für die Prozedur wurde geplant."> + > + ["at37"] = < + text = <"geplanter Termin der Prozedur"> + description = <"Ein Termin für die Prozedur wurde geplant."> + > + ["id36"] = < + text = <"X - Auftrag für Prozedur versendet"> + description = <"Dieses Element ist veraltet, da es fälschlicherweise mit dem Status \"initial\" verknüpft war - verwenden Sie das neue Element \"Geplante Prozedur\" (at0007), das korrekt mit dem Status \"geplant\" verknüpft ist."> + > + ["at36"] = < + text = <"X - Auftrag für Prozedur versendet"> + description = <"Dieses Element ist veraltet, da es fälschlicherweise mit dem Status \"initial\" verknüpft war - verwenden Sie das neue Element \"Geplante Prozedur\" (at0007), das korrekt mit dem Status \"geplant\" verknüpft ist."> + > + ["id35"] = < + text = <"X - Prozedur geplant"> + description = <"Dieses Element ist veraltet, da es fälschlicherweise mit dem Status \"initial\" verknüpft war - verwenden Sie das neue Element \"Prozedur geplant\" (at0004), das korrekt mit dem Status \"geplant\" verknüpft ist."> + > + ["at35"] = < + text = <"X - Prozedur geplant"> + description = <"Dieses Element ist veraltet, da es fälschlicherweise mit dem Status \"initial\" verknüpft war - verwenden Sie das neue Element \"Prozedur geplant\" (at0004), das korrekt mit dem Status \"geplant\" verknüpft ist."> + > + ["id15"] = < + text = <"Grund"> + description = <"Grund, warum die angegebene Aktivität für diese Prozedur durchgeführt wurde."> + > + ["id8"] = < + text = <"Auftrag für Prozedur versendet"> + description = <"Der Auftrag für die Prozedur wurde versendet."> + > + ["at8"] = < + text = <"Auftrag für Prozedur versendet"> + description = <"Der Auftrag für die Prozedur wurde versendet."> + > + ["id7"] = < + text = <"Komplikationen"> + description = <"Details zu allen Komplikationen, die sich aus der Prozedur ergeben haben."> + > + ["id6"] = < + text = <"Kommentar"> + description = <"Zusätzliche Beschreibung der Aktivität oder der \"Pathway\"-Verlaufsschritte, die in anderen Bereichen nicht erfasst wurden."> + > + ["id5"] = < + text = <"Geplante Prozedur"> + description = <"Die Prozedur, die durchgeführt werden soll, ist geplant."> + > + ["at5"] = < + text = <"Geplante Prozedur"> + description = <"Die Prozedur, die durchgeführt werden soll, ist geplant."> + > + ["id4"] = < + text = <"Details zur Prozedur"> + description = <"Strukturierte Informationen über die Prozedur."> + > + ["id3"] = < + text = <"Name der Prozedur"> + description = <"Identifizierung der Prozedur über den Namen."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Prozedur"> + description = <"Eine klinische Aktivität, die zur Früherkennung, Untersuchung, Diagnose, Heilung, Therapie, Bewertung oder in Hinsicht auf palliative Maßnahmen durchgeführt wird."> + > + > + ["ru"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"*Procedural difficulty(en)"> + description = <"*Difficulties or issues encountered during the procedure.(en)"> + > + ["id69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["at69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["id68"] = < + text = <"*Procedure type(en)"> + description = <"*The type of procedure.(en)"> + > + ["id67"] = < + text = <"*Scheduled date/time(en)"> + description = <"*The date and/or time on which the procedure is intended to be performed.(en)"> + > + ["id66"] = < + text = <"*Method(en)"> + description = <"*Identification of specific method or technique for the procedure.(en)"> + > + ["id65"] = < + text = <"*Extension(en)"> + description = <"*Additional information required to capture local content or to align with other reference models/formalisms.(en)"> + > + ["id64"] = < + text = <"*Body site(en)"> + description = <"*Identification of the body site for the procedure.(en)"> + > + ["id63"] = < + text = <"*Multimedia(en)"> + description = <"*Mulitimedia representation of a performed procedure.(en)"> + > + ["id62"] = < + text = <"*Total duration(en)"> + description = <"*The total amount of time taken to complete the procedure, which may include time spent during the active phase of the procedure plus time during which the procedure was suspended.(en)"> + > + ["id61"] = < + text = <"*Final end date/time(en)"> + description = <"*The date and/or time when the entire procedure, or the last component of a multicomponent procedure, was finished.(en)"> + > + ["id59"] = < + text = <"*Urgency(en)"> + description = <"*Urgency of the procedure.(en)"> + > + ["id58"] = < + text = <"Исполнитель"> + description = <"Подробные сведение об организации, получившей заявку на выполнение процедуры"> + > + ["id57"] = < + text = <"*Receiver order identifier(en)"> + description = <"*The ID assigned to the order by the healthcare provider or organisation receiving the request for service. This is also referred to as Filler Order Identifier.(en)"> + > + ["id56"] = < + text = <"Заказчик"> + description = <"Подробности о заказчике (организации), запросившей услугу"> + > + ["id55"] = < + text = <"*Requestor order identifier(en)"> + description = <"*The local ID assigned to the order by the healthcare provider or organisation requesting the service.(en)"> + > + ["id54"] = < + text = <"*Tree(en)"> + description = <"*@ internal @(en)"> + > + ["id50"] = < + text = <"*Description(en)"> + description = <"*Narrative description about the procedure, as appropriate for the pathway step.(en)"> + > + ["id49"] = < + text = <"*Outcome(en)"> + description = <"*Outcome of procedure performed.(en)"> + > + ["id48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["at48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["id44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["at44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["id42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["at42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["id41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["at41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["id40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["at40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["id39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["at39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["id37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["at37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["id36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["at36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["id35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["at35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["id15"] = < + text = <"*Reason(en)"> + description = <"*Reason that the activity or care pathway step for the identified procedure was carried out.(en)"> + > + ["id8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["at8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["id7"] = < + text = <"*Complication(en)"> + description = <"*Details about any complication arising from the procedure.(en)"> + > + ["id6"] = < + text = <"*Comment(en)"> + description = <"*Additional narrative about the activity or care pathway step not captured in other fields.(en)"> + > + ["id5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["at5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["id4"] = < + text = <"*Procedure detail(en)"> + description = <"*Structured information about the procedure. Use to capture detailed, structured information about anatomical location, method & technique, equipment used, devices implanted, results, findings etc.(en)"> + > + ["id3"] = < + text = <"*Procedure name(en)"> + description = <"*Identification of the procedure by name.(en)"> + > + ["id2"] = < + text = <"*Tree(en)"> + description = <"*@ internal @(en)"> + > + ["id1"] = < + text = <"*Procedure(en)"> + description = <"*A clinical activity carried out for screening, investigative, diagnostic, curative, therapeutic, evaluative or palliative purposes.(en)"> + > + > + ["nb"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"Problem ved prosedyre"> + description = <"Vanskeligheter eller problemer som det ble støtt på under prosedyren."> + > + ["id69"] = < + text = <"Prosedyre påbegynt"> + description = <"Prosedyren eller en del av en prosedyre som består av flere delprosedyrer er påbegynt."> + > + ["at69"] = < + text = <"Prosedyre påbegynt"> + description = <"Prosedyren eller en del av en prosedyre som består av flere delprosedyrer er påbegynt."> + > + ["id68"] = < + text = <"Prosedyretype"> + description = <"Typen prosedyre."> + > + ["id67"] = < + text = <"Planlagt dato/tid"> + description = <"Dato/tid når prosedyren er planlagt utført."> + > + ["id66"] = < + text = <"Metode"> + description = <"Den spesifikke metoden eller teknikken for prosedyren."> + > + ["id65"] = < + text = <"Tilleggsinformasjon"> + description = <"Ytterligere informasjon som er nødvendig for å sammenstille med andre referansemodeller/formalismer."> + > + ["id64"] = < + text = <"Kroppssted"> + description = <"Stedet på kroppen der prosedyren er utført."> + > + ["id63"] = < + text = <"Multimedia"> + description = <"Multimediarepresentasjon av en utført prosedyre."> + > + ["id62"] = < + text = <"Total varighet"> + description = <"Den totale tiden som ble brukt til å fullføre prosedyren. Dette kan omfatte tidsbruk under den aktive fasen av prosedyren, og i tillegg tid da prosedyren var midlertidig stanset."> + > + ["id61"] = < + text = <"Dato/tid for avslutning av prosedyren"> + description = <"Datoen og/eller tiden da hele eller den siste av komponentene i en kompleks prosedyre ble avsluttet."> + > + ["id59"] = < + text = <"Hastegrad"> + description = <"Prosedyrens hastegrad."> + > + ["id58"] = < + text = <"Mottaker"> + description = <"Detaljer om helsepersonellet eller organisasjonen som mottar prosedyrerekvisisjonen."> + > + ["id57"] = < + text = <"Mottakers rekvisisjonsidentifikator"> + description = <"IDen tilordnet rekvisisjonen av helsepersonellet eller organisasjonen som mottar rekvisisjonen."> + > + ["id56"] = < + text = <"Rekvirent"> + description = <"Detaljer om helsepersonellet eller organisasjonen som har rekvirert prosedyren."> + > + ["id55"] = < + text = <"Rekvisisjonsidentifikator"> + description = <"Den lokale IDen tilordnet rekvisisjonen av helsepersonellet eller organisasjonen som rekvirerer prosedyren."> + > + ["id54"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"Beskrivelse"> + description = <"Fritekstbeskrivelse av prosedyren, tilpasset det aktuelle prosesstrinnet."> + > + ["id49"] = < + text = <"Resultat"> + description = <"Resultatet av den utførte prosedyren."> + > + ["id48"] = < + text = <"Prosedyre utført"> + description = <"Prosedyren eller en del av en prosedyre som består av flere delprosedyrer er utført."> + > + ["at48"] = < + text = <"Prosedyre utført"> + description = <"Prosedyren eller en del av en prosedyre som består av flere delprosedyrer er utført."> + > + ["id44"] = < + text = <"Prosedyre fullført"> + description = <"Prosedyren er utført og alle tilknyttede kliniske handlinger er fullførte."> + > + ["at44"] = < + text = <"Prosedyre fullført"> + description = <"Prosedyren er utført og alle tilknyttede kliniske handlinger er fullførte."> + > + ["id42"] = < + text = <"Prosedyre avbrutt"> + description = <"Prosedyren har blitt avbrutt."> + > + ["at42"] = < + text = <"Prosedyre avbrutt"> + description = <"Prosedyren har blitt avbrutt."> + > + ["id41"] = < + text = <"Prosedyre midlertidig stanset"> + description = <"Prosedyren er suspendert/ midlertidig stanset."> + > + ["at41"] = < + text = <"Prosedyre midlertidig stanset"> + description = <"Prosedyren er suspendert/ midlertidig stanset."> + > + ["id40"] = < + text = <"Prosedyre avlyst"> + description = <"Den planlagte prosedyren har blitt avlyst før den ble igangsatt."> + > + ["at40"] = < + text = <"Prosedyre avlyst"> + description = <"Den planlagte prosedyren har blitt avlyst før den ble igangsatt."> + > + ["id39"] = < + text = <"Prosedyre utsatt"> + description = <"Prosedyren er utsatt."> + > + ["at39"] = < + text = <"Prosedyre utsatt"> + description = <"Prosedyren er utsatt."> + > + ["id37"] = < + text = <"Fastsatt tidspunkt for prosedyre"> + description = <"Tidspunkt for prosedyre er fastsatt."> + > + ["at37"] = < + text = <"Fastsatt tidspunkt for prosedyre"> + description = <"Tidspunkt for prosedyre er fastsatt."> + > + ["id36"] = < + text = <"X - Prosedyrerekvisisjon sendt"> + description = <"Dette prosesstrinnet er satt ut av bruk, siden det ved en feil hadde statusen \"initial\". Bruk det nye prosesstrinnet \"Prosedyre planlagt\" (at0007) som har den korrekte statusen \"planned\"."> + > + ["at36"] = < + text = <"X - Prosedyrerekvisisjon sendt"> + description = <"Dette prosesstrinnet er satt ut av bruk, siden det ved en feil hadde statusen \"initial\". Bruk det nye prosesstrinnet \"Prosedyre planlagt\" (at0007) som har den korrekte statusen \"planned\"."> + > + ["id35"] = < + text = <"X - Prosedyre planlagt"> + description = <"Dette prosesstrinnet er satt ut av bruk, siden det ved en feil hadde statusen \"initial\". Bruk det nye prosesstrinnet \"Prosedyre planlagt\" (at0004) som har den korrekte statusen \"planned\"."> + > + ["at35"] = < + text = <"X - Prosedyre planlagt"> + description = <"Dette prosesstrinnet er satt ut av bruk, siden det ved en feil hadde statusen \"initial\". Bruk det nye prosesstrinnet \"Prosedyre planlagt\" (at0004) som har den korrekte statusen \"planned\"."> + > + ["id15"] = < + text = <"Begrunnelse"> + description = <"Begrunnelse for at aktiviteten eller prosesstrinnet for den aktuelle prosedyren ble utført."> + > + ["id8"] = < + text = <"Prosedyrerekvisisjon sendt"> + description = <"Det er sendt rekvisisjon for prosedyren."> + > + ["at8"] = < + text = <"Prosedyrerekvisisjon sendt"> + description = <"Det er sendt rekvisisjon for prosedyren."> + > + ["id7"] = < + text = <"Komplikasjon"> + description = <"Detaljer om komplikasjoner oppstått under gjennomføring av prosedyren."> + > + ["id6"] = < + text = <"Kommentar"> + description = <"Ytterligere fritekstbeskrivelse av aktivitet eller prosesstrinn som ikke er registrert i andre felt."> + > + ["id5"] = < + text = <"Prosedyre planlagt"> + description = <"Prosedyren er planlagt."> + > + ["at5"] = < + text = <"Prosedyre planlagt"> + description = <"Prosedyren er planlagt."> + > + ["id4"] = < + text = <"Prosedyredetaljer"> + description = <"Strukturert informasjon om prosedyren."> + > + ["id3"] = < + text = <"Prosedyrenavn"> + description = <"Navnet på prosedyren."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Prosedyre"> + description = <"En klinisk aktivitet som er utført i undersøkende, diagnostisk, kurativ, terapeutisk, evaluerende, prognostisk eller palliativ hensikt."> + > + > + ["pt-br"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"*Procedural difficulty(en)"> + description = <"*Difficulties or issues encountered during the procedure.(en)"> + > + ["id69"] = < + text = <"Procedimento Iniciou"> + description = <"O procedimento, ou procedimento secundário, no caso de procedimentos sequenciados, foi iniciado."> + > + ["at69"] = < + text = <"Procedimento Iniciou"> + description = <"O procedimento, ou procedimento secundário, no caso de procedimentos sequenciados, foi iniciado."> + > + ["id68"] = < + text = <"Tipo do procedimento"> + description = <"O tipo do procedimento."> + > + ["id67"] = < + text = <"Agendamento data/hora"> + description = <"A data e /ou hora em que o processo está previsto para ocorrer."> + > + ["id66"] = < + text = <"Método"> + description = <"Identificação do método específico ou técnica do procedimento."> + > + ["id65"] = < + text = <"Extensão"> + description = <"Informações adicionais necessárias para capturar o conteúdo local ou para se alinhar com outros modelos / formalismos de referência"> + > + ["id64"] = < + text = <"Localização no corpo"> + description = <"Identificação do local no corpo onde será realizado o procedimento."> + > + ["id63"] = < + text = <"Multimidia"> + description = <"Representação multimídia de um procedimento realizado."> + > + ["id62"] = < + text = <"Duração Total"> + description = <"A quantidade total de tempo necessária para concluir o procedimento, o que pode incluir o tempo gasto durante a fase ativa do procedimento mais o tempo durante o qual o procedimento foi suspenso."> + > + ["id61"] = < + text = <"Data final / hora"> + description = <"A data e/ou hora , quando todo o processo , ou o último componente de um procedimento de múltiplas etapas , foi finalizada."> + > + ["id59"] = < + text = <"Urgência"> + description = <"Urgência do procedimento."> + > + ["id58"] = < + text = <"Destinatário"> + description = <"Detalhes sobre o profissional ou organização de saúde que recebeu o requerimento para o serviço."> + > + ["id57"] = < + text = <"Identificador do pedido do destinatário"> + description = <"O ID atribuído ao pedido pelo provedor de cuidados de saúde ou organização que recebe o pedido de serviço. Isto é também relacionado ao preenchimento da identificação do pedido."> + > + ["id56"] = < + text = <"Solicitante"> + description = <"Detalhes sobre o profissional ou organização de saúde que solicitou o serviço."> + > + ["id55"] = < + text = <"Identificador do pedido do solicitante"> + description = <"O ID local atribuído ao pedido realizado pelo profissional de saúde ou organização solicitando o serviço."> + > + ["id54"] = < + text = <"Tree(en)"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"Descrição"> + description = <"Descrição narrativa sobre o procedimento, conforme apropriado para a etapa."> + > + ["id49"] = < + text = <"Resultado"> + description = <"Resultado do procedimento realizado."> + > + ["id48"] = < + text = <"Procedimento realizado"> + description = <"O procedimento, ou procedimento secundário no caso de procedimentos sequenciado, foi realizado."> + > + ["at48"] = < + text = <"Procedimento realizado"> + description = <"O procedimento, ou procedimento secundário no caso de procedimentos sequenciado, foi realizado."> + > + ["id44"] = < + text = <"Procedimento concluído"> + description = <"O procedimento foi realizado e todas as atividades clínicas associadas concluídas."> + > + ["at44"] = < + text = <"Procedimento concluído"> + description = <"O procedimento foi realizado e todas as atividades clínicas associadas concluídas."> + > + ["id42"] = < + text = <"Procedimento abortado"> + description = <"O procedimento foi abortado."> + > + ["at42"] = < + text = <"Procedimento abortado"> + description = <"O procedimento foi abortado."> + > + ["id41"] = < + text = <"Procedimento suspenso"> + description = <"O procedimento foi suspenso."> + > + ["at41"] = < + text = <"Procedimento suspenso"> + description = <"O procedimento foi suspenso."> + > + ["id40"] = < + text = <"Procedimento cancelado"> + description = <"O procedimento planejado foi cancelado antes do início."> + > + ["at40"] = < + text = <"Procedimento cancelado"> + description = <"O procedimento planejado foi cancelado antes do início."> + > + ["id39"] = < + text = <"Procedimento adiado"> + description = <"O procedimento foi adiado."> + > + ["at39"] = < + text = <"Procedimento adiado"> + description = <"O procedimento foi adiado."> + > + ["id37"] = < + text = <"Procedimento agendado"> + description = <"O procedimento foi agendado."> + > + ["at37"] = < + text = <"Procedimento agendado"> + description = <"O procedimento foi agendado."> + > + ["id36"] = < + text = <"Procedimento pedido enviado"> + description = <"Pedido de procedimento enviado."> + > + ["at36"] = < + text = <"Procedimento pedido enviado"> + description = <"Pedido de procedimento enviado."> + > + ["id35"] = < + text = <"Plano de procedimento"> + description = <"O procedimento a ser realizado é planejado"> + > + ["at35"] = < + text = <"Plano de procedimento"> + description = <"O procedimento a ser realizado é planejado"> + > + ["id15"] = < + text = <"Justificativa"> + description = <"Razão pela qual a atividade ou cuidado foi identificada para que o procedimento fosse realizado."> + > + ["id8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["at8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["id7"] = < + text = <"Complicações"> + description = <"Detalhes sobre alguma complicação decorrente do procedimento"> + > + ["id6"] = < + text = <"Comentários"> + description = <"Comentários adicionais sobre a atividade ou etapas não informados em outros campos."> + > + ["id5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["at5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["id4"] = < + text = <"Detalhes do Procedimento"> + description = <"São as informações estruturadas sobre o procedimento."> + > + ["id3"] = < + text = <"Nome do procedimento"> + description = <"Identificação do procedimento pelo nome."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Procedimento"> + description = <"A atividade clínica realizada para rastreamento , investigação , diagnóstico , cura , terapêutica, avaliação ou finalidade paliativos."> + > + > + ["sl"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"*Procedural difficulty(en)"> + description = <"*Difficulties or issues encountered during the procedure.(en)"> + > + ["id69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["at69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["id68"] = < + text = <"*Procedure type(en)"> + description = <"*The type of procedure.(en)"> + > + ["id67"] = < + text = <"*Scheduled date/time(en)"> + description = <"*The date and/or time on which the procedure is intended to be performed.(en)"> + > + ["id66"] = < + text = <"*Method(en)"> + description = <"*Identification of specific method or technique for the procedure.(en)"> + > + ["id65"] = < + text = <"*Extension(en)"> + description = <"*Additional information required to capture local content or to align with other reference models/formalisms.(en)"> + > + ["id64"] = < + text = <"*Body site(en)"> + description = <"*Identification of the body site for the procedure.(en)"> + > + ["id63"] = < + text = <"*Multimedia(en)"> + description = <"*Mulitimedia representation of a performed procedure.(en)"> + > + ["id62"] = < + text = <"*Total duration(en)"> + description = <"*The total amount of time taken to complete the procedure, which may include time spent during the active phase of the procedure plus time during which the procedure was suspended.(en)"> + > + ["id61"] = < + text = <"*Final end date/time(en)"> + description = <"*The date and/or time when the entire procedure, or the last component of a multicomponent procedure, was finished.(en)"> + > + ["id59"] = < + text = <"*Urgency(en)"> + description = <"*Urgency of the procedure.(en)"> + > + ["id58"] = < + text = <"Prejemnik"> + description = <"Prejemnik naročila za izvedbo aktivnosti"> + > + ["id57"] = < + text = <"*Receiver order identifier(en)"> + description = <"*The ID assigned to the order by the healthcare provider or organisation receiving the request for service. This is also referred to as Filler Order Identifier.(en)"> + > + ["id56"] = < + text = <"Naročnik"> + description = <"Kdo je naročil aktivnost, posameznik ali organizacija"> + > + ["id55"] = < + text = <"*Requestor order identifier(en)"> + description = <"*The local ID assigned to the order by the healthcare provider or organisation requesting the service.(en)"> + > + ["id54"] = < + text = <"*Tree(en)"> + description = <"*@ internal @(en)"> + > + ["id50"] = < + text = <"*Description(en)"> + description = <"*Narrative description about the procedure, as appropriate for the pathway step.(en)"> + > + ["id49"] = < + text = <"*Outcome(en)"> + description = <"*Outcome of procedure performed.(en)"> + > + ["id48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["at48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["id44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["at44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["id42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["at42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["id41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["at41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["id40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["at40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["id39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["at39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["id37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["at37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["id36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["at36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["id35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["at35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["id15"] = < + text = <"*Reason(en)"> + description = <"*Reason that the activity or care pathway step for the identified procedure was carried out.(en)"> + > + ["id8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["at8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["id7"] = < + text = <"*Complication(en)"> + description = <"*Details about any complication arising from the procedure.(en)"> + > + ["id6"] = < + text = <"*Comment(en)"> + description = <"*Additional narrative about the activity or care pathway step not captured in other fields.(en)"> + > + ["id5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["at5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["id4"] = < + text = <"*Procedure detail(en)"> + description = <"*Structured information about the procedure. Use to capture detailed, structured information about anatomical location, method & technique, equipment used, devices implanted, results, findings etc.(en)"> + > + ["id3"] = < + text = <"*Procedure name(en)"> + description = <"*Identification of the procedure by name.(en)"> + > + ["id2"] = < + text = <"*Tree(en)"> + description = <"*@ internal @(en)"> + > + ["id1"] = < + text = <"*Procedure(en)"> + description = <"*A clinical activity carried out for screening, investigative, diagnostic, curative, therapeutic, evaluative or palliative purposes.(en)"> + > + > + ["en"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"Indication"> + description = <"The clinical or process-related reason for the procedure."> + > + ["id70"] = < + text = <"Procedural difficulty"> + description = <"Difficulties or issues encountered during performance of the procedure."> + > + ["id69"] = < + text = <"Procedure commenced"> + description = <"The procedure, or subprocedure in a multicomponent procedure, has been commenced."> + > + ["at69"] = < + text = <"Procedure commenced"> + description = <"The procedure, or subprocedure in a multicomponent procedure, has been commenced."> + > + ["id68"] = < + text = <"Procedure type"> + description = <"The type of procedure."> + > + ["id67"] = < + text = <"Scheduled date/time"> + description = <"The date and/or time on which the procedure is intended to be performed."> + > + ["id66"] = < + text = <"Method"> + description = <"Identification of specific method or technique for the procedure."> + > + ["id65"] = < + text = <"Extension"> + description = <"Additional information required to capture local content or to align with other reference models/formalisms."> + > + ["id64"] = < + text = <"Body site"> + description = <"Identification of the body site for the procedure."> + > + ["id63"] = < + text = <"Multimedia"> + description = <"Mulitimedia representation of a performed procedure."> + > + ["id62"] = < + text = <"Total duration"> + description = <"The total amount of time taken to complete the procedure, which may include time spent during the active phase of the procedure plus time during which the procedure was suspended."> + > + ["id61"] = < + text = <"Final end date/time"> + description = <"The date and/or time when the entire procedure, or the last component of a multicomponent procedure, was finished."> + > + ["id59"] = < + text = <"Urgency"> + description = <"Urgency of the procedure."> + > + ["id58"] = < + text = <"Receiver"> + description = <"Details about the healthcare provider or organisation receiving the request for service."> + > + ["id57"] = < + text = <"Receiver order identifier"> + description = <"The ID assigned to the order by the healthcare provider or organisation receiving the request for service. This is also referred to as Filler Order Identifier."> + > + ["id56"] = < + text = <"Requestor"> + description = <"Details about the healthcare provider or organisation requesting the service."> + > + ["id55"] = < + text = <"Requestor order identifier"> + description = <"The local ID assigned to the order by the healthcare provider or organisation requesting the service."> + > + ["id54"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"Description"> + description = <"Narrative description about the procedure, as appropriate for the pathway step."> + > + ["id49"] = < + text = <"Outcome"> + description = <"Outcome of procedure performed."> + > + ["id48"] = < + text = <"Procedure performed"> + description = <"The procedure, or subprocedure in a multicomponent procedure, has been performed."> + > + ["at48"] = < + text = <"Procedure performed"> + description = <"The procedure, or subprocedure in a multicomponent procedure, has been performed."> + > + ["id44"] = < + text = <"Procedure completed"> + description = <"The procedure has been performed and all associated clinical activities completed."> + > + ["at44"] = < + text = <"Procedure completed"> + description = <"The procedure has been performed and all associated clinical activities completed."> + > + ["id42"] = < + text = <"Procedure aborted"> + description = <"The procedure has been aborted."> + > + ["at42"] = < + text = <"Procedure aborted"> + description = <"The procedure has been aborted."> + > + ["id41"] = < + text = <"Procedure suspended"> + description = <"The procedure has been suspended."> + > + ["at41"] = < + text = <"Procedure suspended"> + description = <"The procedure has been suspended."> + > + ["id40"] = < + text = <"Procedure cancelled"> + description = <"The planned procedure has been cancelled prior to commencement."> + > + ["at40"] = < + text = <"Procedure cancelled"> + description = <"The planned procedure has been cancelled prior to commencement."> + > + ["id39"] = < + text = <"Procedure postponed"> + description = <"The procedure has been postponed."> + > + ["at39"] = < + text = <"Procedure postponed"> + description = <"The procedure has been postponed."> + > + ["id37"] = < + text = <"Procedure scheduled"> + description = <"The procedure has been scheduled."> + > + ["at37"] = < + text = <"Procedure scheduled"> + description = <"The procedure has been scheduled."> + > + ["id36"] = < + text = <"X - Procedure request sent"> + description = <"This pathway step has been deprecated as it was incorrectly associated with 'initial' status - use the new 'Procedure request sent' (at0007) pathway step which is correctly associated with 'planned' status."> + > + ["at36"] = < + text = <"X - Procedure request sent"> + description = <"This pathway step has been deprecated as it was incorrectly associated with 'initial' status - use the new 'Procedure request sent' (at0007) pathway step which is correctly associated with 'planned' status."> + > + ["id35"] = < + text = <"X - Procedure planned"> + description = <"This pathway step has been deprecated as it was incorrectly associated with 'initial' status - use the new 'Procedure planned' (at0004) pathway step which is correctly associated with 'planned' status."> + > + ["at35"] = < + text = <"X - Procedure planned"> + description = <"This pathway step has been deprecated as it was incorrectly associated with 'initial' status - use the new 'Procedure planned' (at0004) pathway step which is correctly associated with 'planned' status."> + > + ["id15"] = < + text = <"Reason"> + description = <"Reason that the activity or care pathway step for the identified procedure was carried out."> + > + ["id8"] = < + text = <"Procedure request sent"> + description = <"Request for procedure sent."> + > + ["at8"] = < + text = <"Procedure request sent"> + description = <"Request for procedure sent."> + > + ["id7"] = < + text = <"Complication"> + description = <"Details about any complication arising from the procedure."> + > + ["id6"] = < + text = <"Comment"> + description = <"Additional narrative about the activity or care pathway step not captured in other fields."> + > + ["id5"] = < + text = <"Procedure planned"> + description = <"The procedure to be undertaken is planned."> + > + ["at5"] = < + text = <"Procedure planned"> + description = <"The procedure to be undertaken is planned."> + > + ["id4"] = < + text = <"Procedure detail"> + description = <"Structured information about the procedure."> + > + ["id3"] = < + text = <"Procedure name"> + description = <"Identification of the procedure by name."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Procedure"> + description = <"A clinical activity carried out for screening, investigative, diagnostic, curative, therapeutic, evaluative or palliative purposes."> + > + > + ["ar-sy"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"*Procedural difficulty(en)"> + description = <"*Difficulties or issues encountered during the procedure.(en)"> + > + ["id69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["at69"] = < + text = <"*Procedure commenced(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been commenced.(en)"> + > + ["id68"] = < + text = <"*Procedure type(en)"> + description = <"*The type of procedure.(en)"> + > + ["id67"] = < + text = <"*Scheduled date/time(en)"> + description = <"*The date and/or time on which the procedure is intended to be performed.(en)"> + > + ["id66"] = < + text = <"*Method(en)"> + description = <"*Identification of specific method or technique for the procedure.(en)"> + > + ["id65"] = < + text = <"*Extension(en)"> + description = <"*Additional information required to capture local content or to align with other reference models/formalisms.(en)"> + > + ["id64"] = < + text = <"*Body site(en)"> + description = <"*Identification of the body site for the procedure.(en)"> + > + ["id63"] = < + text = <"*Multimedia(en)"> + description = <"*Mulitimedia representation of a performed procedure.(en)"> + > + ["id62"] = < + text = <"*Total duration(en)"> + description = <"*The total amount of time taken to complete the procedure, which may include time spent during the active phase of the procedure plus time during which the procedure was suspended.(en)"> + > + ["id61"] = < + text = <"*Final end date/time(en)"> + description = <"*The date and/or time when the entire procedure, or the last component of a multicomponent procedure, was finished.(en)"> + > + ["id59"] = < + text = <"*Urgency(en)"> + description = <"*Urgency of the procedure.(en)"> + > + ["id58"] = < + text = <"المستقبِل"> + description = <"تفاصيل حول مقدم الخدمة الصحية أو المؤسسة التي تستقبل طلب الخدمة."> + > + ["id57"] = < + text = <"*Receiver order identifier(en)"> + description = <"*The ID assigned to the order by the healthcare provider or organisation receiving the request for service. This is also referred to as Filler Order Identifier.(en)"> + > + ["id56"] = < + text = <"الطالب"> + description = <"تفاصيل حول مقدم الخدمة الصحية أو المؤسسة التي تطلب الخدمة"> + > + ["id55"] = < + text = <"*Requestor order identifier(en)"> + description = <"*The local ID assigned to the order by the healthcare provider or organisation requesting the service.(en)"> + > + ["id54"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"*Description(en)"> + description = <"*Narrative description about the procedure, as appropriate for the pathway step.(en)"> + > + ["id49"] = < + text = <"*Outcome(en)"> + description = <"*Outcome of procedure performed.(en)"> + > + ["id48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["at48"] = < + text = <"*Procedure performed(en)"> + description = <"*The procedure, or subprocedure in a multicomponent procedure, has been performed.(en)"> + > + ["id44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["at44"] = < + text = <"*Procedure completed(en)"> + description = <"*The procedure has been performed and all associated clinical activities completed.(en)"> + > + ["id42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["at42"] = < + text = <"*Procedure aborted(en)"> + description = <"*The procedure has been aborted.(en)"> + > + ["id41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["at41"] = < + text = <"*Procedure suspended(en)"> + description = <"*The procedure has been suspended.(en)"> + > + ["id40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["at40"] = < + text = <"*Procedure cancelled(en)"> + description = <"*The planned procedure has been cancelled prior to commencement.(en)"> + > + ["id39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["at39"] = < + text = <"*Procedure postponed(en)"> + description = <"*The procedure has been postponed.(en)"> + > + ["id37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["at37"] = < + text = <"*Procedure scheduled(en)"> + description = <"*The procedure has been scheduled.(en)"> + > + ["id36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["at36"] = < + text = <"*Procedure request sent(en)"> + description = <"*Request for procedure sent.(en)"> + > + ["id35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["at35"] = < + text = <"*Procedure planned(en)"> + description = <"*The procedure to be undertaken is planned.(en)"> + > + ["id15"] = < + text = <"*Reason(en)"> + description = <"*Reason that the activity or care pathway step for the identified procedure was carried out.(en)"> + > + ["id8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["at8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["id7"] = < + text = <"*Complication(en)"> + description = <"*Details about any complication arising from the procedure.(en)"> + > + ["id6"] = < + text = <"*Comment(en)"> + description = <"*Additional narrative about the activity or care pathway step not captured in other fields.(en)"> + > + ["id5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["at5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["id4"] = < + text = <"*Procedure detail(en)"> + description = <"*Structured information about the procedure. Use to capture detailed, structured information about anatomical location, method & technique, equipment used, devices implanted, results, findings etc.(en)"> + > + ["id3"] = < + text = <"*Procedure name(en)"> + description = <"*Identification of the procedure by name.(en)"> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"*Procedure(en)"> + description = <"*A clinical activity carried out for screening, investigative, diagnostic, curative, therapeutic, evaluative or palliative purposes.(en)"> + > + > + ["es"] = < + ["at9004"] = < + text = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9004, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9126"] = < + text = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9126, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9001"] = < + text = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9001, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9002"] = < + text = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9002, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9003"] = < + text = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9003, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9005"] = < + text = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9005, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9006"] = < + text = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9006, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["at9007"] = < + text = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9007, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id71"] = < + text = <"*Indication (en)"> + description = <"*The clinical or process-related reason for the procedure. (en)"> + > + ["id70"] = < + text = <"*Procedural difficulty(en)"> + description = <"*Difficulties or issues encountered during the procedure.(en)"> + > + ["id69"] = < + text = <"Procedimiento iniciado"> + description = <"Procedimiento iniciado"> + > + ["at69"] = < + text = <"Procedimiento iniciado"> + description = <"Procedimiento iniciado"> + > + ["id68"] = < + text = <"*Procedure type(en)"> + description = <"*The type of procedure.(en)"> + > + ["id67"] = < + text = <"Fecha coordinada"> + description = <"Fecha y hora en el cual se coordinó la realización del procedimiento"> + > + ["id66"] = < + text = <"Método"> + description = <"Identificación del método o técnica específica para el procedimiento"> + > + ["id65"] = < + text = <"Extensión"> + description = <"Información adicional requerida para capturar contenido local o alinear el arquetipo a otros modelos o formalismos"> + > + ["id64"] = < + text = <"Zona corporal"> + description = <"Identificación de la zona del cuerpo para el procedimiento."> + > + ["id63"] = < + text = <"Multimedia"> + description = <"Representación multimedia del procedimiento realizado"> + > + ["id62"] = < + text = <"Duración"> + description = <"Cantidad total de tiempo que tomó la ejecución del procedimiento."> + > + ["id61"] = < + text = <"Fecha de finalización"> + description = <"Fecha y hora cuando el procedimiento fue finalizado en su totalidad"> + > + ["id59"] = < + text = <"Urgencia"> + description = <"Urgencia del procedimiento"> + > + ["id58"] = < + text = <"Receptor"> + description = <"Detalles sobre el profesional, departamento u organización que debe realizar el procedimiento"> + > + ["id57"] = < + text = <"*Receiver order identifier(en)"> + description = <"*The ID assigned to the order by the healthcare provider or organisation receiving the request for service. This is also referred to as Filler Order Identifier.(en)"> + > + ["id56"] = < + text = <"Solicitante"> + description = <"Detalles del proveedor de salud que solicita la realización del procedimiento"> + > + ["id55"] = < + text = <"*Requestor order identifier(en)"> + description = <"*The local ID assigned to the order by the healthcare provider or organisation requesting the service.(en)"> + > + ["id54"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id50"] = < + text = <"Descripción"> + description = <"Descripción narrativa del procedimiento"> + > + ["id49"] = < + text = <"Resultado"> + description = <"Resultado del procedimiento realizado"> + > + ["id48"] = < + text = <"Procedimiento realizado"> + description = <"Procedimiento realizado"> + > + ["at48"] = < + text = <"Procedimiento realizado"> + description = <"Procedimiento realizado"> + > + ["id44"] = < + text = <"Procedimiento completado"> + description = <"Procedimiento completado"> + > + ["at44"] = < + text = <"Procedimiento completado"> + description = <"Procedimiento completado"> + > + ["id42"] = < + text = <"Procedimiento interrumpido"> + description = <"Procedimiento interrumpido"> + > + ["at42"] = < + text = <"Procedimiento interrumpido"> + description = <"Procedimiento interrumpido"> + > + ["id41"] = < + text = <"Procedimiento suspendido"> + description = <"Procedimiento suspendido"> + > + ["at41"] = < + text = <"Procedimiento suspendido"> + description = <"Procedimiento suspendido"> + > + ["id40"] = < + text = <"Procedimiento cancelado"> + description = <"Procedimiento cancelado antes de comenzar"> + > + ["at40"] = < + text = <"Procedimiento cancelado"> + description = <"Procedimiento cancelado antes de comenzar"> + > + ["id39"] = < + text = <"Procedimiento pospuesto"> + description = <"Procedimiento pospuesto"> + > + ["at39"] = < + text = <"Procedimiento pospuesto"> + description = <"Procedimiento pospuesto"> + > + ["id37"] = < + text = <"Procedimiento coordinado"> + description = <"Procedimiento coordinado"> + > + ["at37"] = < + text = <"Procedimiento coordinado"> + description = <"Procedimiento coordinado"> + > + ["id36"] = < + text = <"Solicitud de procedimiento enviada"> + description = <"Solicitud de procedimiento enviada"> + > + ["at36"] = < + text = <"Solicitud de procedimiento enviada"> + description = <"Solicitud de procedimiento enviada"> + > + ["id35"] = < + text = <"Procedimiento planificado"> + description = <"Está previsto que el procedimiento que se ha llevado a cabo."> + > + ["at35"] = < + text = <"Procedimiento planificado"> + description = <"Está previsto que el procedimiento que se ha llevado a cabo."> + > + ["id15"] = < + text = <"Motivo"> + description = <"Motivo por el cual una actividad o paso de la vía clínica del arquetipo fue ejecutado como parte del procedimiento"> + > + ["id8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["at8"] = < + text = <"*Procedure request sent (en)"> + description = <"*"> + > + ["id7"] = < + text = <"Complicación"> + description = <"Detalles de cualquier complicación surgida durante la ejecución del procedimiento"> + > + ["id6"] = < + text = <"Comentario"> + description = <"Comentario narrativo adicional acerca de las actividades llevadas a cabo en la ejecución del procedimiento y que no son capturadas por otros campos"> + > + ["id5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["at5"] = < + text = <"*Procedure planned (en)"> + description = <"*"> + > + ["id4"] = < + text = <"Detalles"> + description = <"Información estructurada de los detalles del procedimiento"> + > + ["id3"] = < + text = <"Nombre del procedimiento"> + description = <"Nombre del procedimiento"> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Procedimiento"> + description = <"Una actividad clínica llevada a cabo para la detección, investigación, diagnóstico, curativos, terapéuticos, de evaluación o con fines paliativos."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9004"] = + ["at9000"] = + ["at9126"] = + ["at9001"] = + ["at9002"] = + ["at9003"] = + ["at9005"] = + ["at9006"] = + ["at9007"] = + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls b/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls new file mode 100644 index 000000000..56b53202d --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls @@ -0,0 +1,242 @@ +archetype (adl_version=2.0.6; rm_release=1.0.4; generated; uid=aab23408-3f8d-4bc8-b214-34af97e9abbd; build_uid=d62dca65-177e-46cc-b2e9-1ce996b49645) + openEHR-EHR-COMPOSITION.health_summary.v1.0.1 + +language + original_language = <[ISO_639-1::en]> + translations = < + ["nb"] = < + language = <[ISO_639-1::nb]> + author = < + ["name"] = <"John Tore Valand"> + ["organisation"] = <"Helse Bergen HF"> + > + > + ["pt-br"] = < + language = <[ISO_639-1::pt-br]> + author = < + ["name"] = <"Adriana Kitajima, Débora Farage, Fernanda Maia, Laíse Figueiredo, Marivan Abrahão"> + ["organisation"] = <"Core Consulting"> + ["email"] = <"contato@coreconsulting.com.br"> + > + accreditation = <"Hospital Alemão Oswaldo Cruz (HAOC)"> + > + ["es"] = < + language = <[ISO_639-1::es]> + author = < + ["name"] = <"Diego Bosca"> + ["organisation"] = <"VeraTech for Health"> + ["email"] = <"yampeku@gmail.com"> + > + accreditation = <"English C1, Spanish native"> + > + > + +description + original_author = < + ["name"] = <"Heather Leslie"> + ["organisation"] = <"Atomica Informatics"> + ["email"] = <"heather.leslie@atomicainformatics.com"> + ["date"] = <"2015-10-01"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Vebjoern Arntzen, Oslo university hospital, Norway", "Silje Ljosland Bakke, National ICT Norway, Norway (openEHR Editor)", "Sistine Barretto-Daniels, Ocean Informatics, Australia", "Lars Bitsch-Larsen, Haukeland University hospital, Norway", "Heather Grain, Llewelyn Grain Informatics, Australia", "Lars Karlsen, DIPS ASA, Norway", "Heather Leslie, Atomica Informatics, Australia (openEHR Editor)", "Yang Lu, University of Melbourne, Australia", "Ian McNicoll, freshEHR Clinical Informatics, United Kingdom (openEHR Editor)", "Andrej Orel, Marand d.o.o., Slovenia"> + lifecycle_state = <"published"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + other_details = < + ["current_contact"] = <"Heather Leslie, Atomica Informatics"> + ["MD5-CAM-1.0.1"] = <"05F3E1D9A0891A37F1DD10A47CCFA472"> + > + details = < + ["nb"] = < + language = <[ISO_639-1::nb]> + purpose = <"For å registrere et sammendrag av helseinformasjon om et individ på et spesifisert tidspunkt."> + keywords = <"sammendrag", "oversikt", "synopsis", "sammenfatning", "status"> + use = <"Brukes som en generisk konteiner for et sammendrag eller en oversikt over pasientens helse og/eller omsorgsstatus på et spesifikt tidspunkt. + + Forfatteren av helsesammendraget er vanligvis en kliniker som er kjent med alle de relevante aspektene om individets helse som sammendraget består av. + + Formålet med helsesammendraget kan variere utfra ulike kontekster, eksempler på helsesammendrag kan være en oversikt over alle relevant viktige aspekter knyttet til pasientens helse og/eller omsorg eller et sammendrag av informasjon fokusert på et begrenset område av individets helse. + + Mottakere av helsesammendraget vil variere utfra sammendragets primærfokus og kan være: + - Framtidige helsetjenesteytere. + - Klinikere som ikke har noe personlig kjennskap til individet, men som må yte helsetjenester, som akuttbehandling eller behandling når individet er på reise. + som ved diabetes eller gravidiet. + - Individet selv. + + Det er ikke satt begrensinger på hovedkomponenten Section/content. Dette gjør at man kan legge til hvilken som helst SECTION eller ENTRY arketype som er passende for det kliniske formålet i et templat. + + Selv om det kliniske innholdet er ubegrenset, gir denne arketypen muligheter for enkle spørringer etter alle sammendrag av helseinformasjon i en journal."> + misuse = <"Brukes ikke for å registrere detaljer om en enkelt klinisk konsultasjon, prosedyre, prøve, vurdering eller lignende."> + > + ["pt-br"] = < + language = <[ISO_639-1::pt-br]> + purpose = <"Gravar um sumário de informações de saúde sobre um indivíduo, representando um subconjunto de seu registro de saúde em um ponto específico no tempo."> + keywords = <"sumário", "sinopse", "visão geral", "estado"> + use = <"Usado como um repositório genérico para gravar um sumário ou visão geral da saúde e/ou situação do bem-estar de um paciente como um retrato da sua saúde em um ponto específico do tempo. + + O autor de um sumário de saúde é usualmente um clínico que está familiarizado com todos os aspectos relevantes da saúde do indivíduo, que é o conteúdo do sumário. + + O escopo de um sumário de saúde pode variar em diferentes contextos, indo de uma visão geral de todos os aspectos principais da saúde e/ou bem-estar do indivíduo a um sumário de informação focado em um aspecto restrito da saúde do indivíduo. + + Os leitores alvo do sumário de saúde irão variar de acordo com o propósito primário e o foco do sumário, e pode incluir: + - qualquer provedor de saúde futuro; + - clínicos que não tem nenhum conhecimento pessoal do indivíduo, mas são requeridos a fornecer cuidado em saúde, como no tratamento de emergência ou quando o indivíduo está em trânsito; + - clínicos que administram apenas aspectos específicos da saúde do indivíduo, como diabetes e gravidez; e + - os próprios indivíduos. + + Os componentes das Seções/Conteúdo principais foram deixados sem restrição deliberadamente. Isso permite que os campos sejam populados com quaisquer arquétipos tipo SECTION ou ENTRY apropriados para o propósito clínico dentro do modelo. + + Embora o conteúdo clínico seja irrestrito, este arquétipo suporta buscas simples para todos os sumários de saúde que podem estar contidos dentro de um registro de saúde."> + misuse = <"Não deve ser usado para gravar detalhes sobre uma única consulta clínica, procedimento, teste ou avaliação, etc."> + > + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record a summary of health information about an individual, representing a subset of their health record at a specified point in time."> + keywords = <"summary", "synopsis", "overview", "status"> + use = <"Use as a generic containter to record a summary or overview of a patient's health and/or welfare status as a snapshot of their health at a specified point in time. + + The author of a health summary is usually a clinician who is familiar with the all of the relevant aspects of the individual's health that is the content of the summary. + + The scope of a health summary can vary in different contexts, ranging from an overview of all key aspects of the individual's health and/or welfare to a summary of information focused on a limited aspect of the individual's health. + + The intended readers of the health summary will vary according to the primary purpose and focus of the summary, and may include: + - any future healthcare providers; + - clinicians who have no personal knowledge of the individual but are required to provide healthcare, such as emergency treatment or when the individual is travelling; + - clinicians managing only specific aspects of the individual's health, such as diabetes or pregnancy; and + - the individual themselves. + + The main Sections/Content component has been deliberately left unconstrained. This will allow it to be populated with any SECTION or ENTRY archetypes appropriate for the clinical purpose within a template. + + Even though clinical content is unconstrained, this archetype supports simple querying for all Health summaries that might be contained within a health record."> + misuse = <"Not to be used to record details about a single clinical consultation, procedure, test or assessment etc."> + copyright = <"© openEHR Foundation"> + > + ["es"] = < + language = <[ISO_639-1::es]> + purpose = <"Para registrar un resumen de información de salud sobre un individuo, que representa un subconjunto de su registro de salud en un momento de tiempo específico."> + keywords = <"resumen", "sinopsis", "revisión", "estatus"> + use = <"Usar como un contenedor genérico para registrar un resumen o revisión de la salud y/o bienestar de un paciente como una instantánea de su salud en un punto especificado en el tiempo. + + El autor de un resumen de salud es normalmente un profesional clínico familiar con todos los aspectos relevantes de la salud del individuo que compone el contenido del informe. + + El alcance de un resumen de salud puede variar en diferentes contextos, extendiéndose desde una revisión de todos los aspectos claves de la salud y/o bienestar del individuo a un resumen de la información focalizada en un aspecto en concreto de la salud del individuo. + + Los destinatarios de un resumen de salud variarán de acuerdo con el propósito principal del resumen, y puede incluir: + - cualquier proveedor de salud futuro del paciente; + - personal clínico que no tengan conocimiento personal del individuo pero tengan que proveer cuidados de salud al mismo, como pueden ser cuidados de urgencias o cuando el individuo se encuentra de viaje: + - personal clínico que gestione solamente aspectos específicos de la salud del individuo, tal como diabetes o embarazos; + - los propios individuos. + + Las secciones y contenidos principales se han dejado deliberadamente sin restringir. Esto permitirá popularlos con cualquier número de arquetipos Sección (SECTION) o Entrada (ENTRY) apropiados para el propósito clínico dentro de una plantilla. + + Incluso si el contenido clínico no se ha restringido, este arquetipo soporta consultas sencillas para obtener todos los resúmenes de salud que puedan estar contenidos dentro de un registro de salud"> + misuse = <"No debe ser usado para registrar detalles sobre una única consulta, procedimiento, prueba o evaluación clínica, etc."> + > + > + +definition + COMPOSITION[id1] matches { -- Health summary + category matches { + DV_CODED_TEXT[id9001] matches { + defining_code matches {[at9000]} + } + } + context matches { + EVENT_CONTEXT[id9002] matches { + other_context matches { + ITEM_TREE[id2] matches { -- Tree + items cardinality matches {0..*; unordered} matches { + allow_archetype CLUSTER[id3] matches { -- Extension + include + archetype_id/value matches {/.*/} + } + } + } + } + } + } + } + +terminology + term_definitions = < + ["nb"] = < + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id3"] = < + text = <"Tilleggsinformasjon"> + description = <"Ytterligere informasjon som er nødvendig for å registrere lokalt innhold/kontekst, eller for å sammenstille med andre referansemodeller/formalismer."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Sammendrag av helseinformasjon"> + description = <"Generisk dokument som inneholder sammendrag av helseinformasjon om et individ."> + > + > + ["pt-br"] = < + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id3"] = < + text = <"Extensão"> + description = <"Informações adicionais necessárias para capturar o conteúdo local ou para alinhar com outros modelos de referência/ formalismo."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Sumário de saúde"> + description = <"Documento genérico contendo um sumário das informações de saúde sobre um indivíduo."> + > + > + ["en"] = < + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id3"] = < + text = <"Extension"> + description = <"Additional information required to capture local content or to align with other reference models/formalisms."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Health summary"> + description = <"Generic document containing a summary of health information about an individual."> + > + > + ["es"] = < + ["at9000"] = < + text = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + description = <"Term binding for at9000, translation not known in ADL 1.4 -> ADL 2 converter"> + > + ["id3"] = < + text = <"Extensión"> + description = <"Información adicional requerida para capturar contenidos locales o para alinearse con otros modelos de referencia o formalismos."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Resumen de salud"> + description = <"Documento genérico que contiene un resumen de la información de salud sobre un individuo."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls b/opt14/src/test/resources/adl2/openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls new file mode 100644 index 000000000..7368ade86 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls @@ -0,0 +1,56 @@ +archetype (adl_version=2.0.6; rm_release=1.0.4; generated) + openEHR-EHR-SECTION.procedures_rcp.v1.0.0 + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Ian McNicoll"> + ["organisation"] = <"freshEHR Clinical Informatics, UK"> + ["email"] = <"ian@freshehr.com"> + ["date"] = <"2014-07-24"> + > + lifecycle_state = <"0"> + references = < + ["1"] = <"Health and Social Care Information Centre, Academy of Medical Royal Colleges (2013) Standards for the Clinical Structure and Content of Patient Records. HSCIC, Leeds."> + ["2"] = <"Available from: https://www.rcplondon.ac.uk/sites/default/files/standards-for-the-clinical-structure-and-content-of-patient-records.pdf [Accessed July 22, 2014]"> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"77530BD1AE5D2F25431190EC9984A04C"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To organise Procedures details within a standardised record heading as recommended by the UK Academy of Royal Colleges (AoMRC). + + Suggested 'subheading' content includes ... + + Procedure: + The therapeutic procedure performed. This could include site and must include laterality where applicable. + + Complications related to procedure: + Details of any intra-operative complications encountered during the procedure, arising during the patient’s stay in the recovery unit or directly attributable to the procedure. The intent is to be plain text and/ or images but use codes wherever possible. + + Specific anaesthesia issues: + Details of any adverse reaction to any anaesthetic agents including local + anaesthesia. + Problematic intubation, transfusion reaction, etc."> + use = <""> + misuse = <""> + copyright = <"© Clinical Models UK"> + > + > + +definition + SECTION[id1] -- Procedures + +terminology + term_definitions = < + ["en"] = < + ["id1"] = < + text = <"Procedures"> + description = <"Procedures heading (AoMRC)."> + > + > + > diff --git a/opt14/src/test/resources/procedure_list.opt b/opt14/src/test/resources/procedure_list.opt new file mode 100644 index 000000000..20e1c7b72 --- /dev/null +++ b/opt14/src/test/resources/procedure_list.opt @@ -0,0 +1,2183 @@ + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 806003fdf..7d1bd575d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,3 +6,4 @@ include 'archie-all' include 'i18n' include 'test-rm' include 'openehr-terminology' +include 'opt14' From fd0cd10b10921a618d214f5be918c8c3e73f012d Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 4 Jan 2021 12:33:54 +0100 Subject: [PATCH 03/36] Parse domain specific types, add conversion config to archie-utils --- README.md | 5 +- .../Adl14CComplexObjectParser.java | 250 ++++++++++-------- archie-utils/build.gradle | 2 +- .../OpenEHRADL14ConversionConfiguration.java | 9 +- .../adl14conversionconfiguration.json | 25 ++ ...Converter.java => BaseTypesConverter.java} | 10 +- .../archie/opt14/DefinitionConverter.java | 10 +- .../archie/opt14/DescriptionConverter.java | 14 +- .../archie/opt14/DomainTypeConverter.java | 73 +++++ .../nedap/archie/opt14/Opt14Converter.java | 3 + .../archie/opt14/PrimitiveConverter.java | 2 +- .../archie/opt14/TerminologyConverter.java | 2 +- .../OpenEHRADL14ConversionConfiguration.java | 0 .../adl14/ArchetypeSlotConversionTest.java | 2 +- .../archie/adl14/LargeSetOfADL14sTest.java | 2 +- .../adl14/PreviousLogConversionTest.java | 6 +- 16 files changed, 276 insertions(+), 139 deletions(-) rename tools/src/test/java/com/nedap/archie/adl14/ConversionConfigForTest.java => archie-utils/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java (64%) create mode 100644 archie-utils/src/main/resources/adl14conversionconfiguration.json rename opt14/src/main/java/com/nedap/archie/opt14/{IntervalConverter.java => BaseTypesConverter.java} (85%) create mode 100644 tools/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java diff --git a/README.md b/README.md index 5fb296d6a..459cd3a3b 100644 --- a/README.md +++ b/README.md @@ -453,7 +453,8 @@ The following features are experimental. This means its working or API will like Starting from version 0.7, Archie can import ADL 1.4 files, and convert them to ADL 2. To do so, do the following: ```java -ADL14ConversionConfiguration conversionConfiguration = new ADL14ConversionConfiguration(); +//this is the default configuration. You can implement your own if you want to +ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); List archetypes = new ArrayList<>(); @@ -498,7 +499,7 @@ The conversion log can be serialized to a file for storage using Jackson, so it ### Conversion Configuration -You may have noticed an instance of `ADL14ConversionConfiguration` in the previous example. In this configuration the mapping from term codes as used in ADL 1.4 to term URIs as used in ADL 2 can be specified. See the `ConversionConfigForTest.java` file for an example on how this works, and how this can be serialized to a file, and the file `/tools/src/test/java/com/nedap/archie/adl14/configuration.json` for an example of a simple serialized configuration that contains sane defaults for snomed, loinc and openehr URIs. +You may have noticed an instance of `ADL14ConversionConfiguration` in the previous example. In this configuration the mapping from term codes as used in ADL 1.4 to term URIs as used in ADL 2 can be specified. The archie-utils package provides a default configuration in the class `OpenEHRADL14ConversionConfiguration`. It is possible to supply your own, see the default implementation on how this works, and how this can be serialized to a file, and the file `/archie-utils/src/main/resources/adl14conversionconfiguration.json` for an example of a simple serialized configuration that contains sane defaults for snomed, loinc and openehr URIs. If you leave the configuration empty, the converter will fall back to a default URI conversion. diff --git a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java index 51f7526ce..0d0893af8 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java +++ b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java @@ -163,17 +163,15 @@ private CObject parseNonPrimitiveObject(C_non_primitive_objectContext objectCont } else if (objectContext.archetype_slot() != null) { return parseArchetypeSlot(objectContext.archetype_slot()); } else if(objectContext.domainSpecificExtension() != null) { - CComplexObject result = new CComplexObject(); + String type = objectContext.domainSpecificExtension().type_id().getText(); if(type.equalsIgnoreCase("C_DV_QUANTITY")) { - parseCDVQuantity(objectContext, result); + return parseCDVQuantity(objectContext); } else if (type.equalsIgnoreCase("C_DV_ORDINAL")) { - parseCDVOrdinal(objectContext, result); + return parseCDVOrdinal(objectContext); } else { throw new IllegalArgumentException("unknown domain specific type: " + type); } - - return result; } else if (objectContext.c_ordinal() != null) { C_ordinalContext ordinalContext = objectContext.c_ordinal(); @@ -208,137 +206,163 @@ private CObject parseNonPrimitiveObject(C_non_primitive_objectContext objectCont throw new IllegalArgumentException("unknown non-primitive object: " + objectContext.getText()); } - private void parseCDVOrdinal(C_non_primitive_objectContext objectContext, CComplexObject result) { - result.setRmTypeName("DV_ORDINAL"); + private CComplexObject parseCDVOrdinal(C_non_primitive_objectContext objectContext) { + if(objectContext.domainSpecificExtension().odin_text() != null) { CDVOrdinal cdvOrdinal = odinParser.convert(objectContext.domainSpecificExtension().odin_text().getText(), CDVOrdinal.class); - if (cdvOrdinal.getList() != null && !cdvOrdinal.getList().isEmpty()) { - CAttributeTuple tuple = new CAttributeTuple(); - boolean hasValue = cdvOrdinal.getList().values().stream().anyMatch(i -> i.getValue() != null); - boolean hasSymbol = cdvOrdinal.getList().values().stream().anyMatch(i -> i.getSymbol() != null); + return convertCDVOrdinal(cdvOrdinal); + } else { + CComplexObject result = new CComplexObject(); + result.setRmTypeName("DV_ORDINAL"); + return result; + } + } + public static CComplexObject convertCDVOrdinal(CDVOrdinal cdvOrdinal) { + CComplexObject result = new CComplexObject(); + result.setRmTypeName("DV_ORDINAL"); - if (hasValue) { - tuple.addMember(new CAttribute("value")); - } - if (hasSymbol) { - tuple.addMember(new CAttribute("symbol")); - } + if (cdvOrdinal.getList() != null && !cdvOrdinal.getList().isEmpty()) { + CAttributeTuple tuple = new CAttributeTuple(); + boolean hasValue = cdvOrdinal.getList().values().stream().anyMatch(i -> i.getValue() != null); + boolean hasSymbol = cdvOrdinal.getList().values().stream().anyMatch(i -> i.getSymbol() != null); - for (CDVOrdinalItem item : cdvOrdinal.getList().values()) { - CPrimitiveTuple primitiveTuple = new CPrimitiveTuple(); - if(item.getValue() != null) { - primitiveTuple.addMember(item.getValueAdl2()); - } else if (hasValue) { - CInteger integer = new CInteger(); - integer.addConstraint(Interval.upperUnbounded(0L, true)); - primitiveTuple.addMember(integer); - } - if (item.getSymbol() != null) { - primitiveTuple.addMember(item.getSymbolAdl2()); - } else if (hasSymbol) { - CTerminologyCode code = new CTerminologyCode(); - primitiveTuple.addMember(code);//nothing we can do here! - } - tuple.addTuple(primitiveTuple); + if (hasValue) { + tuple.addMember(new CAttribute("value")); + } + if (hasSymbol) { + tuple.addMember(new CAttribute("symbol")); + } + + for (CDVOrdinalItem item : cdvOrdinal.getList().values()) { + CPrimitiveTuple primitiveTuple = new CPrimitiveTuple(); + if(item.getValue() != null) { + primitiveTuple.addMember(item.getValueAdl2()); + } else if (hasValue) { + CInteger integer = new CInteger(); + integer.addConstraint(Interval.upperUnbounded(0L, true)); + primitiveTuple.addMember(integer); } - result.addAttributeTuple(tuple); + if (item.getSymbol() != null) { + primitiveTuple.addMember(item.getSymbolAdl2()); + } else if (hasSymbol) { + CTerminologyCode code = new CTerminologyCode(); + primitiveTuple.addMember(code);//nothing we can do here! + } + + tuple.addTuple(primitiveTuple); } + result.addAttributeTuple(tuple); } + return result; } - private void parseCDVQuantity(C_non_primitive_objectContext objectContext, CComplexObject result) { - result.setRmTypeName("DV_QUANTITY"); + private CComplexObject parseCDVQuantity(C_non_primitive_objectContext objectContext) { + if(objectContext.domainSpecificExtension().odin_text() != null) { CDVQuantity cdvQuantity = odinParser.convert(objectContext.domainSpecificExtension().odin_text().getText(), CDVQuantity.class); - if(cdvQuantity.getProperty() != null) { - CAttribute property = new CAttribute("property"); - CTerminologyCode code = new CTerminologyCode(); - //will be converted later - code.addConstraint(cdvQuantity.getProperty().toString()); - property.addChild(code); - result.addAttribute(property); - } - if (cdvQuantity.getList() != null && !cdvQuantity.getList().isEmpty()) { - if(cdvQuantity.getList().size() == 1) { - CDVQuantityItem item = cdvQuantity.getList().values().iterator().next(); - if (item.getMagnitude() != null) { - CAttribute magnitude = new CAttribute("magnitude"); - CReal magnitudeAdl2 = item.getMagnitudeAdl2(); - magnitude.addChild(magnitudeAdl2); - result.addAttribute(magnitude); - if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getMagnitude() != null) { - Double assumedMagnitude = cdvQuantity.getAssumedValue().getMagnitude(); - magnitudeAdl2.setAssumedValue(assumedMagnitude); - } - } - if (item.getUnits() != null) { - CAttribute units = new CAttribute("units"); - CString unitsAdl2 = item.getUnitsAdl2(); - units.addChild(unitsAdl2); - result.addAttribute(units); - if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getUnits() != null) { - String assumedUnits = cdvQuantity.getAssumedValue().getUnits(); - unitsAdl2.setAssumedValue(assumedUnits); - } - } - if (item.getPrecision() != null) { - CAttribute precision = new CAttribute("precision"); - CInteger precisionAdl2 = item.getPrecisionAdl2(); - precision.addChild(precisionAdl2); - result.addAttribute(precision); - if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getPrecision() != null) { - Long assumedPrecision = cdvQuantity.getAssumedValue().getPrecision(); - precisionAdl2.setAssumedValue(assumedPrecision); - } + return convertCDvQuantity(cdvQuantity); + } else { + CComplexObject result = new CComplexObject(); + result.setRmTypeName("DV_QUANTITY"); + return result; + } + + } + + public static CComplexObject convertCDvQuantity(CDVQuantity cdvQuantity) { + + CComplexObject result = new CComplexObject(); + result.setRmTypeName("DV_QUANTITY"); + + if(cdvQuantity.getProperty() != null) { + CAttribute property = new CAttribute("property"); + CTerminologyCode code = new CTerminologyCode(); + //will be converted later + code.addConstraint(cdvQuantity.getProperty().toString()); + property.addChild(code); + result.addAttribute(property); + } + if (cdvQuantity.getList() != null && !cdvQuantity.getList().isEmpty()) { + if(cdvQuantity.getList().size() == 1) { + CDVQuantityItem item = cdvQuantity.getList().values().iterator().next(); + if (item.getMagnitude() != null) { + CAttribute magnitude = new CAttribute("magnitude"); + CReal magnitudeAdl2 = item.getMagnitudeAdl2(); + magnitude.addChild(magnitudeAdl2); + result.addAttribute(magnitude); + if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getMagnitude() != null) { + Double assumedMagnitude = cdvQuantity.getAssumedValue().getMagnitude(); + magnitudeAdl2.setAssumedValue(assumedMagnitude); } - } else { - CAttributeTuple tuple = new CAttributeTuple(); - boolean hasMagnitude = cdvQuantity.getList().values().stream().anyMatch(i -> i.getMagnitude() != null); - boolean hasUnits = cdvQuantity.getList().values().stream().anyMatch(i -> i.getUnits() != null); - boolean hasPrecision = cdvQuantity.getList().values().stream().anyMatch(i -> i.getPrecision() != null); - - if (hasMagnitude) { - tuple.addMember(new CAttribute("magnitude")); + } + if (item.getUnits() != null) { + CAttribute units = new CAttribute("units"); + CString unitsAdl2 = item.getUnitsAdl2(); + units.addChild(unitsAdl2); + result.addAttribute(units); + if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getUnits() != null) { + String assumedUnits = cdvQuantity.getAssumedValue().getUnits(); + unitsAdl2.setAssumedValue(assumedUnits); } - if (hasUnits) { - tuple.addMember(new CAttribute("units")); + } + if (item.getPrecision() != null) { + CAttribute precision = new CAttribute("precision"); + CInteger precisionAdl2 = item.getPrecisionAdl2(); + precision.addChild(precisionAdl2); + result.addAttribute(precision); + if(cdvQuantity.getAssumedValue() != null && cdvQuantity.getAssumedValue().getPrecision() != null) { + Long assumedPrecision = cdvQuantity.getAssumedValue().getPrecision(); + precisionAdl2.setAssumedValue(assumedPrecision); } - if (hasPrecision) { - tuple.addMember(new CAttribute("precision")); + } + } else { + CAttributeTuple tuple = new CAttributeTuple(); + boolean hasMagnitude = cdvQuantity.getList().values().stream().anyMatch(i -> i.getMagnitude() != null); + boolean hasUnits = cdvQuantity.getList().values().stream().anyMatch(i -> i.getUnits() != null); + boolean hasPrecision = cdvQuantity.getList().values().stream().anyMatch(i -> i.getPrecision() != null); + + if (hasMagnitude) { + tuple.addMember(new CAttribute("magnitude")); + } + if (hasUnits) { + tuple.addMember(new CAttribute("units")); + } + if (hasPrecision) { + tuple.addMember(new CAttribute("precision")); + } + for (CDVQuantityItem item : cdvQuantity.getList().values()) { + CPrimitiveTuple primitiveTuple = new CPrimitiveTuple(); + if (item.getMagnitude() != null) { + primitiveTuple.addMember(item.getMagnitudeAdl2()); + } else if (hasMagnitude) { + CReal cReal = new CReal(); + cReal.addConstraint(Interval.upperUnbounded(0.0, true)); + primitiveTuple.addMember(cReal); } - for (CDVQuantityItem item : cdvQuantity.getList().values()) { - CPrimitiveTuple primitiveTuple = new CPrimitiveTuple(); - if (item.getMagnitude() != null) { - primitiveTuple.addMember(item.getMagnitudeAdl2()); - } else if (hasMagnitude) { - CReal cReal = new CReal(); - cReal.addConstraint(Interval.upperUnbounded(0.0, true)); - primitiveTuple.addMember(cReal); - } - if (item.getUnits() != null) { - primitiveTuple.addMember(item.getUnitsAdl2()); - } else if (hasUnits) { - primitiveTuple.addMember(new CString("/.*/")); - } + if (item.getUnits() != null) { + primitiveTuple.addMember(item.getUnitsAdl2()); + } else if (hasUnits) { + primitiveTuple.addMember(new CString("/.*/")); + } - if (item.getPrecision() != null) { - primitiveTuple.addMember(item.getPrecisionAdl2()); - } else if (hasPrecision) { - CInteger cInteger = new CInteger(); - cInteger.addConstraint(Interval.upperUnbounded(0l, true)); - primitiveTuple.addMember(cInteger); - } - tuple.addTuple(primitiveTuple); + if (item.getPrecision() != null) { + primitiveTuple.addMember(item.getPrecisionAdl2()); + } else if (hasPrecision) { + CInteger cInteger = new CInteger(); + cInteger.addConstraint(Interval.upperUnbounded(0l, true)); + primitiveTuple.addMember(cInteger); } - result.addAttributeTuple(tuple); + tuple.addTuple(primitiveTuple); } - //TODO: assumed value is possible in ADL 1.4, but not really in ADL 2, unless there is just one option possible. Cannot be solved until - //ADL 2 spec is changed + result.addAttributeTuple(tuple); } + //TODO: assumed value is possible in ADL 1.4, but not really in ADL 2, unless there is just one option possible. Cannot be solved until + //ADL 2 spec is changed } + return result; } private CComplexObjectProxy parseCComplexObjectProxy(C_complex_object_proxyContext proxyContext) { diff --git a/archie-utils/build.gradle b/archie-utils/build.gradle index dcd0bfabf..1919ea670 100644 --- a/archie-utils/build.gradle +++ b/archie-utils/build.gradle @@ -1,4 +1,4 @@ -description = "Utils for the Archie OpenEHR library" +description = "OpenEHR-RM specific utils for the Archie OpenEHR library" dependencies { compile project(':base') diff --git a/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigForTest.java b/archie-utils/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java similarity index 64% rename from tools/src/test/java/com/nedap/archie/adl14/ConversionConfigForTest.java rename to archie-utils/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java index 7562e9b43..75560fef2 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigForTest.java +++ b/archie-utils/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java @@ -1,18 +1,17 @@ package com.nedap.archie.adl14; + import com.nedap.archie.json.JacksonUtil; import java.io.IOException; import java.io.InputStream; -public class ConversionConfigForTest { - +public class OpenEHRADL14ConversionConfiguration { public static ADL14ConversionConfiguration getConfig() throws IOException { - - try(InputStream stream = ConversionConfigForTest.class.getResourceAsStream("configuration.json")) { + try(InputStream stream = OpenEHRADL14ConversionConfiguration.class.getResourceAsStream("/adl14conversionconfiguration.json")) { return JacksonUtil.getObjectMapper().readValue(stream, ADL14ConversionConfiguration.class); } - } + } diff --git a/archie-utils/src/main/resources/adl14conversionconfiguration.json b/archie-utils/src/main/resources/adl14conversionconfiguration.json new file mode 100644 index 000000000..5957cf218 --- /dev/null +++ b/archie-utils/src/main/resources/adl14conversionconfiguration.json @@ -0,0 +1,25 @@ +{ + "terminology_conversion_templates": [ + { + "terminology_id": "snomedct", + "template": "http://snomed.info/id/$code_string" + }, + { + "terminology_id": "snomed-ct", + "template": "http://snomed.info/id/$code_string" + }, + { + "terminology_id": "snomed", + "template": "http://snomed.info/id/$code_string" + }, + { + "terminology_id": "openehr", + "template": "http://openehr.org/id/$code_string" + }, + { + "terminology_id": "loinc", + "template": "http://loinc.org/id/$code_string" + } + + ] +} \ No newline at end of file diff --git a/opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java similarity index 85% rename from opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java rename to opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java index 554102180..522f9c61b 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/IntervalConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java @@ -3,8 +3,9 @@ import com.nedap.archie.base.Cardinality; import com.nedap.archie.base.Interval; import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.base.terminology.TerminologyCode; -public class IntervalConverter { +public class BaseTypesConverter { public static Cardinality convertCardinality(CARDINALITY cardinality14) { if(cardinality14 == null) { @@ -52,4 +53,11 @@ public static com.nedap.archie.base.Interval convertInterval(IntervalOfR range.isUpperIncluded() == null ? true : range.isUpperIncluded()); } + public static TerminologyCode convert(CODEPHRASE definingCode) { + if(definingCode == null) { + return null; + } + return TerminologyCode.createFromString(definingCode.getTerminologyId().getValue(), null, definingCode.getCodeString()); + } + } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index 1ad4ee9c5..c27812803 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -9,8 +9,8 @@ import com.nedap.archie.aom.Template; import com.nedap.archie.aom.TemplateOverlay; -import static com.nedap.archie.opt14.IntervalConverter.convertCardinality; -import static com.nedap.archie.opt14.IntervalConverter.convertMultiplicity; +import static com.nedap.archie.opt14.BaseTypesConverter.convertCardinality; +import static com.nedap.archie.opt14.BaseTypesConverter.convertMultiplicity; import static com.nedap.archie.opt14.PrimitiveConverter.convertPrimitive; public class DefinitionConverter { @@ -30,7 +30,7 @@ private CComplexObject convert(CCOMPLEXOBJECT cComplexObject14) { CComplexObject cComplexObject = new CComplexObject(); cComplexObject.setNodeId(cComplexObject14.getNodeId()); cComplexObject.setRmTypeName(cComplexObject14.getRmTypeName()); - cComplexObject.setOccurrences(IntervalConverter.convertMultiplicity(cComplexObject14.getOccurrences())); + cComplexObject.setOccurrences(BaseTypesConverter.convertMultiplicity(cComplexObject14.getOccurrences())); for (CATTRIBUTE attribute14 : cComplexObject14.getAttributes()) { cComplexObject.addAttribute(convert(attribute14)); @@ -81,7 +81,7 @@ private CObject convertSlot(ARCHETYPESLOT cobject14) { archetypeSlot.setNodeId(cobject14.getNodeId()); archetypeSlot.setRmTypeName(cobject14.getRmTypeName()); - archetypeSlot.setOccurrences(IntervalConverter.convertMultiplicity(cobject14.getOccurrences())); + archetypeSlot.setOccurrences(BaseTypesConverter.convertMultiplicity(cobject14.getOccurrences())); //TODO: assertions for include/exclude, should be straightforward return archetypeSlot; } @@ -99,7 +99,7 @@ private CObject convertRoot(CARCHETYPEROOT cRoot14) { CArchetypeRoot root = new CArchetypeRoot(); root.setArchetypeRef(overlay.getArchetypeId().getFullId()); root.setNodeId(cRoot14.getNodeId()); - root.setOccurrences(IntervalConverter.convertMultiplicity(cRoot14.getOccurrences())); + root.setOccurrences(BaseTypesConverter.convertMultiplicity(cRoot14.getOccurrences())); root.setRmTypeName(cRoot14.getRmTypeName()); return root; } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java index 5453cab16..03ad636de 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -19,14 +19,18 @@ public static void convert(Template template, OPERATIONALTEMPLATE opt14) { author.put(item.getId(), item.getValue()); } } + if(description14.getOtherDetails() != null) { + for(StringDictionaryItem item:description14.getOtherDetails()) { + description.getOtherDetails().put(item.getId(), item.getValue()); + } + } + + description.setOtherContributors(description14.getOtherContributors()); + description.setOriginalAuthor(author); template.setDescription(description); - template.setOriginalLanguage( - TerminologyCode.createFromString( - opt14.getLanguage().getTerminologyId().getValue(), - null, - opt14.getLanguage().getCodeString())); + template.setOriginalLanguage(BaseTypesConverter.convert(opt14.getLanguage())); //TODO: implement me further } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java index 4a80456b9..522b2446f 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -1,9 +1,82 @@ package com.nedap.archie.opt14; +import com.nedap.archie.adl14.aom14.CDVOrdinal; +import com.nedap.archie.adl14.aom14.CDVOrdinalItem; +import com.nedap.archie.adl14.aom14.CDVQuantity; + +import com.nedap.archie.adl14.aom14.CDVQuantityAssumedValue; +import com.nedap.archie.adl14.aom14.CDVQuantityItem; +import com.nedap.archie.adl14.treewalkers.Adl14CComplexObjectParser; import com.nedap.archie.aom.CObject; +import com.nedap.archie.base.terminology.TerminologyCode; + +import java.util.LinkedHashMap; +import java.util.Map; + +import static com.nedap.archie.opt14.BaseTypesConverter.convert; public class DomainTypeConverter { public static CObject convertDomainType(CDOMAINTYPE cobject14) { + if(cobject14 instanceof CDVORDINAL) { + return convertCDVOrdinal((CDVORDINAL) cobject14); + } else if (cobject14 instanceof CDVQUANTITY) { + return convertCDVQuantity((CDVQUANTITY) cobject14); + } else if (cobject14 instanceof CDVSTATE) { + + } else if (cobject14 instanceof CCODEPHRASE) { + + } return null; } + + private static CObject convertCDVOrdinal(CDVORDINAL ordinal14) { + CDVOrdinal ordinal = new CDVOrdinal(); + Map items = new LinkedHashMap<>(); + if(ordinal14.getList() != null) { + Integer i = 0; + for(DVORDINAL dvordinal14:ordinal14.getList()) { + CDVOrdinalItem item = new CDVOrdinalItem(); + item.setValue(dvordinal14.getValue()); + if(dvordinal14.getSymbol() != null) { + item.setSymbol(convert(dvordinal14.getSymbol().getDefiningCode())); + } + items.put(i.toString(), item); + i++; + } + } + //TODO: no assumed value in our own model, but there is in the OPT form. + + return Adl14CComplexObjectParser.convertCDVOrdinal(ordinal); + } + + private static CObject convertCDVQuantity(CDVQUANTITY cobject14) { + CDVQUANTITY quantity14 = cobject14; + CDVQuantity quantity = new CDVQuantity(); + Map items = new LinkedHashMap<>(); + + if(quantity14.getList() != null) { + Integer i = 0; + for(CQUANTITYITEM item14:quantity14.getList()) { + CDVQuantityItem item = new CDVQuantityItem(); + item.setMagnitude(BaseTypesConverter.convertInterval(item14.getMagnitude())); + item.setPrecision(BaseTypesConverter.convertInterval(item14.getPrecision())); + item.setUnits(item14.getUnits()); + items.put(i.toString(), item); + i++; + } + } + quantity.setList(items); + + quantity.setProperty(convert(quantity14.getProperty())); + + DVQUANTITY assumedValue14 = quantity14.getAssumedValue(); + if(assumedValue14 != null) { + CDVQuantityAssumedValue assumedValue = new CDVQuantityAssumedValue(); + assumedValue.setMagnitude(assumedValue14.getMagnitude()); + assumedValue.setPrecision(assumedValue14.getPrecision() == null ? null : assumedValue14.getPrecision().longValue()); + assumedValue.setUnits(assumedValue14.getUnits()); + quantity.setAssumedValue(assumedValue); + } + return Adl14CComplexObjectParser.convertCDvQuantity(quantity); + } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 53153e323..4ad0f1ab4 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -9,6 +9,9 @@ public Template convert(OPERATIONALTEMPLATE opt14) { Template template = new Template(); template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); + if(opt14.getUid() != null) { + template.setUid(opt14.getUid().getValue()); + } DescriptionConverter.convert(template, opt14); new DefinitionConverter().convert(template, opt14); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java index 075c94b2f..aae5b355c 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java @@ -6,7 +6,7 @@ import com.nedap.archie.aom.primitives.CReal; import com.nedap.archie.aom.primitives.CString; -import static com.nedap.archie.opt14.IntervalConverter.convertInterval; +import static com.nedap.archie.opt14.BaseTypesConverter.convertInterval; public class PrimitiveConverter { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java index be1df9fe6..6ac41cfa1 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java @@ -17,7 +17,7 @@ public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, ArchetypeTerm term = new ArchetypeTerm(); term.setCode(term14.getCode()); for(StringDictionaryItem item:term14.getItems()) { - term.put(item.getId(), item.getId()); + term.put(item.getId(), item.getValue()); } terms.put(term14.getCode(), term); } diff --git a/tools/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java b/tools/src/main/java/com/nedap/archie/adl14/OpenEHRADL14ConversionConfiguration.java new file mode 100644 index 000000000..e69de29bb diff --git a/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java index 597f0c980..ef890ffdf 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java @@ -20,7 +20,7 @@ public class ArchetypeSlotConversionTest { @Test public void testSlotConversion() throws Exception { - ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); + ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); ADL2ConversionRunLog log = null; diff --git a/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java b/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java index c1b0b60fc..f13aed7d8 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java @@ -41,7 +41,7 @@ public class LargeSetOfADL14sTest { @Before public void setup() throws Exception { - conversionConfiguration = ConversionConfigForTest.getConfig(); + conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); } @Test diff --git a/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java index a2bf695fc..12bcac55d 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java @@ -21,7 +21,7 @@ public class PreviousLogConversionTest { @Test public void applyConsistentConversion() throws Exception { - ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); + ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); ADL2ConversionRunLog log = null; @@ -51,7 +51,7 @@ public void applyConsistentConversion() throws Exception { @Test public void testValueSet() throws Exception { - ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); + ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); ADL2ConversionRunLog log = null; @@ -88,7 +88,7 @@ public void testValueSet() throws Exception { @Test public void unusedValuesAreRemoved() throws Exception { - ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); + ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig(); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); ADL2ConversionRunLog log = null; String createdAtCode = null; From 15f1f5ee45db3ccc1d4bbc4f76ef4af14caff5a6 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 4 Jan 2021 12:55:22 +0100 Subject: [PATCH 04/36] Add conversion to 2.0 (well, partially, for some reason) --- .../adl14/ADL14DescriptionConverter.java | 3 +++ opt14/build.gradle | 9 ++++---- .../nedap/archie/opt14/Opt14Converter.java | 19 ++++++++++++++-- .../com/nedap/archie/opt14/ConverterTest.java | 5 +++-- .../nedap/archie/adl14/ADL14Converter.java | 22 +++++++++++++++++++ .../diff/TerminologyDifferentiator.java | 2 +- 6 files changed, 51 insertions(+), 9 deletions(-) diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14DescriptionConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14DescriptionConverter.java index 11d105214..911e8948a 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14DescriptionConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14DescriptionConverter.java @@ -10,6 +10,9 @@ public class ADL14DescriptionConverter { public void convert(Archetype archetype) { ResourceDescription description = archetype.getDescription(); + if(description == null) { + return; + } description.setLicence(description.getOtherDetails().remove("licence")); description.setOriginalNamespace(description.getOtherDetails().remove("original_namespace")); description.setOriginalPublisher(description.getOtherDetails().remove("original_publisher")); diff --git a/opt14/build.gradle b/opt14/build.gradle index a53b6148f..2feef2b88 100644 --- a/opt14/build.gradle +++ b/opt14/build.gradle @@ -16,11 +16,12 @@ dependencies { compile project(':path-queries') compile project(':utils') compile project(':tools') - testCompile project(':openehr-rm') - testCompile project(':archie-utils') - testCompile project(':i18n') + compile project(':referencemodels') + compile project(':openehr-rm') + compile project(':archie-utils') + compile project(':i18n') testCompile project(':test-rm') - testCompile project(':referencemodels') + xjc "javax.xml.bind:jaxb-api:$jaxbVersion" diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 4ad0f1ab4..923034f88 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -1,11 +1,19 @@ package com.nedap.archie.opt14; +import com.google.common.collect.Lists; +import com.nedap.archie.adl14.ADL14Converter; +import com.nedap.archie.adl14.ADL2ConversionResultList; +import com.nedap.archie.adl14.OpenEHRADL14ConversionConfiguration; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.Template; +import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import org.openehr.referencemodels.BuiltinReferenceModels; + +import java.io.IOException; public class Opt14Converter { - public Template convert(OPERATIONALTEMPLATE opt14) { + public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes) { Template template = new Template(); template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); @@ -15,6 +23,13 @@ public Template convert(OPERATIONALTEMPLATE opt14) { DescriptionConverter.convert(template, opt14); new DefinitionConverter().convert(template, opt14); - return template; + try { + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), OpenEHRADL14ConversionConfiguration.getConfig()); + converter.setExistingRepository(adl2Archetypes); + ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); + return converted; + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java index 1c4c0342b..8044751ca 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java @@ -1,5 +1,6 @@ package com.nedap.archie.opt14; +import com.nedap.archie.adl14.ADL2ConversionResultList; import com.nedap.archie.adlparser.ADLParser; import com.nedap.archie.aom.Archetype; import com.nedap.archie.aom.Template; @@ -28,8 +29,8 @@ public void procedureList() throws Exception { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); try(InputStream stream = getClass().getResourceAsStream("/procedure_list.opt")) { OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); - Template template = new Opt14Converter().convert(opt14); - System.out.println(ADLArchetypeSerializer.serialize(template)); + ADL2ConversionResultList convert = new Opt14Converter().convert(opt14, repository); + System.out.println(ADLArchetypeSerializer.serialize(convert.getConversionResults().get(0).getArchetype())); } } diff --git a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java index 5f5d3e7b7..10a50910c 100644 --- a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java +++ b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java @@ -19,6 +19,7 @@ import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Optional; public class ADL14Converter { @@ -67,6 +68,8 @@ public ADL2ConversionResultList convert(List archetypes, ADL2Conversi for(TemplateOverlay overlay:t.getTemplateOverlays()) { templateOverlays.add(overlay); overlay.setRmRelease(t.getRmRelease()); + overlay.setOriginalLanguage(t.getOriginalLanguage()); + overlay.setTranslationList(t.getTranslationList()); } } } @@ -109,6 +112,25 @@ public ADL2ConversionResultList convert(List archetypes, ADL2Conversi } } + for(ADL2ConversionResult ar:resultList.getConversionResults()) { + //template overlays have been processed as separate archetypes. So combine them here again + if(ar.getArchetype() != null && ar.getArchetype() instanceof Template) { + Template t = (Template) ar.getArchetype(); + + List newOverlays = new ArrayList<>(); + for(TemplateOverlay overlay:t.getTemplateOverlays()) { + Optional convertedOverlay = resultList.getConversionResults().stream().filter(r -> r.getArchetypeId().startsWith(overlay.getArchetypeId().getFullId())).findFirst(); + if(convertedOverlay.isPresent()) { + newOverlays.add((TemplateOverlay) convertedOverlay.get().getArchetype()); + } else { + newOverlays.add(overlay); + //TODO: add error + } + t.setTemplateOverlays(newOverlays); + } + } + } + return resultList; } diff --git a/tools/src/main/java/com/nedap/archie/diff/TerminologyDifferentiator.java b/tools/src/main/java/com/nedap/archie/diff/TerminologyDifferentiator.java index 7085ebeed..4291ba0c7 100644 --- a/tools/src/main/java/com/nedap/archie/diff/TerminologyDifferentiator.java +++ b/tools/src/main/java/com/nedap/archie/diff/TerminologyDifferentiator.java @@ -32,7 +32,7 @@ private void removeAdditionalTranslations(Archetype result) { // so remove all from the terminology that have not been speciafically defined in the archetype resource description List translationsToRemove = new ArrayList<>(); for(String key: result.getTerminology().getTermDefinitions().keySet()) { - if(!result.getTranslations().containsKey(key) && !result.getTerminology().getOriginalLanguage().equals(key)) { + if(!(result.getTranslations() != null && result.getTranslations().containsKey(key)) && !key.equals(result.getTerminology().getOriginalLanguage())) { translationsToRemove.add(key); } } From cacd7bb34e49baf37d6798c6db724e8aa11239ba Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 4 Jan 2021 12:58:55 +0100 Subject: [PATCH 05/36] Set empty opt14 nodeids to null, to fix conversion --- .../archie/opt14/DefinitionConverter.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index c27812803..e48d260a5 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -1,5 +1,6 @@ package com.nedap.archie.opt14; +import com.google.common.base.Strings; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.ArchetypeSlot; import com.nedap.archie.aom.CArchetypeRoot; @@ -28,9 +29,7 @@ public void convert(Template template, OPERATIONALTEMPLATE opt14) { private CComplexObject convert(CCOMPLEXOBJECT cComplexObject14) { CComplexObject cComplexObject = new CComplexObject(); - cComplexObject.setNodeId(cComplexObject14.getNodeId()); - cComplexObject.setRmTypeName(cComplexObject14.getRmTypeName()); - cComplexObject.setOccurrences(BaseTypesConverter.convertMultiplicity(cComplexObject14.getOccurrences())); + setObjectBasics(cComplexObject14, cComplexObject); for (CATTRIBUTE attribute14 : cComplexObject14.getAttributes()) { cComplexObject.addAttribute(convert(attribute14)); @@ -38,6 +37,12 @@ private CComplexObject convert(CCOMPLEXOBJECT cComplexObject14) { return cComplexObject; } + private void setObjectBasics(COBJECT cComplexObject14, CObject cComplexObject) { + cComplexObject.setNodeId(Strings.isNullOrEmpty(cComplexObject14.getNodeId()) ? null : cComplexObject14.getNodeId()); + cComplexObject.setRmTypeName(cComplexObject14.getRmTypeName()); + cComplexObject.setOccurrences(BaseTypesConverter.convertMultiplicity(cComplexObject14.getOccurrences())); + } + private CAttribute convert(CATTRIBUTE attribute14) { CAttribute attribute = new CAttribute(); attribute.setRmAttributeName(attribute14.getRmAttributeName()); @@ -78,10 +83,8 @@ private CObject convert(COBJECT cobject14) { private CObject convertSlot(ARCHETYPESLOT cobject14) { ArchetypeSlot archetypeSlot = new ArchetypeSlot(); - archetypeSlot.setNodeId(cobject14.getNodeId()); - archetypeSlot.setRmTypeName(cobject14.getRmTypeName()); + setObjectBasics(cobject14, archetypeSlot); - archetypeSlot.setOccurrences(BaseTypesConverter.convertMultiplicity(cobject14.getOccurrences())); //TODO: assertions for include/exclude, should be straightforward return archetypeSlot; } @@ -98,9 +101,7 @@ private CObject convertRoot(CARCHETYPEROOT cRoot14) { CArchetypeRoot root = new CArchetypeRoot(); root.setArchetypeRef(overlay.getArchetypeId().getFullId()); - root.setNodeId(cRoot14.getNodeId()); - root.setOccurrences(BaseTypesConverter.convertMultiplicity(cRoot14.getOccurrences())); - root.setRmTypeName(cRoot14.getRmTypeName()); + setObjectBasics(cRoot14, root); return root; } From 9f9e132370ab4531543be0a4376d2fd002213047 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 4 Jan 2021 17:38:40 +0100 Subject: [PATCH 06/36] One more step in converting opt 1.4 --- .../adl14/ADL14ConversionConfiguration.java | 11 ++ .../archie/adl14/ADL14NodeIDConverter.java | 1 - .../adl14/ADL14TermConstraintConverter.java | 3 + .../archie/opt14/DefinitionConverter.java | 6 +- .../archie/opt14/DomainTypeConverter.java | 24 ++- .../archie/opt14/FlatArchetypeProvider.java | 8 + .../com/nedap/archie/opt14/NodeIdFixer.java | 108 ++++++++++++++ .../nedap/archie/opt14/NodeIdSpecializer.java | 141 ++++++++++++++++++ .../nedap/archie/opt14/Opt14Converter.java | 20 ++- .../opt14/RepoFlatArchetypeProvider.java | 40 +++++ .../com/nedap/archie/opt14/ConverterTest.java | 6 + .../openEHR-EHR-ACTION.procedure.v1.4.1.adls | 2 +- 12 files changed, 363 insertions(+), 7 deletions(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/FlatArchetypeProvider.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/RepoFlatArchetypeProvider.java diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14ConversionConfiguration.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14ConversionConfiguration.java index 24006e941..ac89ad809 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14ConversionConfiguration.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14ConversionConfiguration.java @@ -21,6 +21,9 @@ public class ADL14ConversionConfiguration { */ private boolean applyDiff = true; + /** If true, allow empty node ids where specialisations occur. for OPT conversion */ + private boolean allowEmptyNodeIdsForSpecializations = false; + public List getTerminologyConversionTemplates() { return terminologyConversionTemplates; @@ -57,4 +60,12 @@ public boolean isApplyDiff() { public void setApplyDiff(boolean applyDiff) { this.applyDiff = applyDiff; } + + public boolean isAllowEmptyNodeIdsForSpecializations() { + return allowEmptyNodeIdsForSpecializations; + } + + public void setAllowEmptyNodeIdsForSpecializations(boolean allowEmptyNodeIdsForSpecializations) { + this.allowEmptyNodeIdsForSpecializations = allowEmptyNodeIdsForSpecializations; + } } diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java index 2edbb3281..a7555339e 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java @@ -203,7 +203,6 @@ private void convertTermBindings(Archetype archetype) { } private void generateMissingNodeIds(CObject cObject) { - if(!(cObject instanceof CPrimitiveObject) && cObject.getNodeId() == null) { String path = cObject.getPath(); if(archetype.getParentArchetypeId() != null && flatParentArchetype != null) { diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java index 871ce4d1f..a1566f260 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java @@ -203,6 +203,9 @@ private void convertCTerminologyCode(CTerminologyCode cTerminologyCode) { } private Map findOrCreateTermBindings(TerminologyCode termCode) { + if(termCode.getTerminologyId() == null) { + throw new IllegalArgumentException("terminology id cannot be null!"); + } Map termBindings = archetype.getTerminology().getTermBindings().get(termCode.getTerminologyId()); if(termBindings == null) { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index e48d260a5..5eae74d4b 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -101,7 +101,11 @@ private CObject convertRoot(CARCHETYPEROOT cRoot14) { CArchetypeRoot root = new CArchetypeRoot(); root.setArchetypeRef(overlay.getArchetypeId().getFullId()); - setObjectBasics(cRoot14, root); + if(cRoot14.getNodeId() != null && !cRoot14.getNodeId().isEmpty() && !cRoot14.getNodeId().startsWith("at0000")) { + root.setNodeId(cRoot14.getNodeId()); + } + root.setRmTypeName(cRoot14.getRmTypeName()); + root.setOccurrences(BaseTypesConverter.convertMultiplicity(cRoot14.getOccurrences())); return root; } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java index 522b2446f..087ebd9bf 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -3,12 +3,11 @@ import com.nedap.archie.adl14.aom14.CDVOrdinal; import com.nedap.archie.adl14.aom14.CDVOrdinalItem; import com.nedap.archie.adl14.aom14.CDVQuantity; - import com.nedap.archie.adl14.aom14.CDVQuantityAssumedValue; import com.nedap.archie.adl14.aom14.CDVQuantityItem; import com.nedap.archie.adl14.treewalkers.Adl14CComplexObjectParser; import com.nedap.archie.aom.CObject; -import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.aom.primitives.CTerminologyCode; import java.util.LinkedHashMap; import java.util.Map; @@ -24,11 +23,30 @@ public static CObject convertDomainType(CDOMAINTYPE cobject14) { } else if (cobject14 instanceof CDVSTATE) { } else if (cobject14 instanceof CCODEPHRASE) { - + return convertCodePhrase((CCODEPHRASE) cobject14); } return null; } + private static CObject convertCodePhrase(CCODEPHRASE cobject14) { + CTerminologyCode cTerminologyCode = new CTerminologyCode(); + + if(cobject14.getTerminologyId() != null) { + cTerminologyCode.addConstraint(cobject14.getTerminologyId().getValue()); + } else { + System.out.println("HELP"); + } + if(cobject14.getCodeList() != null) { + for(String code:cobject14.getCodeList()) { + cTerminologyCode.addConstraint(code); + } + } + if(cobject14.getAssumedValue() != null) { + cTerminologyCode.setAssumedValue(BaseTypesConverter.convert(cobject14.getAssumedValue())); + } + return cTerminologyCode; + } + private static CObject convertCDVOrdinal(CDVORDINAL ordinal14) { CDVOrdinal ordinal = new CDVOrdinal(); Map items = new LinkedHashMap<>(); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/FlatArchetypeProvider.java b/opt14/src/main/java/com/nedap/archie/opt14/FlatArchetypeProvider.java new file mode 100644 index 000000000..393055d10 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/FlatArchetypeProvider.java @@ -0,0 +1,8 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; + +public interface FlatArchetypeProvider { + + Archetype getFlatArchetype(String archetypeId); +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java new file mode 100644 index 000000000..7598fc3ea --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java @@ -0,0 +1,108 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ArchetypeModelObject; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.aom.terminology.ArchetypeTerminology; +import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.aom.utils.NodeIdUtil; +import com.nedap.archie.archetypevalidator.ErrorType; +import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import org.openehr.utils.message.I18n; + +public class NodeIdFixer { + + private Archetype archetype; + private Archetype flatParent; + + public void fixNodeIds(Archetype archetype, FlatArchetypeProvider repo) { + this.archetype = archetype; + if(archetype.getParentArchetypeId() != null) { + this.flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); + } + fixRootNodeId(archetype); + //fixNodeId(archetype.getDefinition()); + + if(archetype instanceof Template) { + Template template = (Template) archetype; + + for(TemplateOverlay overlay:template.getTemplateOverlays()) { + this.archetype = overlay; + if(archetype.getParentArchetypeId() != null) { + this.flatParent = repo.getFlatArchetype(overlay.getParentArchetypeId()); + } + fixRootNodeId(overlay); + //fixNodeId(overlay.getDefinition()); + } + } + } + + private void fixRootNodeId(Archetype archetype) { + int specDepth = flatParent.specializationDepth()+1; + CObject cObject = archetype.getDefinition(); + if(cObject.isRootNode() && AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) != specDepth) { + //create id1.1.1.1.1.....1 one + String newNodeId = "at0000"; + for(int i = 0; i < specDepth; i++) { + newNodeId += ".1"; + } + cObject.setNodeId(newNodeId); + } + } + + private void fixNodeId(CObject cObject) { + if(flatParent == null) { + return; + } + + + if (cObject.isRootNode() || !cObject.getParent().isSecondOrderConstrained()) { + if (AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) <= flatParent.specializationDepth() + || new NodeIdUtil(cObject.getNodeId()).isRedefined()) { + if (!AOMUtils.isPhantomPathAtLevel(cObject.getPathSegments(), flatParent.specializationDepth())) { + String flatPath = AOMUtils.pathAtSpecializationLevel(cObject.getPathSegments(), flatParent.specializationDepth()); + CObject parentCObject = getCObject(flatParent.itemAtPath(flatPath)); + + if (parentCObject != null) { + if (cObject.isProhibited()) { + if (!parentCObject.getNodeId().equals(cObject.getNodeId())) { + // System.out.println("fixing node id " + cObject.getNodeId() + " for archetype " + archetype.getArchetypeId()); + String oldNodeId = cObject.getNodeId(); + cObject.setNodeId(parentCObject.getNodeId()); + ArchetypeTerminology terminology = cObject.getArchetype().getTerminology(); + for(String language:terminology.getTermDefinitions().keySet()) { + terminology.getTermDefinitions().get(language).remove(oldNodeId); + } + } + } + } + } + } + } + + for(CAttribute attribute:cObject.getAttributes()) { + fixNodeId(attribute); + } + } + + private void fixNodeId(CAttribute cAttribute) { + for(CObject cObject:cAttribute.getChildren()) { + fixNodeId(cObject); + } + } + + private CObject getCObject(ArchetypeModelObject archetypeModelObject) { + if(archetypeModelObject instanceof CAttribute) { + CAttribute attribute = (CAttribute) archetypeModelObject; + if(attribute.getChildren().size() == 1) { + return attribute.getChildren().get(0); + }//TODO: add a numeric identifier to the getPath() method in CObject so this can be deleted and actually works in all cases! + } else if(archetypeModelObject instanceof CObject) { + return (CObject) archetypeModelObject; + } + return null; + } +} \ No newline at end of file diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java new file mode 100644 index 000000000..97d663304 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java @@ -0,0 +1,141 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ArchetypeModelObject; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.CPrimitiveObject; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.aom.primitives.CString; +import com.nedap.archie.aom.terminology.ArchetypeTerm; +import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.query.AOMPathQuery; +import com.nedap.archie.query.RMPathQuery; +import com.nedap.archie.rminfo.ArchieRMInfoLookup; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Walks the archetype tree, then specializes any node ids it finds with change where required. Can be: + * - different type + * - different text or description + * - different primitive node child (TODO: check how in Differentiator?) + * + * + * TODO: remove simple single constraint name constraints, and put them in the terminology instead first! + * + */ +public class NodeIdSpecializer { + + private Archetype archetype; + private Archetype flatParent; + + public void specializeNodeIds(Archetype archetype, FlatArchetypeProvider repo) { + if(archetype.getParentArchetypeId() == null) { + return; + } + this.archetype = archetype; + if(archetype.getParentArchetypeId() != null) { + this.flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); + } + specializeNodeIds(archetype.getDefinition()); + + if(archetype instanceof Template) { + Template template = (Template) archetype; + + for(TemplateOverlay overlay:template.getTemplateOverlays()) { + this.archetype = overlay; + if(archetype.getParentArchetypeId() != null) { + this.flatParent = repo.getFlatArchetype(overlay.getParentArchetypeId()); + } + + specializeNodeIds(overlay.getDefinition()); + } + } + } + + + private void specializeNodeIds(CObject cObject) { + if(!(cObject instanceof CPrimitiveObject)) { + String flatPath = AOMUtils.pathAtSpecializationLevel(cObject.getPathSegments(), flatParent.specializationDepth()); + CObject parentCObject = getCObject(flatParent.itemAtPath(flatPath)); + + if(parentCObject != null) { + ArchetypeTerm term = archetype.getTerm(cObject, archetype.getOriginalLanguage().getCodeString()); + ArchetypeTerm parentTerm = flatParent.getTerm(parentCObject, archetype.getOriginalLanguage().getCodeString()); + if( cObject.getNodeId().equalsIgnoreCase(parentCObject.getNodeId())) { + if(parentTerm != null && term != null) { + if (!term.getText().equalsIgnoreCase(parentTerm.getText()) || + !term.getDescription().equalsIgnoreCase(parentTerm.getDescription())) { + //term changes. We need a new node id + System.out.println("GOT ONE!"); + } + } + } + + } else { + System.out.println("DID NOT EXPECT THIS"); + // throw new RuntimeException("I did not expect the Spanish inquisition!");//TODO: remove or add proper message + } + for(CAttribute attribute:cObject.getAttributes()) { + specializeNodeIds(attribute); + } + } + + } + + private void specializeNodeIds(CAttribute attribute) { + if(attribute.getRmAttributeName().equalsIgnoreCase("name")) { + //ok a name constraint. If it's a simple constraint, replace it with a terminology entry please. + if(attribute.getChildren().size() == 1 && attribute.getChildren().get(0).getRmTypeName().equalsIgnoreCase("DV_TEXT")) { + CObject cObject = attribute.getChildren().get(0); + Object o = new AOMPathQuery("/value[1]").find((CComplexObject) cObject); + if(o instanceof CString) { + CString nameConstraint = (CString) o; + if (nameConstraint.getConstraint().size() == 1 && !CString.isRegexConstraint(nameConstraint.getConstraint().get(0))) { + //remove the crap out of this attribute. + attribute.setChildren(new ArrayList<>()); + ArchetypeTerm term = archetype.getTerm(attribute.getParent(), archetype.getOriginalLanguage().getCodeString()); + if (term != null) { + term.setText((nameConstraint.getConstraint().get(0))); + } else { + term = new ArchetypeTerm(); + term.setCode(attribute.getParent().getNodeId()); + term.setText(nameConstraint.getConstraint().get(0)); + term.setDescription(nameConstraint.getConstraint().get(0)); + getOrCreateTermDefinitions().put(attribute.getParent().getNodeId(), term); + } + } + } + } + } + for(CObject child:attribute.getChildren()) { + specializeNodeIds(child); + } + } + + private Map getOrCreateTermDefinitions() { + Map termDefs = archetype.getTerminology().getTermDefinitions().get(archetype.getOriginalLanguage().getCodeString()); + if(termDefs == null) { + termDefs = new LinkedHashMap<>(); + archetype.getTerminology().getTermDefinitions().put(archetype.getOriginalLanguage().getCodeString(), termDefs); + } + return termDefs; + } + + private CObject getCObject(ArchetypeModelObject archetypeModelObject) { + if(archetypeModelObject instanceof CAttribute) { + CAttribute attribute = (CAttribute) archetypeModelObject; + if(attribute.getChildren().size() == 1) { + return attribute.getChildren().get(0); + }//TODO: add a numeric identifier to the getPath() method in CObject so this can be deleted and actually works in all cases! + } else if(archetypeModelObject instanceof CObject) { + return (CObject) archetypeModelObject; + } + return null; + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 923034f88..cb1fead91 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -1,12 +1,15 @@ package com.nedap.archie.opt14; import com.google.common.collect.Lists; +import com.nedap.archie.adl14.ADL14ConversionConfiguration; import com.nedap.archie.adl14.ADL14Converter; +import com.nedap.archie.adl14.ADL2ConversionResult; import com.nedap.archie.adl14.ADL2ConversionResultList; import com.nedap.archie.adl14.OpenEHRADL14ConversionConfiguration; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.Template; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; import org.openehr.referencemodels.BuiltinReferenceModels; import java.io.IOException; @@ -23,10 +26,25 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA DescriptionConverter.convert(template, opt14); new DefinitionConverter().convert(template, opt14); + + + new NodeIdFixer().fixNodeIds(template, new RepoFlatArchetypeProvider(adl2Archetypes)); + + try { - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), OpenEHRADL14ConversionConfiguration.getConfig()); + ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); + config.setAllowEmptyNodeIdsForSpecializations(true); + config.setApplyDiff(false); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), config); converter.setExistingRepository(adl2Archetypes); ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); + ADL2ConversionResult adl2ConversionResult = converted.getConversionResults().get(0); + if(adl2ConversionResult.getArchetype() != null) { + Template convertedTemplate = (Template) adl2ConversionResult.getArchetype(); + + new NodeIdSpecializer().specializeNodeIds(convertedTemplate, new RepoFlatArchetypeProvider(adl2Archetypes)); + System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate)); + } return converted; } catch (IOException e) { throw new RuntimeException(e); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/RepoFlatArchetypeProvider.java b/opt14/src/main/java/com/nedap/archie/opt14/RepoFlatArchetypeProvider.java new file mode 100644 index 000000000..d22208e81 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/RepoFlatArchetypeProvider.java @@ -0,0 +1,40 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.flattener.ArchetypeHRIDMap; +import com.nedap.archie.flattener.Flattener; +import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import com.nedap.archie.rminfo.MetaModels; +import org.openehr.referencemodels.BuiltinReferenceModels; + +class RepoFlatArchetypeProvider implements FlatArchetypeProvider { + + private InMemoryFullArchetypeRepository repo; + private ArchetypeHRIDMap flatArchetypes = new ArchetypeHRIDMap<>(); + private MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); + + public RepoFlatArchetypeProvider(InMemoryFullArchetypeRepository repo) { + this.repo = repo; + } + + public Archetype getFlatArchetype(String id) { + Archetype flattenedArchetype = repo.getFlattenedArchetype(id); + if(flattenedArchetype != null) { + return flattenedArchetype; + } + flattenedArchetype = flatArchetypes.get(id); + if(flattenedArchetype != null) { + return flattenedArchetype; + } + Archetype archetype = repo.getArchetype(id); + try { + flattenedArchetype = new Flattener(repo, metaModels).flatten(archetype); + flatArchetypes.put(flattenedArchetype.getArchetypeId(), flattenedArchetype); + return flattenedArchetype; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java index 8044751ca..d4c36aaea 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java @@ -1,5 +1,6 @@ package com.nedap.archie.opt14; +import com.nedap.archie.adl14.ADL2ConversionResult; import com.nedap.archie.adl14.ADL2ConversionResultList; import com.nedap.archie.adlparser.ADLParser; import com.nedap.archie.aom.Archetype; @@ -30,6 +31,11 @@ public void procedureList() throws Exception { try(InputStream stream = getClass().getResourceAsStream("/procedure_list.opt")) { OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); ADL2ConversionResultList convert = new Opt14Converter().convert(opt14, repository); + for(ADL2ConversionResult result:convert.getConversionResults()) { + if(result.getException() != null) { + result.getException().printStackTrace(); + } + } System.out.println(ADLArchetypeSerializer.serialize(convert.getConversionResults().get(0).getArchetype())); } } diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls b/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls index 81be01cf4..80a5438af 100644 --- a/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls +++ b/opt14/src/test/resources/adl2/openEHR-EHR-ACTION.procedure.v1.4.1.adls @@ -447,7 +447,7 @@ definition } } description matches { - ITEM_TREE[id9000] matches { + ITEM_TREE[id2] matches { items cardinality matches {1..*; unordered} matches { ELEMENT[id3] matches { -- Procedure name value matches { From 014568e6bbd1dc876af44491fe5aec02c47bd296 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 5 Jan 2021 13:03:01 +0100 Subject: [PATCH 07/36] More fixes --- .../adl14/ADL14TermConstraintConverter.java | 15 ++++ .../archie/opt14/DefinitionConverter.java | 9 ++- .../archie/opt14/DomainTypeConverter.java | 10 ++- .../nedap/archie/opt14/NodeIdSpecializer.java | 69 +++++++++++++------ .../nedap/archie/opt14/Opt14Converter.java | 26 +++---- .../archie/opt14/TerminologyConverter.java | 41 ++++++++++- .../nedap/archie/adl14/ADL14Converter.java | 2 +- .../archie/diff/ConstraintDifferentiator.java | 20 +++++- .../com/nedap/archie/diff/Differentiator.java | 1 + .../nedap/archie/diff/LCSOrderingDiff.java | 2 +- .../diff/UnconstrainedIntervalRemover.java | 1 + 11 files changed, 151 insertions(+), 45 deletions(-) diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java index a1566f260..e3f54f602 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java @@ -142,6 +142,21 @@ private void convertCTerminologyCode(CTerminologyCode cTerminologyCode) { URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode); Map termBindingsMap = findOrCreateTermBindings(termCode); + //TODO: check if this is a converted or old term binding - old is unusual, but could be possible! + String termBinding = findOrAddTermBindingAndCode(termCode, uri, termBindingsMap); + cTerminologyCode.setConstraint(Lists.newArrayList(termBinding)); + } catch (URISyntaxException e) { + //TODO + logger.error("error converting term", e); + } + } else if (cTerminologyCode.getConstraint().size() == 2) { + //still one code. + try { + termCode = TerminologyCode.createFromString(cTerminologyCode.getConstraint().get(0), null, cTerminologyCode.getConstraint().get(1)); + //do not create a value set, create a code plus binding to the old non-local code + URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode); + Map termBindingsMap = findOrCreateTermBindings(termCode); + //TODO: check if this is a converted or old term binding - old is unusual, but could be possible! String termBinding = findOrAddTermBindingAndCode(termCode, uri, termBindingsMap); cTerminologyCode.setConstraint(Lists.newArrayList(termBinding)); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index 5eae74d4b..302a0fdd7 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -1,6 +1,7 @@ package com.nedap.archie.opt14; import com.google.common.base.Strings; +import com.nedap.archie.adl14.ADL14ConversionConfiguration; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.ArchetypeSlot; import com.nedap.archie.aom.CArchetypeRoot; @@ -18,12 +19,14 @@ public class DefinitionConverter { private OPERATIONALTEMPLATE opt14; private Template template; + private ADL14ConversionConfiguration config; - public void convert(Template template, OPERATIONALTEMPLATE opt14) { + public void convert(Template template, OPERATIONALTEMPLATE opt14, ADL14ConversionConfiguration config) { + this.config = config; this.opt14 = opt14; this.template = template; CARCHETYPEROOT definition = opt14.getDefinition(); - template.setTerminology(TerminologyConverter.createTerminology(opt14, definition)); + template.setTerminology(TerminologyConverter.createTerminology(opt14, definition, config)); template.setDefinition(convert(definition)); } @@ -96,7 +99,7 @@ private CObject convertRoot(CARCHETYPEROOT cRoot14) { overlay.getArchetypeId().setConceptId(overlay.getArchetypeId().getConceptId() + "ovl-1"); overlay.setParentArchetypeId(cRoot14.getArchetypeId().getValue()); overlay.setDefinition(convert(cRoot14)); - overlay.setTerminology(TerminologyConverter.createTerminology(opt14, cRoot14)); + overlay.setTerminology(TerminologyConverter.createTerminology(opt14, cRoot14, config)); template.addTemplateOverlay(overlay); CArchetypeRoot root = new CArchetypeRoot(); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java index 087ebd9bf..ee0ce978d 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -21,18 +21,24 @@ public static CObject convertDomainType(CDOMAINTYPE cobject14) { } else if (cobject14 instanceof CDVQUANTITY) { return convertCDVQuantity((CDVQUANTITY) cobject14); } else if (cobject14 instanceof CDVSTATE) { - + return convertCDVState((CDVSTATE) cobject14); } else if (cobject14 instanceof CCODEPHRASE) { return convertCodePhrase((CCODEPHRASE) cobject14); } return null; } + private static CObject convertCDVState(CDVSTATE cobject14) { + return null; + } + private static CObject convertCodePhrase(CCODEPHRASE cobject14) { CTerminologyCode cTerminologyCode = new CTerminologyCode(); if(cobject14.getTerminologyId() != null) { - cTerminologyCode.addConstraint(cobject14.getTerminologyId().getValue()); + if(!cobject14.getTerminologyId().getValue().equalsIgnoreCase("local")) { + cTerminologyCode.addConstraint(cobject14.getTerminologyId().getValue()); + } } else { System.out.println("HELP"); } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java index 97d663304..1cfa3ce42 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java @@ -15,8 +15,11 @@ import com.nedap.archie.query.RMPathQuery; import com.nedap.archie.rminfo.ArchieRMInfoLookup; +import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -72,47 +75,69 @@ private void specializeNodeIds(CObject cObject) { if (!term.getText().equalsIgnoreCase(parentTerm.getText()) || !term.getDescription().equalsIgnoreCase(parentTerm.getDescription())) { //term changes. We need a new node id - System.out.println("GOT ONE!"); + //TODO } } } } else { - System.out.println("DID NOT EXPECT THIS"); + //someone added a new node. It wil have a specialized id already - or it should anyway. let's check! + if(AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) != flatParent.specializationDepth() +1) { + System.out.println("change of code!");//TODO + } // throw new RuntimeException("I did not expect the Spanish inquisition!");//TODO: remove or add proper message } + for(CAttribute attribute:cObject.getAttributes()) { specializeNodeIds(attribute); } + changeNameConstraintToArchetypeTerm(cObject); } } - private void specializeNodeIds(CAttribute attribute) { - if(attribute.getRmAttributeName().equalsIgnoreCase("name")) { - //ok a name constraint. If it's a simple constraint, replace it with a terminology entry please. - if(attribute.getChildren().size() == 1 && attribute.getChildren().get(0).getRmTypeName().equalsIgnoreCase("DV_TEXT")) { - CObject cObject = attribute.getChildren().get(0); - Object o = new AOMPathQuery("/value[1]").find((CComplexObject) cObject); - if(o instanceof CString) { - CString nameConstraint = (CString) o; - if (nameConstraint.getConstraint().size() == 1 && !CString.isRegexConstraint(nameConstraint.getConstraint().get(0))) { - //remove the crap out of this attribute. - attribute.setChildren(new ArrayList<>()); - ArchetypeTerm term = archetype.getTerm(attribute.getParent(), archetype.getOriginalLanguage().getCodeString()); - if (term != null) { - term.setText((nameConstraint.getConstraint().get(0))); - } else { - term = new ArchetypeTerm(); - term.setCode(attribute.getParent().getNodeId()); - term.setText(nameConstraint.getConstraint().get(0)); - term.setDescription(nameConstraint.getConstraint().get(0)); - getOrCreateTermDefinitions().put(attribute.getParent().getNodeId(), term); + /** + * replace all 'name matches DV_TEXT { value matches {"some static name"}}' constraints to archtype terms + * @param cObject + */ + private void changeNameConstraintToArchetypeTerm(CObject cObject) { + List attributesToRemove = new ArrayList<>(); + int i = 0; + for(CAttribute attribute:cObject.getAttributes()) { + if(attribute.getRmAttributeName().equalsIgnoreCase("name")) { + //ok a name constraint. If it's a simple constraint, replace it with a terminology entry please. + if(attribute.getChildren().size() == 1 && attribute.getChildren().get(0).getRmTypeName().equalsIgnoreCase("DV_TEXT")) { + CObject nameCObject = attribute.getChildren().get(0); + Object o = new AOMPathQuery("/value[1]").find((CComplexObject) nameCObject); + if(o instanceof CString) { + CString nameConstraint = (CString) o; + if (nameConstraint.getConstraint().size() == 1 && !CString.isRegexConstraint(nameConstraint.getConstraint().get(0))) { + //remove the crap out of this attribute. + attributesToRemove.add(i); + ArchetypeTerm term = archetype.getTerm(attribute.getParent(), archetype.getOriginalLanguage().getCodeString()); + if (term != null) { + term.setText((nameConstraint.getConstraint().get(0))); + } else { + term = new ArchetypeTerm(); + term.setCode(attribute.getParent().getNodeId()); + term.setText(nameConstraint.getConstraint().get(0)); + term.setDescription(nameConstraint.getConstraint().get(0)); + getOrCreateTermDefinitions().put(attribute.getParent().getNodeId(), term); + } } } } } + i++; + } + Collections.reverse(attributesToRemove); + for(int index:attributesToRemove) { + cObject.getAttributes().remove(index); } + } + + private void specializeNodeIds(CAttribute attribute) { + for(CObject child:attribute.getChildren()) { specializeNodeIds(child); } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index cb1fead91..84d647e58 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -17,24 +17,24 @@ public class Opt14Converter { public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes) { - Template template = new Template(); - template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); - template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); - if(opt14.getUid() != null) { - template.setUid(opt14.getUid().getValue()); - } - DescriptionConverter.convert(template, opt14); + try { + ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); + config.setAllowEmptyNodeIdsForSpecializations(true); + config.setApplyDiff(true);//TODO: check what the LCS diff does! - new DefinitionConverter().convert(template, opt14); + Template template = new Template(); + template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); + if(opt14.getUid() != null) { + template.setUid(opt14.getUid().getValue()); + } + DescriptionConverter.convert(template, opt14); + new DefinitionConverter().convert(template, opt14, config); - new NodeIdFixer().fixNodeIds(template, new RepoFlatArchetypeProvider(adl2Archetypes)); + new NodeIdFixer().fixNodeIds(template, new RepoFlatArchetypeProvider(adl2Archetypes)); - try { - ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); - config.setAllowEmptyNodeIdsForSpecializations(true); - config.setApplyDiff(false); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), config); converter.setExistingRepository(adl2Archetypes); ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java index 6ac41cfa1..5096a1549 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java @@ -1,18 +1,49 @@ package com.nedap.archie.opt14; +import com.nedap.archie.adl14.ADL14ConversionConfiguration; +import com.nedap.archie.adl14.ADL14ConversionUtil; +import com.nedap.archie.adl14.aom14.TermBindingsList; import com.nedap.archie.aom.Template; import com.nedap.archie.aom.terminology.ArchetypeTerm; import com.nedap.archie.aom.terminology.ArchetypeTerminology; +import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.rm.archetyped.Link; +import java.net.URI; +import java.net.URISyntaxException; import java.util.LinkedHashMap; +import java.util.Map; public class TerminologyConverter { - public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, CARCHETYPEROOT definition) { + public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, CARCHETYPEROOT definition, + ADL14ConversionConfiguration config) { ArchetypeTerminology terminology = new ArchetypeTerminology(); String language = opt14.getLanguage().getCodeString(); LinkedHashMap terms = new LinkedHashMap<>(); terminology.getTermDefinitions().put(language, terms); + if(definition.getTermBindings() != null) { + ADL14ConversionUtil conversionUtil = new ADL14ConversionUtil(config); + for(TermBindingSet bindings14:definition.getTermBindings()) { + + ensureTermBindingKeyExists(terminology, bindings14.getTerminology()); + Map newBindings = terminology.getTermBindings().get(bindings14.getTerminology()); + + for(TERMBINDINGITEM item14:bindings14.getItems()) { + try { + URI newBindingValue = conversionUtil.convertToUri(BaseTypesConverter.convert(item14.getValue())); + newBindings.put(item14.getCode(), newBindingValue); + //So this is an old path, will be converted later + //not inside te parser, obviously + //URIs need to be converted to even fit into the new model + } catch (URISyntaxException e) { + //TODO: add to conversion notes/messages/warnings + //logger.warn("error converting term binding to URI", e); + } + + } + } + } for(ARCHETYPETERM term14:definition.getTermDefinitions()) { ArchetypeTerm term = new ArchetypeTerm(); term.setCode(term14.getCode()); @@ -21,7 +52,13 @@ public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, } terms.put(term14.getCode(), term); } - //TODO: term bindings return terminology; } + + + private static void ensureTermBindingKeyExists(ArchetypeTerminology terminology, String key) { + if(!terminology.getTermBindings().containsKey(key)) { + terminology.getTermBindings().put(key, new LinkedHashMap<>()); + } + } } diff --git a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java index 10a50910c..956e4cd74 100644 --- a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java +++ b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java @@ -95,7 +95,7 @@ public ADL2ConversionResultList convert(List archetypes, ADL2Conversi if(conversionConfiguration.isApplyDiff()) { result.setArchetype(differentiator.differentiate(result.getArchetype(), flatParent, true)); } else { - result.setArchetype(differentiator.differentiate(result.getArchetype(), flatParent, false)); + //result.setArchetype(differentiator.differentiate(result.getArchetype(), flatParent, false)); } } resultList.addConversionResult(result); diff --git a/tools/src/main/java/com/nedap/archie/diff/ConstraintDifferentiator.java b/tools/src/main/java/com/nedap/archie/diff/ConstraintDifferentiator.java index e6a137a11..89b5e2e6f 100644 --- a/tools/src/main/java/com/nedap/archie/diff/ConstraintDifferentiator.java +++ b/tools/src/main/java/com/nedap/archie/diff/ConstraintDifferentiator.java @@ -2,19 +2,23 @@ import com.nedap.archie.adlparser.modelconstraints.ModelConstraintImposer; import com.nedap.archie.aom.*; +import com.nedap.archie.aom.terminology.ArchetypeTerm; import com.nedap.archie.aom.utils.AOMUtils; import com.nedap.archie.base.Cardinality; import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.base.terminology.TerminologyCode; import com.nedap.archie.query.ComplexObjectProxyReplacement; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class ConstraintDifferentiator { private final Archetype flatParent; private final ModelConstraintImposer constraintImposer; + private boolean specializeDifferentTerm = false; ConstraintDifferentiator(ModelConstraintImposer constraintImposer, Archetype flatParent) { this.flatParent = flatParent; @@ -195,7 +199,21 @@ private boolean shouldRemoveUnspecializedCObject(CObject childCObject, CObject c } else { //no children, no occurrences, child object is in parent. check specialization id if(childCObject.specialisationDepth() == childCObjectInParent.specialisationDepth()) { - return true; + if(!specializeDifferentTerm) { + return true; + } else { + Archetype archetype = childCObject.getArchetype(); + TerminologyCode originalLanguage = archetype.getOriginalLanguage(); + ArchetypeTerm term = archetype.getTerm(childCObject, originalLanguage.getCodeString()); + ArchetypeTerm parentTerm = flatParent.getTerm(childCObjectInParent, originalLanguage.getCodeString()); + if(term == null || parentTerm == null) { + //can't be handled, get rid of it + return true; + } else { + //delete if term is the same. Otherwise, it will be specialized later. + return Objects.equals(term.getText(), parentTerm.getText()) && Objects.equals(term.getDescription(), parentTerm.getDescription()); + } + } } return false; } diff --git a/tools/src/main/java/com/nedap/archie/diff/Differentiator.java b/tools/src/main/java/com/nedap/archie/diff/Differentiator.java index 42eed7c29..f7420c3ff 100644 --- a/tools/src/main/java/com/nedap/archie/diff/Differentiator.java +++ b/tools/src/main/java/com/nedap/archie/diff/Differentiator.java @@ -37,6 +37,7 @@ public Archetype differentiate(Archetype flatChild, Archetype flatParent, boolea new ConstraintDifferentiator(constraintImposer, flatParent).removeUnspecializedConstraints(result, flatParent); new DifferentialPathGenerator().replace(result); + //TODO: when converting OPT 1.4, add specialized nodes here whenever text/description is changed from parent! new TerminologyDifferentiator().differentiate(result); new DefaultRmStructureRemover(metaModels, false).removeRMDefaults(result); diff --git a/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java b/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java index b31fe26c3..e0ec41da3 100644 --- a/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java +++ b/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java @@ -103,7 +103,7 @@ private void removeLastSiblingOrderIfPossible(LinkedHashMap cObjects = siblingOrders.get(last); - boolean allAdds = true; + for(CObject cObject:cObjects) { if(AOMUtils.getSpecialisationStatusFromCode(cObject.getNodeId(), specializationDepth) == CodeRedefinitionStatus.ADDED || AOMUtils.isOverriddenIdCode(cObject.getNodeId(), last.getSiblingNodeId()) diff --git a/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java b/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java index cf4767223..8db8ac32e 100644 --- a/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java +++ b/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.List; +/** removes all intervals that are lower + upper unbouded, so, matches {*} */ public class UnconstrainedIntervalRemover { public static void removeUnconstrainedIntervals(Archetype archetype) { From 72d26a3e9f46dc7730c99bb365fc9e782a1ae157 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 19 Jul 2021 16:59:21 +0200 Subject: [PATCH 08/36] Implement better node id specializer, make conversion actually work --- ....java => NodeIdFixerBeforeConversion.java} | 8 ++- .../nedap/archie/opt14/NodeIdSpecializer.java | 68 +++++++++++++++++-- .../nedap/archie/opt14/Opt14Converter.java | 25 +++++-- ...erterTest.java => Opt14ConverterTest.java} | 2 +- 4 files changed, 91 insertions(+), 12 deletions(-) rename opt14/src/main/java/com/nedap/archie/opt14/{NodeIdFixer.java => NodeIdFixerBeforeConversion.java} (93%) rename opt14/src/test/java/com/nedap/archie/opt14/{ConverterTest.java => Opt14ConverterTest.java} (98%) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java similarity index 93% rename from opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java rename to opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java index 7598fc3ea..aad5ef987 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java @@ -13,7 +13,13 @@ import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import org.openehr.utils.message.I18n; -public class NodeIdFixer { +/** + * Changes node ids so the archetype becomes a specialization rather than just a changed archetype at a very basic level + * ran before ADL 1.4 -> 2 conversion. + * + * After that a nex step must be taken to ensure more node id fixes after conversion, then diffing must still occur + */ +public class NodeIdFixerBeforeConversion { private Archetype archetype; private Archetype flatParent; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java index 1cfa3ce42..2b51da683 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java @@ -10,7 +10,9 @@ import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.aom.primitives.CString; import com.nedap.archie.aom.terminology.ArchetypeTerm; +import com.nedap.archie.aom.terminology.ArchetypeTerminology; import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.diff.PrimitiveObjectEqualsChecker; import com.nedap.archie.query.AOMPathQuery; import com.nedap.archie.query.RMPathQuery; import com.nedap.archie.rminfo.ArchieRMInfoLookup; @@ -70,12 +72,29 @@ private void specializeNodeIds(CObject cObject) { if(parentCObject != null) { ArchetypeTerm term = archetype.getTerm(cObject, archetype.getOriginalLanguage().getCodeString()); ArchetypeTerm parentTerm = flatParent.getTerm(parentCObject, archetype.getOriginalLanguage().getCodeString()); - if( cObject.getNodeId().equalsIgnoreCase(parentCObject.getNodeId())) { - if(parentTerm != null && term != null) { - if (!term.getText().equalsIgnoreCase(parentTerm.getText()) || - !term.getDescription().equalsIgnoreCase(parentTerm.getDescription())) { - //term changes. We need a new node id - //TODO + if ( cObject.getNodeId().equalsIgnoreCase(parentCObject.getNodeId())) { + boolean createSpecializedObject = false; + if ( parentTerm != null ) { + if (term != null) { + if (!term.getText().equalsIgnoreCase(parentTerm.getText()) || + !term.getDescription().equalsIgnoreCase(parentTerm.getDescription())) { + createSpecializedObject = true; + } + } + } + if (cObjectHasChangedPrimitiveChildren(cObject, parentCObject)) { + createSpecializedObject = true; + + } + if(createSpecializedObject) { + //content changes. We need a new node id + String newNodeId = archetype.generateNextSpecializedIdCode(cObject.getNodeId()); + String oldNodeId = cObject.getNodeId(); + cObject.setNodeId(newNodeId); + ArchetypeTerminology terminology = cObject.getArchetype().getTerminology(); + for (String language : terminology.getTermDefinitions().keySet()) { + ArchetypeTerm removed = terminology.getTermDefinitions().get(language).remove(oldNodeId); + terminology.getTermDefinitions().get(language).put(newNodeId, removed); } } } @@ -88,6 +107,7 @@ private void specializeNodeIds(CObject cObject) { // throw new RuntimeException("I did not expect the Spanish inquisition!");//TODO: remove or add proper message } + for(CAttribute attribute:cObject.getAttributes()) { specializeNodeIds(attribute); } @@ -96,6 +116,42 @@ private void specializeNodeIds(CObject cObject) { } + private boolean cObjectHasChangedPrimitiveChildren(CObject cObject, CObject parentCObject) { + for(CAttribute attribute:cObject.getAttributes()) { + int i = 0; + for(CObject childObject:attribute.getChildren()) { + if(childObject instanceof CPrimitiveObject) { + //found a primitive object. Check if it's exactly the same as the parent + CAttribute attributeFromParent = parentCObject.getAttribute(attribute.getRmAttributeName()); + if(attributeFromParent == null) { + //new attribute with primitive content, needs specialization + return true; + } else { + if(i < attributeFromParent.getChildren().size()) { + CObject childObjectFromParent = attributeFromParent.getChildren().get(i); + if(!(childObjectFromParent instanceof CPrimitiveObject)) { + throw new RuntimeException("primitive object being converted is a non primitive object in parent at " + archetype.getArchetypeId() + " " + cObject.getPath()); + } + if(!primitiveObjectEquals( (CPrimitiveObject) childObject, (CPrimitiveObject) childObjectFromParent)) { + return true; + } + } else { + //more cobjects than the parent has. + return true; + } + } + } + i++; + } + } + return false; + } + + private boolean primitiveObjectEquals(CPrimitiveObject childObject, CPrimitiveObject childObjectFromParent) { + PrimitiveObjectEqualsChecker.isEqual(childObject, childObjectFromParent); + return true; + } + /** * replace all 'name matches DV_TEXT { value matches {"some static name"}}' constraints to archtype terms * @param cObject diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 84d647e58..23aa92350 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -8,11 +8,15 @@ import com.nedap.archie.adl14.OpenEHRADL14ConversionConfiguration; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.diff.Differentiator; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; import org.openehr.referencemodels.BuiltinReferenceModels; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class Opt14Converter { @@ -20,7 +24,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA try { ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); config.setAllowEmptyNodeIdsForSpecializations(true); - config.setApplyDiff(true);//TODO: check what the LCS diff does! + config.setApplyDiff(false);//the diff must be applied manually later, after converting node ids Template template = new Template(); template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); @@ -33,17 +37,30 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA new DefinitionConverter().convert(template, opt14, config); - new NodeIdFixer().fixNodeIds(template, new RepoFlatArchetypeProvider(adl2Archetypes)); + RepoFlatArchetypeProvider flatParentProvider = new RepoFlatArchetypeProvider(adl2Archetypes); + new NodeIdFixerBeforeConversion().fixNodeIds(template, flatParentProvider); + Differentiator differentiator = new Differentiator(BuiltinReferenceModels.getMetaModels()); ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), config); converter.setExistingRepository(adl2Archetypes); ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); ADL2ConversionResult adl2ConversionResult = converted.getConversionResults().get(0); + if(adl2ConversionResult.getArchetype() != null) { Template convertedTemplate = (Template) adl2ConversionResult.getArchetype(); - new NodeIdSpecializer().specializeNodeIds(convertedTemplate, new RepoFlatArchetypeProvider(adl2Archetypes)); - System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate)); + new NodeIdSpecializer().specializeNodeIds(convertedTemplate, flatParentProvider); + for(TemplateOverlay overlay: convertedTemplate.getTemplateOverlays()) { + new NodeIdSpecializer().specializeNodeIds(overlay, flatParentProvider); + } + convertedTemplate = (Template) differentiator.differentiate(convertedTemplate, flatParentProvider.getFlatArchetype(template.getParentArchetypeId()), true); + List newOverlays = new ArrayList(); + for(TemplateOverlay overlay: convertedTemplate.getTemplateOverlays()) { + TemplateOverlay newOverlay = (TemplateOverlay) differentiator.differentiate(overlay, flatParentProvider.getFlatArchetype(overlay.getParentArchetypeId()), true); + newOverlays.add(newOverlay); + } + adl2ConversionResult.setArchetype(convertedTemplate); + convertedTemplate.setTemplateOverlays(newOverlays); } return converted; } catch (IOException e) { diff --git a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java similarity index 98% rename from opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java rename to opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index de2a81a62..b55685656 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -17,7 +17,7 @@ import java.io.IOException; import java.io.InputStream; -public class ConverterTest { +public class Opt14ConverterTest { @Test public void procedureList() throws Exception { From 9256e3666fa1fd29968d48bc0c7ca347ba333fef Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 19 Jul 2021 17:11:24 +0200 Subject: [PATCH 09/36] Add validation to test, add ArchetypeTermFixer and make first conversion validate! --- .../archie/opt14/ArchetypeTermFixer.java | 194 ++++++++++++++++++ .../nedap/archie/opt14/Opt14Converter.java | 2 + .../archie/opt14/Opt14ConverterTest.java | 21 +- 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java diff --git a/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java b/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java new file mode 100644 index 000000000..7e011a51a --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java @@ -0,0 +1,194 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.CArchetypeRoot; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.CPrimitiveObject; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.aom.terminology.ArchetypeTerm; +import com.nedap.archie.aom.terminology.ArchetypeTerminology; +import com.nedap.archie.aom.terminology.ValueSet; +import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.aom.utils.NodeIdUtil; +import com.nedap.archie.base.Interval; +import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.regex.Pattern; + +public class ArchetypeTermFixer { + + private String originalLanguage; + + public void fixTerms(Archetype archetype, FlatArchetypeProvider repo) { + originalLanguage = archetype.getOriginalLanguage().getCodeString(); + addTerminologyIfNotPresent(archetype); + fixTerms(archetype,repo, archetype.getDefinition()); + fixValueSetCodes(archetype, repo); + + removeUntranslatedLanguages(archetype); + + if(archetype instanceof Template) { + Template template = (Template) archetype; + for(TemplateOverlay overlay:template.getTemplateOverlays()) { + addTerminologyIfNotPresent(overlay); + fixTerms(overlay, repo, overlay.getDefinition()); + fixValueSetCodes(overlay, repo); + } + } + } + + private void fixValueSetCodes(Archetype archetype, FlatArchetypeProvider repo) { + String language = originalLanguage; + if(!archetype.getTerminology().getTermDefinitions().containsKey(originalLanguage)) { + language = archetype.getTerminology().getTermDefinitions().keySet().iterator().next(); + } + if(archetype.getTerminology() != null && archetype.getTerminology().getValueSets() != null) { + for(String code:archetype.getTerminology().getValueSets().keySet()) { + if(!archetype.getTerminology().getTermDefinitions().get(language).containsKey(code) && + AOMUtils.getSpecializationDepthFromCode(code) == archetype.specializationDepth()) { + Archetype flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); + createTermForNewCodeWithFlatParent(archetype, code, flatParent); + } + for(String valueCode:archetype.getTerminology().getValueSets().get(code).getMembers()) { + if(!archetype.getTerminology().getTermDefinitions().get(language).containsKey(valueCode) && + AOMUtils.getSpecializationDepthFromCode(valueCode) == archetype.specializationDepth()) { + Archetype flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); + createTermForNewCodeWithFlatParent(archetype, valueCode, flatParent); + } + } + } + } + } + + private void addTerminologyIfNotPresent(Archetype archetype) { + if(archetype.getTerminology() == null) { + archetype.setTerminology(new ArchetypeTerminology()); + } + if(archetype.getTerminology().getTermDefinitions().isEmpty()) { + archetype.getTerminology().getTermDefinitions().put(originalLanguage, new LinkedHashMap<>()); + } + } + + /** If any languages do not exist in the terminology, remove from translations*/ + private void removeUntranslatedLanguages(Archetype archetype) { + if(archetype.getTranslations() == null) { + return; + } + List toRemove = new ArrayList<>(); + for(String translation:archetype.getTranslations().keySet()) { + if(archetype.getTerminology() != null && !archetype.getTerminology().getTermDefinitions().containsKey(translation)) { + toRemove.add(translation); + } + } + if(!toRemove.isEmpty()) { + for(String translation:toRemove) { + archetype.getTranslations().remove(translation); + } + } + } + + private void fixTerms(Archetype archetype, FlatArchetypeProvider repo, CComplexObject cObject) { + String language = originalLanguage; + if(!archetype.getTerminology().getTermDefinitions().containsKey(originalLanguage)) { + language = archetype.getTerminology().getTermDefinitions().keySet().iterator().next(); + } + if(cObject instanceof CArchetypeRoot) { + if(!archetype.getTerminology().getTermDefinitions().get(language).containsKey(cObject.getNodeId()) && + archetype.specializationDepth() == AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) + ) { + Archetype referencedArchetype = repo.getFlatArchetype(((CArchetypeRoot) cObject).getArchetypeRef()); + createTermForNewCodeWithRoot(archetype, cObject.getNodeId(), referencedArchetype); + //TODO: fix lots of problems where node ids are set wrong, for example id2.1 to set the occurrences of id2 to {0} is a problem! + } + } else if(cObject instanceof CComplexObject) { + + if(!archetype.getTerminology().getTermDefinitions().get(language).containsKey(cObject.getNodeId()) && + archetype.specializationDepth() == AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) + ) { + Archetype flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); + createTermForNewCodeWithFlatParent(archetype, cObject.getNodeId(), flatParent); + //TODO: fix lots of problems where node ids are set wrong, for example id2.1 to set the occurrences of id2 to {0} is a problem! + } + } + for(CAttribute attribute:cObject.getAttributes()) { + fixTerms(archetype, repo, attribute); + } + } + + private void fixTerms(Archetype archetype, FlatArchetypeProvider repo, CAttribute cAttribute) { + + for(CObject cObject:cAttribute.getChildren()) { + if(cObject instanceof CComplexObject) { + fixTerms(archetype, repo, (CComplexObject) cObject); + } + } + } + + private static Pattern synthesizedCodesPattern = Pattern.compile("(id)(0\\.)*9[0-9][0-9][0-9](\\.[0-9]*)*"); + + private void createTermForNewCodeWithRoot(Archetype archetype, String code, Archetype referencedArchetype) { + + //if(cObject.getParent().isMultiple()) { + for (String language : archetype.getTerminology().getTermDefinitions().keySet()) { + //TODO: add new archetype term to conversion log? + + ArchetypeTerm newTerm = new ArchetypeTerm(); + newTerm.setCode(code); + ArchetypeTerm rootTerm = null; + if (referencedArchetype != null) { + rootTerm = referencedArchetype.getTerm(referencedArchetype.getDefinition(), language); + if(rootTerm == null) { + rootTerm = referencedArchetype.getDefinition().getTerm(); + } + if(rootTerm == null) { + //yeas this is persistent + rootTerm = referencedArchetype.getTerminology().getTermDefinition("en", "id1"); + } + } + + newTerm.setText(rootTerm == null ? "* missing code" : rootTerm.getText()); + newTerm.setDescription(rootTerm == null ? "* missing code" : rootTerm.getDescription()); + archetype.getTerminology().getTermDefinitions().get(language).put(newTerm.getCode(), newTerm); + + } + + // } + } + + private void createTermForNewCodeWithFlatParent(Archetype archetype, String code, Archetype flatParent) { + if(!synthesizedCodesPattern.matcher(code).matches()) { + //TODO: better would be, but difficult to do correctly: + // if(cObject.getParent().isMultiple()) { + for (String language : archetype.getTerminology().getTermDefinitions().keySet()) { + //TODO: add new archetype term to conversion log? + + ArchetypeTerm newTerm = new ArchetypeTerm(); + newTerm.setCode(code); + ArchetypeTerm parentTerm = null; + if (flatParent != null) { + ArchetypeTerminology parentTerminology = flatParent.getTerminology(); + if(parentTerminology != null) { + if(parentTerminology.getTermDefinitions().get(language) != null) { + parentTerm = parentTerminology.getTermDefinition(language, AOMUtils.codeAtLevel(code, flatParent.specializationDepth())); + } else { + parentTerm = parentTerminology.getTermDefinition(flatParent.getOriginalLanguage().getCodeString(), AOMUtils.codeAtLevel(code, flatParent.specializationDepth())); + } + } + } + + newTerm.setText(parentTerm == null ? "* missing code" : parentTerm.getText()); + newTerm.setDescription(parentTerm == null ? "* missing code" : parentTerm.getDescription()); + archetype.getTerminology().getTermDefinitions().get(language).put(newTerm.getCode(), newTerm); + + } + } + // } + } + +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 23aa92350..2417631ee 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -50,8 +50,10 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA Template convertedTemplate = (Template) adl2ConversionResult.getArchetype(); new NodeIdSpecializer().specializeNodeIds(convertedTemplate, flatParentProvider); + new ArchetypeTermFixer().fixTerms(convertedTemplate, flatParentProvider); for(TemplateOverlay overlay: convertedTemplate.getTemplateOverlays()) { new NodeIdSpecializer().specializeNodeIds(overlay, flatParentProvider); + new ArchetypeTermFixer().fixTerms(overlay, flatParentProvider); } convertedTemplate = (Template) differentiator.differentiate(convertedTemplate, flatParentProvider.getFlatArchetype(template.getParentArchetypeId()), true); List newOverlays = new ArrayList(); diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index b55685656..9928537a9 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -5,7 +5,11 @@ import com.nedap.archie.adlparser.ADLParseException; import com.nedap.archie.adlparser.ADLParser; import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.Template; +import com.nedap.archie.archetypevalidator.ArchetypeValidator; +import com.nedap.archie.archetypevalidator.ValidationResult; +import com.nedap.archie.flattener.Flattener; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; import org.junit.Test; @@ -17,6 +21,8 @@ import java.io.IOException; import java.io.InputStream; +import static org.junit.Assert.assertTrue; + public class Opt14ConverterTest { @Test @@ -37,7 +43,20 @@ public void procedureList() throws Exception { result.getException().printStackTrace(); } } - System.out.println(ADLArchetypeSerializer.serialize(convert.getConversionResults().get(0).getArchetype())); + Template convertedTemplate = (Template) convert.getConversionResults().get(0).getArchetype(); + System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate)); + + OperationalTemplate opt2 = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels()) + .createOperationalTemplate(true) + .keepLanguages("en") + .flatten(convertedTemplate); + + System.out.println(ADLArchetypeSerializer.serialize(opt2)); + + ArchetypeValidator validator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ValidationResult validationResult = validator.validate(convertedTemplate, repository); + assertTrue(validationResult.toString(), validationResult.passes()); + } } From 681020199517b7b29c847be91f4c4f90ba6e01ee Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 19 Jul 2021 17:18:57 +0200 Subject: [PATCH 10/36] Fix javadoc error --- .../com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java index aad5ef987..87f519075 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java @@ -15,7 +15,7 @@ /** * Changes node ids so the archetype becomes a specialization rather than just a changed archetype at a very basic level - * ran before ADL 1.4 -> 2 conversion. + * ran before ADL 1.4 to 2 conversion. * * After that a nex step must be taken to ensure more node id fixes after conversion, then diffing must still occur */ From 4a4fe876f786ff58e8e985e8142afadafd720cef Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 20 Jul 2021 12:16:59 +0200 Subject: [PATCH 11/36] Add more specialization cases, add occurences matches {0} or closed when needed --- .../nedap/archie/opt14/NodeIdSpecializer.java | 76 +++++++++++++++---- .../nedap/archie/opt14/Opt14Converter.java | 10 ++- .../archie/flattener/CAttributeFlattener.java | 40 +--------- .../nedap/archie/flattener/FlattenerUtil.java | 43 +++++++++++ 4 files changed, 111 insertions(+), 58 deletions(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java index 2b51da683..520a2f6ab 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java @@ -1,21 +1,19 @@ package com.nedap.archie.opt14; -import com.nedap.archie.aom.Archetype; -import com.nedap.archie.aom.ArchetypeModelObject; -import com.nedap.archie.aom.CAttribute; -import com.nedap.archie.aom.CComplexObject; -import com.nedap.archie.aom.CObject; -import com.nedap.archie.aom.CPrimitiveObject; -import com.nedap.archie.aom.Template; -import com.nedap.archie.aom.TemplateOverlay; +import com.google.common.collect.Lists; +import com.nedap.archie.aom.*; import com.nedap.archie.aom.primitives.CString; import com.nedap.archie.aom.terminology.ArchetypeTerm; import com.nedap.archie.aom.terminology.ArchetypeTerminology; import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.base.MultiplicityInterval; import com.nedap.archie.diff.PrimitiveObjectEqualsChecker; +import com.nedap.archie.flattener.FlattenerUtil; import com.nedap.archie.query.AOMPathQuery; import com.nedap.archie.query.RMPathQuery; import com.nedap.archie.rminfo.ArchieRMInfoLookup; +import com.nedap.archie.rminfo.MetaModels; +import org.openehr.referencemodels.BuiltinReferenceModels; import java.lang.reflect.Array; import java.util.ArrayList; @@ -38,11 +36,17 @@ public class NodeIdSpecializer { private Archetype archetype; private Archetype flatParent; + private MetaModels metaModels; + + public NodeIdSpecializer(MetaModels metaModels) { + this.metaModels = metaModels; + } public void specializeNodeIds(Archetype archetype, FlatArchetypeProvider repo) { if(archetype.getParentArchetypeId() == null) { return; } + metaModels.selectModel(archetype); this.archetype = archetype; if(archetype.getParentArchetypeId() != null) { this.flatParent = repo.getFlatArchetype(archetype.getParentArchetypeId()); @@ -64,7 +68,13 @@ public void specializeNodeIds(Archetype archetype, FlatArchetypeProvider repo) { } - private void specializeNodeIds(CObject cObject) { + /** + * Specialize the node ids of cObject. Returns to prevent ConcurrentModificationExceptions + * @param cObject the object to check and specialize + * @return null if no object should be added to the parent right after current object, non-null to indicate it must be added + */ + private CObject specializeNodeIds(CObject cObject) { + CObject parentReplacement = null; if(!(cObject instanceof CPrimitiveObject)) { String flatPath = AOMUtils.pathAtSpecializationLevel(cObject.getPathSegments(), flatParent.specializationDepth()); CObject parentCObject = getCObject(flatParent.itemAtPath(flatPath)); @@ -84,10 +94,14 @@ private void specializeNodeIds(CObject cObject) { } if (cObjectHasChangedPrimitiveChildren(cObject, parentCObject)) { createSpecializedObject = true; - + } + if(cObjectIsSpecializedArchetypeRoot(cObject, parentCObject)) { + createSpecializedObject = true; + } + if(cObjectHasTypeNameChange(cObject, parentCObject)) { + createSpecializedObject = true; } if(createSpecializedObject) { - //content changes. We need a new node id String newNodeId = archetype.generateNextSpecializedIdCode(cObject.getNodeId()); String oldNodeId = cObject.getNodeId(); cObject.setNodeId(newNodeId); @@ -96,24 +110,45 @@ private void specializeNodeIds(CObject cObject) { ArchetypeTerm removed = terminology.getTermDefinitions().get(language).remove(oldNodeId); terminology.getTermDefinitions().get(language).put(newNodeId, removed); } + if(!FlattenerUtil.shouldReplaceSpecializedParent(parentCObject, Lists.newArrayList(cObject), metaModels)) { + //this node should not replace its parent, but should just be added. however, the OPT indicates it should + //so create a new CObject with node id of the parent, occurrences matches {0} + if(parentCObject instanceof ArchetypeSlot) { + parentReplacement = new ArchetypeSlot(); + ((ArchetypeSlot) parentReplacement).setClosed(true); + } else { + parentReplacement = new CComplexObject(); + parentReplacement.setOccurrences(MultiplicityInterval.createProhibited()); + } + parentReplacement.setNodeId(oldNodeId); + parentReplacement.setRmTypeName(parentCObject.getRmTypeName()); + } } } } else { //someone added a new node. It wil have a specialized id already - or it should anyway. let's check! if(AOMUtils.getSpecializationDepthFromCode(cObject.getNodeId()) != flatParent.specializationDepth() +1) { - System.out.println("change of code!");//TODO + throw new RuntimeException("Template added a field with an incorrect specialization depth at " + cObject.getPath());//TODO: remove or add proper message } - // throw new RuntimeException("I did not expect the Spanish inquisition!");//TODO: remove or add proper message + // } - for(CAttribute attribute:cObject.getAttributes()) { specializeNodeIds(attribute); } changeNameConstraintToArchetypeTerm(cObject); } + return parentReplacement; + + } + private boolean cObjectIsSpecializedArchetypeRoot(CObject cObject, CObject parentCObject) { + return cObject instanceof CArchetypeRoot && parentCObject instanceof ArchetypeSlot; + } + + private boolean cObjectHasTypeNameChange(CObject cObject, CObject parentCObject) { + return !cObject.getRmTypeName().equals(parentCObject.getRmTypeName()); } private boolean cObjectHasChangedPrimitiveChildren(CObject cObject, CObject parentCObject) { @@ -194,8 +229,19 @@ private void changeNameConstraintToArchetypeTerm(CObject cObject) { private void specializeNodeIds(CAttribute attribute) { + List objectsToAdd = new ArrayList<>(); for(CObject child:attribute.getChildren()) { - specializeNodeIds(child); + CObject toAdd = specializeNodeIds(child); + if(toAdd != null) { + //add temporary sibling order to be able to add this node in the correct position + toAdd.setSiblingOrder(SiblingOrder.createAfter(child.getNodeId())); + objectsToAdd.add(toAdd); + } + } + for(CObject cObject:objectsToAdd) { + attribute.addChild(cObject, cObject.getSiblingOrder()); + //remove temporary sibling order added above + cObject.setSiblingOrder(null); } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 2417631ee..bc436d98e 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -11,6 +11,7 @@ import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.diff.Differentiator; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -22,6 +23,7 @@ public class Opt14Converter { public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes) { try { + MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); config.setAllowEmptyNodeIdsForSpecializations(true); config.setApplyDiff(false);//the diff must be applied manually later, after converting node ids @@ -39,9 +41,9 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA RepoFlatArchetypeProvider flatParentProvider = new RepoFlatArchetypeProvider(adl2Archetypes); new NodeIdFixerBeforeConversion().fixNodeIds(template, flatParentProvider); - Differentiator differentiator = new Differentiator(BuiltinReferenceModels.getMetaModels()); + Differentiator differentiator = new Differentiator(metaModels); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), config); + ADL14Converter converter = new ADL14Converter(metaModels, config); converter.setExistingRepository(adl2Archetypes); ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); ADL2ConversionResult adl2ConversionResult = converted.getConversionResults().get(0); @@ -49,10 +51,10 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA if(adl2ConversionResult.getArchetype() != null) { Template convertedTemplate = (Template) adl2ConversionResult.getArchetype(); - new NodeIdSpecializer().specializeNodeIds(convertedTemplate, flatParentProvider); + new NodeIdSpecializer(metaModels).specializeNodeIds(convertedTemplate, flatParentProvider); new ArchetypeTermFixer().fixTerms(convertedTemplate, flatParentProvider); for(TemplateOverlay overlay: convertedTemplate.getTemplateOverlays()) { - new NodeIdSpecializer().specializeNodeIds(overlay, flatParentProvider); + new NodeIdSpecializer(metaModels).specializeNodeIds(overlay, flatParentProvider); new ArchetypeTermFixer().fixTerms(overlay, flatParentProvider); } convertedTemplate = (Template) differentiator.differentiate(convertedTemplate, flatParentProvider.getFlatArchetype(template.getParentArchetypeId()), true); diff --git a/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java b/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java index 2225c2b39..86eb46c6f 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java +++ b/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java @@ -265,49 +265,11 @@ private boolean shouldRemoveParent(CObject specializedChildCObject, CObject matc } else if(allMatchingChildren.get(allMatchingChildren.size()-1).getNodeId().equalsIgnoreCase(specializedChildCObject.getNodeId())) { //the last matching child should possibly replace the parent, the rest should just add //if there is just one child, that's fine, it should still work - return shouldReplaceSpecializedParent(matchingParentObject, allMatchingChildren); + return FlattenerUtil.shouldReplaceSpecializedParent(matchingParentObject, allMatchingChildren, flattener.getMetaModels()); } return false; } - private boolean shouldReplaceSpecializedParent(CObject parent, List differentialNodes) { - - MultiplicityInterval occurrences = parent.effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity); - //isSingle/isMultiple is tricky and not doable just in the parser. Don't use those - if(isSingle(parent.getParent())) { - return true; - } else if(occurrences != null && occurrences.upperIsOne()) { - //REFINE the parent node case 1, the parent has occurrences upper == 1 - return true; - } else if (differentialNodes.size() == 1) { - MultiplicityInterval effectiveOccurrences; - //the differentialNode can have a differential path instead of an attribute name. In that case, we need to replace the rm type name - //of the parent with the actual typename in the parent archetype. Otherwise, it may fall back to the default type in the RM, - //and that can be an abstract type that does not have the attribute that we are trying to constrain. For example: - //diff archetype: - // /events[id6]/data/items matches { - //in the rm, data maps to an ITEM_STRUCTURE that does not have the attribute items. - //in the parent archetype, that is then an ITEM_TREE. We need to use ITEM_TREE here, which is what this code accomplishes. - if(parent.getParent() == null || parent.getParent().getParent() == null) { - effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity); - } else { - effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences((s, s2) -> flattener.getMetaModels().referenceModelPropMultiplicity( - parent.getParent().getParent().getRmTypeName(), parent.getParent().getRmAttributeName())); - } - if(effectiveOccurrences != null && effectiveOccurrences.upperIsOne()) { - //REFINE the parent node case 2, only one child with occurrences upper == 1 - return true; - } - } - return false; - } - - private boolean isSingle(CAttribute attribute) { - if(attribute != null && attribute.getParent() != null && attribute.getDifferentialPath() == null) { - return !flattener.getMetaModels().isMultiple(attribute.getParent().getRmTypeName(), attribute.getRmAttributeName()); - } - return false; - } /** * Find the matching parent CObject given a specialized child. REturns null if not found. diff --git a/tools/src/main/java/com/nedap/archie/flattener/FlattenerUtil.java b/tools/src/main/java/com/nedap/archie/flattener/FlattenerUtil.java index 96c4d984a..444ab03b5 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/FlattenerUtil.java +++ b/tools/src/main/java/com/nedap/archie/flattener/FlattenerUtil.java @@ -1,6 +1,9 @@ package com.nedap.archie.flattener; +import com.nedap.archie.aom.CAttribute; import com.nedap.archie.aom.CObject; +import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.rules.Assertion; import java.util.List; @@ -22,4 +25,44 @@ public static T getPossiblyOverridenValue(T parent, T specialized) { } return parent; } + + public static boolean shouldReplaceSpecializedParent(CObject parent, List differentialNodes, MetaModels metaModels) { + + MultiplicityInterval occurrences = parent.effectiveOccurrences(metaModels::referenceModelPropMultiplicity); + //isSingle/isMultiple is tricky and not doable just in the parser. Don't use those + if(isSingle(parent.getParent(), metaModels)) { + return true; + } else if(occurrences != null && occurrences.upperIsOne()) { + //REFINE the parent node case 1, the parent has occurrences upper == 1 + return true; + } else if (differentialNodes.size() == 1) { + MultiplicityInterval effectiveOccurrences; + //the differentialNode can have a differential path instead of an attribute name. In that case, we need to replace the rm type name + //of the parent with the actual typename in the parent archetype. Otherwise, it may fall back to the default type in the RM, + //and that can be an abstract type that does not have the attribute that we are trying to constrain. For example: + //diff archetype: + // /events[id6]/data/items matches { + //in the rm, data maps to an ITEM_STRUCTURE that does not have the attribute items. + //in the parent archetype, that is then an ITEM_TREE. We need to use ITEM_TREE here, which is what this code accomplishes. + if(parent.getParent() == null || parent.getParent().getParent() == null) { + effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences(metaModels::referenceModelPropMultiplicity); + } else { + effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences((s, s2) -> metaModels.referenceModelPropMultiplicity( + parent.getParent().getParent().getRmTypeName(), parent.getParent().getRmAttributeName())); + } + if(effectiveOccurrences != null && effectiveOccurrences.upperIsOne()) { + //REFINE the parent node case 2, only one child with occurrences upper == 1 + return true; + } + } + return false; + } + + public static boolean isSingle(CAttribute attribute, MetaModels metaModels) { + if(attribute != null && attribute.getParent() != null && attribute.getDifferentialPath() == null) { + return !metaModels.isMultiple(attribute.getParent().getRmTypeName(), attribute.getRmAttributeName()); + } + return false; + } + } From 4ee25522289bac9be201b82de5c5ec85ae752c80 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 20 Jul 2021 12:51:42 +0200 Subject: [PATCH 12/36] Convert most of the description fields --- .../archie/opt14/DescriptionConverter.java | 48 ++++++++++++++++++- .../nedap/archie/opt14/Opt14Converter.java | 7 +++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java index 03ad636de..c0b307a64 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -1,9 +1,11 @@ package com.nedap.archie.opt14; import com.nedap.archie.aom.ResourceDescription; +import com.nedap.archie.aom.ResourceDescriptionItem; import com.nedap.archie.aom.Template; import com.nedap.archie.base.terminology.TerminologyCode; +import java.net.URI; import java.util.LinkedHashMap; import java.util.Map; @@ -25,12 +27,56 @@ public static void convert(Template template, OPERATIONALTEMPLATE opt14) { } } + if(description14.getParentResource() != null) { + //TODO: this seems to contain the parent archetype. + // however only the top level archetype used, not any included archetype roots. Very odd + //probably can be ignored? + + } + //resource uri + if(description14.getResourcePackageUri() != null) { + description.setResourcePackageUri(description14.getResourcePackageUri()); + } + if(description14.getDetails() != null) { + convertDetails(description14, description); + } description.setOtherContributors(description14.getOtherContributors()); description.setOriginalAuthor(author); template.setDescription(description); template.setOriginalLanguage(BaseTypesConverter.convert(opt14.getLanguage())); - //TODO: implement me further + } + + private static void convertDetails(RESOURCEDESCRIPTION description14, ResourceDescription description) { + Map detailsMap = new LinkedHashMap<>(); + for(RESOURCEDESCRIPTIONITEM details14:description14.getDetails()) { + if(details14.getLanguage() == null || details14.getLanguage().getCodeString() == null) { + throw new RuntimeException("Cannot convert resource description details without a language"); + } + ResourceDescriptionItem details = new ResourceDescriptionItem(); + details.setCopyright(details14.getCopyright()); + details.setKeywords(details14.getKeywords()); + details.setLanguage(BaseTypesConverter.convert(details14.getLanguage())); + details.setMisuse(details14.getMisuse()); + details.setUse(details14.getUse()); + details.setPurpose(details14.getPurpose()); + if(details14.getOriginalResourceUri() != null) { + Map uris = new LinkedHashMap<>(); + for(StringDictionaryItem item:details14.getOriginalResourceUri()) { + uris.put(item.getId(), URI.create(item.getValue())); + } + details.setOriginalResourceUri(uris); + } + if(details14.getOtherDetails() != null) { + Map otherDetails = new LinkedHashMap<>(); + for(StringDictionaryItem item:details14.getOtherDetails()) { + otherDetails.put(item.getId(), item.getValue()); + } + details.setOtherDetails(otherDetails); + } + detailsMap.put(details.getLanguage().getCodeString(), details); + } + description.setDetails(detailsMap); } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index bc436d98e..5bd1235aa 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -19,6 +19,11 @@ import java.util.ArrayList; import java.util.List; +/** + * TODO: + * archetype root DEFAULTVALUES + * + */ public class Opt14Converter { public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes) { @@ -29,7 +34,9 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA config.setApplyDiff(false);//the diff must be applied manually later, after converting node ids Template template = new Template(); + //TODO: should this include the concept, rather than just the template ID? template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + template.setControlled(opt14.isIsControlled(); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); if(opt14.getUid() != null) { template.setUid(opt14.getUid().getValue()); From 9e4475c7f9edac9fda7aef68644d23dfaa048f9f Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 20 Jul 2021 17:06:31 +0200 Subject: [PATCH 13/36] Opt 1.4 conversion: partial untested default value support --- .../archie/opt14/BaseTypesConverter.java | 55 ++++++ .../archie/opt14/DefaultValueConverter.java | 185 ++++++++++++++++++ .../nedap/archie/opt14/Opt14Converter.java | 2 +- 3 files changed, 241 insertions(+), 1 deletion(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java index 522f9c61b..80f214699 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java @@ -4,6 +4,16 @@ import com.nedap.archie.base.Interval; import com.nedap.archie.base.MultiplicityInterval; import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.rm.datatypes.CodePhrase; +import com.nedap.archie.rm.datavalues.DvCodedText; +import com.nedap.archie.rm.datavalues.DvURI; +import com.nedap.archie.rm.datavalues.TermMapping; +import com.nedap.archie.rm.datavalues.quantity.DvInterval; +import com.nedap.archie.rm.datavalues.quantity.DvOrdinal; +import com.nedap.archie.rm.support.identification.TerminologyId; + +import java.util.ArrayList; +import java.util.List; public class BaseTypesConverter { @@ -60,4 +70,49 @@ public static TerminologyCode convert(CODEPHRASE definingCode) { return TerminologyCode.createFromString(definingCode.getTerminologyId().getValue(), null, definingCode.getCodeString()); } + public static DvCodedText convert(DVCODEDTEXT symbol) { + if(symbol == null) { + return null; + } + DvCodedText codedText = new DvCodedText(); + if(symbol.getDefiningCode() != null) { + CodePhrase codePhrase = convertToCodePhrase(symbol.getDefiningCode()); + codedText.setDefiningCode(codePhrase); + } + codedText.setEncoding(convertToCodePhrase(symbol.getEncoding())); + codedText.setFormatting(symbol.getFormatting()); + codedText.setHyperlink(convert(symbol.getHyperlink())); + codedText.setLanguage(convertToCodePhrase(symbol.getLanguage())); + codedText.setMappings(convert(symbol.getMappings())); + codedText.setValue(symbol.getValue()); + + return codedText; + } + + public static List convert(List mappings14) { + if(mappings14 == null) { + return null; + } + List mappings = new ArrayList<>(); + for(TERMMAPPING mapping14:mappings14) { + TermMapping mapping = new TermMapping(convertToCodePhrase(mapping14.getTarget()), + mapping14.getMatch() == null || mapping14.getMatch().isEmpty() ? null : mapping14.getMatch().charAt(0), + convert(mapping14.getPurpose())); + mappings.add(mapping); + } + return mappings; + } + + public static DvURI convert(DVURI hyperlink) { + return hyperlink == null ? null : new DvURI(hyperlink.getValue()); + } + + public static CodePhrase convertToCodePhrase(CODEPHRASE codePhrase) { + if(codePhrase == null) { + return null; + } + //cannot use the codephrase to terminology code conversion + return new CodePhrase(codePhrase.getTerminologyId() != null ? new TerminologyId(codePhrase.getTerminologyId().getValue()) : null, + codePhrase.getCodeString()); + } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java index 440406d57..b501e8014 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -1,5 +1,190 @@ package com.nedap.archie.opt14; +import com.google.common.collect.Lists; +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ArchetypeModelObject; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CDefinedObject; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.OperationalTemplate; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.creation.RMObjectCreator; +import com.nedap.archie.paths.PathSegment; +import com.nedap.archie.query.APathQuery; +import com.nedap.archie.rm.datavalues.quantity.DvInterval; +import com.nedap.archie.rm.datavalues.quantity.DvOrdinal; +import com.nedap.archie.rm.datavalues.quantity.DvQuantity; +import com.nedap.archie.rm.datavalues.quantity.ReferenceRange; +import com.nedap.archie.rminfo.ArchieRMInfoLookup; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + public class DefaultValueConverter { //TODO: default values + + public void convertDefaultValues(OPERATIONALTEMPLATE opt14, OperationalTemplate opt) { + convertDefaultValues(opt14.getDefinition(), opt); + } + + /** + * convert the OPT 1.4 default values and store in the archetype structure. Stop processing on Archetype roots + * , those things will contain new default values at that point. + * @param root14 + * @param archetype + */ + public void convertDefaultValues(CARCHETYPEROOT root14, Archetype archetype) { + List defaultValues = root14.getDefaultValues(); + //the non-primitive default values can directly be converted + List nonPrimitiveDefaults = new ArrayList<>(); + //the primitive ones must be grouped by the first parent non-primitive object to be converted + //to a non-primitive object + Map> groupedPrimitiveDefaults = new LinkedHashMap<>(); + groupDefaultValues(defaultValues, nonPrimitiveDefaults, groupedPrimitiveDefaults); + + addNonPrimitiveDefaultValues(nonPrimitiveDefaults, archetype); + } + + private void addNonPrimitiveDefaultValues(List nonPrimitiveDefaults, Archetype archetype) { + for(DEFAULTVALUE defaultvalue:nonPrimitiveDefaults) { + ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(defaultvalue.getPath()); + if(archetypeModelObject == null) { + //TODO: warn + } else if (archetypeModelObject instanceof CAttribute) { + //ADL 2 requires this under a C_OBJECT< so convert it + CAttribute attribute = (CAttribute) archetypeModelObject; + CObject parent = attribute.getParent(); + if(parent instanceof CDefinedObject) { + CDefinedObject cObject = (CDefinedObject) parent; + cObject.setDefaultValue(convertToNonPrimitiveRMObject(attribute, cObject, defaultvalue)); + } else { + //TODO: warn + } + } else if (archetypeModelObject instanceof CDefinedObject) { + CDefinedObject cObject = (CDefinedObject) archetypeModelObject; + + cObject.setDefaultValue(convertToNonPrimitiveRMObject(defaultvalue)); + + } else { + //right.... + //TODO: WARN + } + } + } + + private Object convertToNonPrimitiveRMObject(CAttribute attribute, CDefinedObject parentCObject, DEFAULTVALUE defaultvalue) { + //get the possible type of the attribute from the default value, get the type of the parent of this and convert + RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); + Object defaultValue = creator.create(parentCObject); + creator.set(defaultValue, attribute.getRmAttributeName(), Lists.newArrayList(convertToNonPrimitiveRMObject(defaultvalue))); + return defaultValue; + } + + private Object convertToNonPrimitiveRMObject(DEFAULTVALUE defaultvalue) { + if(defaultvalue instanceof DEFAULTDVSTATE) { + return null; //this is for later + } else if (defaultvalue instanceof DEFAULTDVORDINAL) { + DEFAULTDVORDINAL defaultdvordinal = (DEFAULTDVORDINAL) defaultvalue; + DvOrdinal ordinal = convertDvOrdinal(defaultdvordinal.getValue()); + + return ordinal; + } else if (defaultvalue instanceof DEFAULTDVQUANTITY) { + DVQUANTITY defaultdvquantity = ((DEFAULTDVQUANTITY) defaultvalue).getValue(); + DvQuantity quantity = convertDvQuantity(defaultdvquantity); + + return quantity; + } + return null; + } + + private DvQuantity convertDvQuantity(DVQUANTITY defaultdvquantity) { + DvQuantity quantity = new DvQuantity(); + quantity.setMagnitude(defaultdvquantity.getMagnitude()); + quantity.setUnits(defaultdvquantity.getUnits()); + quantity.setPrecision(defaultdvquantity.getPrecision() == null ? null : defaultdvquantity.getPrecision().longValue()); + quantity.setAccuracy(defaultdvquantity.getAccuracy() == null ? null : defaultdvquantity.getAccuracy().doubleValue()); + quantity.setAccuracyIsPercent(defaultdvquantity.isAccuracyIsPercent()); + quantity.setNormalStatus(BaseTypesConverter.convertToCodePhrase(defaultdvquantity.getNormalStatus())); + quantity.setNormalRange(convertQuantityNormalRange(defaultdvquantity.getNormalRange())); + quantity.setOtherReferenceRanges(convertQuantityReferenceRanges(defaultdvquantity.getOtherReferenceRanges())); + return quantity; + } + + private DvOrdinal convertDvOrdinal(DVORDINAL ordinal14) { + DvOrdinal ordinal = new DvOrdinal(); + ordinal.setValue((long) ordinal14.getValue()); + ordinal.setSymbol(BaseTypesConverter.convert(ordinal14.getSymbol())); + ordinal.setNormalStatus(BaseTypesConverter.convertToCodePhrase(ordinal14.getNormalStatus())); + ordinal.setNormalRange(convertOrdinalNormalRange(ordinal14.getNormalRange())); + ordinal.setOtherReferenceRanges(convertOrdinalReferenceRanges(ordinal14.getOtherReferenceRanges())); + return ordinal; + } + + private List> convertOrdinalReferenceRanges(List otherReferenceRanges) { + return null;//todo implement me + } + + private List> convertQuantityReferenceRanges(List otherReferenceRanges) { + return null;//todo implement me + } + + private DvInterval convertQuantityNormalRange(DVINTERVAL range) { + if(range == null) { + return null; + } + if(!( (range.getLower() == null || range.getLower() instanceof DVQUANTITY) + && (range.getUpper() == null || range.getUpper() instanceof DVQUANTITY))) { + + } + DvInterval result = new DvInterval<>( + range.getLower() == null ? null : convertDvQuantity((DVQUANTITY) range.getLower()) , + range.getUpper() == null ? null : convertDvQuantity((DVQUANTITY) range.getUpper())); + result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); + result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + result.setLowerUnbounded(range.isLowerUnbounded()); + result.setUpperUnbounded(range.isUpperUnbounded()); + return result; + } + + + + public DvInterval convertOrdinalNormalRange(DVINTERVAL range) { + if(range == null) { + return null; + } + if(!( (range.getLower() == null || range.getLower() instanceof DVORDINAL) + && (range.getUpper() == null || range.getUpper() instanceof DVORDINAL))) { + + } + DvInterval result = new DvInterval<>( + range.getLower() == null ? null : convertDvOrdinal((DVORDINAL) range.getLower()) , + range.getUpper() == null ? null : convertDvOrdinal((DVORDINAL) range.getUpper())); + result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); + result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + result.setLowerUnbounded(range.isLowerUnbounded()); + result.setUpperUnbounded(range.isUpperUnbounded()); + return result; + } + + + private void groupDefaultValues(List defaultValues14, List nonPrimitiveDefaults, Map> groupedPrimitiveDefaults) { + for(DEFAULTVALUE defaultValue:defaultValues14) { + if(defaultValue instanceof DEFAULTDVORDINAL || defaultValue instanceof DEFAULTDVQUANTITY || defaultValue instanceof DEFAULTDVSTATE) { + //non-primitive type + nonPrimitiveDefaults.add(defaultValue); + } else { + //primitive type + APathQuery parsedPath = new APathQuery(defaultValue.getPath()); + PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); + List groupedDefaultValues = groupedPrimitiveDefaults.get(parsedPath.toString()); + if(defaultValues14 == null) { + groupedDefaultValues = new ArrayList<>(); + groupedPrimitiveDefaults.put(parsedPath.toString(), groupedDefaultValues); + } + groupedDefaultValues.add(defaultValue); + } + } + } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 5bd1235aa..316b52d11 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -36,7 +36,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA Template template = new Template(); //TODO: should this include the concept, rather than just the template ID? template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); - template.setControlled(opt14.isIsControlled(); + template.setControlled(opt14.isIsControlled()); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); if(opt14.getUid() != null) { template.setUid(opt14.getUid().getValue()); From b36bf7701159c9061fa6a3c9c55126903f33ccfd Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 20 Jul 2021 19:17:41 +0200 Subject: [PATCH 14/36] Add fully untested primitive default value converter --- .../archie/opt14/DefaultValueConverter.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java index b501e8014..f4d4382af 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -9,6 +9,7 @@ import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.creation.RMObjectCreator; +import com.nedap.archie.datetime.DateTimeParsers; import com.nedap.archie.paths.PathSegment; import com.nedap.archie.query.APathQuery; import com.nedap.archie.rm.datavalues.quantity.DvInterval; @@ -45,6 +46,62 @@ public void convertDefaultValues(CARCHETYPEROOT root14, Archetype archetype) { groupDefaultValues(defaultValues, nonPrimitiveDefaults, groupedPrimitiveDefaults); addNonPrimitiveDefaultValues(nonPrimitiveDefaults, archetype); + addPrimitiveDefaultValues(groupedPrimitiveDefaults, archetype); + } + + private void addPrimitiveDefaultValues(Map> groupedPrimitiveDefaults, Archetype archetype) { + RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); + for(String path:groupedPrimitiveDefaults.keySet()) { + ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(path); + if(archetypeModelObject instanceof CAttribute) { + + } else if (archetypeModelObject instanceof CDefinedObject) { + CDefinedObject cObject = (CDefinedObject) archetypeModelObject; + Object object = creator.create(cObject); + for(DEFAULTVALUE value:groupedPrimitiveDefaults.get(path)) { + APathQuery parsedPath = new APathQuery(value.getPath()); + PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); + creator.set(object, lastPathSegment.getNodeName(), Lists.newArrayList(convertPrimitiveDefaultsValue(value))); + } + cObject.setDefaultValue(object); + } else { + //todo warn + } + + } + } + + private Object convertPrimitiveDefaultsValue(DEFAULTVALUE value) { + if(value instanceof DEFAULTBOOLEAN) { + DEFAULTBOOLEAN d = (DEFAULTBOOLEAN) value; + return d.isValue(); + } else if (value instanceof DEFAULTCODEPHRASE) { + DEFAULTCODEPHRASE d = (DEFAULTCODEPHRASE) value; + //TODO: potentially tricky - coded text may be needed here instead, look at rm model? + BaseTypesConverter.convertToCodePhrase(d.getValue()); + } else if (value instanceof DEFAULTSTRING) { + DEFAULTSTRING d = (DEFAULTSTRING) value; + return d.getValue(); + } else if (value instanceof DEFAULTINTEGER) { + DEFAULTINTEGER d = (DEFAULTINTEGER) value; + return (long) d.getValue(); + } else if (value instanceof DEFAULTREAL) { + DEFAULTREAL d = (DEFAULTREAL) value; + return (double) d.getValue(); + } else if (value instanceof DEFAULTTIME) { + DEFAULTTIME d = (DEFAULTTIME) value; + return DateTimeParsers.parseTimeValue(d.getValue()); + } else if (value instanceof DEFAULTDATE) { + DEFAULTDATE d = (DEFAULTDATE) value; + return DateTimeParsers.parseDateValue(d.getValue()); + } else if (value instanceof DEFAULTDATETIME) { + DEFAULTDATETIME d = (DEFAULTDATETIME) value; + return DateTimeParsers.parseDateTimeValue(d.getValue()); + } else if (value instanceof DEFAULTDURATION) { + DEFAULTDURATION d = (DEFAULTDURATION) value; + return DateTimeParsers.parseDurationValue(d.getValue()); + } + return null; } private void addNonPrimitiveDefaultValues(List nonPrimitiveDefaults, Archetype archetype) { From 76d1262d058d0d87e2ac9a249f7fdd4bcdaf8038 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Fri, 23 Jul 2021 16:02:36 +0200 Subject: [PATCH 15/36] Switch to OPT xsd that is actually in use --- opt14/build.gradle | 5 +- .../archie/opt14/BaseTypesConverter.java | 2 + .../archie/opt14/DefaultValueConverter.java | 438 ++++----- .../archie/opt14/DefinitionConverter.java | 2 + .../archie/opt14/DescriptionConverter.java | 4 +- .../archie/opt14/DomainTypeConverter.java | 4 +- .../nedap/archie/opt14/Opt14Converter.java | 2 + .../archie/opt14/PrimitiveConverter.java | 2 + .../archie/opt14/TerminologyConverter.java | 2 + opt14/src/main/schemas/xjc/Archetype.xsd | 770 ++++++++-------- opt14/src/main/schemas/xjc/BaseTypes.xsd | 836 ++++++------------ .../src/main/schemas/xjc/CharacterMapping.xsd | 13 - opt14/src/main/schemas/xjc/Common.xsd | 205 +++++ opt14/src/main/schemas/xjc/Composition.xsd | 36 - .../main/schemas/xjc/CompositionTemplate.xsd | 489 ---------- opt14/src/main/schemas/xjc/Content.xsd | 132 --- opt14/src/main/schemas/xjc/DataTypes.xsd | 320 +++++++ opt14/src/main/schemas/xjc/Extract.xsd | 142 --- opt14/src/main/schemas/xjc/OpenehrProfile.xsd | 176 ++-- opt14/src/main/schemas/xjc/Resource.xsd | 121 +-- opt14/src/main/schemas/xjc/Structure.xsd | 151 ---- opt14/src/main/schemas/xjc/Template.xsd | 258 +++--- opt14/src/main/schemas/xjc/Version.xsd | 41 - opt14/src/main/schemas/xjc/xjc.xjb.xml | 40 + .../archie/opt14/Opt14ConverterTest.java | 3 + 25 files changed, 1702 insertions(+), 2492 deletions(-) delete mode 100644 opt14/src/main/schemas/xjc/CharacterMapping.xsd create mode 100644 opt14/src/main/schemas/xjc/Common.xsd delete mode 100644 opt14/src/main/schemas/xjc/Composition.xsd delete mode 100644 opt14/src/main/schemas/xjc/CompositionTemplate.xsd delete mode 100644 opt14/src/main/schemas/xjc/Content.xsd create mode 100644 opt14/src/main/schemas/xjc/DataTypes.xsd delete mode 100644 opt14/src/main/schemas/xjc/Extract.xsd delete mode 100644 opt14/src/main/schemas/xjc/Structure.xsd delete mode 100644 opt14/src/main/schemas/xjc/Version.xsd create mode 100644 opt14/src/main/schemas/xjc/xjc.xjb.xml diff --git a/opt14/build.gradle b/opt14/build.gradle index 2feef2b88..d464efe7b 100644 --- a/opt14/build.gradle +++ b/opt14/build.gradle @@ -31,12 +31,13 @@ dependencies { xjcGeneration { defaultAdditionalXjcOptions = ['encoding': 'UTF-8'] - defaultBindingFile = null //file 'src/main/resources//xjc/xjc.xjb.xml' + defaultBindingFile = file 'src/main/schemas/xjc/xjc.xjb.xml' schemas { opt14 { schemaFile = 'Template.xsd' - javaPackageName = 'com.nedap.archie.opt14' + javaPackageName = 'com.nedap.archie.opt14.schema' + } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java index 80f214699..ab783574a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java @@ -12,6 +12,8 @@ import com.nedap.archie.rm.datavalues.quantity.DvOrdinal; import com.nedap.archie.rm.support.identification.TerminologyId; +import com.nedap.archie.opt14.schema.*; + import java.util.ArrayList; import java.util.List; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java index f4d4382af..568d5726f 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -25,223 +25,223 @@ public class DefaultValueConverter { //TODO: default values - - public void convertDefaultValues(OPERATIONALTEMPLATE opt14, OperationalTemplate opt) { - convertDefaultValues(opt14.getDefinition(), opt); - } - - /** - * convert the OPT 1.4 default values and store in the archetype structure. Stop processing on Archetype roots - * , those things will contain new default values at that point. - * @param root14 - * @param archetype - */ - public void convertDefaultValues(CARCHETYPEROOT root14, Archetype archetype) { - List defaultValues = root14.getDefaultValues(); - //the non-primitive default values can directly be converted - List nonPrimitiveDefaults = new ArrayList<>(); - //the primitive ones must be grouped by the first parent non-primitive object to be converted - //to a non-primitive object - Map> groupedPrimitiveDefaults = new LinkedHashMap<>(); - groupDefaultValues(defaultValues, nonPrimitiveDefaults, groupedPrimitiveDefaults); - - addNonPrimitiveDefaultValues(nonPrimitiveDefaults, archetype); - addPrimitiveDefaultValues(groupedPrimitiveDefaults, archetype); - } - - private void addPrimitiveDefaultValues(Map> groupedPrimitiveDefaults, Archetype archetype) { - RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); - for(String path:groupedPrimitiveDefaults.keySet()) { - ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(path); - if(archetypeModelObject instanceof CAttribute) { - - } else if (archetypeModelObject instanceof CDefinedObject) { - CDefinedObject cObject = (CDefinedObject) archetypeModelObject; - Object object = creator.create(cObject); - for(DEFAULTVALUE value:groupedPrimitiveDefaults.get(path)) { - APathQuery parsedPath = new APathQuery(value.getPath()); - PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); - creator.set(object, lastPathSegment.getNodeName(), Lists.newArrayList(convertPrimitiveDefaultsValue(value))); - } - cObject.setDefaultValue(object); - } else { - //todo warn - } - - } - } - - private Object convertPrimitiveDefaultsValue(DEFAULTVALUE value) { - if(value instanceof DEFAULTBOOLEAN) { - DEFAULTBOOLEAN d = (DEFAULTBOOLEAN) value; - return d.isValue(); - } else if (value instanceof DEFAULTCODEPHRASE) { - DEFAULTCODEPHRASE d = (DEFAULTCODEPHRASE) value; - //TODO: potentially tricky - coded text may be needed here instead, look at rm model? - BaseTypesConverter.convertToCodePhrase(d.getValue()); - } else if (value instanceof DEFAULTSTRING) { - DEFAULTSTRING d = (DEFAULTSTRING) value; - return d.getValue(); - } else if (value instanceof DEFAULTINTEGER) { - DEFAULTINTEGER d = (DEFAULTINTEGER) value; - return (long) d.getValue(); - } else if (value instanceof DEFAULTREAL) { - DEFAULTREAL d = (DEFAULTREAL) value; - return (double) d.getValue(); - } else if (value instanceof DEFAULTTIME) { - DEFAULTTIME d = (DEFAULTTIME) value; - return DateTimeParsers.parseTimeValue(d.getValue()); - } else if (value instanceof DEFAULTDATE) { - DEFAULTDATE d = (DEFAULTDATE) value; - return DateTimeParsers.parseDateValue(d.getValue()); - } else if (value instanceof DEFAULTDATETIME) { - DEFAULTDATETIME d = (DEFAULTDATETIME) value; - return DateTimeParsers.parseDateTimeValue(d.getValue()); - } else if (value instanceof DEFAULTDURATION) { - DEFAULTDURATION d = (DEFAULTDURATION) value; - return DateTimeParsers.parseDurationValue(d.getValue()); - } - return null; - } - - private void addNonPrimitiveDefaultValues(List nonPrimitiveDefaults, Archetype archetype) { - for(DEFAULTVALUE defaultvalue:nonPrimitiveDefaults) { - ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(defaultvalue.getPath()); - if(archetypeModelObject == null) { - //TODO: warn - } else if (archetypeModelObject instanceof CAttribute) { - //ADL 2 requires this under a C_OBJECT< so convert it - CAttribute attribute = (CAttribute) archetypeModelObject; - CObject parent = attribute.getParent(); - if(parent instanceof CDefinedObject) { - CDefinedObject cObject = (CDefinedObject) parent; - cObject.setDefaultValue(convertToNonPrimitiveRMObject(attribute, cObject, defaultvalue)); - } else { - //TODO: warn - } - } else if (archetypeModelObject instanceof CDefinedObject) { - CDefinedObject cObject = (CDefinedObject) archetypeModelObject; - - cObject.setDefaultValue(convertToNonPrimitiveRMObject(defaultvalue)); - - } else { - //right.... - //TODO: WARN - } - } - } - - private Object convertToNonPrimitiveRMObject(CAttribute attribute, CDefinedObject parentCObject, DEFAULTVALUE defaultvalue) { - //get the possible type of the attribute from the default value, get the type of the parent of this and convert - RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); - Object defaultValue = creator.create(parentCObject); - creator.set(defaultValue, attribute.getRmAttributeName(), Lists.newArrayList(convertToNonPrimitiveRMObject(defaultvalue))); - return defaultValue; - } - - private Object convertToNonPrimitiveRMObject(DEFAULTVALUE defaultvalue) { - if(defaultvalue instanceof DEFAULTDVSTATE) { - return null; //this is for later - } else if (defaultvalue instanceof DEFAULTDVORDINAL) { - DEFAULTDVORDINAL defaultdvordinal = (DEFAULTDVORDINAL) defaultvalue; - DvOrdinal ordinal = convertDvOrdinal(defaultdvordinal.getValue()); - - return ordinal; - } else if (defaultvalue instanceof DEFAULTDVQUANTITY) { - DVQUANTITY defaultdvquantity = ((DEFAULTDVQUANTITY) defaultvalue).getValue(); - DvQuantity quantity = convertDvQuantity(defaultdvquantity); - - return quantity; - } - return null; - } - - private DvQuantity convertDvQuantity(DVQUANTITY defaultdvquantity) { - DvQuantity quantity = new DvQuantity(); - quantity.setMagnitude(defaultdvquantity.getMagnitude()); - quantity.setUnits(defaultdvquantity.getUnits()); - quantity.setPrecision(defaultdvquantity.getPrecision() == null ? null : defaultdvquantity.getPrecision().longValue()); - quantity.setAccuracy(defaultdvquantity.getAccuracy() == null ? null : defaultdvquantity.getAccuracy().doubleValue()); - quantity.setAccuracyIsPercent(defaultdvquantity.isAccuracyIsPercent()); - quantity.setNormalStatus(BaseTypesConverter.convertToCodePhrase(defaultdvquantity.getNormalStatus())); - quantity.setNormalRange(convertQuantityNormalRange(defaultdvquantity.getNormalRange())); - quantity.setOtherReferenceRanges(convertQuantityReferenceRanges(defaultdvquantity.getOtherReferenceRanges())); - return quantity; - } - - private DvOrdinal convertDvOrdinal(DVORDINAL ordinal14) { - DvOrdinal ordinal = new DvOrdinal(); - ordinal.setValue((long) ordinal14.getValue()); - ordinal.setSymbol(BaseTypesConverter.convert(ordinal14.getSymbol())); - ordinal.setNormalStatus(BaseTypesConverter.convertToCodePhrase(ordinal14.getNormalStatus())); - ordinal.setNormalRange(convertOrdinalNormalRange(ordinal14.getNormalRange())); - ordinal.setOtherReferenceRanges(convertOrdinalReferenceRanges(ordinal14.getOtherReferenceRanges())); - return ordinal; - } - - private List> convertOrdinalReferenceRanges(List otherReferenceRanges) { - return null;//todo implement me - } - - private List> convertQuantityReferenceRanges(List otherReferenceRanges) { - return null;//todo implement me - } - - private DvInterval convertQuantityNormalRange(DVINTERVAL range) { - if(range == null) { - return null; - } - if(!( (range.getLower() == null || range.getLower() instanceof DVQUANTITY) - && (range.getUpper() == null || range.getUpper() instanceof DVQUANTITY))) { - - } - DvInterval result = new DvInterval<>( - range.getLower() == null ? null : convertDvQuantity((DVQUANTITY) range.getLower()) , - range.getUpper() == null ? null : convertDvQuantity((DVQUANTITY) range.getUpper())); - result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); - result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); - result.setLowerUnbounded(range.isLowerUnbounded()); - result.setUpperUnbounded(range.isUpperUnbounded()); - return result; - } - - - - public DvInterval convertOrdinalNormalRange(DVINTERVAL range) { - if(range == null) { - return null; - } - if(!( (range.getLower() == null || range.getLower() instanceof DVORDINAL) - && (range.getUpper() == null || range.getUpper() instanceof DVORDINAL))) { - - } - DvInterval result = new DvInterval<>( - range.getLower() == null ? null : convertDvOrdinal((DVORDINAL) range.getLower()) , - range.getUpper() == null ? null : convertDvOrdinal((DVORDINAL) range.getUpper())); - result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); - result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); - result.setLowerUnbounded(range.isLowerUnbounded()); - result.setUpperUnbounded(range.isUpperUnbounded()); - return result; - } - - - private void groupDefaultValues(List defaultValues14, List nonPrimitiveDefaults, Map> groupedPrimitiveDefaults) { - for(DEFAULTVALUE defaultValue:defaultValues14) { - if(defaultValue instanceof DEFAULTDVORDINAL || defaultValue instanceof DEFAULTDVQUANTITY || defaultValue instanceof DEFAULTDVSTATE) { - //non-primitive type - nonPrimitiveDefaults.add(defaultValue); - } else { - //primitive type - APathQuery parsedPath = new APathQuery(defaultValue.getPath()); - PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); - List groupedDefaultValues = groupedPrimitiveDefaults.get(parsedPath.toString()); - if(defaultValues14 == null) { - groupedDefaultValues = new ArrayList<>(); - groupedPrimitiveDefaults.put(parsedPath.toString(), groupedDefaultValues); - } - groupedDefaultValues.add(defaultValue); - } - } - } +// +// public void convertDefaultValues(OPERATIONALTEMPLATE opt14, OperationalTemplate opt) { +// convertDefaultValues(opt14.getDefinition(), opt); +// } +// +// /** +// * convert the OPT 1.4 default values and store in the archetype structure. Stop processing on Archetype roots +// * , those things will contain new default values at that point. +// * @param root14 +// * @param archetype +// */ +// public void convertDefaultValues(CARCHETYPEROOT root14, Archetype archetype) { +// List defaultValues = root14.getDefaultValues(); +// //the non-primitive default values can directly be converted +// List nonPrimitiveDefaults = new ArrayList<>(); +// //the primitive ones must be grouped by the first parent non-primitive object to be converted +// //to a non-primitive object +// Map> groupedPrimitiveDefaults = new LinkedHashMap<>(); +// groupDefaultValues(defaultValues, nonPrimitiveDefaults, groupedPrimitiveDefaults); +// +// addNonPrimitiveDefaultValues(nonPrimitiveDefaults, archetype); +// addPrimitiveDefaultValues(groupedPrimitiveDefaults, archetype); +// } +// +// private void addPrimitiveDefaultValues(Map> groupedPrimitiveDefaults, Archetype archetype) { +// RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); +// for(String path:groupedPrimitiveDefaults.keySet()) { +// ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(path); +// if(archetypeModelObject instanceof CAttribute) { +// +// } else if (archetypeModelObject instanceof CDefinedObject) { +// CDefinedObject cObject = (CDefinedObject) archetypeModelObject; +// Object object = creator.create(cObject); +// for(DEFAULTVALUE value:groupedPrimitiveDefaults.get(path)) { +// APathQuery parsedPath = new APathQuery(value.getPath()); +// PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); +// creator.set(object, lastPathSegment.getNodeName(), Lists.newArrayList(convertPrimitiveDefaultsValue(value))); +// } +// cObject.setDefaultValue(object); +// } else { +// //todo warn +// } +// +// } +// } +// +// private Object convertPrimitiveDefaultsValue(DEFAULTVALUE value) { +// if(value instanceof DEFAULTBOOLEAN) { +// DEFAULTBOOLEAN d = (DEFAULTBOOLEAN) value; +// return d.isValue(); +// } else if (value instanceof DEFAULTCODEPHRASE) { +// DEFAULTCODEPHRASE d = (DEFAULTCODEPHRASE) value; +// //TODO: potentially tricky - coded text may be needed here instead, look at rm model? +// BaseTypesConverter.convertToCodePhrase(d.getValue()); +// } else if (value instanceof DEFAULTSTRING) { +// DEFAULTSTRING d = (DEFAULTSTRING) value; +// return d.getValue(); +// } else if (value instanceof DEFAULTINTEGER) { +// DEFAULTINTEGER d = (DEFAULTINTEGER) value; +// return (long) d.getValue(); +// } else if (value instanceof DEFAULTREAL) { +// DEFAULTREAL d = (DEFAULTREAL) value; +// return (double) d.getValue(); +// } else if (value instanceof DEFAULTTIME) { +// DEFAULTTIME d = (DEFAULTTIME) value; +// return DateTimeParsers.parseTimeValue(d.getValue()); +// } else if (value instanceof DEFAULTDATE) { +// DEFAULTDATE d = (DEFAULTDATE) value; +// return DateTimeParsers.parseDateValue(d.getValue()); +// } else if (value instanceof DEFAULTDATETIME) { +// DEFAULTDATETIME d = (DEFAULTDATETIME) value; +// return DateTimeParsers.parseDateTimeValue(d.getValue()); +// } else if (value instanceof DEFAULTDURATION) { +// DEFAULTDURATION d = (DEFAULTDURATION) value; +// return DateTimeParsers.parseDurationValue(d.getValue()); +// } +// return null; +// } +// +// private void addNonPrimitiveDefaultValues(List nonPrimitiveDefaults, Archetype archetype) { +// for(DEFAULTVALUE defaultvalue:nonPrimitiveDefaults) { +// ArchetypeModelObject archetypeModelObject = archetype.itemAtPath(defaultvalue.getPath()); +// if(archetypeModelObject == null) { +// //TODO: warn +// } else if (archetypeModelObject instanceof CAttribute) { +// //ADL 2 requires this under a C_OBJECT< so convert it +// CAttribute attribute = (CAttribute) archetypeModelObject; +// CObject parent = attribute.getParent(); +// if(parent instanceof CDefinedObject) { +// CDefinedObject cObject = (CDefinedObject) parent; +// cObject.setDefaultValue(convertToNonPrimitiveRMObject(attribute, cObject, defaultvalue)); +// } else { +// //TODO: warn +// } +// } else if (archetypeModelObject instanceof CDefinedObject) { +// CDefinedObject cObject = (CDefinedObject) archetypeModelObject; +// +// cObject.setDefaultValue(convertToNonPrimitiveRMObject(defaultvalue)); +// +// } else { +// //right.... +// //TODO: WARN +// } +// } +// } +// +// private Object convertToNonPrimitiveRMObject(CAttribute attribute, CDefinedObject parentCObject, DEFAULTVALUE defaultvalue) { +// //get the possible type of the attribute from the default value, get the type of the parent of this and convert +// RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); +// Object defaultValue = creator.create(parentCObject); +// creator.set(defaultValue, attribute.getRmAttributeName(), Lists.newArrayList(convertToNonPrimitiveRMObject(defaultvalue))); +// return defaultValue; +// } +// +// private Object convertToNonPrimitiveRMObject(DEFAULTVALUE defaultvalue) { +// if(defaultvalue instanceof DEFAULTDVSTATE) { +// return null; //this is for later +// } else if (defaultvalue instanceof DEFAULTDVORDINAL) { +// DEFAULTDVORDINAL defaultdvordinal = (DEFAULTDVORDINAL) defaultvalue; +// DvOrdinal ordinal = convertDvOrdinal(defaultdvordinal.getValue()); +// +// return ordinal; +// } else if (defaultvalue instanceof DEFAULTDVQUANTITY) { +// DVQUANTITY defaultdvquantity = ((DEFAULTDVQUANTITY) defaultvalue).getValue(); +// DvQuantity quantity = convertDvQuantity(defaultdvquantity); +// +// return quantity; +// } +// return null; +// } +// +// private DvQuantity convertDvQuantity(DVQUANTITY defaultdvquantity) { +// DvQuantity quantity = new DvQuantity(); +// quantity.setMagnitude(defaultdvquantity.getMagnitude()); +// quantity.setUnits(defaultdvquantity.getUnits()); +// quantity.setPrecision(defaultdvquantity.getPrecision() == null ? null : defaultdvquantity.getPrecision().longValue()); +// quantity.setAccuracy(defaultdvquantity.getAccuracy() == null ? null : defaultdvquantity.getAccuracy().doubleValue()); +// quantity.setAccuracyIsPercent(defaultdvquantity.isAccuracyIsPercent()); +// quantity.setNormalStatus(BaseTypesConverter.convertToCodePhrase(defaultdvquantity.getNormalStatus())); +// quantity.setNormalRange(convertQuantityNormalRange(defaultdvquantity.getNormalRange())); +// quantity.setOtherReferenceRanges(convertQuantityReferenceRanges(defaultdvquantity.getOtherReferenceRanges())); +// return quantity; +// } +// +// private DvOrdinal convertDvOrdinal(DVORDINAL ordinal14) { +// DvOrdinal ordinal = new DvOrdinal(); +// ordinal.setValue((long) ordinal14.getValue()); +// ordinal.setSymbol(BaseTypesConverter.convert(ordinal14.getSymbol())); +// ordinal.setNormalStatus(BaseTypesConverter.convertToCodePhrase(ordinal14.getNormalStatus())); +// ordinal.setNormalRange(convertOrdinalNormalRange(ordinal14.getNormalRange())); +// ordinal.setOtherReferenceRanges(convertOrdinalReferenceRanges(ordinal14.getOtherReferenceRanges())); +// return ordinal; +// } +// +// private List> convertOrdinalReferenceRanges(List otherReferenceRanges) { +// return null;//todo implement me +// } +// +// private List> convertQuantityReferenceRanges(List otherReferenceRanges) { +// return null;//todo implement me +// } +// +// private DvInterval convertQuantityNormalRange(DVINTERVAL range) { +// if(range == null) { +// return null; +// } +// if(!( (range.getLower() == null || range.getLower() instanceof DVQUANTITY) +// && (range.getUpper() == null || range.getUpper() instanceof DVQUANTITY))) { +// +// } +// DvInterval result = new DvInterval<>( +// range.getLower() == null ? null : convertDvQuantity((DVQUANTITY) range.getLower()) , +// range.getUpper() == null ? null : convertDvQuantity((DVQUANTITY) range.getUpper())); +// result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); +// result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); +// result.setLowerUnbounded(range.isLowerUnbounded()); +// result.setUpperUnbounded(range.isUpperUnbounded()); +// return result; +// } +// +// +// +// public DvInterval convertOrdinalNormalRange(DVINTERVAL range) { +// if(range == null) { +// return null; +// } +// if(!( (range.getLower() == null || range.getLower() instanceof DVORDINAL) +// && (range.getUpper() == null || range.getUpper() instanceof DVORDINAL))) { +// +// } +// DvInterval result = new DvInterval<>( +// range.getLower() == null ? null : convertDvOrdinal((DVORDINAL) range.getLower()) , +// range.getUpper() == null ? null : convertDvOrdinal((DVORDINAL) range.getUpper())); +// result.setLowerIncluded(range.isLowerIncluded() == null ? true : range.isLowerIncluded()); +// result.setUpperIncluded(range.isUpperIncluded() == null ? true : range.isUpperIncluded()); +// result.setLowerUnbounded(range.isLowerUnbounded()); +// result.setUpperUnbounded(range.isUpperUnbounded()); +// return result; +// } +// +// +// private void groupDefaultValues(List defaultValues14, List nonPrimitiveDefaults, Map> groupedPrimitiveDefaults) { +// for(DEFAULTVALUE defaultValue:defaultValues14) { +// if(defaultValue instanceof DEFAULTDVORDINAL || defaultValue instanceof DEFAULTDVQUANTITY || defaultValue instanceof DEFAULTDVSTATE) { +// //non-primitive type +// nonPrimitiveDefaults.add(defaultValue); +// } else { +// //primitive type +// APathQuery parsedPath = new APathQuery(defaultValue.getPath()); +// PathSegment lastPathSegment = parsedPath.getPathSegments().remove(parsedPath.getPathSegments().size() - 1); +// List groupedDefaultValues = groupedPrimitiveDefaults.get(parsedPath.toString()); +// if(defaultValues14 == null) { +// groupedDefaultValues = new ArrayList<>(); +// groupedPrimitiveDefaults.put(parsedPath.toString(), groupedDefaultValues); +// } +// groupedDefaultValues.add(defaultValue); +// } +// } +// } } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index 302a0fdd7..74e274458 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -15,6 +15,8 @@ import static com.nedap.archie.opt14.BaseTypesConverter.convertMultiplicity; import static com.nedap.archie.opt14.PrimitiveConverter.convertPrimitive; +import com.nedap.archie.opt14.schema.*; + public class DefinitionConverter { private OPERATIONALTEMPLATE opt14; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java index c0b307a64..6b8f7727c 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -9,12 +9,14 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.nedap.archie.opt14.schema.*; + public class DescriptionConverter { public static void convert(Template template, OPERATIONALTEMPLATE opt14) { RESOURCEDESCRIPTION description14 = opt14.getDescription(); ResourceDescription description = new ResourceDescription(); - description.setLifecycleState(TerminologyCode.createFromString("openehr", null, description14.lifecycleState)); + description.setLifecycleState(TerminologyCode.createFromString("openehr", null, description14.getLifecycleState())); Map author = new LinkedHashMap<>(); if(description14.getOriginalAuthor() != null) { for(StringDictionaryItem item:description14.getOriginalAuthor()) { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java index ee0ce978d..38060d6bc 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -14,6 +14,8 @@ import static com.nedap.archie.opt14.BaseTypesConverter.convert; +import com.nedap.archie.opt14.schema.*; + public class DomainTypeConverter { public static CObject convertDomainType(CDOMAINTYPE cobject14) { if(cobject14 instanceof CDVORDINAL) { @@ -96,7 +98,7 @@ private static CObject convertCDVQuantity(CDVQUANTITY cobject14) { DVQUANTITY assumedValue14 = quantity14.getAssumedValue(); if(assumedValue14 != null) { CDVQuantityAssumedValue assumedValue = new CDVQuantityAssumedValue(); - assumedValue.setMagnitude(assumedValue14.getMagnitude()); + assumedValue.setMagnitude((double) assumedValue14.getMagnitude()); assumedValue.setPrecision(assumedValue14.getPrecision() == null ? null : assumedValue14.getPrecision().longValue()); assumedValue.setUnits(assumedValue14.getUnits()); quantity.setAssumedValue(assumedValue); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 316b52d11..3de185195 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.List; +import com.nedap.archie.opt14.schema.*; + /** * TODO: * archetype root DEFAULTVALUES diff --git a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java index aae5b355c..2c8a705f0 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java @@ -8,6 +8,8 @@ import static com.nedap.archie.opt14.BaseTypesConverter.convertInterval; +import com.nedap.archie.opt14.schema.*; + public class PrimitiveConverter { public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java index 5096a1549..9cc9bec8a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java @@ -14,6 +14,8 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.nedap.archie.opt14.schema.*; + public class TerminologyConverter { public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, CARCHETYPEROOT definition, diff --git a/opt14/src/main/schemas/xjc/Archetype.xsd b/opt14/src/main/schemas/xjc/Archetype.xsd index cbeddf394..bbba4f624 100644 --- a/opt14/src/main/schemas/xjc/Archetype.xsd +++ b/opt14/src/main/schemas/xjc/Archetype.xsd @@ -1,394 +1,390 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/BaseTypes.xsd b/opt14/src/main/schemas/xjc/BaseTypes.xsd index 3fc959837..d1132aed6 100644 --- a/opt14/src/main/schemas/xjc/BaseTypes.xsd +++ b/opt14/src/main/schemas/xjc/BaseTypes.xsd @@ -1,594 +1,264 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/CharacterMapping.xsd b/opt14/src/main/schemas/xjc/CharacterMapping.xsd deleted file mode 100644 index f63868e3f..000000000 --- a/opt14/src/main/schemas/xjc/CharacterMapping.xsd +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/opt14/src/main/schemas/xjc/Common.xsd b/opt14/src/main/schemas/xjc/Common.xsd new file mode 100644 index 000000000..3e9cb5b94 --- /dev/null +++ b/opt14/src/main/schemas/xjc/Common.xsd @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Version control abstraction, defining semantics for versioning one complex object. + + + + + + + + An ordered list of VERSIONs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Composition.xsd b/opt14/src/main/schemas/xjc/Composition.xsd deleted file mode 100644 index 71ba5ef71..000000000 --- a/opt14/src/main/schemas/xjc/Composition.xsd +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/CompositionTemplate.xsd b/opt14/src/main/schemas/xjc/CompositionTemplate.xsd deleted file mode 100644 index f9a86aeb2..000000000 --- a/opt14/src/main/schemas/xjc/CompositionTemplate.xsd +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - openEHR schema base types for the default values - DEFAULT_VALUE <== is a ==> DEFAULT_DV_BOOLEAN == has a ==> DV_BOOLEAN - - use AOM constraint objects for the DV constraints - - - - - - - - - - 1. Is authored Resource - 2. Uid [1..1]: Add UID which is a GUID (fulfils AuthoredResource req for optional ID) - 3. TemplateId [1..1]: id now called TemplateId (fulfils AuthoredResource req for ID) - 4. Name [1..1]: Has logical name - - - - - - - - - - - - - 1. Remove 'from_template' is not needed - 2. Otherwise is same. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - termQueryId discussion - ====================== - termQueryId --> TSU - terminology subset URI - eg. terminology://Snomed?language=en-GB&subset=AllBacteria - TSU should be (subsetName{terminologyId+queryName})?language=en-GB&terminologyVersion=2007.1 - eg. TSU = Snomed_BloodPhenotype?langauge=en-GB&terminologyVersion=2007.1 - - the combination of terminology name and term subset query name is like a GUID - to refer to a particular term query in the OTS query register - therefore the TSU should be something like: - Snomed[version=2007.1, langauge=en-GB]/BloodPhenotype - - limitTolist, includedValues, excludedValues discussion - ====================================================== - When the included/excluded values include values no longer returned by the TSU - these are simply ignored, so only the intersection of TSU-return terms and includedTerms - are considered for inclusion. Similarly the terms excluded by excludedValues which - are not present in the TSU-return terms are ingored. - - LimitToList is relevant for free text (functions as list_open on C_STRING) - LimitToList is relevant for MOST ext coded text (functions as list_open on C_CODE_REFERENCE) - LimitToList not relevant for internally coded text (where archetype has restricted - codes to internally-defined list; could include list of ext codes in AC binding). - - Included values - - - relevant to include free text values (much as in list in C_STRING) - - relevant to include ext coded text values (might need includedCodes property on a - C_CODE_REFERENCE) - - Excluded values - - - relevant to remove internal term codes - - relevant to remove terms from external term subset - - relevant to remove included text values in embedded templates - - relevant to remove terms from external term subsets in embedded templates - - AllowTerminologyLookup moved out and into form definition. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/opt14/src/main/schemas/xjc/Content.xsd b/opt14/src/main/schemas/xjc/Content.xsd deleted file mode 100644 index a88e9b6c0..000000000 --- a/opt14/src/main/schemas/xjc/Content.xsd +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/DataTypes.xsd b/opt14/src/main/schemas/xjc/DataTypes.xsd new file mode 100644 index 000000000..d2015e4aa --- /dev/null +++ b/opt14/src/main/schemas/xjc/DataTypes.xsd @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Extract.xsd b/opt14/src/main/schemas/xjc/Extract.xsd deleted file mode 100644 index ede0020ef..000000000 --- a/opt14/src/main/schemas/xjc/Extract.xsd +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/OpenehrProfile.xsd b/opt14/src/main/schemas/xjc/OpenehrProfile.xsd index efa28ac8f..a01ca3abe 100644 --- a/opt14/src/main/schemas/xjc/OpenehrProfile.xsd +++ b/opt14/src/main/schemas/xjc/OpenehrProfile.xsd @@ -1,94 +1,96 @@ - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Resource.xsd b/opt14/src/main/schemas/xjc/Resource.xsd index f60733a1e..94e81430c 100644 --- a/opt14/src/main/schemas/xjc/Resource.xsd +++ b/opt14/src/main/schemas/xjc/Resource.xsd @@ -1,63 +1,66 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Structure.xsd b/opt14/src/main/schemas/xjc/Structure.xsd deleted file mode 100644 index 717560989..000000000 --- a/opt14/src/main/schemas/xjc/Structure.xsd +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/Template.xsd b/opt14/src/main/schemas/xjc/Template.xsd index 95cd28974..2b55bdabd 100644 --- a/opt14/src/main/schemas/xjc/Template.xsd +++ b/opt14/src/main/schemas/xjc/Template.xsd @@ -1,164 +1,124 @@ - - - - + + + + + + + - - - - - + + + Element 'annotations' added 3 May 2010 to provide a location for + annotations on any template node. The location of the annotations is intended to be + forwardly compatible with the upcoming Template specification (and Template Object Model) + which adds an annotations attribute to the AUTHORED_RESOURCE class (from which + the operational template as represented in this schema will inherit). + + + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + + + + + + + + + + diff --git a/opt14/src/main/schemas/xjc/Version.xsd b/opt14/src/main/schemas/xjc/Version.xsd deleted file mode 100644 index da5d5c7af..000000000 --- a/opt14/src/main/schemas/xjc/Version.xsd +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/opt14/src/main/schemas/xjc/xjc.xjb.xml b/opt14/src/main/schemas/xjc/xjc.xjb.xml new file mode 100644 index 000000000..b1263924b --- /dev/null +++ b/opt14/src/main/schemas/xjc/xjc.xjb.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index 9928537a9..5cc0b2c89 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue; +import com.nedap.archie.opt14.schema.*; + public class Opt14ConverterTest { @Test @@ -36,6 +38,7 @@ public void procedureList() throws Exception { JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); try(InputStream stream = getClass().getResourceAsStream("/procedure_list.opt")) { + OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); ADL2ConversionResultList convert = new Opt14Converter().convert(opt14, repository); for(ADL2ConversionResult result:convert.getConversionResults()) { From 93fe353d67793c636bc1adc0180e3c5256ce6fab Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Fri, 23 Jul 2021 16:19:49 +0200 Subject: [PATCH 16/36] Revert nearly all custom bindings for now - they don't work --- opt14/src/main/schemas/xjc/xjc.xjb.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opt14/src/main/schemas/xjc/xjc.xjb.xml b/opt14/src/main/schemas/xjc/xjc.xjb.xml index b1263924b..7faff289c 100644 --- a/opt14/src/main/schemas/xjc/xjc.xjb.xml +++ b/opt14/src/main/schemas/xjc/xjc.xjb.xml @@ -12,7 +12,7 @@ --> - + \ No newline at end of file From 76e710c8b96c8fcf30fc4ce1c00825f636c43c58 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 26 Jul 2021 15:24:03 +0200 Subject: [PATCH 17/36] First parse the entire OPT1.4 in OPT2, then convert to Template later, for constraint oerlays --- .../archie/opt14/DefinitionConverter.java | 25 ++--- .../archie/opt14/DescriptionConverter.java | 3 +- .../nedap/archie/opt14/Opt14Converter.java | 24 ++++- .../archie/opt14/OptToTemplateConverter.java | 92 +++++++++++++++++++ 4 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index 74e274458..4006e2dbe 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -8,6 +8,7 @@ import com.nedap.archie.aom.CAttribute; import com.nedap.archie.aom.CComplexObject; import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.Template; import com.nedap.archie.aom.TemplateOverlay; @@ -15,15 +16,16 @@ import static com.nedap.archie.opt14.BaseTypesConverter.convertMultiplicity; import static com.nedap.archie.opt14.PrimitiveConverter.convertPrimitive; +import com.nedap.archie.aom.terminology.ArchetypeTerminology; import com.nedap.archie.opt14.schema.*; public class DefinitionConverter { private OPERATIONALTEMPLATE opt14; - private Template template; + private OperationalTemplate template; private ADL14ConversionConfiguration config; - public void convert(Template template, OPERATIONALTEMPLATE opt14, ADL14ConversionConfiguration config) { + public void convert(OperationalTemplate template, OPERATIONALTEMPLATE opt14, ADL14ConversionConfiguration config) { this.config = config; this.opt14 = opt14; this.template = template; @@ -96,21 +98,22 @@ private CObject convertSlot(ARCHETYPESLOT cobject14) { private CObject convertRoot(CARCHETYPEROOT cRoot14) { - TemplateOverlay overlay = new TemplateOverlay(); - overlay.setArchetypeId(new ArchetypeHRID(cRoot14.getArchetypeId().getValue())); - overlay.getArchetypeId().setConceptId(overlay.getArchetypeId().getConceptId() + "ovl-1"); - overlay.setParentArchetypeId(cRoot14.getArchetypeId().getValue()); - overlay.setDefinition(convert(cRoot14)); - overlay.setTerminology(TerminologyConverter.createTerminology(opt14, cRoot14, config)); - template.addTemplateOverlay(overlay); - + ArchetypeTerminology terminology = TerminologyConverter.createTerminology(opt14, cRoot14, config); CArchetypeRoot root = new CArchetypeRoot(); - root.setArchetypeRef(overlay.getArchetypeId().getFullId()); + root.setArchetypeRef(cRoot14.getArchetypeId().getValue()); if(cRoot14.getNodeId() != null && !cRoot14.getNodeId().isEmpty() && !cRoot14.getNodeId().startsWith("at0000")) { root.setNodeId(cRoot14.getNodeId()); } root.setRmTypeName(cRoot14.getRmTypeName()); root.setOccurrences(BaseTypesConverter.convertMultiplicity(cRoot14.getOccurrences())); + + setObjectBasics(cRoot14, root); + + for (CATTRIBUTE attribute14 : cRoot14.getAttributes()) { + root.addAttribute(convert(attribute14)); + } + + template.addComponentTerminology(cRoot14.getArchetypeId().getValue(), terminology); return root; } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java index 6b8f7727c..4da37bc91 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -1,5 +1,6 @@ package com.nedap.archie.opt14; +import com.nedap.archie.aom.Archetype; import com.nedap.archie.aom.ResourceDescription; import com.nedap.archie.aom.ResourceDescriptionItem; import com.nedap.archie.aom.Template; @@ -13,7 +14,7 @@ public class DescriptionConverter { - public static void convert(Template template, OPERATIONALTEMPLATE opt14) { + public static void convert(Archetype template, OPERATIONALTEMPLATE opt14) { RESOURCEDESCRIPTION description14 = opt14.getDescription(); ResourceDescription description = new ResourceDescription(); description.setLifecycleState(TerminologyCode.createFromString("openehr", null, description14.getLifecycleState())); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 3de185195..8ea6b058f 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -7,6 +7,7 @@ import com.nedap.archie.adl14.ADL2ConversionResultList; import com.nedap.archie.adl14.OpenEHRADL14ConversionConfiguration; import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.Template; import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.diff.Differentiator; @@ -35,18 +36,33 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA config.setAllowEmptyNodeIdsForSpecializations(true); config.setApplyDiff(false);//the diff must be applied manually later, after converting node ids - Template template = new Template(); + //First create an OPT 2 + OperationalTemplate opt2 = new OperationalTemplate(); //TODO: should this include the concept, rather than just the template ID? + opt2.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + opt2.setControlled(opt14.isIsControlled()); + opt2.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); + if(opt14.getUid() != null) { + opt2.setUid(opt14.getUid().getValue()); + } + DescriptionConverter.convert(opt2, opt14); + + new DefinitionConverter().convert(opt2, opt14, config); + + + Template template = new Template(); template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); template.setControlled(opt14.isIsControlled()); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); + template.setTerminology(opt2.getTerminology()); if(opt14.getUid() != null) { template.setUid(opt14.getUid().getValue()); } - DescriptionConverter.convert(template, opt14); - - new DefinitionConverter().convert(template, opt14, config); + DescriptionConverter.convert(template, opt14); + new OptToTemplateConverter().convert(opt2, template); + //template.setDefinition(opt2.getDefinition()); + //TODO: convert to template overlays here RepoFlatArchetypeProvider flatParentProvider = new RepoFlatArchetypeProvider(adl2Archetypes); new NodeIdFixerBeforeConversion().fixNodeIds(template, flatParentProvider); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java new file mode 100644 index 000000000..3e496edcc --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java @@ -0,0 +1,92 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.CArchetypeRoot; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.OperationalTemplate; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.opt14.schema.CARCHETYPEROOT; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Performs an in-place conversion of the OPT2 to a source form template. Destorys the OPT2 in the process! + * + * Does not perform any diffing, just creates template overlays where required + */ +public class OptToTemplateConverter { + private Template template; + private OperationalTemplate opt2; + + public void convert(OperationalTemplate opt2, Template template) { + this.template = template; + this.opt2 = opt2; + convert(opt2.getDefinition()); + template.setDefinition(opt2.getDefinition()); + } + + public void convert(CAttribute cAttribute) { + LinkedHashMap replacements = new LinkedHashMap<>(); + List children = cAttribute.getChildren(); + int i = 0; + for(CObject child: children) { + CObject replacement = convert(child); + if(replacement != null) { + replacements.put(i, replacement); + } + i++; + } + + for(Map.Entry replacement: replacements.entrySet()) { + int index = replacement.getKey(); + CObject constraint = replacement.getValue(); + children.set(index, constraint); + constraint.setParent(cAttribute); + } + } + + public CObject convert(CObject cObject) { + CObject replacement = null; + if(cObject instanceof CArchetypeRoot) { + replacement = convertRoot((CArchetypeRoot) cObject); + } + //but do continue processing, even if there is a replacement! + for(CAttribute attribute:cObject.getAttributes()) { + convert(attribute); + } + + return replacement; + } + + private CObject convertRoot(CArchetypeRoot cRoot14) { + + CComplexObject templateRoot = new CComplexObject(); + templateRoot.setNodeId("at0000"); + templateRoot.setRmTypeName(cRoot14.getRmTypeName()); + templateRoot.setAttributes(cRoot14.getAttributes()); + + TemplateOverlay overlay = new TemplateOverlay(); + overlay.setArchetypeId(new ArchetypeHRID(cRoot14.getArchetypeRef())); + overlay.getArchetypeId().setConceptId(overlay.getArchetypeId().getConceptId() + "ovl-1"); + overlay.setParentArchetypeId(cRoot14.getArchetypeRef()); + overlay.setDefinition(templateRoot); + overlay.setTerminology(opt2.getComponentTerminologies().get(cRoot14.getArchetypeRef())); + template.addTemplateOverlay(overlay); + + CArchetypeRoot root = new CArchetypeRoot(); + root.setArchetypeRef(overlay.getArchetypeId().getFullId()); + if(cRoot14.getNodeId() != null && !cRoot14.getNodeId().isEmpty() && !cRoot14.getNodeId().startsWith("at0000")) { + root.setNodeId(cRoot14.getNodeId()); + } + root.setRmTypeName(cRoot14.getRmTypeName()); + root.setOccurrences(cRoot14.getOccurrences()); + return root; + } +} From 56e05847b76884ab14c798b7a620ef9f848ad368 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 26 Jul 2021 16:17:03 +0200 Subject: [PATCH 18/36] Add the beginning of the TCONSTRAINT conversion, plus a test class is still missing source of the parent archetypes, first just parsing, conversion will be later.... --- .../archie/opt14/ArchetypeTermFixer.java | 2 +- .../archie/opt14/BaseTypesConverter.java | 21 +- .../archie/opt14/DefaultValueConverter.java | 2 +- .../archie/opt14/DefinitionConverter.java | 2 +- .../archie/opt14/DescriptionConverter.java | 4 +- .../archie/opt14/DomainTypeConverter.java | 2 +- .../opt14/NodeIdFixerBeforeConversion.java | 2 +- .../nedap/archie/opt14/NodeIdSpecializer.java | 2 +- .../nedap/archie/opt14/Opt14Converter.java | 10 +- .../archie/opt14/OptToTemplateConverter.java | 2 +- .../archie/opt14/PrimitiveConverter.java | 2 +- .../archie/opt14/TConstraintApplier.java | 69 + .../archie/opt14/TerminologyConverter.java | 2 +- opt14/src/main/schemas/xjc/xjc.xjb.xml | 13 +- .../archie/opt14/Opt14ConverterTest.java | 36 + opt14/src/test/resources/RESPECT_NSS-v0.opt | 7390 +++++++++++++++++ 16 files changed, 7541 insertions(+), 20 deletions(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java create mode 100644 opt14/src/test/resources/RESPECT_NSS-v0.opt diff --git a/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java b/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java index 7e011a51a..b0b2359ba 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/ArchetypeTermFixer.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.regex.Pattern; -public class ArchetypeTermFixer { +class ArchetypeTermFixer { private String originalLanguage; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java index ab783574a..256a44f78 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java @@ -6,6 +6,7 @@ import com.nedap.archie.base.terminology.TerminologyCode; import com.nedap.archie.rm.datatypes.CodePhrase; import com.nedap.archie.rm.datavalues.DvCodedText; +import com.nedap.archie.rm.datavalues.DvText; import com.nedap.archie.rm.datavalues.DvURI; import com.nedap.archie.rm.datavalues.TermMapping; import com.nedap.archie.rm.datavalues.quantity.DvInterval; @@ -17,7 +18,7 @@ import java.util.ArrayList; import java.util.List; -public class BaseTypesConverter { +class BaseTypesConverter { public static Cardinality convertCardinality(CARDINALITY cardinality14) { if(cardinality14 == null) { @@ -91,6 +92,20 @@ public static DvCodedText convert(DVCODEDTEXT symbol) { return codedText; } + public static DvText convert(DVTEXT text) { + if(text == null) { + return null; + } + DvText convertedText = new DvText(); + convertedText.setEncoding(convertToCodePhrase(text.getEncoding())); + convertedText.setFormatting(text.getFormatting()); + convertedText.setHyperlink(convert(text.getHyperlink())); + convertedText.setLanguage(convertToCodePhrase(text.getLanguage())); + convertedText.setMappings(convert(text.getMappings())); + convertedText.setValue(text.getValue()); + return convertedText; + } + public static List convert(List mappings14) { if(mappings14 == null) { return null; @@ -114,7 +129,9 @@ public static CodePhrase convertToCodePhrase(CODEPHRASE codePhrase) { return null; } //cannot use the codephrase to terminology code conversion - return new CodePhrase(codePhrase.getTerminologyId() != null ? new TerminologyId(codePhrase.getTerminologyId().getValue()) : null, + return new CodePhrase(codePhrase.getTerminologyId() != null ? new TerminologyId(codePhrase.getTerminologyId().getValue()) : new TerminologyId("local"), codePhrase.getCodeString()); } + + } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java index 568d5726f..d5e1d0d09 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Map; -public class DefaultValueConverter { +class DefaultValueConverter { //TODO: default values // // public void convertDefaultValues(OPERATIONALTEMPLATE opt14, OperationalTemplate opt) { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index 4006e2dbe..a9e96679a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -19,7 +19,7 @@ import com.nedap.archie.aom.terminology.ArchetypeTerminology; import com.nedap.archie.opt14.schema.*; -public class DefinitionConverter { +class DefinitionConverter { private OPERATIONALTEMPLATE opt14; private OperationalTemplate template; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java index 4da37bc91..bca69ae53 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DescriptionConverter.java @@ -12,9 +12,9 @@ import com.nedap.archie.opt14.schema.*; -public class DescriptionConverter { +class DescriptionConverter { - public static void convert(Archetype template, OPERATIONALTEMPLATE opt14) { + public static void convert(OPERATIONALTEMPLATE opt14, Archetype template) { RESOURCEDESCRIPTION description14 = opt14.getDescription(); ResourceDescription description = new ResourceDescription(); description.setLifecycleState(TerminologyCode.createFromString("openehr", null, description14.getLifecycleState())); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java index 38060d6bc..ff4f7925a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DomainTypeConverter.java @@ -16,7 +16,7 @@ import com.nedap.archie.opt14.schema.*; -public class DomainTypeConverter { +class DomainTypeConverter { public static CObject convertDomainType(CDOMAINTYPE cobject14) { if(cobject14 instanceof CDVORDINAL) { return convertCDVOrdinal((CDVORDINAL) cobject14); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java index 87f519075..05193567f 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdFixerBeforeConversion.java @@ -19,7 +19,7 @@ * * After that a nex step must be taken to ensure more node id fixes after conversion, then diffing must still occur */ -public class NodeIdFixerBeforeConversion { +class NodeIdFixerBeforeConversion { private Archetype archetype; private Archetype flatParent; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java index 520a2f6ab..07b1e843a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/NodeIdSpecializer.java @@ -32,7 +32,7 @@ * TODO: remove simple single constraint name constraints, and put them in the terminology instead first! * */ -public class NodeIdSpecializer { +class NodeIdSpecializer { private Archetype archetype; private Archetype flatParent; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 8ea6b058f..a62bea59e 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -39,19 +39,21 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA //First create an OPT 2 OperationalTemplate opt2 = new OperationalTemplate(); //TODO: should this include the concept, rather than just the template ID? - opt2.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + opt2.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + ".v1.0.0")); opt2.setControlled(opt14.isIsControlled()); opt2.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); if(opt14.getUid() != null) { opt2.setUid(opt14.getUid().getValue()); } - DescriptionConverter.convert(opt2, opt14); + DescriptionConverter.convert(opt14, opt2); + new DefinitionConverter().convert(opt2, opt14, config); + new TConstraintApplier().apply(opt14, opt2); Template template = new Template(); - template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + "v1.0.0")); + template.setArchetypeId(new ArchetypeHRID("openEHR-EHR-" + opt14.getDefinition().getRmTypeName() + "." + opt14.getTemplateId().getValue() + ".v1.0.0")); template.setControlled(opt14.isIsControlled()); template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); template.setTerminology(opt2.getTerminology()); @@ -59,7 +61,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA template.setUid(opt14.getUid().getValue()); } - DescriptionConverter.convert(template, opt14); + DescriptionConverter.convert(opt14, template); new OptToTemplateConverter().convert(opt2, template); //template.setDefinition(opt2.getDefinition()); //TODO: convert to template overlays here diff --git a/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java index 3e496edcc..9ddc1a418 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java @@ -21,7 +21,7 @@ * * Does not perform any diffing, just creates template overlays where required */ -public class OptToTemplateConverter { +class OptToTemplateConverter { private Template template; private OperationalTemplate opt2; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java index 2c8a705f0..0640c610c 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java @@ -10,7 +10,7 @@ import com.nedap.archie.opt14.schema.*; -public class PrimitiveConverter { +class PrimitiveConverter { public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { CPRIMITIVE primitive14 = cobject14.getItem(); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java b/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java new file mode 100644 index 000000000..8747205d6 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java @@ -0,0 +1,69 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.ArchetypeModelObject; +import com.nedap.archie.aom.OperationalTemplate; +import com.nedap.archie.opt14.schema.DATAVALUE; +import com.nedap.archie.opt14.schema.DVCODEDTEXT; +import com.nedap.archie.opt14.schema.DVTEXT; +import com.nedap.archie.opt14.schema.OPERATIONALTEMPLATE; +import com.nedap.archie.opt14.schema.TATTRIBUTE; +import com.nedap.archie.opt14.schema.TCOMPLEXOBJECT; +import com.nedap.archie.opt14.schema.TCONSTRAINT; +import com.nedap.archie.rm.datavalues.DataValue; +import com.nedap.archie.rm.datavalues.DvCodedText; +import com.nedap.archie.rm.datavalues.DvText; + +import java.util.List; + +class TConstraintApplier { + + + public void apply(OPERATIONALTEMPLATE opt14, OperationalTemplate opt2) { + TCONSTRAINT constraints = opt14.getConstraints(); + if(constraints != null && constraints.getAttributes() != null) { + for(TATTRIBUTE attribute: constraints.getAttributes()) { + String diffPath = attribute.getDifferentialPath(); + if(diffPath.startsWith("[")) { + //sometimes these paths start with a root node constraint. Sice there's only one + //and we don't support that, strip that here. + diffPath = diffPath.substring(diffPath.indexOf(']')+1); + } + List archetypeModelObjects = opt2.itemsAtPath(diffPath); + if(archetypeModelObjects.isEmpty()) { + System.out.println("no archetype objects found for " + diffPath); + } else if (archetypeModelObjects.size() > 1) { + System.out.println("many archetype objects found for " + diffPath); + } else { + ArchetypeModelObject obj = archetypeModelObjects.get(0); + + String attributeName = attribute.getRmAttributeName(); + for(TCOMPLEXOBJECT tcomplexobject:attribute.getChildren()) { + //TODO: + //occurrences + //rm type name + //node id? + //child-attributes? + + DATAVALUE defaultValue = tcomplexobject.getDefaultValue(); + if(defaultValue != null) { + + if(defaultValue instanceof DVCODEDTEXT) { + DvCodedText converted = BaseTypesConverter.convert((DVCODEDTEXT) defaultValue); + System.out.println(converted); + } else if (defaultValue instanceof DVTEXT) { + DvText converted = BaseTypesConverter.convert((DVTEXT) defaultValue); + System.out.println(converted); + } + System.out.println(diffPath); + System.out.println(attributeName); + System.out.println(defaultValue); + System.out.println(obj); + } + } + } + + } + } + + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java index 9cc9bec8a..9da216932 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TerminologyConverter.java @@ -16,7 +16,7 @@ import com.nedap.archie.opt14.schema.*; -public class TerminologyConverter { +class TerminologyConverter { public static ArchetypeTerminology createTerminology(OPERATIONALTEMPLATE opt14, CARCHETYPEROOT definition, ADL14ConversionConfiguration config) { diff --git a/opt14/src/main/schemas/xjc/xjc.xjb.xml b/opt14/src/main/schemas/xjc/xjc.xjb.xml index 7faff289c..ab92bc348 100644 --- a/opt14/src/main/schemas/xjc/xjc.xjb.xml +++ b/opt14/src/main/schemas/xjc/xjc.xjb.xml @@ -4,9 +4,16 @@ version="2.1"> - - - + + + + + + + + + + + \ No newline at end of file From 58c9faef5cf9aee0041180bb10192a2e904d15a6 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 16 Aug 2021 14:47:23 +0200 Subject: [PATCH 27/36] Allow previous conversion log to be passed, refactor tests a bit --- .../nedap/archie/opt14/Opt14Converter.java | 9 +- .../archie/opt14/Opt14ConverterTest.java | 121 +++++------------- 2 files changed, 39 insertions(+), 91 deletions(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index b899e375a..921111987 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -6,6 +6,7 @@ import com.nedap.archie.adl14.ADL2ConversionResult; import com.nedap.archie.adl14.ADL2ConversionResultList; import com.nedap.archie.adl14.OpenEHRADL14ConversionConfiguration; +import com.nedap.archie.adl14.log.ADL2ConversionRunLog; import com.nedap.archie.aom.ArchetypeHRID; import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.Template; @@ -27,8 +28,12 @@ * */ public class Opt14Converter { - + public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes) { + return convert(opt14, adl2Archetypes, null); + } + + public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullArchetypeRepository adl2Archetypes, ADL2ConversionRunLog previousConversion) { try { MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); ADL14ConversionConfiguration config = OpenEHRADL14ConversionConfiguration.getConfig(); @@ -72,7 +77,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA ADL14Converter converter = new ADL14Converter(metaModels, config); converter.setExistingRepository(adl2Archetypes); - ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template)); + ADL2ConversionResultList converted = converter.convert(Lists.newArrayList(template), previousConversion); ADL2ConversionResult adl2ConversionResult = converted.getConversionResults().get(0); if(adl2ConversionResult.getArchetype() != null) { diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index f621a9fef..76a461cab 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -31,38 +31,10 @@ public class Opt14ConverterTest { @Test public void procedureList() throws Exception { - InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); - repository.addArchetype(parseAdl2("openEHR-EHR-ACTION.procedure.v1.4.1.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls")); - - - JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - try(InputStream stream = getClass().getResourceAsStream("/procedure_list.opt")) { - - OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); - ADL2ConversionResultList convert = new Opt14Converter().convert(opt14, repository); - for(ADL2ConversionResult result:convert.getConversionResults()) { - if(result.getException() != null) { - result.getException().printStackTrace(); - } - } - Template convertedTemplate = (Template) convert.getConversionResults().get(0).getArchetype(); - System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate)); - - OperationalTemplate opt2 = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels()) - .createOperationalTemplate(true) - .keepLanguages("en") - .flatten(convertedTemplate); - - System.out.println(ADLArchetypeSerializer.serialize(opt2)); - - ArchetypeValidator validator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); - ValidationResult validationResult = validator.validate(convertedTemplate, repository); - assertTrue(validationResult.toString(), validationResult.passes()); - - } + testTemplate("/procedure_list.opt", + "openEHR-EHR-ACTION.procedure.v1.4.1.adls", + "openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls", + "openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls"); } @Test @@ -79,6 +51,34 @@ public void vitalSigns() throws Exception { "openEHR-EHR-OBSERVATION.pulse_oximetry.v1.1.3.adls"); } + @Test + @Ignore + public void respectFromRipple() throws Exception { + testTemplate("/RESPECT_NSS-v0.opt", + "openEHR-EHR-ACTION.procedure.v1.4.1.adls", + "openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls", + "openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls", + "openEHR-EHR-COMPOSITION.report.v1.0.0.adls", + "openEHR-EHR-SECTION.respect_headings.v0.0.1-alpha.adls", + "openEHR-EHR-ADMIN_ENTRY.respect_summary.v0.0.1-alpha.adls", + "openEHR-EHR-EVALUATION.clinical_synopsis.v1.0.2.adls", + "openEHR-EHR-EVALUATION.advance_planning_documentation.v0.0.1-alpha.adls", + "openEHR-EHR-ADMIN_ENTRY.care_preference_uk.v1.0.0.adls", + "openEHR-EHR-EVALUATION.care_preference_uk.v1.0.0.adls", + "openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls", + "openEHR-EHR-EVALUATION.cpr_decision_uk.v0.0.1-alpha.adls", + "openEHR-EHR-ADMIN_ENTRY.capacity_respect.v0.0.1-alpha.adls", + "openEHR-EHR-ADMIN_ENTRY.involvement_respect.v0.0.1-alpha.adls", + "openEHR-EHR-ACTION.service.v0.0.1-alpha.adls", + "openEHR-EHR-CLUSTER.practitioner_cc.v0.0.1-alpha.adls", + "openEHR-EHR-CLUSTER.practitioner_role_cc.v0.0.1-alpha.adls", + "openEHR-EHR-CLUSTER.name_cc.v0.0.1-alpha.adls", + " openEHR-EHR-CLUSTER.identifier_cc.v0.0.1-alpha.adls", + "openEHR-EHR-ADMIN_ENTRY.careteam_cc.v0.0.1-alpha.adls", + "openEHR-EHR-CLUSTER.contact_cc.v0.0.1-alpha.adls", + "openEHR-EHR-CLUSTER.telecom_cc.v0.0.1-alpha.adls"); + } + private ValidationResult testTemplate(String templateFileName, String... sourceArchetypes) throws IOException, ADLParseException, JAXBException { InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); for(String sourcefile:sourceArchetypes) { @@ -124,62 +124,5 @@ public Archetype parseAdl2(String resource) throws IOException, ADLParseExceptio - @Test - public void respectFromRipple() throws Exception { - InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); - //TODO: the correct archetypes - repository.addArchetype(parseAdl2("openEHR-EHR-ACTION.procedure.v1.4.1.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-COMPOSITION.report.v1.0.0.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-SECTION.respect_headings.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ADMIN_ENTRY.respect_summary.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.clinical_synopsis.v1.0.2.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.advance_planning_documentation.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ADMIN_ENTRY.care_preference_uk.v1.0.0.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.care_preference_uk.v1.0.0.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.cpr_decision_uk.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ADMIN_ENTRY.capacity_respect.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ADMIN_ENTRY.involvement_respect.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ACTION.service.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-CLUSTER.practitioner_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-CLUSTER.practitioner_role_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-CLUSTER.name_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2(" openEHR-EHR-CLUSTER.identifier_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-ADMIN_ENTRY.careteam_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-CLUSTER.contact_cc.v0.0.1-alpha.adls")); - repository.addArchetype(parseAdl2("openEHR-EHR-CLUSTER.telecom_cc.v0.0.1-alpha.adls")); -// repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls")); -// repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls")); -// repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls")); -// repository.addArchetype(parseAdl2("openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls")); - JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - try(InputStream stream = getClass().getResourceAsStream("/RESPECT_NSS-v0.opt")) { - - OPERATIONALTEMPLATE opt14 = ((JAXBElement) unmarshaller.unmarshal(stream)).getValue(); - ADL2ConversionResultList convert = new Opt14Converter().convert(opt14, repository); - for(ADL2ConversionResult result:convert.getConversionResults()) { - if(result.getException() != null) { - result.getException().printStackTrace(); - } - } - Template convertedTemplate = (Template) convert.getConversionResults().get(0).getArchetype(); - System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate, null, new ArchieRMObjectMapperProvider())); - - OperationalTemplate opt2 = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels()) - .createOperationalTemplate(true) - .keepLanguages("en") - .flatten(convertedTemplate); - - System.out.println(ADLArchetypeSerializer.serialize(opt2)); - - ArchetypeValidator validator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); - ValidationResult validationResult = validator.validate(convertedTemplate, repository); - assertTrue(validationResult.toString(), validationResult.passes()); - } - - } } From 70a35fd6b6a2ae12426e884b120eecf1e6503537 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Mon, 16 Aug 2021 14:48:10 +0200 Subject: [PATCH 28/36] Fix compile --- .../src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index 76a461cab..1a7e84f99 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -13,6 +13,7 @@ import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.json.ArchieRMObjectMapperProvider; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; +import org.junit.Ignore; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; From 2becdc792cd8e42e91e007182ba9f0f33f0002ec Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 17 Aug 2021 16:16:49 +0200 Subject: [PATCH 29/36] Fix archetype id rm model parsing --- .../support/identification/ArchetypeID.java | 9 ++++++++ .../composition/test_all_types.fixed.v1.xml | 21 ++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/openehr-rm/src/main/java/com/nedap/archie/rm/support/identification/ArchetypeID.java b/openehr-rm/src/main/java/com/nedap/archie/rm/support/identification/ArchetypeID.java index e0158d60f..635b488d0 100644 --- a/openehr-rm/src/main/java/com/nedap/archie/rm/support/identification/ArchetypeID.java +++ b/openehr-rm/src/main/java/com/nedap/archie/rm/support/identification/ArchetypeID.java @@ -5,6 +5,7 @@ import com.nedap.archie.rminfo.RMPropertyIgnore; import javax.annotation.Nullable; +import javax.xml.bind.Unmarshaller; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -251,4 +252,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(super.hashCode(), namespace, qualifiedRmEntity, domainConcept, rmOriginator, rmName, rmEntity, specialisation, versionId); } + + // after JAXB unmarshalling, set the field values correctly + public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { + if(this.rmName == null) { + parseValue(getValue()); + } + + } } diff --git a/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml b/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml index e21401ee6..ae6dd4029 100644 --- a/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml +++ b/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml @@ -1,18 +1,19 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://schemas.openehr.org/v1"> Test all types - - - - - - - - - + + + openEHR-EHR-COMPOSITION.test_all_types.v1 + + + test_all_types.en.v1 + + 1.0.2 + ISO_639-1 From 48a0f1c4e01c7aa18e4f30950fa9d066530ee5f2 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Thu, 19 Aug 2021 11:56:35 +0200 Subject: [PATCH 30/36] Add comment to why the no longer used DefaultValueConverter is still there for the moment --- .../java/com/nedap/archie/opt14/DefaultValueConverter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java index d5e1d0d09..fdf35fa0b 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefaultValueConverter.java @@ -23,6 +23,12 @@ import java.util.List; import java.util.Map; +/** + * This class is here only because there are two varaints of storing default values in OPTs, + * actually in different XSDs. I can merge the XSDs and make both variants work. + * However, only doing that if necessary. This class contains a commented out implementation + * in case that will be necessary, and will be removed otherwise. + */ class DefaultValueConverter { //TODO: default values // From 3b5805ad94c8a1d38420ab35bfd291e8ca6d603b Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Wed, 15 Sep 2021 12:10:58 +0200 Subject: [PATCH 31/36] Convert into rm_overlay + visibility, fix tests --- .../archie/adl14/ADL14NodeIDConverter.java | 14 ++++ .../composition/test_all_types.fixed.v1.xml | 2 +- .../nedap/archie/opt14/Opt14Converter.java | 1 + .../nedap/archie/opt14/TViewConverter.java | 64 +++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java index c64ec6033..623160961 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java @@ -7,6 +7,7 @@ import com.nedap.archie.adl14.log.ReasonForCodeCreation; import com.nedap.archie.aom.*; import com.nedap.archie.aom.primitives.CString; +import com.nedap.archie.aom.rmoverlay.RmOverlay; import com.nedap.archie.aom.terminology.ArchetypeTerm; import com.nedap.archie.aom.terminology.ValueSet; import com.nedap.archie.aom.utils.AOMUtils; @@ -95,6 +96,7 @@ public ADL2ConversionLog convert() { convertTermDefinitions(archetype, convertedCodes); convertAnnotations(archetype); + convertRmOverlay(archetype); previousConversionApplier.removeCreatedUnusedTermCodesAndValueSets(); return new ADL2ConversionLog(/*convertedCodes*/ null, createdCodes, createdValueSets); } @@ -115,6 +117,18 @@ private void convertAnnotations(Archetype archetype) { archetype.setAnnotations(converted); } + private void convertRmOverlay(Archetype archetype) { + RmOverlay convertedOverlay = new RmOverlay(); + convertedOverlay.setRmVisibility(new LinkedHashMap<>()); + if(archetype.getRmOverlay() != null && archetype.getRmOverlay().getRmVisibility() != null) { + for(String path:archetype.getRmOverlay().getRmVisibility().keySet()) { + convertedOverlay.getRmVisibility().put(convertPath(path), archetype.getRmOverlay().getRmVisibility().get(path)); + } + } + archetype.setRmOverlay(convertedOverlay); + } + + private void correctItemsCardinality(CObject cObject) { for(CAttribute attribute:cObject.getAttributes()) { if(attribute.getRmAttributeName().equalsIgnoreCase("items") && cObject.getRmTypeName().equalsIgnoreCase("CLUSTER") && attribute.getCardinality() != null) { diff --git a/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml b/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml index ae6dd4029..30753320a 100644 --- a/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml +++ b/openehr-rm/src/test/resources/com/nedap/archie/rm/composition/test_all_types.fixed.v1.xml @@ -1,6 +1,6 @@ +> Test all types diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index 921111987..ab4ed9baf 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -54,6 +54,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA TerminologyConverter.convertOntologies(opt14, opt2, config); new TConstraintApplier().apply(opt14, opt2); + new TViewConverter().apply(opt14, opt2); //System.out.println(ADLArchetypeSerializer.serialize(opt2, null, new ArchieRMObjectMapperProvider())); Template template = new Template(); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java new file mode 100644 index 000000000..ddb17e7d2 --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java @@ -0,0 +1,64 @@ +package com.nedap.archie.opt14; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ResourceAnnotations; +import com.nedap.archie.aom.rmoverlay.RmAttributeVisibility; +import com.nedap.archie.aom.rmoverlay.RmOverlay; +import com.nedap.archie.aom.rmoverlay.VisibilityType; +import com.nedap.archie.aom.terminology.ArchetypeTerm; +import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.opt14.schema.ANNOTATION; +import com.nedap.archie.opt14.schema.OPERATIONALTEMPLATE; +import com.nedap.archie.opt14.schema.StringDictionaryItem; +import com.nedap.archie.opt14.schema.TVIEW; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class TViewConverter { + + public static void apply(OPERATIONALTEMPLATE opt14, Archetype adl2Archetype) { + TVIEW view = opt14.getView(); + if (view != null) { + if (view.getConstraints() != null) { + RmOverlay overlay = adl2Archetype.getRmOverlay(); + if (overlay == null) { + adl2Archetype.setRmOverlay(new RmOverlay()); + overlay = adl2Archetype.getRmOverlay(); + } + Map rmVisibility = overlay.getRmVisibility(); + if (rmVisibility == null) { + overlay.setRmVisibility(new LinkedHashMap<>()); + rmVisibility = overlay.getRmVisibility(); + } + for (TVIEW.Constraints constraints : view.getConstraints()) { + for (TVIEW.Constraints.Items item : constraints.getItems()) { + RmAttributeVisibility attributeVisibility = rmVisibility.get(constraints.getPath()); + if(attributeVisibility == null) { + attributeVisibility = new RmAttributeVisibility(); + rmVisibility.put(constraints.getPath(), attributeVisibility); + } + switch (item.getId()) { + case "pass_through": + if("true".equals(item.getValue()) || new Boolean(true).equals(item.getValue())) { + attributeVisibility.setVisibility(VisibilityType.SHOW); + } else { + attributeVisibility.setVisibility(VisibilityType.HIDE); + } + break; + case "VisibleInView": + //create at code and link alias to terminology + String atCode = adl2Archetype.generateNextValueCode(); + attributeVisibility.setAlias(TerminologyCode.createFromString("local", null, atCode)); + adl2Archetype.getTerminology().getTermDefinitions().forEach((language, terms) -> { + terms.put(atCode, new ArchetypeTerm(atCode, (String) item.getValue(), (String) item.getValue())); + }); + break; + } + + } + } + } + } + } +} From 9ee2fbfc74020945911815824df8d86f7e084c4d Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Wed, 15 Sep 2021 15:19:21 +0200 Subject: [PATCH 32/36] Support and name/value='' queries, refactor RM Path queries WARNING: dangerous commit, might break things --- .../com/nedap/archie/aom/ArchetypeHRID.java | 21 +-- .../com/nedap/archie/aom/utils/AOMUtils.java | 24 +++ .../archie/query/ArchetypeRefPredicate.java | 43 +++++ .../nedap/archie/query/NoNodeIdPredicate.java | 31 +++ .../nedap/archie/query/NodeIdPredicate.java | 26 +++ .../nedap/archie/query/NodeNamePredicate.java | 43 +++++ .../com/nedap/archie/query/RMPathQuery.java | 176 +++++++----------- .../query/RmPathQueryPredicateConverter.java | 45 +++++ .../nedap/archie/query/RMPathQueryTest.java | 20 ++ .../archie/adlparser/RMPathQueryTest.java | 2 +- .../ArchetypeSlotValidationTest.java | 12 +- .../evaluation/ParsedRulesEvaluationTest.java | 26 +-- .../com/nedap/archie/paths/PathSegment.java | 15 +- .../com/nedap/archie/query/APathQuery.java | 8 + 14 files changed, 342 insertions(+), 150 deletions(-) create mode 100644 path-queries/src/main/java/com/nedap/archie/query/ArchetypeRefPredicate.java create mode 100644 path-queries/src/main/java/com/nedap/archie/query/NoNodeIdPredicate.java create mode 100644 path-queries/src/main/java/com/nedap/archie/query/NodeIdPredicate.java create mode 100644 path-queries/src/main/java/com/nedap/archie/query/NodeNamePredicate.java create mode 100644 path-queries/src/main/java/com/nedap/archie/query/RmPathQueryPredicateConverter.java diff --git a/aom/src/main/java/com/nedap/archie/aom/ArchetypeHRID.java b/aom/src/main/java/com/nedap/archie/aom/ArchetypeHRID.java index 9b6a60b7a..2cc7fa8cb 100644 --- a/aom/src/main/java/com/nedap/archie/aom/ArchetypeHRID.java +++ b/aom/src/main/java/com/nedap/archie/aom/ArchetypeHRID.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Strings; +import com.nedap.archie.aom.utils.AOMUtils; import com.nedap.archie.definitions.VersionStatus; import com.nedap.archie.rminfo.RMPropertyIgnore; @@ -49,24 +50,6 @@ public class ArchetypeHRID extends ArchetypeModelObject { private String buildCount; //TODO: XML attribute 'physical id', which is the full id - private static final Pattern namespacePattern = Pattern.compile("((?.*)::)?"); - private static final Pattern publisherPattern = Pattern.compile("(?[^.-]*)"); - private static final Pattern packagePattern = Pattern.compile("(?[^.-]*)"); - private static final Pattern classPattern = Pattern.compile("(?[^.-]*)"); - private static final Pattern conceptPattern = Pattern.compile("(?[^.]*)"); - private static final Pattern releaseVersionPattern = Pattern.compile("(\\.v(?[^-+]*))?"); - private static final Pattern versionStatusPattern = Pattern.compile("(?[^.\\d]*)?"); - private static final Pattern buildStatusPattern = Pattern.compile("(\\.?(?\\d*))"); - private static final Pattern archetypeHRIDPattern = Pattern.compile("" - + namespacePattern - + publisherPattern - + "-" + packagePattern - + "-" + classPattern - + "\\." + conceptPattern - + releaseVersionPattern - + versionStatusPattern - + buildStatusPattern - ); public ArchetypeHRID() { @@ -74,7 +57,7 @@ public ArchetypeHRID() { @JsonCreator public ArchetypeHRID(String value) { - Matcher m = archetypeHRIDPattern.matcher(value); + Matcher m = AOMUtils.ARCHETYPE_HRID_PATTERN.matcher(value); if(!m.matches()) { throw new IllegalArgumentException(value + " is not a valid archetype human readable id"); diff --git a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java index 43e0f56ee..eb2db8b58 100644 --- a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java +++ b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class AOMUtils { @@ -42,6 +43,25 @@ public class AOMUtils { private static Pattern idCodePattern = Pattern.compile("(id|at|ac)(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*"); private static Pattern adl14CodePattern = Pattern.compile("(id|at|ac)([0-9]+)(\\.(0|[1-9][0-9]*))*"); + private static final Pattern namespacePattern = Pattern.compile("((?.*)::)?"); + private static final Pattern publisherPattern = Pattern.compile("(?[^.-]*)"); + private static final Pattern packagePattern = Pattern.compile("(?[^.-]*)"); + private static final Pattern classPattern = Pattern.compile("(?[^.-]*)"); + private static final Pattern conceptPattern = Pattern.compile("(?[^.]*)"); + private static final Pattern releaseVersionPattern = Pattern.compile("(\\.v(?[^-+]*))?"); + private static final Pattern versionStatusPattern = Pattern.compile("(?[^.\\d]*)?"); + private static final Pattern buildStatusPattern = Pattern.compile("(\\.?(?\\d*))"); + public static final Pattern ARCHETYPE_HRID_PATTERN = Pattern.compile("" + + namespacePattern + + publisherPattern + + "-" + packagePattern + + "-" + classPattern + + "\\." + conceptPattern + + releaseVersionPattern + + versionStatusPattern + + buildStatusPattern + ); + public static int getSpecializationDepthFromCode(String code) { if(code == null) { return -1; @@ -56,6 +76,10 @@ public static boolean isIdCode(String code) { return code.startsWith(AdlCodeDefinitions.ID_CODE_LEADER); } + public static boolean isArchetypeRef(String archetypeRef) { + return ARCHETYPE_HRID_PATTERN.matcher(archetypeRef).matches(); + } + public static boolean isValueCode(String code) { return code.startsWith(AdlCodeDefinitions.VALUE_CODE_LEADER); } diff --git a/path-queries/src/main/java/com/nedap/archie/query/ArchetypeRefPredicate.java b/path-queries/src/main/java/com/nedap/archie/query/ArchetypeRefPredicate.java new file mode 100644 index 000000000..3cfe761f3 --- /dev/null +++ b/path-queries/src/main/java/com/nedap/archie/query/ArchetypeRefPredicate.java @@ -0,0 +1,43 @@ +package com.nedap.archie.query; + +import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.rminfo.ModelInfoLookup; + +import java.util.Objects; +import java.util.function.Predicate; + +class ArchetypeRefPredicate implements Predicate { + + private final ModelInfoLookup lookup; + private final ArchetypeHRID archetypeRef; + + public ArchetypeRefPredicate(ModelInfoLookup lookup, String archetypeRef) { + this.lookup = lookup; + this.archetypeRef = new ArchetypeHRID(archetypeRef); + } + + @Override + public boolean test(Object input) { + if(input == null) { + return false; + } + String nodeIdFromRMObject = lookup.getArchetypeNodeIdFromRMObject(input); + String archetypeIdFromRMObject = lookup.getArchetypeIdFromArchetypedRmObject(input); + + return versionMatches(archetypeRef, archetypeIdFromRMObject) || (nodeIdFromRMObject != null && AOMUtils.isArchetypeRef(nodeIdFromRMObject) && versionMatches(archetypeRef, nodeIdFromRMObject)); + + } + + private static boolean versionMatches(ArchetypeHRID ref, String id) { + if(id == null) { + return false; + } + ArchetypeHRID toTest = new ArchetypeHRID(id); + return toTest.getIdUpToConcept().equals(ref.getIdUpToConcept()) && + (ref.getMajorVersion() == null || toTest.getMajorVersion().equals(ref.getMajorVersion())) && + (ref.getMinorVersion() == null || toTest.getMinorVersion().equals(ref.getMinorVersion())) && + (ref.getPatchVersion() == null || toTest.getPatchVersion().equals(ref.getPatchVersion())); + } +} + diff --git a/path-queries/src/main/java/com/nedap/archie/query/NoNodeIdPredicate.java b/path-queries/src/main/java/com/nedap/archie/query/NoNodeIdPredicate.java new file mode 100644 index 000000000..c26ffd706 --- /dev/null +++ b/path-queries/src/main/java/com/nedap/archie/query/NoNodeIdPredicate.java @@ -0,0 +1,31 @@ +package com.nedap.archie.query; + +import com.nedap.archie.rminfo.ModelInfoLookup; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Special predicate that checks for a non-existing node id + * needed when people fire archetype paths at RM instances, where the RM instance does not have a node id, but the + * archetype does! + */ +class NoNodeIdPredicate implements Predicate { + private final ModelInfoLookup lookup; + private final String nodeId; + + public NoNodeIdPredicate(ModelInfoLookup lookup, String nodeId) {//constructor nodeid parameter is there only to indicate it must be present + this.lookup = lookup; + this.nodeId = nodeId; + } + + @Override + public boolean test(Object o) { + if(o == null) { + return false; + } + String archetypeNodeIdFromRMObject = lookup.getArchetypeNodeIdFromRMObject(o); + //the null is because sometimes things in archetypes have node ids, and in rm objects they do not! + return archetypeNodeIdFromRMObject == null; + } +} \ No newline at end of file diff --git a/path-queries/src/main/java/com/nedap/archie/query/NodeIdPredicate.java b/path-queries/src/main/java/com/nedap/archie/query/NodeIdPredicate.java new file mode 100644 index 000000000..f28b3a3f8 --- /dev/null +++ b/path-queries/src/main/java/com/nedap/archie/query/NodeIdPredicate.java @@ -0,0 +1,26 @@ +package com.nedap.archie.query; + +import com.nedap.archie.rminfo.ModelInfoLookup; + +import java.util.Objects; +import java.util.function.Predicate; + +class NodeIdPredicate implements Predicate { + private final ModelInfoLookup lookup; + private final String nodeId; + + public NodeIdPredicate(ModelInfoLookup lookup, String nodeId) { + this.lookup = lookup; + this.nodeId = nodeId; + } + + @Override + public boolean test(Object o) { + if(o == null) { + return false; + } + String archetypeNodeIdFromRMObject = lookup.getArchetypeNodeIdFromRMObject(o); + + return Objects.equals(archetypeNodeIdFromRMObject, nodeId);//TODO: also match specialized nodes! + } +} diff --git a/path-queries/src/main/java/com/nedap/archie/query/NodeNamePredicate.java b/path-queries/src/main/java/com/nedap/archie/query/NodeNamePredicate.java new file mode 100644 index 000000000..4f2d016b4 --- /dev/null +++ b/path-queries/src/main/java/com/nedap/archie/query/NodeNamePredicate.java @@ -0,0 +1,43 @@ +package com.nedap.archie.query; + +import com.nedap.archie.rminfo.ModelInfoLookup; + +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; + +class NodeNamePredicate implements Predicate { + + private final ModelInfoLookup lookup; + private final String nodeName; + + public NodeNamePredicate(ModelInfoLookup lookup, String nodeName) { + this.lookup = lookup; + this.nodeName = nodeName; + } + + @Override + public boolean test(Object input) { + if(input == null) { + return false; + } + String nameFromRMObject = lookup.getNameFromRMObject(input); + if(nameFromRMObject == null) { + return false; + } + return equalsName(nameFromRMObject, nodeName); + + } + + private boolean equalsName(String name, String nameFromQuery) { + //the grammar throws away whitespace. And it should, because it's kind of tricky otherwise. So match names without whitespace + //TODO: should this be case sensitive? + if(name == null) { + return false; + } + name = name.replaceAll("( |\\t|\\n|\\r)+", ""); + nameFromQuery = nameFromQuery.replaceAll("( |\\t|\\n|\\r)+", ""); + return name.equalsIgnoreCase(nameFromQuery); + + } +} diff --git a/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java b/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java index c15b14d66..8f0bc5b7d 100644 --- a/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java +++ b/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java @@ -13,6 +13,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.Predicate; /** * For now only accepts rather simple xpath-like expressions. @@ -36,6 +37,13 @@ public RMPathQuery(String query) { //TODO: get diagnostic information about where the finder stopped in the path - could be very useful! + /** + * WARNING: this method has many quirks. Please use findList instead! + * Quirks include: + * - if at a certain level in the path several objects match, it will only search the first match + * - it includes a collection if it matches a collection attribute, in all other cases a single item + */ + @Deprecated public T find(ModelInfoLookup lookup, Object root) { Object currentObject = root; try { @@ -65,22 +73,14 @@ public T find(ModelInfoLookup lookup, Object root) { } else if (archetypeNodeIdFromObject != null) { if (segment.hasExpressions()) { - if (segment.hasIdCode()) { - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - return null; - } - } else if (segment.hasNumberIndex()) { - int number = segment.getIndex(); - if (number != 1) { + Predicate predicate = RmPathQueryPredicateConverter.convert(segment, lookup); + + if(!predicate.test(currentObject)) { + predicate = RmPathQueryPredicateConverter.convertWithoutNodeId(segment, lookup); + //TODO: maybe build this ina single predicate? BUt should we for something deprecated? + if(!predicate.test(currentObject)) { return null; } - } else if (segment.hasArchetypeRef()) { - //operational templates in RM Objects have their archetype node ID set to an archetype ref. That - //we support. Other things not so much - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - throw new IllegalArgumentException("cannot handle RM-queries with node names or archetype references yet"); - } - } } } else if (segment.hasNumberIndex()) { @@ -102,6 +102,29 @@ public T find(ModelInfoLookup lookup, Object root) { } } + @Deprecated //please remove as soon as no longer used! + private Object findRMObject(ModelInfoLookup lookup, PathSegment segment, Collection collection) { + + if(segment.hasNumberIndex()) { + int number = segment.getIndex(); + for(Object object:collection) { + if(number == 1) { + return object; + } + number--; + } + return null; + } + for(Object o:collection) { + Predicate predicate = RmPathQueryPredicateConverter.convert(segment, lookup); + + if(predicate.test(o)) { + return o; + } + } + return null; + } + /** * You will want to use RMQueryContext in many cases. For perforamnce reasons, this could still be useful */ @@ -132,47 +155,15 @@ public List findList(ModelInfoLookup lookup, Object root) if (currentRMObject == null) { continue; } - String archetypeNodeIdFromObject = lookup.getArchetypeNodeIdFromRMObject(currentObject); if (currentRMObject instanceof Collection) { Collection collection = (Collection) currentRMObject; if (!segment.hasExpressions()) { addAllFromCollection(lookup, newCurrentObjects, collection, newPath); } else { - //TODO newCurrentObjects.addAll(findRMObjectsWithPathCollection(lookup, segment, collection, newPath)); } - } else if (archetypeNodeIdFromObject != null) { - - if (segment.hasExpressions()) { - if (segment.hasIdCode()) { - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - continue; - } - } else if (segment.hasNumberIndex()) { - int number = segment.getIndex(); - if (number != 1) { - continue; - } - } else if (segment.hasArchetypeRef()) { - //operational templates in RM Objects have their archetype node ID set to an archetype ref. That - //we support. Other things not so much - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - continue; - } - - } - newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); - } - } else if (segment.hasNumberIndex()) { - int number = segment.getIndex(); - if (number != 1) { - continue; - } } else { - //The object does not have an archetypeNodeId - //in openehr, in archetypes everythign has node ids. Datavalues do not in the rm. a bit ugly if you ask - //me, but that's why there's no 'if there's a nodeId set, this won't match!' code here. - newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); + newCurrentObjects.addAll(findRMObjectsWithPathCollection(lookup, segment, Lists.newArrayList(currentRMObject), newPath)); } } currentObjects = newCurrentObjects; @@ -239,86 +230,51 @@ private boolean archetypeNodeIdPresent(String archetypeNodeId) { private Collection findRMObjectsWithPathCollection(ModelInfoLookup lookup, PathSegment segment, Collection collection, String path) { - if(segment.hasNumberIndex()) { - int number = segment.getIndex(); - int i = 1; - for(Object object:collection) { - if(number == i) { - //TODO: check for other constraints as well - return Lists.newArrayList(new RMObjectWithPath(object, path + buildPathConstraint(i-1, lookup.getArchetypeNodeIdFromRMObject(object)))); - } - i++; - } - } + collection = getNumberedElement(segment, collection); + + Predicate predicate = RmPathQueryPredicateConverter.convert(segment, lookup); List result = new ArrayList<>(); int i = 1; for(Object object:collection) { + String archetypeNodeId = lookup.getArchetypeNodeIdFromRMObject(object); + if(predicate.test(object)) { + result.add(new RMObjectWithPath(object, path + buildPathConstraint(collection.size() == 1 ? null : i, archetypeNodeId))); + } + i++; + } + if(result.isEmpty()) { + predicate = RmPathQueryPredicateConverter.convertWithoutNodeId(segment, lookup); - if (segment.hasIdCode()) { - if (segment.getNodeId().equals(archetypeNodeId)) { - result.add(new RMObjectWithPath(object, path + buildPathConstraint(i, archetypeNodeId))); - } - } else if (segment.hasArchetypeRef()) { - //operational templates in RM Objects have their archetype node ID set to an archetype ref. That - //we support. Other things not so much - if (segment.getNodeId().equals(archetypeNodeId)) { - result.add(new RMObjectWithPath(object, path + buildPathConstraint(i, archetypeNodeId))); - } - } else { - if(equalsName(lookup.getNameFromRMObject(object), segment.getNodeId())) { - result.add(new RMObjectWithPath(object, path + buildPathConstraint(i, archetypeNodeId))); + i = 1; + for (Object object : collection) { + + String archetypeNodeId = lookup.getArchetypeNodeIdFromRMObject(object); + if (predicate.test(object)) { + result.add(new RMObjectWithPath(object, path + buildPathConstraint(collection.size() == 1 ? null : i, archetypeNodeId))); } + i++; } - i++; } return result; } - private Object findRMObject(ModelInfoLookup lookup, PathSegment segment, Collection collection) { - + private Collection getNumberedElement(PathSegment segment, Collection collection) { if(segment.hasNumberIndex()) { int number = segment.getIndex(); + int i = 1; for(Object object:collection) { - if(number == 1) { - return object; - } - number--; - } - return null; - } - for(Object o:collection) { - String archetypeNodeId = lookup.getArchetypeNodeIdFromRMObject(o); - - if (segment.hasIdCode()) { - if (segment.getNodeId().equals(archetypeNodeId)) { - return o; - } - } else if (segment.hasArchetypeRef()) { - //operational templates in RM Objects have their archetype node ID set to an archetype ref. That - //we support. Other things not so much - if (segment.getNodeId().equals(archetypeNodeId)) { - return o; - } - } else { - if(equalsName(lookup.getNameFromRMObject(o), segment.getNodeId())) { - return o; + if(number == i) { + //TODO: check for other constraints as well + ArrayList newCollection = new ArrayList<>(); + newCollection.add(object); + collection = newCollection; + break; } + i++; } } - return null; - } - - private boolean equalsName(String name, String nameFromQuery) { - //the grammar throws away whitespace. And it should, because it's kind of tricky otherwise. So match names without whitespace - //TODO: should this be case sensitive? - if(name == null) { - return false; - } - name = name.replaceAll("( |\\t|\\n|\\r)+", ""); - nameFromQuery = nameFromQuery.replaceAll("( |\\t|\\n|\\r)+", ""); - return name.equalsIgnoreCase(nameFromQuery); - + return collection; } public List getPathSegments() { diff --git a/path-queries/src/main/java/com/nedap/archie/query/RmPathQueryPredicateConverter.java b/path-queries/src/main/java/com/nedap/archie/query/RmPathQueryPredicateConverter.java new file mode 100644 index 000000000..cb189dcd5 --- /dev/null +++ b/path-queries/src/main/java/com/nedap/archie/query/RmPathQueryPredicateConverter.java @@ -0,0 +1,45 @@ +package com.nedap.archie.query; + +import com.nedap.archie.paths.PathSegment; +import com.nedap.archie.rminfo.ModelInfoLookup; + +import java.util.function.Predicate; + +/** converts the nodeid/nodename/position part of a path segment to a java Predicate to tests + **/ + +public class RmPathQueryPredicateConverter { + public static Predicate convert(PathSegment segment, ModelInfoLookup lookup) { + Predicate result = o -> true; + if(segment.hasIdCode()) { + result = result.and(new NodeIdPredicate(lookup, segment.getNodeId())); + } + if(segment.hasArchetypeRef()) { + result = result.and(new ArchetypeRefPredicate(lookup, segment.getNodeId())); + } + if(segment.getArchetypeRef() != null) { //TODO: why is this a different case - solve this! + result = result.and(new ArchetypeRefPredicate(lookup, segment.getArchetypeRef())); + } + if(segment.hasObjectNameConstraint()) { + result = result.and(new NodeNamePredicate(lookup, segment.getObjectNameConstraint())); + } + return result; + } + + public static Predicate convertWithoutNodeId(PathSegment segment, ModelInfoLookup lookup) { + Predicate result = o -> true; + if(segment.hasIdCode()) { + result = result.and(new NoNodeIdPredicate(lookup, segment.getNodeId())); + } + if(segment.hasArchetypeRef()) { + result = result.and(new ArchetypeRefPredicate(lookup, segment.getNodeId())); + } + if(segment.getArchetypeRef() != null) { //TODO: why is this a different case - solve this! + result = result.and(new ArchetypeRefPredicate(lookup, segment.getArchetypeRef())); + } + if(segment.hasObjectNameConstraint()) { + result = result.and(new NodeNamePredicate(lookup, segment.getObjectNameConstraint())); + } + return result; + } +} diff --git a/path-queries/src/test/java/com/nedap/archie/query/RMPathQueryTest.java b/path-queries/src/test/java/com/nedap/archie/query/RMPathQueryTest.java index d0b8c1309..d4e4e0a53 100644 --- a/path-queries/src/test/java/com/nedap/archie/query/RMPathQueryTest.java +++ b/path-queries/src/test/java/com/nedap/archie/query/RMPathQueryTest.java @@ -2,6 +2,7 @@ import com.nedap.archie.rm.datastructures.Cluster; import com.nedap.archie.rm.datastructures.Element; +import com.nedap.archie.rm.datavalues.DvText; import org.junit.Before; import org.junit.Test; @@ -74,4 +75,23 @@ public void adl14NodeIdMatch() { assertEquals(elementAt0001, cluster.itemAtPath("/items[at0001]")); assertEquals(elementAt0002_3, cluster.itemAtPath("/items[at0002.3]")); } + + @Test + public void andNameIs() { + Cluster cluster = new Cluster(); + cluster.setArchetypeNodeId("at0000"); + cluster.setName(new DvText("my name")); + Element elementAt0001 = new Element(); + elementAt0001.setName(new DvText("some element")); + elementAt0001.setArchetypeNodeId("at0001"); + Element elementAt0001_2 = new Element(); + elementAt0001_2.setName(new DvText("some other element")); + elementAt0001_2.setArchetypeNodeId("at0001"); + + cluster.addItem(elementAt0001); + cluster.addItem(elementAt0001_2); + APathQuery query = new APathQuery("/items[at0001 and name/value='some element']"); + assertEquals(elementAt0001, cluster.itemAtPath("/items[at0001 and name/value='some element']")); + assertEquals(elementAt0001_2, cluster.itemAtPath("/items[at0001 and name/value='some other element']")); + } } diff --git a/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java b/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java index f13874401..ad825de4a 100644 --- a/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java +++ b/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertNotNull; /** - * Test APath query with RM Objects + * Test Path query with RM Objects * Created by pieter.bos on 06/04/16. */ public class RMPathQueryTest { diff --git a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java index b8775189b..a2cd0e0f6 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java @@ -93,7 +93,7 @@ public void validateWithCorrectArchetypeInSlot() throws Exception { validated = rmObjectValidator.validate(parentOpt, example); assertEquals(validated.toString(), 1, validated.size()); RMObjectValidationMessage rmObjectValidationMessage = validated.get(0); - assertEquals("/items[id2, 1]/data[id9]/events[id3, 1]/data[id10]/items[id4.1, 3]/value/defining_code[id9999]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]/data[id9]/events[id3, 1]/data[id10]/items[id4.1, 3]/value/defining_code[id9999]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.DEFAULT, rmObjectValidationMessage.getType()); } @@ -111,7 +111,7 @@ public void incorrectArchetypeInSlot() throws Exception { List validated = rmObjectValidator.validate(parentOpt, example); assertEquals(validated.toString(), 1, validated.size()); RMObjectValidationMessage rmObjectValidationMessage = validated.get(0); - assertEquals("/items[id2, 1]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.ARCHETYPE_SLOT_ID_MISMATCH, rmObjectValidationMessage.getType()); } @@ -130,7 +130,7 @@ public void unknownArchetypeInSlot() throws Exception { List validated = rmObjectValidator.validate(parentOpt, example); assertEquals(validated.toString(), 1, validated.size()); RMObjectValidationMessage rmObjectValidationMessage = validated.get(0); - assertEquals("/items[id2, 1]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.ARCHETYPE_NOT_FOUND, rmObjectValidationMessage.getType()); } @@ -155,15 +155,15 @@ public void noArchetypeIdInSlot() throws Exception { //there must be an archetype id in a slot RMObjectValidationMessage rmObjectValidationMessage = validated.get(0); - assertEquals("/items[id2, 1]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.ARCHETYPE_SLOT_ID_MISMATCH, rmObjectValidationMessage.getType()); //but also an observation must have an archetype id (invariant) rmObjectValidationMessage = validated.get(1); - assertEquals("/items[id2, 1]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.INVARIANT_ERROR, rmObjectValidationMessage.getType()); //and an element must either have a value or a null flavour (invariant) rmObjectValidationMessage = validated.get(2); - assertEquals("/items[id2, 1]/data[id9]/events[id3, 1]/data[id10]/items[id4.1, 3]", rmObjectValidationMessage.getPath()); + assertEquals("/items[id2]/data[id9]/events[id3, 1]/data[id10]/items[id4.1, 3]", rmObjectValidationMessage.getPath()); assertEquals(RMObjectValidationMessageType.INVARIANT_ERROR, rmObjectValidationMessage.getType()); } diff --git a/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java b/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java index cca86882f..2ff3f0615 100644 --- a/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java +++ b/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java @@ -137,7 +137,7 @@ public void modelReferences() throws Exception { assertEquals("the assertion should have succeeded", true, result.getResult()); assertEquals("the assertion tag should be correct", "blood_pressure_valid", result.getTag()); assertEquals(1, result.getRawResult().getPaths(0).size()); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", result.getRawResult().getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", result.getRawResult().getPaths(0).get(0)); } @@ -162,38 +162,38 @@ public void booleanConstraint() throws Exception { assertEquals(false, extendedValidity.getObject(0)); assertEquals(false, extendedValidity2.getObject(0)); assertEquals(false, variableMatches.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity.getPaths(0).get(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity2.getPaths(0).get(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", variableMatches.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity2.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", variableMatches.getPaths(0).get(0)); quantity.setMagnitude(20d); ruleEvaluation.evaluate(root, archetype.getRules().getRules()); extendedValidity = ruleEvaluation.getVariableMap().get("extended_validity"); assertEquals(true, extendedValidity.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity.getPaths(0).get(0)); extendedValidity2 = ruleEvaluation.getVariableMap().get("extended_validity_2"); assertEquals(true, extendedValidity2.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity2.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity2.getPaths(0).get(0)); variableMatches = ruleEvaluation.getVariableMap().get("variable_matches"); assertEquals(true, variableMatches.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", variableMatches.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", variableMatches.getPaths(0).get(0)); quantity.setMagnitude(0d); ruleEvaluation.evaluate(root, archetype.getRules().getRules()); extendedValidity = ruleEvaluation.getVariableMap().get("extended_validity"); assertEquals(true, extendedValidity.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity.getPaths(0).get(0)); extendedValidity2 = ruleEvaluation.getVariableMap().get("extended_validity_2"); assertEquals(false, extendedValidity2.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", extendedValidity2.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", extendedValidity2.getPaths(0).get(0)); variableMatches = ruleEvaluation.getVariableMap().get("variable_matches"); assertEquals(true, variableMatches.getObject(0)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5, 1]/value/magnitude", variableMatches.getPaths(0).get(0)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", variableMatches.getPaths(0).get(0)); } @@ -485,7 +485,7 @@ public void existsFailed() throws Exception { assertEquals(3, evaluationResult.getPathsThatMustExist().size()); assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", evaluationResult.getPathsThatMustExist().get(0)); assertEquals("/data[id2]/events[id3]/data[id4]/items[id6]/value/magnitude", evaluationResult.getPathsThatMustExist().get(1)); - assertEquals("/data[id2]/events[id3, 1]/data[id4]/items[id5]/value/magnitude", evaluationResult.getPathsThatMustExist().get(2)); + assertEquals("/data[id2]/events[id3]/data[id4]/items[id5]/value/magnitude", evaluationResult.getPathsThatMustExist().get(2)); assertEquals(0, evaluationResult.getPathsThatMustNotExist().size()); assertEquals(0, evaluationResult.getSetPathValues().size()); @@ -672,7 +672,7 @@ public void flattenedRules() throws IOException, ADLParseException { EvaluationResult result = ruleEvaluation.evaluate(cluster, opt.getRules().getRules()); AssertionResult assertionResult = result.getAssertionResults().get(0); assertTrue("The given validation rule should pass", assertionResult.getResult()); - assertEquals("ac3", assertionResult.getPathsConstrainedToValueSets().get("/items[id2, 1]/items[id2]/value/defining_code")); + assertEquals("ac3", assertionResult.getPathsConstrainedToValueSets().get("/items[id2]/items[id2]/value/defining_code")); //incorrect case next codedText.setDefiningCode(new CodePhrase(new TerminologyId("local"), "at26"));//wrong code! @@ -680,7 +680,7 @@ public void flattenedRules() throws IOException, ADLParseException { EvaluationResult falseResult = ruleEvaluation.evaluate(cluster, opt.getRules().getRules()); AssertionResult falseAssertionResult = falseResult.getAssertionResults().get(0); assertFalse(falseAssertionResult.getResult()); - assertEquals("ac3", assertionResult.getPathsConstrainedToValueSets().get("/items[id2, 1]/items[id2]/value/defining_code")); + assertEquals("ac3", assertionResult.getPathsConstrainedToValueSets().get("/items[id2]/items[id2]/value/defining_code")); } diff --git a/utils/src/main/java/com/nedap/archie/paths/PathSegment.java b/utils/src/main/java/com/nedap/archie/paths/PathSegment.java index 49360611c..56fffecc4 100644 --- a/utils/src/main/java/com/nedap/archie/paths/PathSegment.java +++ b/utils/src/main/java/com/nedap/archie/paths/PathSegment.java @@ -16,6 +16,7 @@ public class PathSegment { private String nodeName; private String nodeId; + private String objectNameConstraint; // An explicit archetype ref from a C_ARCHETYPE_ROOT (use archetype...). null otherwise private String archetypeRef = null; private Integer index; @@ -70,6 +71,14 @@ public void setArchetypeRef(String archetypeRef) { this.archetypeRef = archetypeRef; } + public String getObjectNameConstraint() { + return objectNameConstraint; + } + + public void setObjectNameConstraint(String objectNameConstraint) { + this.objectNameConstraint = objectNameConstraint; + } + public boolean hasIdCode() { return nodeId != null && nodeIdPattern.matcher(nodeId).matches(); } @@ -90,6 +99,10 @@ public String toString() { } public boolean hasExpressions() { - return nodeId != null || index != null; + return nodeId != null || index != null || objectNameConstraint != null; + } + + public boolean hasObjectNameConstraint() { + return objectNameConstraint != null; } } diff --git a/utils/src/main/java/com/nedap/archie/query/APathQuery.java b/utils/src/main/java/com/nedap/archie/query/APathQuery.java index 5332a0d12..a14d51b71 100644 --- a/utils/src/main/java/com/nedap/archie/query/APathQuery.java +++ b/utils/src/main/java/com/nedap/archie/query/APathQuery.java @@ -75,6 +75,14 @@ public APathQuery(String query) { } else { pathSegment.setNodeId(expression); } + } else { + if(equalityExprContext.relationalExpr(0).getText().equals("name/value") && + equalityExprContext.getChild(1).getText().equals("=")) { + String nameConstraint = equalityExprContext.relationalExpr(1).getText(); + nameConstraint = nameConstraint.replaceAll("^[\"\']|[\"\']$", ""); + pathSegment.setObjectNameConstraint(nameConstraint); + } + } } From 9745f574629f7a59c6c7dee54ca1bc0071aa5086 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Wed, 15 Sep 2021 16:23:55 +0200 Subject: [PATCH 33/36] Add combined name + archetype ref lookup to AOM Path queries - still a bit ugly --- .../java/com/nedap/archie/aom/CAttribute.java | 12 +++++++++ .../com/nedap/archie/query/AOMPathQuery.java | 24 ++++++++++++++---- .../com/nedap/archie/paths/PathSegment.java | 25 +++++++++++++++---- .../java/com/nedap/archie/paths/PathUtil.java | 16 +----------- .../com/nedap/archie/query/APathQuery.java | 9 ++++--- 5 files changed, 58 insertions(+), 28 deletions(-) diff --git a/aom/src/main/java/com/nedap/archie/aom/CAttribute.java b/aom/src/main/java/com/nedap/archie/aom/CAttribute.java index 79d644735..56015464e 100644 --- a/aom/src/main/java/com/nedap/archie/aom/CAttribute.java +++ b/aom/src/main/java/com/nedap/archie/aom/CAttribute.java @@ -501,4 +501,16 @@ public List getChildrenByRmTypeName(String rmTypeName) { return result; } + + public List getChildrenByArchetypeRef(String archetypeRef) { + List result = new ArrayList<>(); + for(CObject child:children) { + if(child instanceof CArchetypeRoot) { + if (((CArchetypeRoot) child).getArchetypeRef().equals(archetypeRef)) { + result.add(child); + } + } + } + return result; + } } diff --git a/aom/src/main/java/com/nedap/archie/query/AOMPathQuery.java b/aom/src/main/java/com/nedap/archie/query/AOMPathQuery.java index de793409c..19d7ffda1 100644 --- a/aom/src/main/java/com/nedap/archie/query/AOMPathQuery.java +++ b/aom/src/main/java/com/nedap/archie/query/AOMPathQuery.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -198,24 +199,37 @@ protected List findOneSegment(PathSegment pathSegment, Lis } protected ArchetypeModelObject findOneMatchingObject(CAttribute attribute, PathSegment pathSegment, boolean matchSpecializedNodes) { - if (pathSegment.hasIdCode() || pathSegment.hasArchetypeRef()) { + List result = new ArrayList<>(); + + if (pathSegment.hasIdCode()) { if(matchSpecializedNodes) { return attribute.getPossiblySpecializedChild(pathSegment.getNodeId()); } return attribute.getChild(pathSegment.getNodeId()); + } else if (pathSegment.hasArchetypeRef()) { + List children = attribute.getChildrenByArchetypeRef(pathSegment.getNodeId()); + if(pathSegment.getObjectNameConstraint() != null) { + for(CObject child:children) { + if(Objects.equals(pathSegment.getObjectNameConstraint(), child.getMeaning())) { + return child; + } + } + } + if(!children.isEmpty()) { + return children.get(0); + } + return null; } else if (pathSegment.hasNumberIndex()) { // APath path numbers start at 1 instead of 0 int index = pathSegment.getIndex() - 1; return index < attribute.getChildren().size() ? attribute.getChildren().get(index) : null; - } else if (pathSegment.getNodeId() != null) { - return attribute.getChildByMeaning(pathSegment.getNodeId());//TODO: the ANTLR grammar removes all whitespace. what to do here? + } else if (pathSegment.getObjectNameConstraint() != null) { + return attribute.getChildByMeaning(pathSegment.getObjectNameConstraint());//TODO: the ANTLR grammar removes all whitespace. what to do here? } else { return attribute; } } - //TODO: get diagnostic information about where the finder stopped in the path - could be very useful! - public List getPathSegments() { return pathSegments; diff --git a/utils/src/main/java/com/nedap/archie/paths/PathSegment.java b/utils/src/main/java/com/nedap/archie/paths/PathSegment.java index 56fffecc4..53e788334 100644 --- a/utils/src/main/java/com/nedap/archie/paths/PathSegment.java +++ b/utils/src/main/java/com/nedap/archie/paths/PathSegment.java @@ -80,22 +80,37 @@ public void setObjectNameConstraint(String objectNameConstraint) { } public boolean hasIdCode() { - return nodeId != null && nodeIdPattern.matcher(nodeId).matches(); + return nodeId != null && isIdCode(nodeId); } public boolean hasNumberIndex() { return index != null;} + public static boolean isIdCode(String code) { + return nodeIdPattern.matcher(code).matches(); + } + + public static boolean isArchetypeRef(String code) { + return archetypeRefPattern.matcher(code).matches(); + } + public boolean hasArchetypeRef() { - return nodeId != null && archetypeRefPattern.matcher(nodeId).matches(); + return nodeId != null && isArchetypeRef(nodeId); } @Override public String toString() { if(hasExpressions()) { - return "/" + nodeName + "[" + expressionJoiner.join(nodeId, index) + "]"; - } else { - return "/" + nodeName; + if(objectNameConstraint != null && nodeId != null && !nodeId.equals("id9999")) { + return "/" + nodeName + "[" + expressionJoiner.join(nodeId, index) + " and name/value='" + objectNameConstraint + "']"; + } else if(objectNameConstraint == null && nodeId != null && !nodeId.equals("id9999")){ + return "/" + nodeName + "[" + expressionJoiner.join(nodeId, index) + "]"; + } else if (nodeId == null || !nodeId.equals("id9999")) { + return "/" + nodeName + "[" + expressionJoiner.join(objectNameConstraint, index) + "]"; + } else if(index != null) { + return "/" + nodeName + "[" + index + "]"; + } } + return "/" + nodeName; } public boolean hasExpressions() { diff --git a/utils/src/main/java/com/nedap/archie/paths/PathUtil.java b/utils/src/main/java/com/nedap/archie/paths/PathUtil.java index bd9cdc4a8..ea88a0a3d 100644 --- a/utils/src/main/java/com/nedap/archie/paths/PathUtil.java +++ b/utils/src/main/java/com/nedap/archie/paths/PathUtil.java @@ -17,21 +17,7 @@ public static String getPath(List pathSegments) { return "/"; } for(PathSegment segment: pathSegments) { - result.append("/"); - result.append(segment.getNodeName()); - if(segment.getNodeId() != null && !segment.getNodeId().equals(AdlCodeDefinitions.PRIMITIVE_NODE_ID)) { - result.append("["); - result.append(segment.getNodeId()); - if(segment.hasNumberIndex()) { - result.append(","); - result.append(segment.getIndex().toString()); - } - result.append("]"); - } else if (segment.hasNumberIndex()) { - result.append("["); - result.append(segment.getIndex()); - result.append("]"); - } + result.append(segment.toString()); } return result.toString(); } diff --git a/utils/src/main/java/com/nedap/archie/query/APathQuery.java b/utils/src/main/java/com/nedap/archie/query/APathQuery.java index a14d51b71..d02e3f3d6 100644 --- a/utils/src/main/java/com/nedap/archie/query/APathQuery.java +++ b/utils/src/main/java/com/nedap/archie/query/APathQuery.java @@ -70,10 +70,13 @@ public APathQuery(String query) { String expression = equalityExprContext.getText(); if (isDigit.matcher(expression).matches()) { pathSegment.setIndex(Integer.parseInt(expression)); - } else if(expression.matches("\".*\"") || expression.matches("'.*'")) { - pathSegment.setNodeId(expression.substring(1, expression.length()-1)); } else { - pathSegment.setNodeId(expression); + expression = expression.replaceAll("^[\"\']|[\"\']$", ""); + if(PathSegment.isIdCode(expression) || PathSegment.isArchetypeRef(expression)) { + pathSegment.setNodeId(expression); + } else { + pathSegment.setObjectNameConstraint(expression); + } } } else { if(equalityExprContext.relationalExpr(0).getText().equals("name/value") && From 2b0dedd40f2e7a99d2ff289d0f2f16564c03b957 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Fri, 17 Sep 2021 16:27:53 +0200 Subject: [PATCH 34/36] Add converter for annotations/rm visibility paths in OPT. TODO: call, and test --- .../com/nedap/archie/aom/utils/AOMUtils.java | 10 + .../adl/ADLArchetypeSerializer.java | 4 +- .../archie/opt14/Opt14PathConverter.java | 213 ++++++++++++++++++ .../archie/opt14/Opt14ConverterTest.java | 2 +- 4 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java diff --git a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java index eb2db8b58..99f8283f5 100644 --- a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java +++ b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java @@ -34,6 +34,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -294,6 +295,15 @@ private static Boolean matchesExpression(Expression expression, String archetype return null;// unsupported expression type } + public static boolean matchesArchetypeRef(String archetypeRef, String archetypeId) { + ArchetypeHRID archetypeHRID = new ArchetypeHRID(archetypeId); + ArchetypeHRID archetypeHRIDRef = new ArchetypeHRID(archetypeRef); + return archetypeHRID.getIdUpToConcept().equals(archetypeHRIDRef.getIdUpToConcept()) && + ((archetypeHRIDRef.getMajorVersion() == null) || Objects.equals(archetypeHRID.getMajorVersion(), archetypeHRIDRef.getMajorVersion())) && + ((archetypeHRIDRef.getMinorVersion() == null) || Objects.equals(archetypeHRID.getMinorVersion(), archetypeHRIDRef.getMinorVersion())) && + ((archetypeHRIDRef.getPatchVersion() == null) || Objects.equals(archetypeHRID.getPatchVersion(), archetypeHRIDRef.getPatchVersion())); + } + public static boolean codesConformant(String childNodeId, String parentNodeId) { return isValidCode(childNodeId) && childNodeId.startsWith(parentNodeId) && (childNodeId.length() == parentNodeId.length() || (childNodeId.length() > parentNodeId.length() && childNodeId.charAt(parentNodeId.length()) == AdlCodeDefinitions.SPECIALIZATION_SEPARATOR)); diff --git a/aom/src/main/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializer.java b/aom/src/main/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializer.java index 3d005ef7e..c7a0568b6 100644 --- a/aom/src/main/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializer.java +++ b/aom/src/main/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializer.java @@ -75,7 +75,9 @@ protected String serialize() { } protected void appendAnnotations() { - if (archetype.getAnnotations()==null) return; + if (archetype.getAnnotations()==null || archetype.getAnnotations().getDocumentation() == null || archetype.getAnnotations().getDocumentation().isEmpty()) { + return; + } builder.newline().append("annotations").newIndentedLine() .odin(archetype.getAnnotations()) .unindent(); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java new file mode 100644 index 000000000..9d261f2ca --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java @@ -0,0 +1,213 @@ +package com.nedap.archie.opt14; + +import com.google.common.collect.Lists; +import com.nedap.archie.aom.ArchetypeModelObject; +import com.nedap.archie.aom.CArchetypeRoot; +import com.nedap.archie.aom.CAttribute; +import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.CComplexObjectProxy; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.OperationalTemplate; +import com.nedap.archie.aom.Template; +import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.aom.rmoverlay.RmAttributeVisibility; +import com.nedap.archie.aom.utils.AOMUtils; +import com.nedap.archie.flattener.ArchetypeHRIDMap; +import com.nedap.archie.paths.PathSegment; +import com.nedap.archie.paths.PathUtil; +import com.nedap.archie.query.APathQuery; +import com.nedap.archie.query.ComplexObjectProxyReplacement; +import com.nedap.archie.query.PartialMatch; +import com.nedap.archie.rm.archetyped.Link; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * TODO: implement + * Get paths from annotations and RM overlay + * Do a partial lookup: find through the archetype and find the longest matching path + * When encountering archetype root + archetype ref in path, lookup through the inheritance tree to find a matching archetype as well as the direct archetype id. + * + * then call getPath() on the found node, and replace the original content of the path with the newly converted path, which will be a more unique version, no longer + * reliant on name/value=..., but id codes only + */ +public class Opt14PathConverter { + + private Template template; + + public void convertPaths(Template template, OperationalTemplate opt) { + this.template = template; + if(template.getRmOverlay() != null && template.getRmOverlay().getRmVisibility() != null) { + Map newRmVisibility = template.getRmOverlay().getRmVisibility(); + Map rmVisibility = template.getRmOverlay().getRmVisibility(); + for(String path:rmVisibility.keySet()) { + PartialMatch partial = findPartial(new APathQuery(path), opt.getDefinition()); + if(!partial.getFoundObjects().isEmpty() && !partial.getPathMatched().equals("/")) { + ArchetypeModelObject archetypeModelObject = partial.getFoundObjects().get(0); + String newPath = convertPath(path, partial, archetypeModelObject); + newRmVisibility.put(newPath , rmVisibility.get(path)); + + } else { + newRmVisibility.put(path , rmVisibility.get(path)); + } + } + template.getRmOverlay().setRmVisibility(newRmVisibility); + } + + if(template.getAnnotations() != null && template.getAnnotations().getDocumentation() != null) { + Map>> documentation = template.getAnnotations().getDocumentation(); + + Map>> newDocumentation = new LinkedHashMap<>(); + for(String language:documentation.keySet()) { + Map> newDocs = new LinkedHashMap<>(); + for(String path:documentation.get(language).keySet()) { + PartialMatch partial = findPartial(new APathQuery(path), opt.getDefinition()); + if(!partial.getFoundObjects().isEmpty() && !partial.getPathMatched().equals("/")) { + ArchetypeModelObject archetypeModelObject = partial.getFoundObjects().get(0); + String newPath = convertPath(path, partial, archetypeModelObject); + newDocs.put(newPath, documentation.get(language).get(path)); + } else { + newDocs.put(path, documentation.get(language).get(path)); + } + } + + newDocumentation.put(language, newDocs); + } + + template.getAnnotations().setDocumentation(newDocumentation); + } + + } + + private String convertPath(String path, PartialMatch partial, ArchetypeModelObject archetypeModelObject) { + String newPath; + if(archetypeModelObject instanceof CAttribute) { + newPath = ((CAttribute) archetypeModelObject).getPath() + partial.getRemainingPath(); + } else if (archetypeModelObject instanceof CObject){ + newPath = ((CObject) archetypeModelObject).getPath() + partial.getRemainingPath(); + } else { + newPath = path; + } + return newPath; + } + + + /** + * Find a partial match, also matching if halfway a query, including what has not yet been matched and what has not + * Does not support finding through differential paths. + * So, use on an OperationalTemplate! + * @param root the CObject to find for + * @return the partial match + */ + public PartialMatch findPartial(APathQuery query, CComplexObject root) { + List pathSegments = query.getPathSegments(); + List pathsMatched = new ArrayList<>(); + List remainingSegments = new ArrayList<>(pathSegments); + + List result = Lists.newArrayList(root); + List lastResult; + + while (!remainingSegments.isEmpty()) { + lastResult = result; + PathSegment segment = remainingSegments.remove(0); + result = findOneSegment(segment, result, false); + + if (result.size() == 0) { + //no more matches, return partial match. + //the last segment did not match anything, add it again! + remainingSegments.add(0, segment); + return new PartialMatch(lastResult, PathUtil.getPath(pathsMatched), PathUtil.getPath(remainingSegments)); + } else { + pathsMatched.add(segment); + } + } + //full match, remainingSegments is empty + return new PartialMatch(result, PathUtil.getPath(pathsMatched), PathUtil.getPath(remainingSegments)); + + + } + + protected List findOneSegment(PathSegment pathSegment, List objects, boolean matchSpecializedNodes) { + List result = new ArrayList<>(); + + List preProcessedObjects = new ArrayList<>(); + + for(ArchetypeModelObject object:objects) { + if (object instanceof CAttribute) { + CAttribute cAttribute = (CAttribute) object; + preProcessedObjects.addAll(cAttribute.getChildren()); + } else { + preProcessedObjects.add(object); + } + + } + for(ArchetypeModelObject objectToCheck:preProcessedObjects) { + ArchetypeModelObject object = objectToCheck; + if(object instanceof CObject) { + CObject cobject = (CObject) object; + CAttribute attribute = cobject.getAttribute(pathSegment.getNodeName()); + if(attribute != null) { + ArchetypeModelObject r = findOneMatchingObject(attribute, pathSegment, matchSpecializedNodes); + if(r != null) { + result.add(r); + } + } + } + } + return result; + } + + protected ArchetypeModelObject findOneMatchingObject(CAttribute attribute, PathSegment pathSegment, boolean matchSpecializedNodes) { + List result = new ArrayList<>(); + + if (pathSegment.hasIdCode()) { + if(matchSpecializedNodes) { + return attribute.getPossiblySpecializedChild(pathSegment.getNodeId()); + } + return attribute.getChild(pathSegment.getNodeId()); + } else if (pathSegment.hasArchetypeRef()) { + List children = getChildrenByArchetypeRef(template, attribute, pathSegment.getNodeId()); + if(pathSegment.getObjectNameConstraint() != null) { + for(CObject child:children) { + if(Objects.equals(pathSegment.getObjectNameConstraint(), child.getMeaning())) { + return child; + } + } + } + if(!children.isEmpty()) { + return children.get(0); + } + return null; + } else if (pathSegment.hasNumberIndex()) { + // APath path numbers start at 1 instead of 0 + int index = pathSegment.getIndex() - 1; + return index < attribute.getChildren().size() ? attribute.getChildren().get(index) : null; + } else if (pathSegment.getObjectNameConstraint() != null) { + return attribute.getChildByMeaning(pathSegment.getObjectNameConstraint());//TODO: the ANTLR grammar removes all whitespace. what to do here? + } else { + return attribute; + } + } + + public List getChildrenByArchetypeRef(Template template, CAttribute attribute, String archetypeRef) { + List result = new ArrayList<>(); + for(CObject child:attribute.getChildren()) { + if(child instanceof CArchetypeRoot) { + if (((CArchetypeRoot) child).getArchetypeRef().equals(archetypeRef)) { + result.add(child); + } else { + TemplateOverlay templateOverlay = template.getTemplateOverlay(((CArchetypeRoot) child).getArchetypeRef()); + if (AOMUtils.matchesArchetypeRef(archetypeRef, templateOverlay.getParentArchetypeId())) { + result.add(child); + } + } + } + } + return result; + } + +} diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index 1a7e84f99..b6c7cc295 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -53,7 +53,7 @@ public void vitalSigns() throws Exception { } @Test - @Ignore + //@Ignore public void respectFromRipple() throws Exception { testTemplate("/RESPECT_NSS-v0.opt", "openEHR-EHR-ACTION.procedure.v1.4.1.adls", From 792f3c9590b97c61c7b15474029ff07134afe105 Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 21 Sep 2021 12:45:27 +0200 Subject: [PATCH 35/36] OPT1.4: Add new test, support more CPrimitives conversion, support more than one overlay --- .../archie/opt14/BaseTypesConverter.java | 50 +- .../archie/opt14/DefinitionConverter.java | 18 +- .../archie/opt14/Opt14ConversionMessage.java | 24 + .../nedap/archie/opt14/Opt14Converter.java | 14 +- .../archie/opt14/OptToTemplateConverter.java | 13 +- .../archie/opt14/PrimitiveConverter.java | 63 +- .../archie/opt14/Opt14ConverterTest.java | 78 +- ...medication_authorisation.v0.0.1-alpha.adls | 195 + ...edication_course_summary.v0.0.1-alpha.adls | 195 + ...TER.medication_substance.v0.0.1-alpha.adls | 286 + ...medication_supply_amount.v0.0.1-alpha.adls | 139 + ...EHR-CLUSTER.timing_daily.v0.0.1-alpha.adls | 282 + ...LUSTER.timing_repetition.v0.0.1-alpha.adls | 159 + ...COMPOSITION.prescription.v0.0.1-alpha.adls | 128 + ...RUCTION.medication_order.v0.0.1-alpha.adls | 807 +++ ...EHR-OBSERVATION.blood_pressure.v1.0.0.adls | 1344 ++++ opt14/src/test/resources/ePrescription.opt | 5988 +++++++++++++++++ 17 files changed, 9718 insertions(+), 65 deletions(-) create mode 100644 opt14/src/main/java/com/nedap/archie/opt14/Opt14ConversionMessage.java create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_authorisation.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_course_summary.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_substance.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_supply_amount.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_daily.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_repetition.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.prescription.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-INSTRUCTION.medication_order.v0.0.1-alpha.adls create mode 100644 opt14/src/test/resources/adl2/openEHR-EHR-OBSERVATION.blood_pressure.v1.0.0.adls create mode 100644 opt14/src/test/resources/ePrescription.opt diff --git a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java index 14a0a83ac..078b40c89 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/BaseTypesConverter.java @@ -4,6 +4,7 @@ import com.nedap.archie.base.Interval; import com.nedap.archie.base.MultiplicityInterval; import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.datetime.DateTimeParsers; import com.nedap.archie.rm.datatypes.CodePhrase; import com.nedap.archie.rm.datavalues.DvCodedText; import com.nedap.archie.rm.datavalues.DvText; @@ -15,6 +16,9 @@ import com.nedap.archie.opt14.schema.*; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAmount; import java.util.ArrayList; import java.util.List; @@ -48,13 +52,57 @@ public static com.nedap.archie.base.Interval convertInterval(IntervalOfInt if(range == null) { return null; } - return new com.nedap.archie.base.Interval( + return new com.nedap.archie.base.Interval<>( range.getLower() == null ? null : range.getLower().longValue() , range.getUpper() == null ? null : range.getUpper().longValue() , range.isLowerIncluded() == null ? true : range.isLowerIncluded(), range.isUpperIncluded() == null ? true : range.isUpperIncluded()); } + public static com.nedap.archie.base.Interval convertInterval(IntervalOfDuration range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval<>( + range.getLower() == null ? null : DateTimeParsers.parseDurationValue(range.getLower()), + range.getUpper() == null ? null : DateTimeParsers.parseDurationValue(range.getUpper()), + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + + public static com.nedap.archie.base.Interval convertInterval(IntervalOfDate range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval<>( + range.getLower() == null ? null : DateTimeParsers.parseDateValue(range.getLower()), + range.getUpper() == null ? null : DateTimeParsers.parseDateValue(range.getUpper()), + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + + public static com.nedap.archie.base.Interval convertInterval(IntervalOfDateTime range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval<>( + range.getLower() == null ? null : DateTimeParsers.parseDateTimeValue(range.getLower()), + range.getUpper() == null ? null : DateTimeParsers.parseDateTimeValue(range.getUpper()), + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + + public static com.nedap.archie.base.Interval convertInterval(IntervalOfTime range) { + if(range == null) { + return null; + } + return new com.nedap.archie.base.Interval<>( + range.getLower() == null ? null : DateTimeParsers.parseTimeValue(range.getLower()), + range.getUpper() == null ? null : DateTimeParsers.parseTimeValue(range.getUpper()), + range.isLowerIncluded() == null ? true : range.isLowerIncluded(), + range.isUpperIncluded() == null ? true : range.isUpperIncluded()); + } + public static com.nedap.archie.base.Interval convertInterval(IntervalOfReal range) { if(range == null) { return null; diff --git a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java index a9e96679a..4975a7cc1 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/DefinitionConverter.java @@ -2,15 +2,7 @@ import com.google.common.base.Strings; import com.nedap.archie.adl14.ADL14ConversionConfiguration; -import com.nedap.archie.aom.ArchetypeHRID; -import com.nedap.archie.aom.ArchetypeSlot; -import com.nedap.archie.aom.CArchetypeRoot; -import com.nedap.archie.aom.CAttribute; -import com.nedap.archie.aom.CComplexObject; -import com.nedap.archie.aom.CObject; -import com.nedap.archie.aom.OperationalTemplate; -import com.nedap.archie.aom.Template; -import com.nedap.archie.aom.TemplateOverlay; +import com.nedap.archie.aom.*; import static com.nedap.archie.opt14.BaseTypesConverter.convertCardinality; import static com.nedap.archie.opt14.BaseTypesConverter.convertMultiplicity; @@ -82,10 +74,18 @@ private CObject convert(COBJECT cobject14) { return convertPrimitive((CPRIMITIVEOBJECT) cobject14); } else if (cobject14 instanceof CDOMAINTYPE) { return DomainTypeConverter.convertDomainType((CDOMAINTYPE) cobject14); + } else if (cobject14 instanceof CONSTRAINTREF) { + return convertConstraintRef((CONSTRAINTREF) cobject14); } throw new IllegalArgumentException("unknown COBJECT subtype: " + cobject14.getClass()); } + private CObject convertConstraintRef(CONSTRAINTREF cobject14) { + CComplexObjectProxy proxy = new CComplexObjectProxy(); + proxy.setTargetPath(cobject14.getReference()); + setObjectBasics(cobject14, proxy); + return proxy; + } private CObject convertSlot(ARCHETYPESLOT cobject14) { diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14ConversionMessage.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14ConversionMessage.java new file mode 100644 index 000000000..7b11e7a1f --- /dev/null +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14ConversionMessage.java @@ -0,0 +1,24 @@ +package com.nedap.archie.opt14; + +import org.openehr.utils.message.MessageCode; + +public enum Opt14ConversionMessage implements MessageCode { + PATH_CONVERSION_ERROR("Could not convert annotation and rm_overlay paths. They will possibly not be correct: {0}"); + + + private final String messageTemplate; + + Opt14ConversionMessage(String messageTemplate) { + this.messageTemplate = messageTemplate; + } + + @Override + public String getCode() { + return name(); + } + + @Override + public String getMessageTemplate() { + return messageTemplate; + } +} diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index ab4ed9baf..e17951ad2 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -12,6 +12,9 @@ import com.nedap.archie.aom.Template; import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.diff.Differentiator; +import com.nedap.archie.flattener.Flattener; +import com.nedap.archie.flattener.FlattenerConfiguration; + import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.rminfo.MetaModels; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -21,6 +24,7 @@ import java.util.List; import com.nedap.archie.opt14.schema.*; +import org.openehr.utils.message.MessageDescriptor; /** * TODO: @@ -69,8 +73,6 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA DescriptionConverter.convert(opt14, template); new OptToTemplateConverter().convert(opt2, template); - //template.setDefinition(opt2.getDefinition()); - //TODO: convert to template overlays here RepoFlatArchetypeProvider flatParentProvider = new RepoFlatArchetypeProvider(adl2Archetypes); new NodeIdFixerBeforeConversion().fixNodeIds(template, flatParentProvider); @@ -98,7 +100,15 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA } adl2ConversionResult.setArchetype(convertedTemplate); convertedTemplate.setTemplateOverlays(newOverlays); + + try { + OperationalTemplate generatedOpt2 = (OperationalTemplate) new Flattener(adl2Archetypes, metaModels, FlattenerConfiguration.forOperationalTemplate()).flatten(convertedTemplate); + new Opt14PathConverter().convertPaths(convertedTemplate, opt2); + } catch (Exception e) { + converted.getConversionResults().get(0).getLog().addError(Opt14ConversionMessage.PATH_CONVERSION_ERROR, e.getMessage()); + } } + return converted; } catch (IOException e) { throw new RuntimeException(e); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java index 9ddc1a418..fcd1cc67b 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/OptToTemplateConverter.java @@ -74,7 +74,18 @@ private CObject convertRoot(CArchetypeRoot cRoot14) { TemplateOverlay overlay = new TemplateOverlay(); overlay.setArchetypeId(new ArchetypeHRID(cRoot14.getArchetypeRef())); - overlay.getArchetypeId().setConceptId(overlay.getArchetypeId().getConceptId() + "ovl-1"); + int overlayIndex = 1; + String overlayId = null; + ArchetypeHRID ovlFullId = null; + do { + overlayId = overlay.getArchetypeId().getConceptId() + "_ovl-" + overlayIndex; + ovlFullId = (ArchetypeHRID) overlay.getArchetypeId().clone(); + ovlFullId.setConceptId(overlayId); + overlayIndex++; + } + while(template.getTemplateOverlay(ovlFullId.getFullId()) != null); + + overlay.getArchetypeId().setConceptId(overlayId); overlay.setParentArchetypeId(cRoot14.getArchetypeRef()); overlay.setDefinition(templateRoot); overlay.setTerminology(opt2.getComponentTerminologies().get(cRoot14.getArchetypeRef())); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java index 0640c610c..c8db1df59 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/PrimitiveConverter.java @@ -2,14 +2,23 @@ import com.nedap.archie.aom.CObject; import com.nedap.archie.aom.primitives.CBoolean; +import com.nedap.archie.aom.primitives.CDate; +import com.nedap.archie.aom.primitives.CDateTime; +import com.nedap.archie.aom.primitives.CDuration; import com.nedap.archie.aom.primitives.CInteger; import com.nedap.archie.aom.primitives.CReal; import com.nedap.archie.aom.primitives.CString; import static com.nedap.archie.opt14.BaseTypesConverter.convertInterval; +import com.nedap.archie.aom.primitives.CTime; +import com.nedap.archie.base.Interval; +import com.nedap.archie.datetime.DateTimeParsers; import com.nedap.archie.opt14.schema.*; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; + class PrimitiveConverter { public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { @@ -56,6 +65,7 @@ public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { if(cboolean14.isAssumedValue() != null) { cBoolean.setAssumedValue(cboolean14.isAssumedValue()); } + return cBoolean; } else if (primitive14 instanceof CSTRING) { CSTRING cstring14 = (CSTRING) primitive14; CString cString = new CString(); @@ -70,20 +80,53 @@ public static CObject convertPrimitive(CPRIMITIVEOBJECT cobject14) { } cString.setAssumedValue(cstring14.getAssumedValue()); return cString; - } else if (primitive14 instanceof CDATE) { - return null; + } + else if (primitive14 instanceof CDATE) { + CDATE cDate14 = (CDATE) primitive14; + CDate cDate = new CDate(); + cDate.setPatternedConstraint(cDate.getPatternedConstraint()); + if(cDate14.getRange() != null) { + cDate.addConstraint(convertInterval(cDate14.getRange())); + } + if(cDate14.getAssumedValue() != null) { + cDate.setAssumedValue(DateTimeParsers.parseDateValue(cDate14.getAssumedValue())); + } + return cDate; } else if (primitive14 instanceof CDATETIME) { - return null; + CDATETIME cDateTime14 = (CDATETIME) primitive14; + CDateTime cDateTime = new CDateTime(); + cDateTime.setPatternedConstraint(cDateTime.getPatternedConstraint()); + if(cDateTime14.getRange() != null) { + cDateTime.addConstraint(convertInterval(cDateTime14.getRange())); + } + if(cDateTime14.getAssumedValue() != null) { + cDateTime.setAssumedValue(DateTimeParsers.parseDateValue(cDateTime14.getAssumedValue())); + } + return cDateTime; } else if (primitive14 instanceof CTIME) { - return null; + CTIME cTime14 = (CTIME) primitive14; + CTime cTime = new CTime(); + cTime.setPatternedConstraint(cTime.getPatternedConstraint()); + if(cTime14.getRange() != null) { + cTime.addConstraint(convertInterval(cTime14.getRange())); + } + if(cTime14.getAssumedValue() != null) { + cTime.setAssumedValue(DateTimeParsers.parseDateValue(cTime14.getAssumedValue())); + } + return cTime; } else if (primitive14 instanceof CDURATION) { - return null; + CDURATION cDuration14 = (CDURATION) primitive14; + CDuration cDuration = new CDuration(); + cDuration.setPatternedConstraint(cDuration14.getPattern()); + if(cDuration14.getRange() != null) { + cDuration.addConstraint(convertInterval(cDuration14.getRange())); + } + if(cDuration14.getAssumedValue() != null) { + cDuration.setAssumedValue(DateTimeParsers.parseDurationValue(cDuration14.getAssumedValue())); + } + return cDuration; } - throw new IllegalArgumentException("Uknoown primitive type found"); - - - - + throw new IllegalArgumentException("Unknown primitive type found: " + primitive14.getClass()); } } diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index b6c7cc295..7b1d3ded4 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -12,7 +12,9 @@ import com.nedap.archie.flattener.Flattener; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.json.ArchieRMObjectMapperProvider; +import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -23,68 +25,60 @@ import javax.xml.bind.Unmarshaller; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; import static org.junit.Assert.assertTrue; import com.nedap.archie.opt14.schema.*; +import org.reflections.Reflections; +import org.reflections.scanners.ResourcesScanner; public class Opt14ConverterTest { + InMemoryFullArchetypeRepository repository; + + @Before + public void readArchetypes() throws ADLParseException, IOException { + Reflections reflections = new Reflections("adl2", new ResourcesScanner()); + List adlFiles = new ArrayList<>(reflections.getResources(Pattern.compile(".*\\.adls"))); + repository = new InMemoryFullArchetypeRepository(); + MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); + for(String adlFile:adlFiles) { + try(InputStream stream = getClass().getResourceAsStream("/" + adlFile)) { + Archetype parsed = new ADLParser(metaModels).parse(stream); + repository.addArchetype(parsed); + } + } + } + @Test public void procedureList() throws Exception { - testTemplate("/procedure_list.opt", - "openEHR-EHR-ACTION.procedure.v1.4.1.adls", - "openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls", - "openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls"); + testTemplate("/procedure_list.opt"); } @Test public void vitalSigns() throws Exception { - ValidationResult result = testTemplate("/vital_signs.opt", - "openEHR-EHR-COMPOSITION.encounter.v1.0.7.adls", - "openEHR-EHR-OBSERVATION.body_temperature.v2.1.2.adls", - "openEHR-EHR-OBSERVATION.blood_pressure.v2.0.8.adls", - "openEHR-EHR-OBSERVATION.body_mass_index.v2.0.6.adls", - "openEHR-EHR-OBSERVATION.height.v2.0.8.adls", - "openEHR-EHR-OBSERVATION.body_weight.v2.1.6.adls", - "openEHR-EHR-OBSERVATION.pulse.v2.0.4.adls", - "openEHR-EHR-OBSERVATION.respiration.v2.0.9.adls", - "openEHR-EHR-OBSERVATION.pulse_oximetry.v1.1.3.adls"); + ValidationResult result = testTemplate("/vital_signs.opt"); } @Test - //@Ignore + @Ignore public void respectFromRipple() throws Exception { - testTemplate("/RESPECT_NSS-v0.opt", - "openEHR-EHR-ACTION.procedure.v1.4.1.adls", - "openEHR-EHR-COMPOSITION.health_summary.v1.0.1.adls", - "openEHR-EHR-SECTION.procedures_rcp.v1.0.0.adls", - "openEHR-EHR-COMPOSITION.report.v1.0.0.adls", - "openEHR-EHR-SECTION.respect_headings.v0.0.1-alpha.adls", - "openEHR-EHR-ADMIN_ENTRY.respect_summary.v0.0.1-alpha.adls", - "openEHR-EHR-EVALUATION.clinical_synopsis.v1.0.2.adls", - "openEHR-EHR-EVALUATION.advance_planning_documentation.v0.0.1-alpha.adls", - "openEHR-EHR-ADMIN_ENTRY.care_preference_uk.v1.0.0.adls", - "openEHR-EHR-EVALUATION.care_preference_uk.v1.0.0.adls", - "openEHR-EHR-EVALUATION.recommendation.v1.1.3-alpha.adls", - "openEHR-EHR-EVALUATION.cpr_decision_uk.v0.0.1-alpha.adls", - "openEHR-EHR-ADMIN_ENTRY.capacity_respect.v0.0.1-alpha.adls", - "openEHR-EHR-ADMIN_ENTRY.involvement_respect.v0.0.1-alpha.adls", - "openEHR-EHR-ACTION.service.v0.0.1-alpha.adls", - "openEHR-EHR-CLUSTER.practitioner_cc.v0.0.1-alpha.adls", - "openEHR-EHR-CLUSTER.practitioner_role_cc.v0.0.1-alpha.adls", - "openEHR-EHR-CLUSTER.name_cc.v0.0.1-alpha.adls", - " openEHR-EHR-CLUSTER.identifier_cc.v0.0.1-alpha.adls", - "openEHR-EHR-ADMIN_ENTRY.careteam_cc.v0.0.1-alpha.adls", - "openEHR-EHR-CLUSTER.contact_cc.v0.0.1-alpha.adls", - "openEHR-EHR-CLUSTER.telecom_cc.v0.0.1-alpha.adls"); + testTemplate("/RESPECT_NSS-v0.opt"); + } + + @Test + public void ePrescription() throws Exception { + testTemplate("/ePrescription.opt"); } private ValidationResult testTemplate(String templateFileName, String... sourceArchetypes) throws IOException, ADLParseException, JAXBException { - InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); - for(String sourcefile:sourceArchetypes) { - repository.addArchetype(parseAdl2(sourcefile)); - } +// InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); +// for(String sourcefile:sourceArchetypes) { +// repository.addArchetype(parseAdl2(sourcefile)); +// } JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_authorisation.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_authorisation.v0.0.1-alpha.adls new file mode 100644 index 000000000..4e3a87ff2 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_authorisation.v0.0.1-alpha.adls @@ -0,0 +1,195 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=073360e3-7a26-48ea-bf09-000665ec3e69; build_uid=bb1c1a6b-ebe9-456d-b2f8-562a05580cf6) + openEHR-EHR-CLUSTER.medication_authorisation.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"NEHTA"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"2010-11-08"> + > + other_contributors = <"Silje Ljosland Bakke, Helse Bergen HF, Norway (Editor)", "John Bennett, NEHTA, Australia", "Sharmila Biswas, Australia", "Stephen Chu, NEHTA, Australia (Editor)", "Matthew Cordell, NEHTA, Australia", "Gail Easterbrook, Flinders Medical Centre, Australia", "David Evans, Queensland Health, Australia", "Sarah Gaunt, NEHTA, Australia", "Trina Gregory, cpc, Australia", "Sam Heard, Ocean Informatics, Australia (Editor)", "Mary Kelaher, NEHTA, Australia", "Robert L'egan, NEHTA, Australia", "Heather Leslie, Ocean Informatics, Australia (Editor)", "Susan McIndoe, Royal District Nursing Service, Australia", "David McKillop, NEHTA, Australia", "Chris Mitchell, RACGP, Australia", "Stewart Morrison, NEHTA, Australia", "Chris Pearce, Melbourne East GP Network, Australia", "Camilla Preeston, Royal Australian College of General Practitioners, Australia", "Margaret Prichard, NEHTA, Australia", "Cathy Richardson, NEHTA, Australia", "Robyn Richards, NEHTA - Clinical Terminology, Australia", "John Taylor, NEHTA, Australia", "Richard Townley-O'Neill, NEHTA, Australia (Editor)", "Kylie Young, The Royal Australian College of General Practitioners, Australia"> + lifecycle_state = <"in_development"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + references = < + ["1"] = <"openEHR Foundation Medication archetypes http://www.openehr.org/knowledge"> + ["2"] = <"NEHTA's Therapeutic Good Use Data Group from the NEHTA Website http://www.nehta.gov.au"> + ["3"] = <"Intermountain Healthcare Medication order model, Personal Communication to Sam Heard by Dr Stan Huff."> + ["4"] = <"Royal Australian College of General Practitioners. Fact Sheet: Medicines List. 2010."> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"418EDCE16FC97D91FD25C5F4EB8C0A63"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record details of authorisation of a medication, which may be of the original prescription, or of re-authorisation of a repeat refill."> + keywords = <"medication", "order", "prescribe", "therapy", "substance", "drug", "therapeutic", "otc", "therapeutic good", "repeat"> + use = <"Use in the content of a medication order INSTRUCTION to specify the original authorisation, or in the context of a Medication action ACTION to record details of a re-authorisation or authorisation of a re-issue. + + This archetype covers the common, universal requirements for authorisation of medication but other local archetypes may be required to cover national or regional variants e.g special contractual arrangements or requirements for further attestation by a secondary clinician."> + misuse = <""> + > + > + +definition + CLUSTER[id1] matches { -- Medication authorisation + items cardinality matches {1..*; unordered} matches { + ELEMENT[id74] occurrences matches {0..1} matches { -- Authorisation type + value matches { + DV_CODED_TEXT[id9001] matches { + defining_code matches {[ac9000]} -- Authorisation type (synthesised) + } + } + } + ELEMENT[id26] occurrences matches {0..1} matches { -- Maximum number of refills + value matches { + DV_COUNT[id9002] matches { + magnitude matches {|>=0|} + } + } + } + ELEMENT[id79] occurrences matches {0..1} matches { -- Number of refills issued + value matches { + DV_COUNT[id9003] matches { + magnitude matches {|>=0|} + } + } + } + ELEMENT[id80] occurrences matches {0..1} matches { -- Number of refills remaining + value matches { + DV_COUNT[id9004] matches { + magnitude matches {|>=0|} + } + } + } + ELEMENT[id47] occurrences matches {0..1} matches { -- Minimum interval between refills + value matches { + DV_DURATION[id9005] + } + } + ELEMENT[id73] occurrences matches {0..1} matches { -- Authorisation expiry date + value matches { + DV_DATE_TIME[id9006] + } + } + ELEMENT[id81] matches { -- Prescriber endorsement + value matches { + DV_TEXT[id9007] + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["ac9000"] = < + text = <"Authorisation type (synthesised)"> + description = <"Whether the medication is only issued once or may re-issued and dispensed 're-filled' after authorisation by the prescriber. (synthesised)"> + > + ["id81"] = < + text = <"Prescriber endorsement"> + description = <"An endorsement by the prescriber that the medication may be supplied under a specific contractual arrangement."> + > + ["id80"] = < + text = <"Number of refills remaining"> + description = <"The number of re-fills or re-issues that remain valid for this authorisation period."> + > + ["id79"] = < + text = <"Number of refills issued"> + description = <"The number of refills which have been issued or dispensed for this period of authorisation."> + > + ["at77"] = < + text = <"Repeat dispensing"> + description = <"Multiple refills of the prescription may be obtained from the dispenser."> + > + ["at76"] = < + text = <"Repeat prescribing"> + description = <"Multiple refills of the prescription may be obtained from the prescriber."> + > + ["at75"] = < + text = <"No repeat supply"> + description = <"Repeat supply has not been authorised."> + > + ["id74"] = < + text = <"Authorisation type"> + description = <"Whether the medication is only issued once or may re-issued and dispensed 're-filled' after authorisation by the prescriber."> + > + ["id73"] = < + text = <"Authorisation expiry date"> + description = <"The repeat supply authorisation has expired after this date."> + > + ["id47"] = < + text = <"Minimum interval between refills"> + description = <"The minimum time between repeat supply of the medicine, vaccine or therapeutic good. Note: This is specified by the ordering clinician for a specific reason such as safety or best practice."> + > + ["id26"] = < + text = <"Maximum number of refills"> + description = <"The number of times the expressed quantity of medicine, vaccine or other therapeutic good may be refilled or redispensed without a new prescription."> + > + ["id1"] = < + text = <"Medication authorisation"> + description = <"Details of the authorisation of a medicine, vaccine or other therapeutic good."> + > + > + ["sl"] = < + ["ac9000"] = < + text = <"*Authorisation type(en) (synthesised)"> + description = <"*Whether the medication is only issued once or may re-issued and dispensed 're-filled' after authorisation by the prescriber.(en) (synthesised)"> + > + ["id81"] = < + text = <"*Prescriber endorsement(en)"> + description = <"*An endorsement by the prescriber that the medication may be supplied under a specific contractual arrangement. (en)"> + > + ["id80"] = < + text = <"*Number of refills remaining(en)"> + description = <"*The number of re-fills or re-issues that remain valid for this authorisation period.(en)"> + > + ["id79"] = < + text = <"*Number of refills issued(en)"> + description = <"*The number of refills which have been issued or dispensed for this period of authorisation.(en)"> + > + ["at77"] = < + text = <"*Repeat dispensing(en)"> + description = <"*Multiple refills of the prescription may be obtained from the dispenser.(en)"> + > + ["at76"] = < + text = <"*Repeat prescribing(en)"> + description = <"*Multiple refills of the prescription may be obtained from the prescriber.(en)"> + > + ["at75"] = < + text = <"*No repeat supply(en)"> + description = <"*Repeat supply has not been authorised.(en)"> + > + ["id74"] = < + text = <"*Authorisation type(en)"> + description = <"*Whether the medication is only issued once or may re-issued and dispensed 're-filled' after authorisation by the prescriber.(en)"> + > + ["id73"] = < + text = <"*Authorisation expiry date(en)"> + description = <"*The repeat supply authorisation has expired after this date.(en)"> + > + ["id47"] = < + text = <"*Minimum interval between refills(en)"> + description = <"*The minimum time between repeat supply of the medicine, vaccine or therapeutic good. Note: This is specified by the ordering clinician for a specific reason such as safety or best practice.(en)"> + > + ["id26"] = < + text = <"*Maximum number of refills(en)"> + description = <"*The number of times the expressed quantity of medicine, vaccine or other therapeutic good may be refilled or redispensed without a new prescription.(en)"> + > + ["id1"] = < + text = <"*Medication authorisation(en)"> + description = <"*Details of the authorisation of a medicine, vaccine or other therapeutic good.(en)"> + > + > + > + value_sets = < + ["ac9000"] = < + id = <"ac9000"> + members = <"at75", "at76", "at77"> + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_course_summary.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_course_summary.v0.0.1-alpha.adls new file mode 100644 index 000000000..eeaac3ef0 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_course_summary.v0.0.1-alpha.adls @@ -0,0 +1,195 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=c5a66d77-2a93-4d0d-9f55-10ac3df59b05; build_uid=01ee809e-809a-478a-97bb-445cdad67233) + openEHR-EHR-CLUSTER.medication_course_summary.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Ian McNicoll"> + ["organisation"] = <"freshEHR Clinical Informatics Ltd."> + ["email"] = <"ian@freshehr.com"> + ["date"] = <"2015-11-01"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + references = < + ["1"] = <"Medication item, Draft Archetype [Internet]. UK Clinical Models, UK Clinical Models Clinical Knowledge Manager [cited: 2015-11-01]. Available from: http://clinicalmodels.org.uk/ckm/#showArchetype_1051.32.3"> + ["2"] = <"Medication event summary, Draft Archetype [Internet]. UK Clinical Models, UK Clinical Models Clinical Knowledge Manager [cited: 2015-11-01]. Available from: http://clinicalmodels.org.uk/ckm/#showArchetype_1051.32.140"> + ["3"] = <"Medication order status valueset[Internet]. HL7 FHIR , HL7 FHIR DSTU2 [cited: 2015-11-01]. Available from https://www.hl7.org/fhir/valueset-medication-order-status.html"> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"1E7D6F795F76E5D62071822152161AFE"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To provide an overall summary of the status and key dates, related to a medication order."> + use = <"Use within the context of a medication order Instruction where a summary of the overallcourse is required. This will normally be where the order is is being used within the context of a medicaton summary list, and not in the context of an orderable prescription record, where medication ctions will normally carry the primary record of the status of the order and key date information."> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + > + +definition + CLUSTER[id1] matches { -- Medication course summary + items cardinality matches {1..*; unordered} matches { + ELEMENT[id2] occurrences matches {0..1} matches { -- Course status + value matches { + DV_CODED_TEXT[id9002] matches { + defining_code matches {[ac9000]} -- Course status (synthesised) + } + } + } + ELEMENT[id3] matches { -- Key course dates + name matches { + DV_CODED_TEXT[id9003] matches { + defining_code matches {[ac9001]} -- Key course dates (synthesised) + } + } + value matches { + DV_DATE_TIME[id9004] + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["ac9000"] = < + text = <"Course status (synthesised)"> + description = <"The overall status of this order. (synthesised)"> + > + ["ac9001"] = < + text = <"Key course dates (synthesised)"> + description = <"Key medication event dates. (synthesised)"> + > + ["at28"] = < + text = <"Draft"> + description = <"The medication order has been made but further processes e.g. sign-off or verification are required before it becomes actionable."> + > + ["at27"] = < + text = <"Suspended"> + description = <"Actions reuulting from the order are to be temporarily halted, but are expected to continue later. May also be called 'on-hold'."> + > + ["at26"] = < + text = <"Obsolete"> + description = <"This medication order has been superseded by another."> + > + ["at25"] = < + text = <"Completed"> + description = <"The medication course has been completed."> + > + ["at24"] = < + text = <"Never active"> + description = <"A medication which was ordered or authorised but has been cancelled prior to being issued, dispensed or adiminstered."> + > + ["at23"] = < + text = <"Stopped"> + description = <"This is a medication that has previously been issued, dispensed or administered but has now been discontinued."> + > + ["at22"] = < + text = <"Active"> + description = <"This is an active medication."> + > + ["at21"] = < + text = <"Date changed"> + description = <"The date at which the medication instruction was modified."> + > + ["at20"] = < + text = <"Date last reviewed"> + description = <"The date at which the medication order was last reviewed."> + > + ["at19"] = < + text = <"Date reviewed"> + description = <"The date at which the medication order was reviewed."> + > + ["at18"] = < + text = <"Date administration withheld"> + description = <"The data at which administration of a medication was withheld or suspended."> + > + ["at17"] = < + text = <"Date administered"> + description = <"The date at which a medication was administered."> + > + ["at16"] = < + text = <"Date dispensed"> + description = <"The date at which a medication was dispensed."> + > + ["at15"] = < + text = <"Date prescription issued"> + description = <"The date at which a medication prescription was issued i.e the physical or electronic prescription token was created."> + > + ["at14"] = < + text = <"Date authorised"> + description = <"The date at which the medication was authorised or re-authorised."> + > + ["at13"] = < + text = <"Date discontinued"> + description = <"The date at which the medication was discontinued."> + > + ["at12"] = < + text = <"Date last administered"> + description = <"The date at which the medication was last administered."> + > + ["at11"] = < + text = <"Date first administered"> + description = <"The date at which the medication was first administered to the patient."> + > + ["at10"] = < + text = <"Date last dispensed"> + description = <"The date at which the medication was last dispensed."> + > + ["at9"] = < + text = <"Date first dispensed"> + description = <"The date at which the medicaton was first physically dispensed."> + > + ["at8"] = < + text = <"Date last authorised"> + description = <"The data at which the medication was last authorised.The date at which the medication was first authorised.For a repeat prescription, authorisation refers to the creation of the repeat prescription 'master' which is followed by the production of one or more prescription issues. Authorisation is generally only given for a limited period or limited number of issues, after which re-authorisation is required."> + > + ["at7"] = < + text = <"Date first authorised"> + description = <"The date at which the medication was first authorised.For a repeat prescription, authorisation refers to the creation of the repeat prescription 'master' which is followed by the production of one or more prescription issues."> + > + ["at6"] = < + text = <"Date last prescription issued"> + description = <"The date at which the medication prescription was last issued. This refers to the prescription 'token' electronic or paper which authorises supply of a medication."> + > + ["at5"] = < + text = <"Date first prescription issued"> + description = <"The date at which the medication was first issued. 'Issued' refers to the prescription 'token' electronic or paper which authorises supply of a medication."> + > + ["at4"] = < + text = <"Date ordered/recommended"> + description = <"The data at which the medication course was first ordered or recommended."> + > + ["id3"] = < + text = <"Key course dates"> + description = <"Key medication event dates."> + > + ["id2"] = < + text = <"Course status"> + description = <"The overall status of this order."> + > + ["id1"] = < + text = <"Medication course summary"> + description = <"Overall summary of the medication course."> + > + > + > + value_sets = < + ["ac9001"] = < + id = <"ac9001"> + members = <"at4", "at5", "at6", "at7", "at8", "at9", "at10", "at11", "at12", "at13", "at14", "at15", "at16", "at17", "at18", "at19", "at20", "at21"> + > + ["ac9000"] = < + id = <"ac9000"> + members = <"at22", "at23", "at24", "at25", "at26", "at27", "at28"> + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_substance.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_substance.v0.0.1-alpha.adls new file mode 100644 index 000000000..5ef2129c7 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_substance.v0.0.1-alpha.adls @@ -0,0 +1,286 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=b99802e4-3553-4a78-b146-7935a444cb70; build_uid=a1b18250-9cb6-4fc8-9db4-96350e8d5fb4) + openEHR-EHR-CLUSTER.medication_substance.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"NEHTA"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"2015-10-21"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Silje Ljosland Bakke, Helse Bergen HF, Norway (Editor)", "John Bennett, NEHTA, Australia", "Sharmila Biswas, Australia", "Stephen Chu, NEHTA, Australia (Editor)", "Matthew Cordell, NEHTA, Australia", "Gail Easterbrook, Flinders Medical Centre, Australia", "David Evans, Queensland Health, Australia", "Sarah Gaunt, NEHTA, Australia", "Trina Gregory, cpc, Australia", "Sam Heard, Ocean Informatics, Australia (Editor)", "Mary Kelaher, NEHTA, Australia", "Robert L'egan, NEHTA, Australia", "Heather Leslie, Ocean Informatics, Australia (Editor)", "Susan McIndoe, Royal District Nursing Service, Australia", "David McKillop, NEHTA, Australia", "Chris Mitchell, RACGP, Australia", "Stewart Morrison, NEHTA, Australia", "Chris Pearce, Melbourne East GP Network, Australia", "Camilla Preeston, Royal Australian College of General Practitioners, Australia", "Margaret Prichard, NEHTA, Australia", "Cathy Richardson, NEHTA, Australia", "Robyn Richards, NEHTA - Clinical Terminology, Australia", "John Taylor, NEHTA, Australia", "Richard Townley-O'Neill, NEHTA, Australia (Editor)", "Kylie Young, The Royal Australian College of General Practitioners, Australia", "Ian McNicoll, freshEHR Clinical Informatics Ltd., UK"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + references = < + ["1"] = <"openEHR Foundation Medication archetypes http://www.openehr.org/knowledge"> + ["2"] = <"NEHTA's Therapeutic Good Use Data Group from the NEHTA Website http://www.nehta.gov.au"> + ["3"] = <"Intermountain Healthcare Medication order model, Personal Communication to Sam Heard by Dr Stan Huff."> + ["4"] = <"Royal Australian College of General Practitioners. Fact Sheet: Medicines List. 2010."> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"48E7562836049F5F865845C7456F08D4"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record details of a medication preparation, including ,where necessary, details of mutliple ingredients, in the context of an infusion or ad-hoc (extemperaneous) preparation. The majority of dose-based prescriptions will have their precise preparation determined by available ward stock, or by pharmacy supply, while with product-based prescribing, the medication name carries details of the form and strength of the preparation."> + keywords = <"medication", "order", "prescribe", "therapy", "substance", "drug", "therapeutic", "otc", "therapeutic good", "ad-hoc", "extemperaneous"> + use = <"For recording details of a medication preparation with in the context of the original medication order INSTRUCTION and carrying the prescriber's intent, or in the context of a medication ACTION where it serves of a record of the prepartion actually supplied."> + misuse = <"Use in pharmacy stock-control is out-of-scope of the design of this archetype."> + copyright = <"© openEHR Foundation"> + > + > + +definition + CLUSTER[id1] occurrences matches {0..1} matches { -- Medication substance + items cardinality matches {1..*; unordered} matches { + ELEMENT[id133] occurrences matches {0..1} matches { -- Substance name + value matches { + DV_TEXT[id9003] + } + } + ELEMENT[id72] matches { -- Form + value matches { + DV_TEXT[id9004] + } + } + ELEMENT[id143] occurrences matches {0..1} matches { -- Category + value matches { + DV_CODED_TEXT[id9005] matches { + defining_code matches {[ac9000; at148]} -- Category (synthesised) + } + } + } + ELEMENT[id116] occurrences matches {0..1} matches { -- Strength + value matches { + DV_QUANTITY[id9006] matches { + property matches {[at9001]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id117] occurrences matches {0..1} matches { -- Strength unit + value matches { + DV_TEXT[id9007] + } + } + CLUSTER[id118] occurrences matches {0..1} matches { -- Diluent + items cardinality matches {1..*; unordered} matches { + ELEMENT[id125] occurrences matches {0..1} matches { -- Diluent amount + value matches { + DV_QUANTITY[id9008] matches { + property matches {[at9001]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id126] occurrences matches {0..1} matches { -- Diluent unit + value matches { + DV_TEXT[id9009] + } + } + } + } + CLUSTER[id127] matches { -- Ingredient + items cardinality matches {1..*; unordered} matches { + allow_archetype CLUSTER[id139] occurrences matches {0..1} matches { -- Ingredient substance + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.medication_substance(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + ELEMENT[id140] occurrences matches {0..1} matches { -- Ingredient amount + value matches { + DV_QUANTITY[id9010] matches { + property matches {[at9001]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id141] occurrences matches {0..1} matches { -- Ingredient amount unit + value matches { + DV_TEXT[id9011] + } + } + ELEMENT[id128] occurrences matches {0..1} matches { -- Role + value matches { + DV_CODED_TEXT[id9012] matches { + defining_code matches {[ac9002]} -- Role (synthesised) + } + DV_TEXT[id9013] + } + } + } + } + ELEMENT[id134] occurrences matches {0..1} matches { -- Description + value matches { + DV_TEXT[id9014] + } + } + allow_archetype CLUSTER[id142] matches { -- Substance details + include + archetype_id/value matches {/.*/} + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["ac9000"] = < + text = <"Category (synthesised)"> + description = <"The nature of a compound product, consisting of multiple ingredients. (synthesised)"> + > + ["at9001"] = < + text = <"Qualified real"> + description = <"Qualified real"> + > + ["ac9002"] = < + text = <"Role (synthesised)"> + description = <"The role of the ingredient within the mixture or infusion. (synthesised)"> + > + ["at148"] = < + text = <"Product"> + description = <"The substance is a manufactured product, containing one or more ingredients."> + > + ["at147"] = < + text = <"Ingredient"> + description = <"The substance is an individual ingredient of the medication."> + > + ["at146"] = < + text = <"Single-substance product"> + description = <"The substance is a manufactured product containing a single ingredient."> + > + ["at145"] = < + text = <"Combination product"> + description = <"The preparation consists of a number of ingredients which are pre-combined by the manufacturer."> + > + ["at144"] = < + text = <"Ad-hoc mixture"> + description = <"The substance is composed of a mixture of ingredients specificied within this order."> + > + ["id143"] = < + text = <"Category"> + description = <"The nature of a compound product, consisting of multiple ingredients."> + > + ["id142"] = < + text = <"Substance details"> + description = <"Further details about the medicatin preparation."> + > + ["id141"] = < + text = <"Ingredient amount unit"> + description = <"The dose unit of the ingredient amount."> + > + ["id140"] = < + text = <"Ingredient amount"> + description = <"The value of the amount of the ingredient as a real number."> + > + ["id139"] = < + text = <"Ingredient substance"> + description = <"Details of ingredient substance."> + > + ["id134"] = < + text = <"Description"> + description = <"A text description of the substance where it is not possible to describe this fully using numerical strengths and amounts."> + > + ["id133"] = < + text = <"Substance name"> + description = <"The name of the medication substance. This item should be coded if possible."> + > + ["id128"] = < + text = <"Role"> + description = <"The role of the ingredient within the mixture or infusion."> + > + ["id127"] = < + text = <"Ingredient"> + description = <"Details of an ingredient used to make up a mixed preparation or infuson."> + > + ["id126"] = < + text = <"Diluent unit"> + description = <"The unit for the preparation diluent."> + > + ["id125"] = < + text = <"Diluent amount"> + description = <"The value of the amount of diluent as a real number."> + > + ["id118"] = < + text = <"Diluent"> + description = <"The strength of any diluent used as part of the preparation."> + > + ["id117"] = < + text = <"Strength unit"> + description = <"The dose unit of the medication substance strength."> + > + ["id116"] = < + text = <"Strength"> + description = <"The value of the strength of medication as a real number."> + > + ["at88"] = < + text = <"Colouring"> + description = <"The ingredient is used to colour the substance."> + > + ["at87"] = < + text = <"Preservative"> + description = <"The ingredient is present to prolong the life of the substance."> + > + ["at86"] = < + text = <"Propellent"> + description = <"Inert propellent."> + > + ["at85"] = < + text = <"Diluent"> + description = <"Inert diluent."> + > + ["at84"] = < + text = <"Adjuvant"> + description = <"The chemical is active but aids the therapeutic effect of another ingredient."> + > + ["at83"] = < + text = <"Toxic"> + description = <"This chemical is toxic and has no therapeutic effect."> + > + ["at82"] = < + text = <"Electrolyte"> + description = <"This ingredient is an electrolyte."> + > + ["at81"] = < + text = <"Therapeutic"> + description = <"The chemical has a known and desired effect which is positive."> + > + ["at75"] = < + text = <"Ingredient"> + description = <"Details of an ingredient used to make up a mixed preparation or infuson."> + > + ["id72"] = < + text = <"Form"> + description = <"The formulation or presentation of the medication."> + > + ["id1"] = < + text = <"Medication substance"> + description = <"The strength and form of the medication substance, including details of specific ingredients where required by an ad-hoc preparation or infusion."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9001"] = + > + > + value_sets = < + ["ac9002"] = < + id = <"ac9002"> + members = <"at81", "at82", "at83", "at84", "at85", "at86", "at87", "at88", "at75"> + > + ["ac9000"] = < + id = <"ac9000"> + members = <"at148", "at144", "at147", "at145", "at146"> + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_supply_amount.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_supply_amount.v0.0.1-alpha.adls new file mode 100644 index 000000000..2fe235146 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.medication_supply_amount.v0.0.1-alpha.adls @@ -0,0 +1,139 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=365f8abf-be21-43e8-bb00-f053ca88947a; build_uid=ea36918b-ac00-4684-a524-f4f09d0369a7) + openEHR-EHR-CLUSTER.medication_supply_amount.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Ian McNicoll"> + ["organisation"] = <"freshEHR Clinical Informatics Ltd. UK"> + ["email"] = <"ian@freshehr.com"> + ["date"] = <"2016-05-12"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Silje Ljosland Bakke, Helse Bergen HF, Norway (Editor)", "John Bennett, NEHTA, Australia", "Sharmila Biswas, Australia", "Stephen Chu, NEHTA, Australia (Editor)", "Matthew Cordell, NEHTA, Australia", "Gail Easterbrook, Flinders Medical Centre, Australia", "David Evans, Queensland Health, Australia", "Sarah Gaunt, NEHTA, Australia", "Trina Gregory, cpc, Australia", "Sam Heard, Ocean Informatics, Australia (Editor)", "Mary Kelaher, NEHTA, Australia", "Robert L'egan, NEHTA, Australia", "Heather Leslie, Ocean Informatics, Australia (Editor)", "Susan McIndoe, Royal District Nursing Service, Australia", "David McKillop, NEHTA, Australia", "Chris Mitchell, RACGP, Australia", "Stewart Morrison, NEHTA, Australia", "Chris Pearce, Melbourne East GP Network, Australia", "Camilla Preeston, Royal Australian College of General Practitioners, Australia", "Margaret Prichard, NEHTA, Australia", "Cathy Richardson, NEHTA, Australia", "Robyn Richards, NEHTA - Clinical Terminology, Australia", "John Taylor, NEHTA, Australia", "Richard Townley-O'Neill, NEHTA, Australia (Editor)", "Kylie Young, The Royal Australian College of General Practitioners, Australia", "Ian McNicoll, freshEHR Clinical Informatics Ltd., UK", "Sam Heard, Ocean Informatics, Australia"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + references = < + ["1"] = <"Medication instruction, Draft Archetype [Internet]. nehta, Australia, nehta Clinical Knowledge Manager [cited: 2015-12-15]. Available from: http://dcm.nehta.org.au/ckm/#showArchetype_1013.1.838"> + ["2"] = <"Intermountain Healthcare Medication order model, Personal Communication to Sam Heard by Dr Stan Huff."> + ["3"] = <"Royal Australian College of General Practitioners. Fact Sheet: Medicines List. 2010."> + ["4"] = <"NHS HSCIC Messaging Implementation Manual (GP2GP messages) http://www.uktcregistration.nss.cfh.nhs.uk/trud3"> + ["5"] = <"Standards for medication and medical device records – technical annex [Internet]. RCP London. [cited 2015 Dec 15]. Available from: https://www.rcplondon.ac.uk/projects/outputs/standards-medication-and-medical-device-records-technical-annex"> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"06CF3E9489AF6D497D85F3A0EDEC0EC7"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record the amount of a medication, vaccine or other therapeutic item to be supplied or supplied to the patient, as part of authorisation, dispensing or administration, both in the context of the original medication order and in a subsequent action. "> + use = <"Use to record the amount of a medication, vaccine or other therapeutic item to be supplied or supplied to the patient, as part of authorisation, dispensing or administration, both in the context of the original medication order and in a subsequent action. "> + misuse = <"This archetype should not be used to record the original dose amount as part of a dose direction or the strength of a preparation. These are recorded as part of the Medication Order INSTRUCTION, or Medication Substance CLUSTER."> + copyright = <"© openEHR Foundation"> + > + > + +definition + CLUSTER[id1] occurrences matches {0..1} matches { -- Medication supply amount + items cardinality matches {1..*; unordered} matches { + ELEMENT[id162] occurrences matches {0..1} matches { -- Amount description + value matches { + DV_TEXT[id9001] + } + } + ELEMENT[id132] occurrences matches {0..1} matches { -- Amount + value matches { + DV_QUANTITY[id9002] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id148] occurrences matches {0..1} matches { -- Units + value matches { + DV_TEXT[id9003] + } + } + ELEMENT[id159] occurrences matches {0..1} matches { -- Number of packs + value matches { + DV_COUNT[id9004] matches { + magnitude matches {|>=1|} + } + } + } + ELEMENT[id160] occurrences matches {0..1} matches { -- Pack size + value matches { + DV_QUANTITY[id9005] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id161] occurrences matches {0..1} matches { -- Pack units + value matches { + DV_TEXT[id9006] + } + } + ELEMENT[id143] occurrences matches {0..1} matches { -- Duration of supply + value matches { + DV_DURATION[id9007] matches { + value matches {PYMWDTS/|>=P0D|} + } + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["at9000"] = < + text = <"Qualified real"> + description = <"Qualified real"> + > + ["id162"] = < + text = <"Amount description"> + description = <"A narrative representation of the amount The amount of medication, vaccine or therapeutic good intended to be supplied or actually supplied."> + > + ["id161"] = < + text = <"Pack units"> + description = <"The units of measurement associated with pack size."> + > + ["id160"] = < + text = <"Pack size"> + description = <"The pack size specifed by the prescriber or dispensed by the dispenser."> + > + ["id159"] = < + text = <"Number of packs"> + description = <"The number of packs specified by the prescriber or dispensed by the dispenser."> + > + ["id148"] = < + text = <"Units"> + description = <"The dose unit or pack unit associated with the dispense amount."> + > + ["id143"] = < + text = <"Duration of supply"> + description = <"The period of time for which the medication should be dispensed or for which a suppy was dispensed."> + > + ["id132"] = < + text = <"Amount"> + description = <"The amount of medication, vaccine or therapeutic good intended to be supplied or actually supplied."> + > + ["id1"] = < + text = <"Medication supply amount"> + description = <"Details related to the amount of a medication, vaccine or other therapeutic item to be supplied or supplied to the patient, as part of authorisation, dispensing or administration."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_daily.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_daily.v0.0.1-alpha.adls new file mode 100644 index 000000000..94de81d3e --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_daily.v0.0.1-alpha.adls @@ -0,0 +1,282 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=990278cc-5954-4bc3-8599-919417da096b; build_uid=266bd0e6-23e0-4c8e-91f6-22e6a136014b) + openEHR-EHR-CLUSTER.timing_daily.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + translations = < + ["sl"] = < + language = <[ISO_639-1::sl]> + author = < + ["name"] = <"?"> + > + > + > + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"NEHTA"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"2010-11-12"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Sharmila Biswas, Dr Sharmila Biswas, Australia", "Stephen Chu, NEHTA, Australia (Editor)", "David Evans, Queensland Health, Australia", "Sam Heard, Ocean Informatics, Australia (Editor)", "Heather Leslie, Ocean Informatics, Australia (Editor)", "Richard Townley-O'Neill, NEHTA, Australia (Editor)"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + other_details = < + ["MD5-CAM-1.0.1"] = <"CDC67E20EB91938ECCCE0FF3B9497829"> + > + details = < + ["sl"] = < + language = <[ISO_639-1::sl]> + purpose = <"*To provide structured information on time schedules within a single day that is suitable for computation and display for human interpretation.(en)"> + use = <""> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To provide structured information on time schedules within a single day that is suitable for computation and display for human interpretation."> + keywords = <"timing", "administration", "dosing", "frequency"> + use = <"For use with medication orders and other instructions where timing is complex and needs to be computable."> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + > + +definition + CLUSTER[id1] matches { -- Timing - daily + items cardinality matches {1..*; unordered} matches { + ELEMENT[id4] occurrences matches {0..1} matches { -- Frequency + value matches { + DV_QUANTITY[id9002] matches { + property matches {[at9000]} -- Frequency + [magnitude, units, precision] matches { + [{|0.0..1.0|}, {"1/d"}, {0}], + [{|>=0.0|}, {"1/min"}, {|>=0|}], + [{|>=0.0|}, {"1/s"}, {|>=0|}], + [{|>=0.0|}, {"1/h"}, {|>=0|}] + } + } + DV_INTERVAL[id9003] matches { + upper matches { + DV_QUANTITY[id9004] matches { + property matches {[at9000]} -- Frequency + [magnitude, units, precision] matches { + [{|<=1.0|}, {"1/d"}, {0}], + [{|>=0.0|}, {"1/min"}, {|>=0|}], + [{|>=0.0|}, {"1/s"}, {|>=0|}], + [{|0.0..24.0|}, {"1/h"}, {0}] + } + } + } + lower matches { + DV_QUANTITY[id9005] matches { + property matches {[at9000]} -- Frequency + [magnitude, units] matches { + [{|>=0.0|}, {"1/d"}], + [{|>=0.0|}, {"1/min"}], + [{|>=0.0|}, {"1/s"}], + [{|>=0.0|}, {"1/h"}] + } + } + } + } + } + } + ELEMENT[id15] occurrences matches {0..1} matches { -- Interval + value matches { + DV_DURATION[id9006] matches { + value matches {PTHMS/|PT0S..PT24H|} + } + DV_INTERVAL[id9007] matches { + upper matches { + DV_DURATION[id5001] matches { + value matches {PTHMS/|PT0S..PT24H|} + } + } + lower matches { + DV_DURATION[id5002] matches { + value matches {PTHMS/|PT0S..PT24H|} + } + } + + } + } + } + ELEMENT[id5] matches { -- Specific time + value matches { + DV_TIME[id9008] + DV_INTERVAL[id9009] matches { + upper matches { + DV_DATE_TIME[id9010] + } + lower matches { + DV_DATE_TIME[id9011] + } + } + } + } + ELEMENT[id27] matches { -- Named time event + value matches { + DV_TEXT[id9012] + DV_CODED_TEXT[id9013] matches { + defining_code matches {[ac9001]} -- Named time event (synthesised) + } + } + } + ELEMENT[id24] occurrences matches {0..1} matches { -- Exact timing critical + value matches { + DV_BOOLEAN[id9014] matches { + value matches {True, False} + } + } + } + ELEMENT[id25] occurrences matches {0..1} matches { -- As required + value matches { + DV_BOOLEAN[id9015] matches { + value matches {True, False} + } + } + } + ELEMENT[id26] occurrences matches {0..1} matches { -- As required criterion + value matches { + DV_TEXT[id9016] + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["at9000"] = < + text = <"Frequency"> + description = <"Frequency"> + > + ["ac9001"] = < + text = <"Named time event (synthesised)"> + description = <"A specific, named time event within a single day, when the activity should occur. (synthesised)"> + > + ["at35"] = < + text = <"in the morning and at night"> + description = <"Perform the activity in the morning and at night."> + > + ["at34"] = < + text = <"at night"> + description = <"Perform the activity at night."> + > + ["at33"] = < + text = <"in the morning"> + description = <"Perform the activity in the morning."> + > + ["at32"] = < + text = <"immediately (stat)"> + description = <"Perform the activity immediately."> + > + ["id27"] = < + text = <"Named time event"> + description = <"A specific, named time event within a single day, when the activity should occur."> + > + ["id26"] = < + text = <"As required criterion"> + description = <"The condition which triggers an 'as required' activity."> + > + ["id25"] = < + text = <"As required"> + description = <"The activity should only occur when the \"as required\" trigger condition is met."> + > + ["id24"] = < + text = <"Exact timing critical"> + description = <"Is exact timing of the activity critical to patient safety or wellbeing?"> + > + ["id15"] = < + text = <"Interval"> + description = <"The time interval or minimum and maximum range of an interval between each scheduled activity, limited to a single day."> + > + ["id5"] = < + text = <"Specific time"> + description = <"A specific time or interval of time during a single day when the activity should occur."> + > + ["id4"] = < + text = <"Frequency"> + description = <"The frequency as number of times per time period (limited to a single day) that the activity is to take place."> + > + ["id1"] = < + text = <"Timing - daily"> + description = <"Structured information about the timing (intended or actual) of administration or use of a medicine, other therapeutic good or other intervention that is given on a scheduled basis."> + > + > + ["sl"] = < + ["at9000"] = < + text = <"* Frequency (en)"> + description = <"* Frequency (en)"> + > + ["ac9001"] = < + text = <"*Named time event(en) (synthesised)"> + description = <"*A specific, named time event within a single day, when the activity should occur.(en) (synthesised)"> + > + ["at35"] = < + text = <"*in the morning and at night(en)"> + description = <"*Perform the activity in the morning and at night.(en)"> + > + ["at34"] = < + text = <"*at night(en)"> + description = <"*Perform the activity at night.(en)"> + > + ["at33"] = < + text = <"*in the morning(en)"> + description = <"*Perform the activity in the morning.(en)"> + > + ["at32"] = < + text = <"*immediately (stat)(en)"> + description = <"*Perform the activity immediately.(en)"> + > + ["id27"] = < + text = <"*Named time event(en)"> + description = <"*A specific, named time event within a single day, when the activity should occur.(en)"> + > + ["id26"] = < + text = <"*As required criterion(en)"> + description = <"*The condition which triggers an 'as required' activity.(en)"> + > + ["id25"] = < + text = <"*As required(en)"> + description = <"*The activity should only occur when the \"as required\" trigger condition is met.(en)"> + > + ["id24"] = < + text = <"*Exact timing critical(en)"> + description = <"*Is exact timing of the activity critical to patient safety or wellbeing?(en)"> + > + ["id15"] = < + text = <"*Interval(en)"> + description = <"*The time interval between each scheduled activity, limited to a single day.(en)"> + > + ["id5"] = < + text = <"*Specific time(en)"> + description = <"*A specific time during a single day when the activity should occur.(en)"> + > + ["id4"] = < + text = <"*Frequency(en)"> + description = <"*The frequency as number of times per time period (limited to a single day) that the activity is to take place.(en)"> + > + ["id1"] = < + text = <"*Daily timing(en)"> + description = <"*Structured information about the timing (intended or actual) of administration or use of a medicine, other therapeutic good or other intervention that is given on a scheduled basis.(en)"> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + > + > + value_sets = < + ["ac9001"] = < + id = <"ac9001"> + members = <"at32", "at33", "at34", "at35"> + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_repetition.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_repetition.v0.0.1-alpha.adls new file mode 100644 index 000000000..23798f57e --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-CLUSTER.timing_repetition.v0.0.1-alpha.adls @@ -0,0 +1,159 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=b40ad367-5aeb-4689-93bd-576986ede5cc; build_uid=66fa1b3d-9fd2-4079-ab97-aa25705c5446) + openEHR-EHR-CLUSTER.timing_repetition.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Ian McNicoll"> + ["organisation"] = <"freshEHR Clinical Informatics Ltd."> + ["email"] = <"ian@freshehr.com"> + ["date"] = <"2015-09-11"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Silje Ljosland Bakke, National ICT Norway, Norway (openEHR Editor)", "Heather Leslie, Ocean Informatics, Australia (openEHR Editor)", "Ian McNicoll, freshEHR Clinical Informatics, United Kingdom (openEHR Editor)", "John Tore Valand, Helse Bergen, Norway (openEHR Editor)"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + other_details = < + ["MD5-CAM-1.0.1"] = <"55B0B08763D142BC502C82C36B0ED959"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record details of scheduled activities over periods longer than a single day."> + use = <""> + misuse = <""> + copyright = <"© openEHR Foundation"> + > + > + +definition + CLUSTER[id1] matches { -- Timing - repetition + items cardinality matches {1..*; unordered} matches { + ELEMENT[id3] occurrences matches {0..1} matches { -- Repetition interval + value matches { + DV_DURATION[id9000] matches { + value matches {PYMWD/|>=P0D|} + } + } + } + ELEMENT[id2] matches { -- Specific date + value matches { + DV_DATE_TIME[id9001] + } + } + ELEMENT[id4] matches { -- Specific day of week + value matches { + DV_COUNT[id9002] matches { + magnitude matches {|0..6|} + } + } + } + ELEMENT[id5] matches { -- Specific day of month + value matches { + DV_COUNT[id9003] matches { + magnitude matches {|1..31|} + } + } + } + CLUSTER[id7] matches { -- Specific event + items cardinality matches {1..*; unordered} matches { + ELEMENT[id6] occurrences matches {0..1} matches { -- Event name + value matches { + DV_TEXT[id9004] + } + } + ELEMENT[id10] occurrences matches {0..1} matches { -- Start interval + value matches { + DV_DURATION[id9005] matches { + value + } + } + } + } + } + CLUSTER[id11] matches { -- On /off cycle + items cardinality matches {1..*; unordered} matches { + ELEMENT[id12] occurrences matches {0..1} matches { -- On + value matches { + DV_DURATION[id9006] matches { + value matches {PYMWD/|>=P0D|} + } + } + } + ELEMENT[id13] occurrences matches {0..1} matches { -- Off + value matches { + DV_DURATION[id9007] matches { + value matches {PYWD/|>=P0D|} + } + } + } + ELEMENT[id14] occurrences matches {0..1} matches { -- Repetitions + value matches { + DV_COUNT[id9008] matches { + magnitude matches {|>=0|} + } + } + } + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["id14"] = < + text = <"Repetitions"> + description = <"The number of repetitions of the on/off cycle."> + > + ["id13"] = < + text = <"Off"> + description = <"The period of time for which the activity should NOT take place."> + > + ["id12"] = < + text = <"On"> + description = <"The period of time for which the activity should take place."> + > + ["id11"] = < + text = <"On /off cycle"> + description = <"A cycle of activity where an on-off pattern is required."> + > + ["id10"] = < + text = <"Start interval"> + description = <"The period of time before or after the named event when the activity should take place. Negative durations can be used to signifify that the activity should be taken before a known event."> + > + ["id7"] = < + text = <"Specific event"> + description = <"The activity should take place in relation to a specific named event."> + > + ["id6"] = < + text = <"Event name"> + description = <"The name of the event that triggers the activity to take place."> + > + ["id5"] = < + text = <"Specific day of month"> + description = <"The activity should take place on a specific day of the month."> + > + ["id4"] = < + text = <"Specific day of week"> + description = <"The activity should take place on a specific day of the week, with 0 representing Sunday."> + > + ["id3"] = < + text = <"Repetition interval"> + description = <"The interval between repetitions of the activity."> + > + ["id2"] = < + text = <"Specific date"> + description = <"The activity should take place on a specific date."> + > + ["id1"] = < + text = <"Timing - repetition"> + description = <"Details of timing schedules repeating over periods longer than a single day."> + > + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.prescription.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.prescription.v0.0.1-alpha.adls new file mode 100644 index 000000000..5da39176b --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-COMPOSITION.prescription.v0.0.1-alpha.adls @@ -0,0 +1,128 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=dd3c4fc0-05cf-487e-b6e2-9b22d49489b0; build_uid=a686d8f6-84c3-41cf-96f2-8ece363ae217) + openEHR-EHR-COMPOSITION.prescription.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + translations = < + ["ar-sy"] = < + language = <[ISO_639-1::ar-sy]> + author = < + ["name"] = <"Monica Saleh"> + > + > + > + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"Ocean Informatics"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"2006-03-23"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + other_details = < + ["MD5-CAM-1.0.1"] = <"F6E374B7E08DE198D867B90CCC3D4755"> + > + details = < + ["ar-sy"] = < + language = <[ISO_639-1::ar-sy]> + purpose = <"بِنية لنقل الأوامر بالأدوية إلى الصيدلية."> + keywords = <"الدواء", "وصف العلاج", "الأمر"> + use = <"تستخدم هذه البنية فقط في توصيل الأدوية إلى الصيدلية."> + misuse = <"يستخدم نموذج فعل. وصف العلاج, لتسجيل الأوامر بالأدوية و التعليمات الخاصة بها. + تستخدم هذه البنية فقط في توصيل الأدوية إلى الصيدلية عبر الـ openEHR."> + > + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"A composition for transferring medication orders to the pharmacy."> + keywords = <"medication", "prescribe", "order"> + use = <"This composition is only required for transfer of medications to the pharmacy."> + misuse = <"Medication orders, as instructions, have a prescribe action that records prescription and communication to the pharmacy. This composition is only required if the medication orders are required to be transmitted within openEHR to the pharmacy."> + > + > + +definition + COMPOSITION[id1] matches { -- Prescription + category matches { + DV_CODED_TEXT[id9002] matches { + defining_code matches {[at9000]} -- event + } + } + context matches { + EVENT_CONTEXT[id9003] matches { + other_context matches { + ITEM_TREE[id2] matches { -- Tree + items cardinality matches {0..*; unordered} matches { + allow_archetype CLUSTER[id8] matches { -- Extension + include + archetype_id/value matches {/.*/} + } + ELEMENT[id9] matches { -- Prescription identifier + value matches { + DV_IDENTIFIER[id9004] + } + } + } + } + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["at9000"] = < + text = <"event"> + description = <"event"> + > + ["id9"] = < + text = <"Prescription identifier"> + description = <"An identifier for the prescription as a whole."> + > + ["id8"] = < + text = <"Extension"> + description = <"Additional information required to capture local context or to align with other reference models/formalisms."> + > + ["id2"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id1"] = < + text = <"Prescription"> + description = <"Set of medication orders communicated to pharmacy."> + > + > + ["ar-sy"] = < + ["at9000"] = < + text = <"* event (en)"> + description = <"* event (en)"> + > + ["id9"] = < + text = <"*Prescription identifier(en)"> + description = <"*An identifier for the prescription as a whole.(en)"> + > + ["id8"] = < + text = <"*Extension(en)"> + description = <"*Additional information required to capture local context or to align with other reference models/formalisms.(en)"> + > + ["id2"] = < + text = <"*Tree(en)"> + description = <"*@ internal @(en)"> + > + ["id1"] = < + text = <"وصف العلاج"> + description = <"مجموعة من أوامر الأدوية يتم توصيلها إلى الصيدلية."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-INSTRUCTION.medication_order.v0.0.1-alpha.adls b/opt14/src/test/resources/adl2/openEHR-EHR-INSTRUCTION.medication_order.v0.0.1-alpha.adls new file mode 100644 index 000000000..688b9fb45 --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-INSTRUCTION.medication_order.v0.0.1-alpha.adls @@ -0,0 +1,807 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated; uid=32802688-cbff-4d61-970d-da85810e6a07; build_uid=a3f2f974-a21b-4177-acd0-f3de1699aa05) + openEHR-EHR-INSTRUCTION.medication_order.v0.0.1-alpha + +language + original_language = <[ISO_639-1::en]> + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"NEHTA"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"2015-10-21"> + > + original_namespace = <"org.openehr"> + original_publisher = <"openEHR Foundation"> + other_contributors = <"Vebjørn Arntzen, Oslo University Hospital, Norway", "Koray Atalag, University of Auckland, New Zealand", "Silje Ljosland Bakke, National ICT Norway, Norway (openEHR Editor)", "John Bennett, NEHTA, Australia", "SBhusan Bhattacharyya, Sudisa Consultancy Services, India", "Sharmila Biswas, Australia", "Lars Bitsch-Larsen, Haukeland University hospital, Norway", "Stephen Chu, NEHTA, Australia (Editor)", "Matthew Cordell, NEHTA, Australia", "Gail Easterbrook, Flinders Medical Centre, Australia", "David Evans, Queensland Health, Australia", "Hildegard Franke, freshEHR Clinical Informatics Ltd., United Kingdom", "Sarah Gaunt, NEHTA, Australia", "Heather Grain, Llewelyn Grain Informatics, Australia", "Trina Gregory, cpc, Australia", "Sam Heard, Ocean Informatics, Australia (Editor)", "Evelyn Hovenga, EJSH Consulting, Australia", "Mary Kelaher, NEHTA, Australia", "Robert L'egan, NEHTA, Australia", "Russell Leftwich, Russell B Leftwich MD, United States", "Heather Leslie, Ocean Informatics, Australia (openEHR Editor)", "Susan McIndoe, Royal District Nursing Service, Australia", "David McKillop, NEHTA, Australia", "Ian McNicoll, freshEHR Clinical Informatics, United Kingdom (openEHR Editor)", "Chris Mitchell, RACGP, Australia", "Stewart Morrison, NEHTA, Australia", "Andrej Orel, Marand d.o.o., Slovenia", "Chris Pearce, Melbourne East GP Network, Australia", "Vladimir Pizzo, Hospital Sírio Libanês, Brazil", "Camilla Preeston, Royal Australian College of General Practitioners, Australia", "Margaret Prichard, NEHTA, Australia", "Cathy Richardson, NEHTA, Australia", "Robyn Richards, NEHTA - Clinical Terminology, Australia", "Anoop Shah, University College London, United Kingdom", "Iztok Stotl, UKCLJ, Slovenia", "Norwegian Review Summary, National ICT Norway, Norway", "John Taylor, NEHTA, Australia", "Richard Townley-O'Neill, NEHTA, Australia (Editor)", "John Tore Valand, Helse Bergen, Norway (openEHR Editor)", "Ines Vaz, UFN, Portugal", "Kylie Young, The Royal Australian College of General Practitioners, Australia"> + lifecycle_state = <"in_development"> + custodian_namespace = <"org.openehr"> + custodian_organisation = <"openEHR Foundation"> + licence = <"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/."> + references = < + ["1"] = <"Medication instruction, Draft Archetype [Internet]. nehta, Australia, nehta Clinical Knowledge Manager [cited: 2015-12-15]. Available from: http://dcm.nehta.org.au/ckm/#showArchetype_1013.1.838"> + ["2"] = <"Intermountain Healthcare Medication order model, Personal Communication to Sam Heard by Dr Stan Huff."> + ["3"] = <"Royal Australian College of General Practitioners. Fact Sheet: Medicines List. 2010."> + ["4"] = <"NHS HSCIC Messaging Implementation Manual (GP2GP messages) http://www.uktcregistration.nss.cfh.nhs.uk/trud3"> + ["5"] = <"Standards for medication and medical device records – technical annex [Internet]. RCP London. [cited 2015 Dec 15]. Available from: https://www.rcplondon.ac.uk/projects/outputs/standards-medication-and-medical-device-records-technical-annex"> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"6B5A7E7C137E9AC00A52EE9481BEC73E"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record the instructions for use of a medication, vaccine or other therapeutic item."> + keywords = <"medication", "order", "prescribe", "therapy", "substance", "drug", "therapeutic", "otc", "therapeutic good", "pharmaceutical", "product", "posology"> + use = <"Use to record the instructions for use of a medication, vaccine or other therapeutic item. + + It is intended to be used for any type of medication and related order, whether prescribed by a health professional or available for purchase 'over the counter'. The scope of this medication archetype also includes orders for vaccinations or other therapeutic goods, such as bandages or other items that are applied or administered to have a therapeutic effect which have a common pattern for data recording. + + This archetype is designed to be used in a number of clinical contexts, including but not limited to: + - a record in a clinical consultation (COMPOSITION.encounter); + - a written prescription by a physician, dentist, nurse practitioner, or other designated health professional for a medication to be dispensed and administered (within a COMPOSITION.prescription); + - an item in a current medication list, prescription or drug chart (within COMPOSITION.medication_list); and + - an item in a summary document such as transfer of care (COMPOSITION.transfer_summary) or a referral (COMPOSITION.request). + + In most cases the order will be simple - for a single item with uncomplicated instructions for dispensing and administration. However this archetype is also designed to allow for more complex orders. For example: + - a reducing dose of predisolone over a period of weeks; + - titration of insulin, with dosing dependent on test results; + - multiple medications prescribed simultaneously as part of a single drug regimen, such as a triple therapy for peptic ulcer; and + - intravenous administration of medications or nutrition supplements. + + The archetype has been designed to allow for a range of complexity, from: + - simple narrative instructions for orders like 'furosemide 40mg two tablets in the morning and one at lunch' to ensure compatibility with existing systems; through to + - structured detail for dose, route and timing to represent a fully computable specification. + + It has also been designed so that a single medication order structure can represent: + - complex sequential medication orders using the same preparation strength to be supported within a single order structure; and + - multiple medication orders can be chained in circumstances where different medications or preparations need to be given sequentially. + + The amount of the medication is usually represented in terms of a number and corresponding dose unit, however there can also be a narrative statement to ensure compatibility with existing systems and also coverage of all scenarios. + + Cluster archetypes have been used to represent some of the content for two reasons: + - in situations where the content has been identified as being also used in other clinical contexts, in particular the paired ACTION.medication archetype for recording actual dispensing, administration etc; and + - to remove less commonly used content from the core archetype framework."> + misuse = <"Not to be used to record the activities related to carrying out the order for medication, vaccine or therapeutic good, such as details about actual administration or dispensing. Use the ACTION.medication for this purpose. + + Not to be used to record the ordering of blood products. Use the INSTRUCTION.transfusion for this purpose. + + Not to be used to record the order for insertion of implants or medical devices such as pacemakers and defibrillators. Use the INSTRUCTION.procedure for this purpose."> + copyright = <"© openEHR Foundation"> + > + > + +definition + INSTRUCTION[id1] matches { -- Medication order + activities cardinality matches {0..*; unordered} matches { + ACTIVITY[id2] matches { -- Order + description matches { + ITEM_TREE[id3] matches { -- Tree + items cardinality matches {1..*} matches { + ELEMENT[id71] matches { -- Medication item + value matches { + DV_TEXT[id9005] + } + } + allow_archetype CLUSTER[id144] occurrences matches {0..1} matches { -- Preparation details + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.medication_substance(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + ELEMENT[id92] matches { -- Route + value matches { + DV_TEXT[id9006] + } + } + ELEMENT[id10] occurrences matches {0..1} matches { -- Dose directions description + value matches { + DV_TEXT[id9007] + } + } + ELEMENT[id48] occurrences matches {0..1} matches { -- Parsable dose directions + value matches { + DV_PARSABLE[id9008] matches { + formalism matches {"text/html", "text/plain", "text/xml", "text/rtf"} + } + } + } + ELEMENT[id110] occurrences matches {0..1} matches { -- Dose amount description + value matches { + DV_TEXT[id9009] + } + } + ELEMENT[id56] occurrences matches {0..1} matches { -- Dose timing description + value matches { + DV_TEXT[id9010] + } + } + CLUSTER[id57] matches { -- Dose direction + items cardinality matches {1..*; unordered} matches { + ELEMENT[id58] occurrences matches {0..1} matches { -- Direction sequence + value matches { + DV_COUNT[id9011] matches { + magnitude matches {|>=1|} + } + } + } + CLUSTER[id59] matches { -- Dose pattern + items cardinality matches {1..*; unordered} matches { + ELEMENT[id165] occurrences matches {0..1} matches { -- Pattern sequence + value matches { + DV_COUNT[id9012] matches { + magnitude matches {|>=1|} + } + } + } + ELEMENT[id145] occurrences matches {0..1} matches { -- Dose amount + value matches { + DV_QUANTITY[id9013] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + DV_INTERVAL[id9014] matches { + upper matches { + DV_QUANTITY[id9015] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + lower matches { + DV_QUANTITY[id9016] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + } + } + ELEMENT[id146] occurrences matches {0..1} matches { -- Dose unit + value matches { + DV_TEXT[id9017] + } + } + allow_archetype CLUSTER[id38] occurrences matches {0..1} matches { -- Dose timing + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.timing_daily(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + ELEMENT[id135] occurrences matches {0..1} matches { -- Infusion administration rate + value matches { + DV_QUANTITY[id9018] matches { + property matches {[at9001]} -- Flow rate, volume + [magnitude, units] matches { + [{|>=0.0|}, {"l/h"}], + [{|>=0.0|}, {"ml/min"}], + [{|>=0.0|}, {"ml/s"}], + [{|>=0.0|}, {"ml/h"}] + } + } + DV_TEXT[id9019] + } + } + ELEMENT[id103] occurrences matches {0..1} matches { -- Dose administration duration + value matches { + DV_DURATION[id9020] matches { + value matches {PDTHMS/|>=PT0S|} + } + } + } + allow_archetype CLUSTER[id157] occurrences matches {0..1} matches { -- Conditional administration + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.conditional_medication_rules(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + } + } + ELEMENT[id67] occurrences matches {0..1} matches { -- Direction duration + value matches { + DV_CODED_TEXT[id9021] matches { + defining_code matches {[ac9002]} -- Direction duration (synthesised) + } + DV_DURATION[id9022] matches { + value matches {|>=PT0S|} + } + } + } + allow_archetype CLUSTER[id91] occurrences matches {0..1} matches { -- Direction repetition + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.timing_repetition(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + } + } + CLUSTER[id63] occurrences matches {0..1} matches { -- Medication safety + items cardinality matches {1..*; unordered} matches { + CLUSTER[id52] matches { -- Maximum dose + items cardinality matches {1..*; unordered} matches { + ELEMENT[id131] occurrences matches {0..1} matches { -- Maximum amount + value matches { + DV_QUANTITY[id9023] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id147] occurrences matches {0..1} matches { -- Maximum amount dose unit + value matches { + DV_TEXT[id9024] + } + } + ELEMENT[id54] occurrences matches {0..1} matches { -- Allowed period + value matches { + DV_DURATION[id9025] matches { + value matches {|>=PT0S|} + } + } + } + } + } + ELEMENT[id65] occurrences matches {0..1} matches { -- Exceptional dose override? + value matches { + DV_BOOLEAN[id9026] matches { + value matches {True, False} + } + } + } + ELEMENT[id163] occurrences matches {0..1} matches { -- Override reason + value matches { + DV_TEXT[id9027] + } + } + CLUSTER[id151] occurrences matches {0..1} matches { -- Dose goal + items cardinality matches {1..*; unordered} matches { + ELEMENT[id166] occurrences matches {0..1} matches { -- Goal + value matches { + DV_TEXT[id9028] + } + } + ELEMENT[id152] occurrences matches {0..1} matches { -- Total daily dose amount + value matches { + DV_QUANTITY[id9029] matches { + property matches {[at9000]} -- Qualified real + magnitude matches {|>=0.0|} + units matches {"1"} + } + } + } + ELEMENT[id153] occurrences matches {0..1} matches { -- Total daily dose unit + value matches { + DV_TEXT[id9030] + } + } + } + } + } + } + ELEMENT[id45] matches { -- Additional instruction + value matches { + DV_TEXT[id9031] + } + } + ELEMENT[id106] matches { -- Patient guidance + value matches { + DV_TEXT[id9032] + } + } + ELEMENT[id108] matches { -- Monitoring instruction + value matches { + DV_TEXT[id9033] + } + } + ELEMENT[id19] matches { -- Clinical indication + value matches { + DV_TEXT[id9034] + } + } + ELEMENT[id149] matches { -- Therapeutic intent + value matches { + DV_TEXT[id9035] + } + } + CLUSTER[id114] occurrences matches {0..1} matches { -- Order details + items cardinality matches {1..*; unordered} matches { + ELEMENT[id13] occurrences matches {0..1} matches { -- Order start date/time + value matches { + DV_DATE_TIME[id9036] + } + } + ELEMENT[id14] occurrences matches {0..1} matches { -- Order stop date/time + value matches { + DV_DATE_TIME[id9037] + } + } + ELEMENT[id12] matches { -- Order start criterion + value matches { + DV_TEXT[id9038] + } + } + ELEMENT[id17] matches { -- Order stop criterion + value matches { + DV_TEXT[id9039] + } + } + ELEMENT[id61] occurrences matches {0..1} matches { -- Administrations already complete + value matches { + DV_COUNT[id9040] + } + } + ELEMENT[id51] occurrences matches {0..1} matches { -- Duration of course already complete + value matches { + DV_DURATION[id9041] matches { + value matches {PWDTH/|>=PT0S|} + } + } + } + allow_archetype CLUSTER[id113] matches { -- Course summary + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.medication_course_summary(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + } + } + allow_archetype CLUSTER[id70] matches { -- Authorisation directions + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.medication_authorisation(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + CLUSTER[id130] occurrences matches {0..1} matches { -- Dispense directions + items cardinality matches {1..*; unordered} matches { + ELEMENT[id107] matches { -- Dispense instruction + value matches { + DV_TEXT[id9042] + } + } + allow_archetype CLUSTER[id66] matches { -- Dispense amount + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.medication_supply_amount(-[a-zA-Z0-9_]+)*\.v0\..*/} + } + ELEMENT[id133] occurrences matches {0..1} matches { -- Substitution direction + value matches { + DV_CODED_TEXT[id9043] matches { + defining_code matches {[ac9003]} -- Substitution direction (synthesised) + } + } + } + ELEMENT[id155] occurrences matches {0..1} matches { -- Non-substitution reason + value matches { + DV_TEXT[id9044] + } + } + ELEMENT[id140] occurrences matches {0..1} matches { -- Priority + value matches { + DV_TEXT[id9045] + } + } + ELEMENT[id156] occurrences matches {0..1} matches { -- Start date + value matches { + DV_DATE_TIME[id9046] + } + } + ELEMENT[id162] occurrences matches {0..1} matches { -- Expiry date + value matches { + DV_DATE_TIME[id9047] + } + } + allow_archetype CLUSTER[id171] matches { -- Dispense details + include + archetype_id/value matches {/.*/} + } + } + } + CLUSTER[id134] occurrences matches {0..1} matches { -- Administration directions + items cardinality matches {1..*; unordered} matches { + ELEMENT[id109] matches { -- Administration instruction + value matches { + DV_TEXT[id9048] + } + } + ELEMENT[id137] occurrences matches {0..1} matches { -- Infusion purpose + value matches { + DV_CODED_TEXT[id9049] matches { + defining_code matches {[ac9004]} -- Infusion purpose (synthesised) + } + } + } + ELEMENT[id93] occurrences matches {0..1} matches { -- Body site + value matches { + DV_TEXT[id9050] + } + } + allow_archetype CLUSTER[id94] occurrences matches {0..1} matches { -- Structured body site + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.anatomical_location(-[a-zA-Z0-9_]+)*\.v1\..*|openEHR-EHR-CLUSTER\.anatomical_location_clock(-[a-zA-Z0-9_]+)*\.v0\..*|openEHR-EHR-CLUSTER\.anatomical_location_relative(-[a-zA-Z0-9_]+)*\.v1\..*/} + } + ELEMENT[id95] matches { -- Delivery method + value matches { + DV_TEXT[id9051] + } + } + allow_archetype CLUSTER[id96] matches { -- Delivery device details + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.device(-[a-zA-Z0-9_]+)*\.v1\..*/} + } + } + } + allow_archetype CLUSTER[id167] matches { -- Additional details + include + archetype_id/value matches {/.*/} + } + ELEMENT[id168] occurrences matches {0..1} matches { -- Comment + value matches { + DV_TEXT[id9052] + } + } + } + } + } + } + } + protocol matches { + ITEM_TREE[id6] matches { -- Dose amount description + items cardinality matches {0..*; unordered} matches { + ELEMENT[id5] matches { -- Order identifier + value matches { + DV_IDENTIFIER[id9053] + } + } + ELEMENT[id136] matches { -- Dosage formula + value matches { + DV_TEXT[id9054] + } + } + allow_archetype CLUSTER[id9] matches { -- Extension + include + archetype_id/value matches {/.*/} + } + } + } + } + } + +terminology + term_definitions = < + ["en"] = < + ["at9000"] = < + text = <"Qualified real"> + description = <"Qualified real"> + > + ["at9001"] = < + text = <"Flow rate, volume"> + description = <"Flow rate, volume"> + > + ["ac9002"] = < + text = <"Direction duration (synthesised)"> + description = <"The duration of this dose direction. (synthesised)"> + > + ["ac9003"] = < + text = <"Substitution direction (synthesised)"> + description = <"Permission for substitution with a bioequivalent medication. (synthesised)"> + > + ["ac9004"] = < + text = <"Infusion purpose (synthesised)"> + description = <"The purpose of the infusion. (synthesised)"> + > + ["id171"] = < + text = <"Dispense details"> + description = <"Further details related to dispense directions."> + > + ["at170"] = < + text = <"Not permitted"> + description = <"Substitution of the Medication with a bioequivalent medication is not allowed."> + > + ["at169"] = < + text = <"Permitted"> + description = <"Substitution of the Medication with a bioequivalent medication is allowed."> + > + ["id168"] = < + text = <"Comment"> + description = <"Additional narrative about the medication order not captured in other fields."> + > + ["id167"] = < + text = <"Additional details"> + description = <"Additional structured details about the medication order not captured in other fields."> + > + ["id166"] = < + text = <"Goal"> + description = <"Description of the goal."> + > + ["id165"] = < + text = <"Pattern sequence"> + description = <"The intended sequence of this dose pattern within the overall sequence of dose directions."> + > + ["at164"] = < + text = <"Nutritional infusion"> + description = <"The infusion provides parenteral nutrition."> + > + ["id163"] = < + text = <"Override reason"> + description = <"The reason for a maximum dose override."> + > + ["id162"] = < + text = <"Expiry date"> + description = <"The date after which the prescription is no longer valid to be dispensed."> + > + ["id157"] = < + text = <"Conditional administration"> + description = <"Details of dose amount / administration rate dependent on specific conditions."> + > + ["id156"] = < + text = <"Start date"> + description = <"The date after which the medication is permitted to be dispensed for the first time."> + > + ["id155"] = < + text = <"Non-substitution reason"> + description = <"The reason why a medication should not be substituted at dispense."> + > + ["id153"] = < + text = <"Total daily dose unit"> + description = <"The dose unit associated with the total daily dose amount."> + > + ["id152"] = < + text = <"Total daily dose amount"> + description = <"The amount of medication which is intended to be taken each day if the medication is administered as intended."> + > + ["id151"] = < + text = <"Dose goal"> + description = <"Details about the proposed total daily amount of medication."> + > + ["id149"] = < + text = <"Therapeutic intent"> + description = <"The overall therapeutic intent of the medication."> + > + ["id147"] = < + text = <"Maximum amount dose unit"> + description = <"The dose unit for the maximum amount allowed."> + > + ["id146"] = < + text = <"Dose unit"> + description = <"The dose unit of the amount of medication."> + > + ["id145"] = < + text = <"Dose amount"> + description = <"The value of the amount of medication as a real number."> + > + ["id144"] = < + text = <"Preparation details"> + description = <"Structured details about the strength and form of the overall preparation."> + > + ["id140"] = < + text = <"Priority"> + description = <"An indicator of the urgency with which the medication should be dispensed."> + > + ["at139"] = < + text = <"Active medication infusion"> + description = <"The infusion carries an active pharmaceutical ingredient."> + > + ["at138"] = < + text = <"Baseline electrolyte infusion"> + description = <"The infusion provides baseline hydration."> + > + ["id137"] = < + text = <"Infusion purpose"> + description = <"The purpose of the infusion."> + > + ["id136"] = < + text = <"Dosage formula"> + description = <"The formula used to calculate the Dose amount or administration rate where this is dependent on some other factor such as patient weight. For example: 10mg/kg/day."> + > + ["id135"] = < + text = <"Infusion administration rate"> + description = <"The rate at which the medication infusion is to be administered."> + > + ["id134"] = < + text = <"Administration directions"> + description = <"Details about the administration of the medication, vaccine or other therapeutic good."> + > + ["id133"] = < + text = <"Substitution direction"> + description = <"Permission for substitution with a bioequivalent medication."> + > + ["id131"] = < + text = <"Maximum amount"> + description = <"The maximum amount of medication allowed in the allowed period."> + > + ["id130"] = < + text = <"Dispense directions"> + description = <"Directions about the dispensing of the medication, vaccine or other therapeutic good."> + > + ["id114"] = < + text = <"Order details"> + description = <"Details about the intended course of the medication."> + > + ["id113"] = < + text = <"Course summary"> + description = <"Summary information about the medication, such as current status or key dates, generally used in non-prescription contexts."> + > + ["id110"] = < + text = <"Dose amount description"> + description = <"The narrative description of the dose amount of the medication, vaccine or other therapeutic item."> + > + ["id109"] = < + text = <"Administration instruction"> + description = <"An additional instruction directed primarily at the person administering the medication, vaccine or therapeutic good."> + > + ["id108"] = < + text = <"Monitoring instruction"> + description = <"An additional instruction which gives advice on appropriate monitoring of the medication."> + > + ["id107"] = < + text = <"Dispense instruction"> + description = <"An additional instruction directed primarily at the person dispensing the medication, vaccine or therapeutic good."> + > + ["id106"] = < + text = <"Patient guidance"> + description = <"An additional instruction directed primarily at the patient or carers."> + > + ["id103"] = < + text = <"Dose administration duration"> + description = <"The period of time over which a single dose of the medication or vaccine should be administered."> + > + ["id96"] = < + text = <"Delivery device details"> + description = <"Details of the medical device used to assist delivery of the medication."> + > + ["id95"] = < + text = <"Delivery method"> + description = <"The method by which the medication is to be delivered."> + > + ["id94"] = < + text = <"Structured body site"> + description = <"Structured description of the site of administration of the medication, vaccine or therapeutic good."> + > + ["id93"] = < + text = <"Body site"> + description = <"Identification of the site of administration of the medication, vaccine or therapeutic good."> + > + ["id92"] = < + text = <"Route"> + description = <"The route of administration."> + > + ["id91"] = < + text = <"Direction repetition"> + description = <"Structured details about pattern of repetition for each set of daily dose directions."> + > + ["id71"] = < + text = <"Medication item"> + description = <"Identification of the medication, vaccine or other therapeutic item being ordered."> + > + ["id70"] = < + text = <"Authorisation directions"> + description = <"Details of authorisation of the medication, vaccine or other therapeutic good."> + > + ["at69"] = < + text = <"Indefinite - Do not discontinue"> + description = <"The direction should be continued indefinitely and discontinuation is not recommended."> + > + ["at68"] = < + text = <"Indefinite"> + description = <"The direction should be continued indefinitely."> + > + ["id67"] = < + text = <"Direction duration"> + description = <"The duration of this dose direction."> + > + ["id66"] = < + text = <"Dispense amount"> + description = <"Details about the amount of the medication, vaccine or other therapeutic good to be dispensed."> + > + ["id65"] = < + text = <"Exceptional dose override?"> + description = <"Confirmation by the prescriber that the normal dose has been overridden due to exceptional circumstances?"> + > + ["id63"] = < + text = <"Medication safety"> + description = <"Details about medication safety for the medication, vaccine or other therapeutic item."> + > + ["id61"] = < + text = <"Administrations already complete"> + description = <"The number of administrations of the medication, vaccine or other therapeutic good that have been completed, as part of the proposed overall course but prior to the issue of this order."> + > + ["id59"] = < + text = <"Dose pattern"> + description = <"The combination of a medication amount associated with a single medication timing."> + > + ["id58"] = < + text = <"Direction sequence"> + description = <"The intended sequence of this dose direction within the overall sequence of dose directions."> + > + ["id57"] = < + text = <"Dose direction"> + description = <"Details about a dose direction for the medication order."> + > + ["id56"] = < + text = <"Dose timing description"> + description = <"The narrative description of the dose frequency and other timing of the medication, vaccine or other therapeutic item."> + > + ["id54"] = < + text = <"Allowed period"> + description = <"The period of time during which the maximum dose is calculated."> + > + ["id52"] = < + text = <"Maximum dose"> + description = <"Details about the maximum dose allowed over a defined period."> + > + ["id51"] = < + text = <"Duration of course already complete"> + description = <"The time period during which the patient has already been using the medication, vaccine or other therapeutic good, as a part of the proposed overall course but prior to the issue of this order."> + > + ["id48"] = < + text = <"Parsable dose directions"> + description = <"The structured, parsable and computable representation of the dose directions."> + > + ["id45"] = < + text = <"Additional instruction"> + description = <"An additional instruction on how to use the medication, vaccine or other therapeutic good."> + > + ["id38"] = < + text = <"Dose timing"> + description = <"Structured details about the timing of a single use or administration."> + > + ["id19"] = < + text = <"Clinical indication"> + description = <"The clinical reason for ordering the medication, vaccine or other therapeutic good."> + > + ["id17"] = < + text = <"Order stop criterion"> + description = <"A condition which, when met, requires the cessation of administration or use."> + > + ["id14"] = < + text = <"Order stop date/time"> + description = <"The date and optional time to cease use of the medication, vaccine or other therapeutic good."> + > + ["id13"] = < + text = <"Order start date/time"> + description = <"The date and optional time to commence use of the medication, vaccine or other therapeutic good."> + > + ["id12"] = < + text = <"Order start criterion"> + description = <"A condition which, when met, requires the commencement of administration or use."> + > + ["id10"] = < + text = <"Dose directions description"> + description = <"Complete narrative description about how the medication is to be used."> + > + ["id9"] = < + text = <"Extension"> + description = <"Additional information required to capture local content or to align with other reference models/formalisms."> + > + ["id6"] = < + text = <"Dose amount description"> + description = <"The amount and units of the medication, vaccine or other therapeutic good to be used or administered at one time."> + > + ["id5"] = < + text = <"Order identifier"> + description = <"Unique identifier for the medication order."> + > + ["id3"] = < + text = <"Tree"> + description = <"@ internal @"> + > + ["id2"] = < + text = <"Order"> + description = <"Order."> + > + ["id1"] = < + text = <"Medication order"> + description = <"Instructions for use of a medication, vaccine or other therapeutic item."> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + ["at9001"] = + > + > + value_sets = < + ["ac9002"] = < + id = <"ac9002"> + members = <"at68", "at69"> + > + ["ac9004"] = < + id = <"ac9004"> + members = <"at138", "at139", "at164"> + > + ["ac9003"] = < + id = <"ac9003"> + members = <"at169", "at170"> + > + > diff --git a/opt14/src/test/resources/adl2/openEHR-EHR-OBSERVATION.blood_pressure.v1.0.0.adls b/opt14/src/test/resources/adl2/openEHR-EHR-OBSERVATION.blood_pressure.v1.0.0.adls new file mode 100644 index 000000000..c3bc8eeac --- /dev/null +++ b/opt14/src/test/resources/adl2/openEHR-EHR-OBSERVATION.blood_pressure.v1.0.0.adls @@ -0,0 +1,1344 @@ +archetype (adl_version=2.0.6; rm_release=1.1.0; generated) + openEHR-EHR-OBSERVATION.blood_pressure.v1.0.0 + +language + original_language = <[ISO_639-1::en]> + translations = < + ["de"] = < + language = <[ISO_639-1::de]> + author = < + ["name"] = <"Sebastian Garde, Jasmin Buck"> + ["organisation"] = <"Central Queensland University, University of Heidelberg"> + > + > + ["zh-cn"] = < + language = <[ISO_639-1::zh-cn]> + author = < + ["name"] = <"Chunlan Ma"> + ["organisation"] = <"Ocean Informatics"> + > + > + ["ja"] = < + language = <[ISO_639-1::ja]> + author = < + ["name"] = <"Shinji Kobayashi"> + > + > + > + +description + original_author = < + ["name"] = <"Sam Heard"> + ["organisation"] = <"Ocean Informatics"> + ["email"] = <"sam.heard@oceaninformatics.com"> + ["date"] = <"22/03/2006"> + > + other_contributors = <"Koray Atalag, University of Auckland, New Zealand", "Knut Bernstein, MEDIQ, Denmark", "Marja Buur, Medisch Centrum Alkmaar, Netherlands", "Rong Chen, Cambio Healthcare Systems, Sweden", "Beatriz de Faria Leão, Zilics, Brazil", "Paul Donaldson, Nursing Informatics Australia, Australia", "Jose Florez Arango, Universidad de Antioquia, Colombia", "Gerard Freriks, ERC, Netherlands", "Sebastian Garde, Ocean Informatics, Germany", "Anneke Goossen, Results 4 Care, Netherlands", "Sam Heard, Ocean Informatics, Australia", "Karsten Heusser, Hannover Medical School, Germany", "Omer Hotomaroglu, Turkey", "Evelyn Hovenga, EJSH Consulting, Australia", "Derek Hoy, United Kingdom", "Pieter Hummel, Medisch Centrum Alkmaar, Netherlands", "Eugene Igras, IRIS Systems, Inc., Canada", "Sundaresan Jagannathan, Scottish NHS, United Kingdom", "Andrew James, University of Toronto, Canada", "Heather Leslie, Ocean Informatics, Australia (Editor)", "Rikard Lovstrom, Swedish Medical Association, Sweden", "Rohan Martin, Ambulance Victoria, Australia", "Ian McNicoll, Ocean Informatics, United Kingdom", "Jeroen Meintjens, Medisch Centrum Alkmaar, Netherlands", "Udo Müller-Oest, CompuGROUP Software, Germany", "Melvin Reynolds, United Kingdom", "Tony Shannon, NHS, United Kingdom", "Hwei-Yee Tai, Tan Tock Seng Hospital, Singapore", "Stef Verlinden, Vivici, Netherlands", "Soon Ghee Yap, Singapore Health Services Pte Ltd, Singapore"> + lifecycle_state = <"AuthorDraft"> + references = < + ["1"] = <"O'Brien E, Asmar R, Beilin L, et al. European Society of Hypertension recommendations for conventional, ambulatory and home blood pressure measurement. Journal of Hypertension [Internet]. 2003 [cited 2009 Jul 30] ; 21(5):821-848. Available from http://www.bhsoc.org/bp_monitors/ESH_BP_rec.pdf"> + ["2"] = <"Perloff D, Grim C, Flack J, Frohlich ED, Hill M, McDonald M, Morgenstern BZ. Human blood pressure determination by sphygmomanometry. Circulation [Internet]. 1993 [cited 2009 Jul 29] 88 (5): 2460. Available from: http://circ.ahajournals.org/cgi/reprint/88/5/2460"> + > + other_details = < + ["MD5-CAM-1.0.1"] = <"D2C5F2928F1B4D9D717A6BA03CE968DF"> + > + details = < + ["en"] = < + language = <[ISO_639-1::en]> + purpose = <"To record the systemic arterial blood pressure of an individual. "> + keywords = <"observations", "measurement", "bp", "vital signs", "mean arterial pressure", "pulse pressure", "systolic", "diastolic", "RR", "NIBP"> + use = <"Use to record all representations of systemic arterial blood pressure measurement, no matter which method or body location is used to record it. The archetype is intended to capture blood pressure measurements in all clinical scenarios - for example, self-measurement with a home blood pressure machine; an emergency assessment of systolic using palpation and a sphygmomanometer; measurements taken in clinical consultations or during exercise stress testing; and a series of measurements made by a machine in Intensive Care. + There is a rich state model that supports interpretation of measurements through identifying patient position, exercise, confounding factors and angle of a tilt table in research. + Named events have been limited to average over a 24 hour period, however templates can further constrain the default 'any event' to cater for specific requirements for blood pressure measurements such as recording Blood Pressure against specific points in time, or over a range of intervals (+/- mathematical functions)."> + misuse = <"Not to be used for intravenous pressure. + Not to be used for the measurement of arterial blood pressure which is NOT a surrogate for arterial pressure in the systemic circulation eg specific measurement of right Pulmonary artery pressure. + Use OBSERVATION.intravascular_pressure and related specialisations in both of these situations."> + copyright = <"copyright (c) 2009 openEHR Foundation"> + > + ["ja"] = < + language = <[ISO_639-1::ja]> + purpose = <"*To record the systemic blood pressure of a person. The measurement records the systolic and the diastolic pressure by some means suitable for the result to be seen as a surrogate for the general and systemic blood pressure.(en)"> + keywords = <"*observations(en)", "*blood pressure(en)", "*measurement(en)"> + use = <"*All blood pressure measurements are recorded using this archetype. There is a rich state model for use with exercise ECGs and Tilt Table measurements.(en)"> + misuse = <"*Not to be used for intravascular pressure.(en)"> + copyright = <"copyright (c) 2009 openEHR Foundation"> + > + ["de"] = < + language = <[ISO_639-1::de]> + purpose = <"Dient der Dokumentation des systemischen Blutdrucks einer Person. Die Messung zeichnet den systolischen und diastolischen Blutdruck auf geeignete Art und Weise auf, sodass das Resultat der Messung als charakteristisch für den tatsächlichen systemischen Blutdruck angesehen werden kann."> + use = <"Alle Blutdruckmessungen werden unter Zuhilfenahme dieses Archetypen dokumentiert. Der Archetyp beinhaltet ein umfassendes Status-Modell z.B. bei Durchführung von Belastungs-EKGs und Kipptischuntersuchungen."> + misuse = <"Nicht zu Benutzen zur Dokumentation des intravaskulären Drucks."> + copyright = <"copyright (c) 2009 openEHR Foundation"> + > + ["zh-cn"] = < + language = <[ISO_639-1::zh-cn]> + purpose = <"*To record the systemic blood pressure of a person. The measurement records the systolic and the diastolic pressure by some means suitable for the result to be seen as a surrogate for the general and systemic blood pressure.(en)"> + keywords = <"*observations(en)", "*blood pressure(en)", "*measurement(en)"> + use = <"*All blood pressure measurements are recorded using this archetype. There is a rich state model for use with exercise ECGs and Tilt Table measurements.(en)"> + misuse = <"*Not to be used for intravascular pressure.(en)"> + copyright = <"copyright (c) 2009 openEHR Foundation"> + > + > + +definition + OBSERVATION[id1] matches { -- Blood Pressure + data matches { + HISTORY[id2] matches { -- history + events cardinality matches {1..*; unordered} matches { + EVENT[id7] matches { -- any event + data matches { + ITEM_TREE[id4] matches { -- blood pressure + items cardinality matches {0..*; unordered} matches { + ELEMENT[id5] occurrences matches {0..1} matches { -- Systolic + value matches { + DV_QUANTITY[id9009] matches { + property matches {[at9000]} -- Pressure + magnitude matches {|0.0..<1000.0|} + units matches {"mm[Hg]"} + precision matches {0} + } + } + } + ELEMENT[id6] occurrences matches {0..1} matches { -- Diastolic + value matches { + DV_QUANTITY[id9010] matches { + property matches {[at9000]} -- Pressure + magnitude matches {|0.0..<1000.0|} + units matches {"mm[Hg]"} + precision matches {0} + } + } + } + ELEMENT[id1007] occurrences matches {0..1} matches { -- Mean Arterial Pressure + value matches { + DV_QUANTITY[id9011] matches { + property matches {[at9000]} -- Pressure + magnitude matches {|0.0..<1000.0|} + units matches {"mm[Hg]"} + precision matches {0} + } + } + } + ELEMENT[id1008] occurrences matches {0..1} matches { -- Pulse Pressure + value matches { + DV_QUANTITY[id9012] matches { + property matches {[at9000]} -- Pressure + magnitude matches {|0.0..<1000.0|} + units matches {"mm[Hg]"} + precision matches {0} + } + } + } + ELEMENT[id34] occurrences matches {0..1} matches { -- Comment + value matches { + DV_TEXT[id9013] + } + } + } + } + } + state matches { + ITEM_TREE[id8] matches { -- state structure + items cardinality matches {0..*; unordered} matches { + ELEMENT[id9] occurrences matches {0..1} matches { -- Position + value matches { + DV_CODED_TEXT[id9014] matches { + defining_code matches {[ac9001; at1002]} -- Position (synthesised) + } + } + } + ELEMENT[id1053] occurrences matches {0..1} matches { -- Confounding factors + value matches { + DV_TEXT[id9015] + } + } + allow_archetype CLUSTER[id1031] occurrences matches {0..1} matches { -- Exertion + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.level_of_exertion(-[a-zA-Z0-9_]+)*\.v1\..*/} + } + ELEMENT[id1044] occurrences matches {0..1} matches { -- Sleep status + value matches { + DV_CODED_TEXT[id9016] matches { + defining_code matches {[ac9002; at1045]} -- Sleep status (synthesised) + } + } + } + ELEMENT[id1006] occurrences matches {0..1} matches { -- Tilt + value matches { + DV_QUANTITY[id9017] matches { + property matches {[at9003]} -- Angle, plane + magnitude matches {|-90.0..90.0|; 0.0} + units matches {"°"; "°"} + precision matches {0; 0} + } + } + } + } + } + } + } + INTERVAL_EVENT[id1043] occurrences matches {0..1} matches { -- 24 hour average + math_function matches { + DV_CODED_TEXT[id9018] matches { + defining_code matches {[at9004]} -- mean + } + } + width matches { + DV_DURATION[id9019] matches { + value matches {PT24H; PT24H} + } + } + data matches { + use_node ITEM_TREE[id9020] /data[id2]/events[id7]/data[id4] + } + state matches { + use_node ITEM_TREE[id9021] /data[id2]/events[id7]/state[id8] + } + } + } + } + } + protocol matches { + ITEM_TREE[id12] matches { -- list structure + items cardinality matches {0..*; unordered} matches { + ELEMENT[id14] occurrences matches {0..1} matches { -- Cuff size + value matches { + DV_CODED_TEXT[id9022] matches { + defining_code matches {[ac9005]} -- Cuff size (synthesised) + } + } + } + CLUSTER[id1034] occurrences matches {0..1} matches { -- Location + items cardinality matches {1..*; unordered} matches { + ELEMENT[id15] occurrences matches {0..1} matches { -- Location of measurement + value matches { + DV_CODED_TEXT[id9023] matches { + defining_code matches {[ac9006]} -- Location of measurement (synthesised) + } + } + } + ELEMENT[id1035] occurrences matches {0..1} matches { -- Specific location + value matches { + DV_TEXT[id9024] + } + } + } + } + ELEMENT[id1036] occurrences matches {0..1} matches { -- Method + value matches { + DV_CODED_TEXT[id9025] matches { + defining_code matches {[ac9007]} -- Method (synthesised) + } + } + } + ELEMENT[id1039] occurrences matches {0..1} matches { -- Mean Arterial Pressure Formula + value matches { + DV_TEXT[id9026] + } + } + ELEMENT[id1011] occurrences matches {0..1} matches { -- Diastolic endpoint + value matches { + DV_CODED_TEXT[id9027] matches { + defining_code matches {[ac9008]} -- Diastolic endpoint (synthesised) + } + } + } + allow_archetype CLUSTER[id1026] occurrences matches {0..1} matches { -- Device + include + archetype_id/value matches {/openEHR-EHR-CLUSTER\.device(-[a-zA-Z0-9_]+)*\.v1\..*/} + } + } + } + } + } + +terminology + term_definitions = < + ["de"] = < + ["at9000"] = < + text = <"* Pressure (en)"> + description = <"* Pressure (en)"> + > + ["ac9001"] = < + text = <"*Position(en) (synthesised)"> + description = <"*The position of the subject at the time of measurement(en) (synthesised)"> + > + ["ac9002"] = < + text = <"*Sleep status(en) (synthesised)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en) (synthesised)"> + > + ["at9003"] = < + text = <"* Angle, plane (en)"> + description = <"* Angle, plane (en)"> + > + ["at9004"] = < + text = <"* mean (en)"> + description = <"* mean (en)"> + > + ["ac9005"] = < + text = <"*Cuff size(en) (synthesised)"> + description = <"*The size of the cuff used for blood pressure measurement(en) (synthesised)"> + > + ["ac9006"] = < + text = <"*Location of measurement(en) (synthesised)"> + description = <"*Common body locations where blood pressure is recorded(en) (synthesised)"> + > + ["ac9007"] = < + text = <"*New element(en) (synthesised)"> + description = <"**(en) (synthesised)"> + > + ["ac9008"] = < + text = <"*Diastolic endpoint(en) (synthesised)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en) (synthesised)"> + > + ["at1054"] = < + text = <"*Intra-arterial(en)"> + description = <"*Invasive measurement via transducer access line within an artery. Location of the transducer can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["id1053"] = < + text = <"*Confounding factors(en)"> + description = <"*Comment on and record other incidental factors that may be contributing to the blood pressure measurement. For example, level of anxiety or 'white coat syndrome'; pain or fever; changes in atmospheric pressure etc.(en)"> + > + ["at1052"] = < + text = <"*Toe(en)"> + description = <"*A toe of the subject. Identification of the toe can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1046"] = < + text = <"*Sleeping(en)"> + description = <"*Subject is in the natural state of bodily rest(en)"> + > + ["at1045"] = < + text = <"*Alert & awake(en)"> + description = <"*Subject is fully conscious(en)"> + > + ["id1044"] = < + text = <"*Sleep status(en)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en)"> + > + ["id1043"] = < + text = <"*24 hour average (en)"> + description = <"*Estimate of the average blood pressure over a 24 hour period(en)"> + > + ["at1041"] = < + text = <"*Invasive(en)"> + description = <"*Method of measuring blood pressure internally ie involving penetration of the skin and measuring inside blood vessels(en)"> + > + ["at1040"] = < + text = <"*Machine(en)"> + description = <"*Method of measuring blood pressure externally, using a blood pressure machine(en)"> + > + ["id1039"] = < + text = <"*Mean Arterial Pressure Formula(en)"> + description = <"*Formula used to calculate the MAP (if recorded in data)(en)"> + > + ["at1038"] = < + text = <"*Palpation(en)"> + description = <"*Method of measuring blood pressure externally, using palpation (usually of the brachial or radial arteries)(en)"> + > + ["at1037"] = < + text = <"*Auscultation(en)"> + description = <"*Method of measuring blood pressure externally, using a stethoscope and Korotkoff sounds(en)"> + > + ["id1036"] = < + text = <"*New element(en)"> + description = <"**(en)"> + > + ["id1035"] = < + text = <"*Specific location(en)"> + description = <"*Detailed description about the site of the measurement of the blood pressure(en)"> + > + ["id1034"] = < + text = <"*New cluster(en)"> + description = <"**(en)"> + > + ["at1033"] = < + text = <"*Finger(en)"> + description = <"*A finger of the subject. Identification of the finger can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1032"] = < + text = <"*Left ankle(en)"> + description = <"*The left ankle of the subject(en)"> + > + ["id1031"] = < + text = <"*Exertion (en)"> + description = <"*Details about physical activity undertaken at the time of blood pressure measurement(en)"> + > + ["at1027"] = < + text = <"*Right ankle(en)"> + description = <"*The right ankle of the subject(en)"> + > + ["id1026"] = < + text = <"*Device(en)"> + description = <"*Details about sphygmomanometer or other device used to measure the blood pressure(en)"> + > + ["at1022"] = < + text = <"*Left wrist(en)"> + description = <"*The left wrist of the subject(en)"> + > + ["at1021"] = < + text = <"*Right wrist(en)"> + description = <"*The right wrist of the subject(en)"> + > + ["at1020"] = < + text = <"*Neonatal(en)"> + description = <"*A cuff used for a neonate, assuming cuff is the appropriate size for maturity and birthweight of the neonate(en)"> + > + ["at1019"] = < + text = <"*Infant(en)"> + description = <"*A cuff used for infants - bladder approx 5cm x 15cm(en)"> + > + ["at1015"] = < + text = <"*Lying with tilt to left(en)"> + description = <"*Lying flat with some lateral tilt, usually angled towards the left side. Commonly required in the last trimester of pregnancy to relieve aortocaval compression.(en)"> + > + ["at1013"] = < + text = <"*Phase V(en)"> + description = <"*The fifth Korotkoff sound is identified by absence of sounds as the cuff pressure drops below the diastolic blood pressure(en)"> + > + ["at1012"] = < + text = <"*Phase IV(en)"> + description = <"*The fourth Korotkoff sound is identified as an abrupt muffling of sounds(en)"> + > + ["id1011"] = < + text = <"*Diastolic endpoint(en)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en)"> + > + ["at1010"] = < + text = <"*Paediatric/Child(en)"> + description = <"*A cuff that is appropriate for a child or adult with a thin arm - bladder approx 8cm x 21cm.(en)"> + > + ["at1009"] = < + text = <"*Small Adult(en)"> + description = <"*A cuff used for a small adult - bladder approx 10cm x 24cm(en)"> + > + ["id1008"] = < + text = <"Pulsdruck"> + description = <"Der Abstand zwischen dem systolischen und dem diastolischen Blutdruckwert. Beschreibt die Druckwelle, die mit jedem Herzschlag durch das Blutgefäßsystem läuft."> + > + ["id1007"] = < + text = <"*Mean Arterial Pressure(en)"> + description = <"*The average arterial pressure that occurs over the entire course of the heart contraction and relaxation cycle. (en)"> + > + ["id1006"] = < + text = <"*Tilt(en)"> + description = <"*The craniocaudal tilt of the surface on which the person is lying at the time of measurement(en)"> + > + ["at1004"] = < + text = <"*Lying(en)"> + description = <"*Lying flat at the time of blood pressure measurement.(en)"> + > + ["at1003"] = < + text = <"Zurückgelehnt"> + description = <"Patient 45 Grad zurückgelehnt zum Zeitpunkt der Blutdruckmessung"> + > + ["at1002"] = < + text = <"Sitzend"> + description = <"Sitzend zum Zeitpunkt der Blutdruckmessung"> + > + ["at1001"] = < + text = <"Stehend"> + description = <"Stehend zum Zeitpunkt der Blutdruckmessung"> + > + ["id34"] = < + text = <"Kommentar"> + description = <"Kommentar zur Blutdruckmessung"> + > + ["at29"] = < + text = <"Linkes Bein"> + description = <"Linkes Bein des Patienten"> + > + ["at28"] = < + text = <"*Right leg(en)"> + description = <"*The right leg of the person(en)"> + > + ["at27"] = < + text = <"Linker Arm"> + description = <"Der linke Arm der Person"> + > + ["at26"] = < + text = <"Rechter Arm"> + description = <"Der rechte Arm der Person"> + > + ["at18"] = < + text = <"*Adult(en)"> + description = <"*A cuff that is standard for an adult - bladder approx 13cm x 30cm(en)"> + > + ["at17"] = < + text = <"*Large Adult(en)"> + description = <"*A cuff for adults with larger arms - bladder approx 16cm x 38cm(en)"> + > + ["at16"] = < + text = <"*Adult Thigh(en)"> + description = <"*A cuff used for an adult thigh - bladder approx 20cm x 42cm(en)"> + > + ["id15"] = < + text = <"*Location of measurement(en)"> + description = <"*Common body locations where blood pressure is recorded(en)"> + > + ["id14"] = < + text = <"*Cuff size(en)"> + description = <"*The size of the cuff used for blood pressure measurement(en)"> + > + ["id12"] = < + text = <"Listenstruktur"> + description = <"Listenstruktur"> + > + ["id9"] = < + text = <"*Position(en)"> + description = <"*The position of the subject at the time of measurement(en)"> + > + ["id8"] = < + text = <"*state structure(en)"> + description = <"*@ internal @(en)"> + > + ["id7"] = < + text = <"*any event(en)"> + description = <"*Default event(en)"> + > + ["id6"] = < + text = <"Diastolisch"> + description = <"Der minimale systemische arterielle Blutdruck eines Zyklus - gemessen in der diastolischen oder Entspannungsphase des Herzens."> + > + ["id5"] = < + text = <"Systolisch"> + description = <"Der höchste arterielle Blutdruck eines Zyklus - gemessen in der systolischen oder Kontraktionsphase des Herzens."> + > + ["id4"] = < + text = <"Blutdruck"> + description = <"*@ internal @(en)"> + > + ["id2"] = < + text = <"Historie"> + description = <"Historie"> + > + ["id1"] = < + text = <"*Blood Pressure(en)"> + description = <"*The local measurement of arterial blood pressure which is a surrogate for arterial pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm.(en)"> + > + > + ["ja"] = < + ["at9000"] = < + text = <"圧力"> + description = <"圧力"> + > + ["ac9001"] = < + text = <"*Position(en) (synthesised)"> + description = <"*The position of the subject at the time of measurement(en) (synthesised)"> + > + ["ac9002"] = < + text = <"*Sleep status(en) (synthesised)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en) (synthesised)"> + > + ["at9003"] = < + text = <"平面角"> + description = <"平面角"> + > + ["at9004"] = < + text = <"平均値"> + description = <"平均値"> + > + ["ac9005"] = < + text = <"*Cuff size(en) (synthesised)"> + description = <"*The size of the cuff used for blood pressure measurement(en) (synthesised)"> + > + ["ac9006"] = < + text = <"*Location of measurement(en) (synthesised)"> + description = <"*Common body locations where blood pressure is recorded(en) (synthesised)"> + > + ["ac9007"] = < + text = <"*New element(en) (synthesised)"> + description = <"**(en) (synthesised)"> + > + ["ac9008"] = < + text = <"*Diastolic endpoint(en) (synthesised)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en) (synthesised)"> + > + ["at1054"] = < + text = <"*Intra-arterial(en)"> + description = <"*Invasive measurement via transducer access line within an artery. Location of the transducer can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["id1053"] = < + text = <"*Confounding factors(en)"> + description = <"*Comment on and record other incidental factors that may be contributing to the blood pressure measurement. For example, level of anxiety or 'white coat syndrome'; pain or fever; changes in atmospheric pressure etc.(en)"> + > + ["at1052"] = < + text = <"*Toe(en)"> + description = <"*A toe of the subject. Identification of the toe can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1046"] = < + text = <"*Sleeping(en)"> + description = <"*Subject is in the natural state of bodily rest(en)"> + > + ["at1045"] = < + text = <"*Alert & awake(en)"> + description = <"*Subject is fully conscious(en)"> + > + ["id1044"] = < + text = <"*Sleep status(en)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en)"> + > + ["id1043"] = < + text = <"*24 hour average (en)"> + description = <"*Estimate of the average blood pressure over a 24 hour period(en)"> + > + ["at1041"] = < + text = <"*Invasive(en)"> + description = <"*Method of measuring blood pressure internally ie involving penetration of the skin and measuring inside blood vessels(en)"> + > + ["at1040"] = < + text = <"*Machine(en)"> + description = <"*Method of measuring blood pressure externally, using a blood pressure machine(en)"> + > + ["id1039"] = < + text = <"*Mean Arterial Pressure Formula(en)"> + description = <"*Formula used to calculate the MAP (if recorded in data)(en)"> + > + ["at1038"] = < + text = <"*Palpation(en)"> + description = <"*Method of measuring blood pressure externally, using palpation (usually of the brachial or radial arteries)(en)"> + > + ["at1037"] = < + text = <"*Auscultation(en)"> + description = <"*Method of measuring blood pressure externally, using a stethoscope and Korotkoff sounds(en)"> + > + ["id1036"] = < + text = <"*New element(en)"> + description = <"**(en)"> + > + ["id1035"] = < + text = <"*Specific location(en)"> + description = <"*Detailed description about the site of the measurement of the blood pressure(en)"> + > + ["id1034"] = < + text = <"*New cluster(en)"> + description = <"**(en)"> + > + ["at1033"] = < + text = <"*Finger(en)"> + description = <"*A finger of the subject. Identification of the finger can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1032"] = < + text = <"*Left ankle(en)"> + description = <"*The left ankle of the subject(en)"> + > + ["id1031"] = < + text = <"*Exertion (en)"> + description = <"*Details about physical activity undertaken at the time of blood pressure measurement(en)"> + > + ["at1027"] = < + text = <"*Right ankle(en)"> + description = <"*The right ankle of the subject(en)"> + > + ["id1026"] = < + text = <"*Device(en)"> + description = <"*Details about sphygmomanometer or other device used to measure the blood pressure(en)"> + > + ["at1022"] = < + text = <"*Left wrist(en)"> + description = <"*The left wrist of the subject(en)"> + > + ["at1021"] = < + text = <"*Right wrist(en)"> + description = <"*The right wrist of the subject(en)"> + > + ["at1020"] = < + text = <"*Neonatal(en)"> + description = <"*A cuff used for a neonate, assuming cuff is the appropriate size for maturity and birthweight of the neonate(en)"> + > + ["at1019"] = < + text = <"*Infant(en)"> + description = <"*A cuff used for infants - bladder approx 5cm x 15cm(en)"> + > + ["at1015"] = < + text = <"*Lying with tilt to left(en)"> + description = <"*Lying flat with some lateral tilt, usually angled towards the left side. Commonly required in the last trimester of pregnancy to relieve aortocaval compression.(en)"> + > + ["at1013"] = < + text = <"*Phase V(en)"> + description = <"*The fifth Korotkoff sound is identified by absence of sounds as the cuff pressure drops below the diastolic blood pressure(en)"> + > + ["at1012"] = < + text = <"*Phase IV(en)"> + description = <"*The fourth Korotkoff sound is identified as an abrupt muffling of sounds(en)"> + > + ["id1011"] = < + text = <"*Diastolic endpoint(en)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en)"> + > + ["at1010"] = < + text = <"*Paediatric/Child(en)"> + description = <"*A cuff that is appropriate for a child or adult with a thin arm - bladder approx 8cm x 21cm.(en)"> + > + ["at1009"] = < + text = <"*Small Adult(en)"> + description = <"*A cuff used for a small adult - bladder approx 10cm x 24cm(en)"> + > + ["id1008"] = < + text = <"脈圧"> + description = <"1回の収縮サイクルでの血圧の変動"> + > + ["id1007"] = < + text = <"*Mean Arterial Pressure(en)"> + description = <"*The average arterial pressure that occurs over the entire course of the heart contraction and relaxation cycle. (en)"> + > + ["id1006"] = < + text = <"*Tilt(en)"> + description = <"*The craniocaudal tilt of the surface on which the person is lying at the time of measurement(en)"> + > + ["at1004"] = < + text = <"*Lying(en)"> + description = <"*Lying flat at the time of blood pressure measurement.(en)"> + > + ["at1003"] = < + text = <"斜位"> + description = <"*Person reclining at 45 degrees at the time of blood pressure measurement(en)"> + > + ["at1002"] = < + text = <"座位"> + description = <"*Sitting on bed or chair at the time of blood pressure measurement(en)"> + > + ["at1001"] = < + text = <"立位"> + description = <"*Standing at the time of blood pressure measurement(en)"> + > + ["id34"] = < + text = <"コメント"> + description = <"血圧測定のコメント"> + > + ["at29"] = < + text = <"左脚"> + description = <"*The left leg of the person(en)"> + > + ["at28"] = < + text = <"*Right leg(en)"> + description = <"*The right leg of the person(en)"> + > + ["at27"] = < + text = <"左腕"> + description = <"*The left arm of the person(en)"> + > + ["at26"] = < + text = <"右腕"> + description = <"*The right arm of the person(en)"> + > + ["at18"] = < + text = <"*Adult(en)"> + description = <"*A cuff that is standard for an adult - bladder approx 13cm x 30cm(en)"> + > + ["at17"] = < + text = <"*Large Adult(en)"> + description = <"*A cuff for adults with larger arms - bladder approx 16cm x 38cm(en)"> + > + ["at16"] = < + text = <"*Adult thigh(en)"> + description = <"*A cuff used for an adult thigh - bladder approx 20cm x 42cm(en)"> + > + ["id15"] = < + text = <"*Location of measurement(en)"> + description = <"*Common body locations where blood pressure is recorded(en)"> + > + ["id14"] = < + text = <"*Cuff size(en)"> + description = <"*The size of the cuff used for blood pressure measurement(en)"> + > + ["id12"] = < + text = <"*list structure(en)"> + description = <"*list structure(en)"> + > + ["id9"] = < + text = <"*Position(en)"> + description = <"*The position of the subject at the time of measurement(en)"> + > + ["id8"] = < + text = <"*state structure(en)"> + description = <"*@ internal @(en)"> + > + ["id7"] = < + text = <"*any event(en)"> + description = <"*Default event(en)"> + > + ["id6"] = < + text = <"拡張期"> + description = <"1つ以上の脈の間で最低値を示す全身の動脈圧 - 心機図の拡張期で測定される"> + > + ["id5"] = < + text = <"収縮期"> + description = <"1つ以上の脈の間で最高値を示す全身の動脈圧 - 心機図の収縮期で測定される"> + > + ["id4"] = < + text = <"血圧"> + description = <"*@ internal @(en)"> + > + ["id2"] = < + text = <"*history(en)"> + description = <"*history Structural node(en)"> + > + ["id1"] = < + text = <"*Blood Pressure(en)"> + description = <"*The local measurement of arterial blood pressure which is a surrogate for arterial pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm.(en)"> + > + > + ["en"] = < + ["at9000"] = < + text = <"Pressure"> + description = <"Pressure"> + > + ["ac9001"] = < + text = <"Position (synthesised)"> + description = <"The position of the subject at the time of measurement. (synthesised)"> + > + ["ac9002"] = < + text = <"Sleep status (synthesised)"> + description = <"Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (synthesised)"> + > + ["at9003"] = < + text = <"Angle, plane"> + description = <"Angle, plane"> + > + ["at9004"] = < + text = <"mean"> + description = <"mean"> + > + ["ac9005"] = < + text = <"Cuff size (synthesised)"> + description = <"The size of the cuff used for blood pressure measurement. (synthesised)"> + > + ["ac9006"] = < + text = <"Location of measurement (synthesised)"> + description = <"Common body sites where blood pressure is recorded. (synthesised)"> + > + ["ac9007"] = < + text = <"Method (synthesised)"> + description = <"Method of measurement of blood pressure. (synthesised)"> + > + ["ac9008"] = < + text = <"Diastolic endpoint (synthesised)"> + description = <"Record which Korotkoff sound is used for determining diastolic pressure using auscultative method. (synthesised)"> + > + ["at1054"] = < + text = <"Intra-arterial"> + description = <"Invasive measurement via transducer access line within an artery. Location of the transducer can be recorded in 'Specific Location' data element, if required."> + > + ["id1053"] = < + text = <"Confounding factors"> + description = <"Comment on and record other incidental factors that may be contributing to the blood pressure measurement. For example, level of anxiety or 'white coat syndrome'; pain or fever; changes in atmospheric pressure etc."> + > + ["at1052"] = < + text = <"Toe"> + description = <"A toe of the subject. Identification of the toe can be recorded in 'Specific Location' data element, if required."> + > + ["at1046"] = < + text = <"Sleeping"> + description = <"Subject is in the natural state of bodily rest."> + > + ["at1045"] = < + text = <"Alert & awake"> + description = <"Subject is fully conscious."> + > + ["id1044"] = < + text = <"Sleep status"> + description = <"Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. "> + > + ["id1043"] = < + text = <"24 hour average "> + description = <"Estimate of the average blood pressure over a 24 hour period."> + > + ["at1041"] = < + text = <"Invasive"> + description = <"Method of measuring blood pressure internally ie involving penetration of the skin and measuring inside blood vessels."> + > + ["at1040"] = < + text = <"Machine"> + description = <"Method of measuring blood pressure externally, using a blood pressure machine."> + > + ["id1039"] = < + text = <"Mean Arterial Pressure Formula"> + description = <"Formula used to calculate the MAP (if recorded in data)."> + > + ["at1038"] = < + text = <"Palpation"> + description = <"Method of measuring blood pressure externally, using palpation (usually of the brachial or radial arteries)."> + > + ["at1037"] = < + text = <"Auscultation"> + description = <"Method of measuring blood pressure externally, using a stethoscope and Korotkoff sounds."> + > + ["id1036"] = < + text = <"Method"> + description = <"Method of measurement of blood pressure."> + > + ["id1035"] = < + text = <"Specific location"> + description = <"Specific details about the body site where blood pressure is recorded."> + > + ["id1034"] = < + text = <"Location"> + description = <"Body location where blood pressure is measured. Use 'Location of measurement' to select from common sites. Use 'Specific location' to record more specific details or a site that is not in the common set or to refer to an external terminology."> + > + ["at1033"] = < + text = <"Finger"> + description = <"A finger of the subject. Identification of the finger can be recorded in 'Specific Location' data element, if required."> + > + ["at1032"] = < + text = <"Left ankle"> + description = <"The left ankle of the subject."> + > + ["id1031"] = < + text = <"Exertion "> + description = <"Details about physical activity undertaken at the time of blood pressure.measurement."> + > + ["at1027"] = < + text = <"Right ankle"> + description = <"The right ankle of the subject."> + > + ["id1026"] = < + text = <"Device"> + description = <"Details about sphygmomanometer or other device used to measure the blood pressure."> + > + ["at1022"] = < + text = <"Left wrist"> + description = <"The left wrist of the subject."> + > + ["at1021"] = < + text = <"Right wrist"> + description = <"The right wrist of the subject."> + > + ["at1020"] = < + text = <"Neonatal"> + description = <"A cuff used for a neonate, assuming cuff is the appropriate size for maturity and birthweight of the neonate."> + > + ["at1019"] = < + text = <"Infant"> + description = <"A cuff used for infants - bladder approx 5cm x 15cm."> + > + ["at1015"] = < + text = <"Lying with tilt to left"> + description = <"Lying flat with some lateral tilt, usually angled towards the left side. Commonly required in the last trimester of pregnancy to relieve aortocaval compression."> + > + ["at1013"] = < + text = <"Phase V"> + description = <"The fifth Korotkoff sound is identified by absence of sounds as the cuff pressure drops below the diastolic blood pressure."> + > + ["at1012"] = < + text = <"Phase IV"> + description = <"The fourth Korotkoff sound is identified as an abrupt muffling of sounds."> + > + ["id1011"] = < + text = <"Diastolic endpoint"> + description = <"Record which Korotkoff sound is used for determining diastolic pressure using auscultative method."> + > + ["at1010"] = < + text = <"Paediatric/Child"> + description = <"A cuff that is appropriate for a child or adult with a thin arm - bladder approx 8cm x 21cm."> + > + ["at1009"] = < + text = <"Small Adult"> + description = <"A cuff used for a small adult - bladder approx 10cm x 24cm."> + > + ["id1008"] = < + text = <"Pulse Pressure"> + description = <"The difference between the systolic and diastolic pressure."> + > + ["id1007"] = < + text = <"Mean Arterial Pressure"> + description = <"The average arterial pressure that occurs over the entire course of the heart contraction and relaxation cycle."> + > + ["id1006"] = < + text = <"Tilt"> + description = <"The craniocaudal tilt of the surface on which the person is lying at the time of measurement."> + > + ["at1004"] = < + text = <"Lying"> + description = <"Lying flat at the time of blood pressure measurement."> + > + ["at1003"] = < + text = <"Reclining"> + description = <"Reclining at the time of blood pressure measurement."> + > + ["at1002"] = < + text = <"Sitting"> + description = <"Sitting (for example on bed or chair) at the time of blood pressure measurement."> + > + ["at1001"] = < + text = <"Standing"> + description = <"Standing at the time of blood pressure measurement."> + > + ["id34"] = < + text = <"Comment"> + description = <"Comment on blood pressure measurement."> + > + ["at29"] = < + text = <"Left thigh"> + description = <"The left thigh of the person."> + > + ["at28"] = < + text = <"Right thigh"> + description = <"The right thigh of the person."> + > + ["at27"] = < + text = <"Left arm"> + description = <"The left arm of the person."> + > + ["at26"] = < + text = <"Right arm"> + description = <"The right arm of the person."> + > + ["at18"] = < + text = <"Adult"> + description = <"A cuff that is standard for an adult - bladder approx 13cm x 30cm."> + > + ["at17"] = < + text = <"Large Adult"> + description = <"A cuff for adults with larger arms - bladder approx 16cm x 38cm."> + > + ["at16"] = < + text = <"Adult Thigh"> + description = <"A cuff used for an adult thigh - bladder approx 20cm x 42cm."> + > + ["id15"] = < + text = <"Location of measurement"> + description = <"Common body sites where blood pressure is recorded."> + > + ["id14"] = < + text = <"Cuff size"> + description = <"The size of the cuff used for blood pressure measurement. "> + > + ["id12"] = < + text = <"list structure"> + description = <"list structure"> + > + ["id9"] = < + text = <"Position"> + description = <"The position of the subject at the time of measurement."> + > + ["id8"] = < + text = <"state structure"> + description = <"@ internal @"> + > + ["id7"] = < + text = <"any event"> + description = <"Default event"> + > + ["id6"] = < + text = <"Diastolic"> + description = <"Minimum systemic arterial blood pressure - measured in the diastolic or relaxation phase of the heart cycle."> + > + ["id5"] = < + text = <"Systolic"> + description = <"Peak systemic arterial blood pressure - measured in systolic or contraction phase of the heart cycle."> + > + ["id4"] = < + text = <"blood pressure"> + description = <"@ internal @"> + > + ["id2"] = < + text = <"history"> + description = <"history Structural node"> + > + ["id1"] = < + text = <"Blood Pressure"> + description = <"The local measurement of arterial blood pressure which is a surrogate for arterial. pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm."> + > + > + ["zh-cn"] = < + ["at9000"] = < + text = <"* Pressure (en)"> + description = <"* Pressure (en)"> + > + ["ac9001"] = < + text = <"*Position(en) (synthesised)"> + description = <"*The position of the subject at the time of measurement(en) (synthesised)"> + > + ["ac9002"] = < + text = <"*Sleep status(en) (synthesised)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en) (synthesised)"> + > + ["at9003"] = < + text = <"* Angle, plane (en)"> + description = <"* Angle, plane (en)"> + > + ["at9004"] = < + text = <"* mean (en)"> + description = <"* mean (en)"> + > + ["ac9005"] = < + text = <"*Cuff size(en) (synthesised)"> + description = <"*The size of the cuff used for blood pressure measurement(en) (synthesised)"> + > + ["ac9006"] = < + text = <"*Location of measurement(en) (synthesised)"> + description = <"*Common body locations where blood pressure is recorded(en) (synthesised)"> + > + ["ac9007"] = < + text = <"*New element(en) (synthesised)"> + description = <"**(en) (synthesised)"> + > + ["ac9008"] = < + text = <"*Diastolic endpoint(en) (synthesised)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en) (synthesised)"> + > + ["at1054"] = < + text = <"*Intra-arterial(en)"> + description = <"*Invasive measurement via transducer access line within an artery. Location of the transducer can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["id1053"] = < + text = <"*Confounding factors(en)"> + description = <"*Comment on and record other incidental factors that may be contributing to the blood pressure measurement. For example, level of anxiety or 'white coat syndrome'; pain or fever; changes in atmospheric pressure etc.(en)"> + > + ["at1052"] = < + text = <"*Toe(en)"> + description = <"*A toe of the subject. Identification of the toe can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1046"] = < + text = <"*Sleeping(en)"> + description = <"*Subject is in the natural state of bodily rest(en)"> + > + ["at1045"] = < + text = <"*Alert & awake(en)"> + description = <"*Subject is fully conscious(en)"> + > + ["id1044"] = < + text = <"*Sleep status(en)"> + description = <"*Sleep status - supports interpretation of 24 hour ambulatory blood pressure records. (en)"> + > + ["id1043"] = < + text = <"*24 hour average (en)"> + description = <"*Estimate of the average blood pressure over a 24 hour period(en)"> + > + ["at1041"] = < + text = <"*Invasive(en)"> + description = <"*Method of measuring blood pressure internally ie involving penetration of the skin and measuring inside blood vessels(en)"> + > + ["at1040"] = < + text = <"*Machine(en)"> + description = <"*Method of measuring blood pressure externally, using a blood pressure machine(en)"> + > + ["id1039"] = < + text = <"*Mean Arterial Pressure Formula(en)"> + description = <"*Formula used to calculate the MAP (if recorded in data)(en)"> + > + ["at1038"] = < + text = <"*Palpation(en)"> + description = <"*Method of measuring blood pressure externally, using palpation (usually of the brachial or radial arteries)(en)"> + > + ["at1037"] = < + text = <"*Auscultation(en)"> + description = <"*Method of measuring blood pressure externally, using a stethoscope and Korotkoff sounds(en)"> + > + ["id1036"] = < + text = <"*New element(en)"> + description = <"**(en)"> + > + ["id1035"] = < + text = <"*Specific location(en)"> + description = <"*Detailed description about the site of the measurement of the blood pressure(en)"> + > + ["id1034"] = < + text = <"*New cluster(en)"> + description = <"**(en)"> + > + ["at1033"] = < + text = <"*Finger(en)"> + description = <"*A finger of the subject. Identification of the finger can be recorded in 'Specific Location' data element, if required.(en)"> + > + ["at1032"] = < + text = <"*Left ankle(en)"> + description = <"*The left ankle of the subject(en)"> + > + ["id1031"] = < + text = <"*Exertion (en)"> + description = <"*Details about physical activity undertaken at the time of blood pressure measurement(en)"> + > + ["at1027"] = < + text = <"*Right ankle(en)"> + description = <"*The right ankle of the subject(en)"> + > + ["id1026"] = < + text = <"*Device(en)"> + description = <"*Details about sphygmomanometer or other device used to measure the blood pressure(en)"> + > + ["at1022"] = < + text = <"*Left wrist(en)"> + description = <"*The left wrist of the subject(en)"> + > + ["at1021"] = < + text = <"*Right wrist(en)"> + description = <"*The right wrist of the subject(en)"> + > + ["at1020"] = < + text = <"*Neonatal(en)"> + description = <"*A cuff used for a neonate, assuming cuff is the appropriate size for maturity and birthweight of the neonate(en)"> + > + ["at1019"] = < + text = <"*Infant(en)"> + description = <"*A cuff used for infants - bladder approx 5cm x 15cm(en)"> + > + ["at1015"] = < + text = <"*Lying with tilt to left(en)"> + description = <"*Lying flat with some lateral tilt, usually angled towards the left side. Commonly required in the last trimester of pregnancy to relieve aortocaval compression.(en)"> + > + ["at1013"] = < + text = <"*Phase V(en)"> + description = <"*The fifth Korotkoff sound is identified by absence of sounds as the cuff pressure drops below the diastolic blood pressure(en)"> + > + ["at1012"] = < + text = <"*Phase IV(en)"> + description = <"*The fourth Korotkoff sound is identified as an abrupt muffling of sounds(en)"> + > + ["id1011"] = < + text = <"*Diastolic endpoint(en)"> + description = <"*Record which Korotkoff sound is used for determining diastolic pressure using auscultative method(en)"> + > + ["at1010"] = < + text = <"*Paediatric/Child(en)"> + description = <"*A cuff that is appropriate for a child or adult with a thin arm - bladder approx 8cm x 21cm.(en)"> + > + ["at1009"] = < + text = <"*Small Adult(en)"> + description = <"*A cuff used for a small adult - bladder approx 10cm x 24cm(en)"> + > + ["id1008"] = < + text = <"脉压"> + description = <"*The variation in pressure over one contraction cycle(en)"> + > + ["id1007"] = < + text = <"*Mean Arterial Pressure(en)"> + description = <"*The average arterial pressure that occurs over the entire course of the heart contraction and relaxation cycle. (en)"> + > + ["id1006"] = < + text = <"*Tilt(en)"> + description = <"*The craniocaudal tilt of the surface on which the person is lying at the time of measurement(en)"> + > + ["at1004"] = < + text = <"*Lying(en)"> + description = <"*Lying flat at the time of blood pressure measurement.(en)"> + > + ["at1003"] = < + text = <"侧卧位"> + description = <"测量血压时身体处于45度角侧卧位"> + > + ["at1002"] = < + text = <"坐位"> + description = <"测量血压时身体处于坐位"> + > + ["at1001"] = < + text = <"立位"> + description = <"测量血压时身体处于站立体位"> + > + ["id34"] = < + text = <"注释"> + description = <"有关血压值的注释"> + > + ["at29"] = < + text = <"左腿"> + description = <"被测试者左下肢"> + > + ["at28"] = < + text = <"*Right leg(en)"> + description = <"*The right leg of the person(en)"> + > + ["at27"] = < + text = <"左臂"> + description = <"被测试者左臂"> + > + ["at26"] = < + text = <"右臂"> + description = <"被测试者右臂"> + > + ["at18"] = < + text = <"*Adult(en)"> + description = <"*A cuff that is standard for an adult - bladder approx 13cm x 30cm(en)"> + > + ["at17"] = < + text = <"*Large Adult(en)"> + description = <"*A cuff for adults with larger arms - bladder approx 16cm x 38cm(en)"> + > + ["at16"] = < + text = <"*Adult Thigh(en)"> + description = <"*A cuff used for an adult thigh - bladder approx 20cm x 42cm(en)"> + > + ["id15"] = < + text = <"*Location of measurement(en)"> + description = <"*Common body locations where blood pressure is recorded(en)"> + > + ["id14"] = < + text = <"*Cuff size(en)"> + description = <"*The size of the cuff used for blood pressure measurement(en)"> + > + ["id12"] = < + text = <"*list structure(en)"> + description = <"*list structure(en)"> + > + ["id9"] = < + text = <"*Position(en)"> + description = <"*The position of the subject at the time of measurement(en)"> + > + ["id8"] = < + text = <"*state structure(en)"> + description = <"*@ internal @(en)"> + > + ["id7"] = < + text = <"*any event(en)"> + description = <"*Default event(en)"> + > + ["id6"] = < + text = <"舒张压"> + description = <"一个血液循环周期中,系统性动脉血压最低值。 舒张期血压"> + > + ["id5"] = < + text = <"收缩压"> + description = <"一个血液循环周期中,系统性动脉血压高峰值。 收缩期血压"> + > + ["id4"] = < + text = <"血压"> + description = <"*@ internal @(en)"> + > + ["id2"] = < + text = <"*history(en)"> + description = <"*history Structural node(en)"> + > + ["id1"] = < + text = <"*Blood Pressure(en)"> + description = <"*The local measurement of arterial blood pressure which is a surrogate for arterial pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm.(en)"> + > + > + > + term_bindings = < + ["openehr"] = < + ["at9000"] = + ["at9003"] = + ["at9004"] = + > + ["SNOMED-CT"] = < + ["id1"] = + ["id5"] = + ["id6"] = + ["id14"] = + > + > + value_sets = < + ["ac9008"] = < + id = <"ac9008"> + members = <"at1012", "at1013"> + > + ["ac9007"] = < + id = <"ac9007"> + members = <"at1037", "at1038", "at1040", "at1041"> + > + ["ac9002"] = < + id = <"ac9002"> + members = <"at1045", "at1046"> + > + ["ac9001"] = < + id = <"ac9001"> + members = <"at1001", "at1002", "at1003", "at1004", "at1015"> + > + ["ac9006"] = < + id = <"ac9006"> + members = <"at26", "at27", "at28", "at29", "at1021", "at1022", "at1027", "at1032", "at1033", "at1052", "at1054"> + > + ["ac9005"] = < + id = <"ac9005"> + members = <"at16", "at17", "at18", "at1009", "at1010", "at1019", "at1020"> + > + > diff --git a/opt14/src/test/resources/ePrescription.opt b/opt14/src/test/resources/ePrescription.opt new file mode 100644 index 000000000..493d624d9 --- /dev/null +++ b/opt14/src/test/resources/ePrescription.opt @@ -0,0 +1,5988 @@ + + + \ No newline at end of file From 3b1ca91f84de73866f99ee6c2145dd16e977569d Mon Sep 17 00:00:00 2001 From: Pieter Bos Date: Tue, 21 Sep 2021 12:59:59 +0200 Subject: [PATCH 36/36] Fix rm overlay conversion, improve serialization in test --- .../com/nedap/archie/opt14/Opt14Converter.java | 3 ++- .../com/nedap/archie/opt14/Opt14PathConverter.java | 14 +++++++------- .../com/nedap/archie/opt14/TConstraintApplier.java | 1 + .../com/nedap/archie/opt14/TViewConverter.java | 12 ++++++++++-- .../com/nedap/archie/opt14/Opt14ConverterTest.java | 4 ++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java index e17951ad2..50492e93d 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14Converter.java @@ -67,6 +67,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA template.setParentArchetypeId(opt14.getDefinition().getArchetypeId().getValue()); template.setTerminology(opt2.getTerminology()); AnnotationsConverter.convertAnnotations(opt14, opt2); + template.setRmOverlay(opt2.getRmOverlay()); if(opt14.getUid() != null) { template.setUid(opt14.getUid().getValue()); } @@ -103,7 +104,7 @@ public ADL2ConversionResultList convert(OPERATIONALTEMPLATE opt14, InMemoryFullA try { OperationalTemplate generatedOpt2 = (OperationalTemplate) new Flattener(adl2Archetypes, metaModels, FlattenerConfiguration.forOperationalTemplate()).flatten(convertedTemplate); - new Opt14PathConverter().convertPaths(convertedTemplate, opt2); + new Opt14PathConverter().convertPaths(convertedTemplate, generatedOpt2); } catch (Exception e) { converted.getConversionResults().get(0).getLog().addError(Opt14ConversionMessage.PATH_CONVERSION_ERROR, e.getMessage()); } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java index 9d261f2ca..16ee27d2f 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/Opt14PathConverter.java @@ -5,20 +5,16 @@ import com.nedap.archie.aom.CArchetypeRoot; import com.nedap.archie.aom.CAttribute; import com.nedap.archie.aom.CComplexObject; -import com.nedap.archie.aom.CComplexObjectProxy; import com.nedap.archie.aom.CObject; import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.aom.Template; import com.nedap.archie.aom.TemplateOverlay; import com.nedap.archie.aom.rmoverlay.RmAttributeVisibility; import com.nedap.archie.aom.utils.AOMUtils; -import com.nedap.archie.flattener.ArchetypeHRIDMap; import com.nedap.archie.paths.PathSegment; import com.nedap.archie.paths.PathUtil; import com.nedap.archie.query.APathQuery; -import com.nedap.archie.query.ComplexObjectProxyReplacement; import com.nedap.archie.query.PartialMatch; -import com.nedap.archie.rm.archetyped.Link; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -42,7 +38,7 @@ public class Opt14PathConverter { public void convertPaths(Template template, OperationalTemplate opt) { this.template = template; if(template.getRmOverlay() != null && template.getRmOverlay().getRmVisibility() != null) { - Map newRmVisibility = template.getRmOverlay().getRmVisibility(); + Map newRmVisibility = new LinkedHashMap<>(); Map rmVisibility = template.getRmOverlay().getRmVisibility(); for(String path:rmVisibility.keySet()) { PartialMatch partial = findPartial(new APathQuery(path), opt.getDefinition()); @@ -85,10 +81,14 @@ public void convertPaths(Template template, OperationalTemplate opt) { private String convertPath(String path, PartialMatch partial, ArchetypeModelObject archetypeModelObject) { String newPath; + String remainingPath = partial.getRemainingPath(); + if(Objects.equals(remainingPath, "/")) { + remainingPath = ""; + } if(archetypeModelObject instanceof CAttribute) { - newPath = ((CAttribute) archetypeModelObject).getPath() + partial.getRemainingPath(); + newPath = ((CAttribute) archetypeModelObject).getPath() + remainingPath; } else if (archetypeModelObject instanceof CObject){ - newPath = ((CObject) archetypeModelObject).getPath() + partial.getRemainingPath(); + newPath = ((CObject) archetypeModelObject).getPath() + remainingPath; } else { newPath = path; } diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java b/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java index 8dce9665b..57f47881a 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TConstraintApplier.java @@ -25,6 +25,7 @@ public void apply(OPERATIONALTEMPLATE opt14, OperationalTemplate opt2) { for(TATTRIBUTE attribute: constraints.getAttributes()) { String diffPath = attribute.getDifferentialPath(); if(diffPath.startsWith("[")) { + //TODO: remove this hack //sometimes these paths start with a root node constraint. Sice there's only one //and we don't support that, strip that here. diffPath = diffPath.substring(diffPath.indexOf(']')+1); diff --git a/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java b/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java index ddb17e7d2..4ce9eec64 100644 --- a/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java +++ b/opt14/src/main/java/com/nedap/archie/opt14/TViewConverter.java @@ -33,10 +33,18 @@ public static void apply(OPERATIONALTEMPLATE opt14, Archetype adl2Archetype) { } for (TVIEW.Constraints constraints : view.getConstraints()) { for (TVIEW.Constraints.Items item : constraints.getItems()) { - RmAttributeVisibility attributeVisibility = rmVisibility.get(constraints.getPath()); + + String path = constraints.getPath(); + if(path.startsWith("[")) { + //TODO: remove this hack + // sometimes these paths start with a root node constraint. Sice there's only one + //and we don't support that, strip that here. + path = path.substring(path.indexOf(']')+1); + } + RmAttributeVisibility attributeVisibility = rmVisibility.get(path); if(attributeVisibility == null) { attributeVisibility = new RmAttributeVisibility(); - rmVisibility.put(constraints.getPath(), attributeVisibility); + rmVisibility.put(path, attributeVisibility); } switch (item.getId()) { case "pass_through": diff --git a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java index 7b1d3ded4..6361a8341 100644 --- a/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java +++ b/opt14/src/test/java/com/nedap/archie/opt14/Opt14ConverterTest.java @@ -74,7 +74,7 @@ public void ePrescription() throws Exception { testTemplate("/ePrescription.opt"); } - private ValidationResult testTemplate(String templateFileName, String... sourceArchetypes) throws IOException, ADLParseException, JAXBException { + private ValidationResult testTemplate(String templateFileName) throws IOException, ADLParseException, JAXBException { // InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); // for(String sourcefile:sourceArchetypes) { // repository.addArchetype(parseAdl2(sourcefile)); @@ -92,7 +92,7 @@ private ValidationResult testTemplate(String templateFileName, String... sourceA } } Template convertedTemplate = (Template) convert.getConversionResults().get(0).getArchetype(); - System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate)); + System.out.println(ADLArchetypeSerializer.serialize(convertedTemplate, new RepoFlatArchetypeProvider(repository)::getFlatArchetype, null)); OperationalTemplate opt2 = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels()) .createOperationalTemplate(true)