From 1b94a10b36e82aa9f74e7379204756c5b54fa2c3 Mon Sep 17 00:00:00 2001 From: Niklas Reimer Date: Mon, 26 Feb 2024 19:58:20 +0100 Subject: [PATCH] implement default values and multiple values --- .../java/de/uksh/medic/etl/OpenEhrObds.java | 51 ++++--- .../medic/etl/openehrmapper/EHRParser.java | 15 +- .../medic/etl/openehrmapper/Generator.java | 130 +++++++++++++++--- 3 files changed, 156 insertions(+), 40 deletions(-) diff --git a/src/main/java/de/uksh/medic/etl/OpenEhrObds.java b/src/main/java/de/uksh/medic/etl/OpenEhrObds.java index 674a64f..8060f70 100644 --- a/src/main/java/de/uksh/medic/etl/OpenEhrObds.java +++ b/src/main/java/de/uksh/medic/etl/OpenEhrObds.java @@ -76,7 +76,7 @@ public static void main(String[] args) throws IOException { // ToDo: Replace with Kafka consumer - File f = new File("tod.xml"); + File f = new File("tuko.xml"); Map m = new LinkedHashMap<>(); walkXmlTree(xmlMapper.readValue(f, new TypeReference>() { @@ -97,6 +97,7 @@ public static void walkXmlTree(Set> xmlSet, int depth, Mapping m = Settings.getMapping().get(path); Map mapped = convertMdr(xmlSet, m); + listConv(mapped); mapped.entrySet().forEach(e -> queryFhirTs(m, e)); Map result = formatMap((Map) mapped); @@ -149,27 +150,45 @@ public static void walkXmlTree(Set> xmlSet, int depth, } - @SuppressWarnings("unchecked") + private static void listConv(Map input) { + input.entrySet().forEach(e -> { + switch (e.getValue()) { + case List l -> { + } + default -> { + e.setValue(List.of(e.getValue())); + } + } + }); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) private static void queryFhirTs(Mapping m, Map.Entry e) { MappingAttributes fa = FHIR_ATTRIBUTES.get(m.getTarget()).get(e.getKey()); - if (fa != null && fa.getSystem() != null) { - String code = switch (e.getValue()) { - case String c -> c; - case Map map -> ((Map) map).get("code"); - default -> null; - }; - if (fa.getConceptMap() == null) { - String version = switch (e.getValue()) { - case String c -> fa.getVersion(); - case Map map -> ((Map) map).get("version"); + List listed = new ArrayList<>(); + for (Object o : (List) e.getValue()) { + if (fa != null && fa.getSystem() != null) { + String code = switch (o) { + case String c -> c; + case Map map -> ((Map) map).get("code"); default -> null; }; - e.setValue(FhirResolver.lookUp(fa.getSystem(), version, code)); - } else if (fa.getConceptMap() != null) { - e.setValue(FhirResolver.conceptMap(fa.getConceptMap(), fa.getId(), fa.getSource(), - fa.getTarget(), code)); + if (fa.getConceptMap() == null) { + String version = switch (o) { + case String c -> fa.getVersion(); + case Map map -> ((Map) map).get("version"); + default -> null; + }; + listed.add(FhirResolver.lookUp(fa.getSystem(), version, code)); + } else if (fa.getConceptMap() != null) { + listed.add(FhirResolver.conceptMap(fa.getConceptMap(), fa.getId(), fa.getSource(), + fa.getTarget(), code)); + } + } else { + listed.add(o); } } + e.setValue(listed); } private static Map formatMap(Map input) { diff --git a/src/main/java/de/uksh/medic/etl/openehrmapper/EHRParser.java b/src/main/java/de/uksh/medic/etl/openehrmapper/EHRParser.java index a8ec142..6a9c7f8 100644 --- a/src/main/java/de/uksh/medic/etl/openehrmapper/EHRParser.java +++ b/src/main/java/de/uksh/medic/etl/openehrmapper/EHRParser.java @@ -29,7 +29,7 @@ public class EHRParser { public String build(Map map) throws ParserConfigurationException, SAXException, XPathExpressionException, IOException { - String file = "oBDS_Tod.opt"; + String file = "oBDS_Tumorkonferenz.opt"; String path = "/template/definition[rm_type_name = \"COMPOSITION\"]/attributes[rm_attribute_name=\"content\"]"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -43,14 +43,17 @@ public String build(Map map) Document doc = builder.parse(new File(file)); composition.setArchetypeNodeId( - ((String) xp.evaluate("/template/definition/archetype_id", doc, XPathConstants.STRING)).trim()); + ((String) xp.evaluate("/template/definition/archetype_id", doc, XPathConstants.STRING)) + .trim()); composition.setNameAsString( - ((String) xp.evaluate("/template/definition/template_id", doc, XPathConstants.STRING)).trim()); + ((String) xp.evaluate("/template/definition/template_id", doc, XPathConstants.STRING)) + .trim()); Archetyped archetypeDetails = new Archetyped(); archetypeDetails.setArchetypeId(new ArchetypeID( - ((String) xp.evaluate("/template/definition/archetype_id", doc, XPathConstants.STRING)).trim())); + ((String) xp.evaluate("/template/definition/archetype_id", doc, XPathConstants.STRING)) + .trim())); TemplateId templateId = new TemplateId(); templateId.setValue(((String) xp.evaluate("/template/template_id", doc, XPathConstants.STRING)).trim()); @@ -72,9 +75,10 @@ public String build(Map map) Generator g = new Generator(doc); ArrayList content = new ArrayList(); + Map applyMap = Generator.applyDefaults(map); composition.setContent(content); - Generator.processAttributeChildren(path, "", content, map); + Generator.processAttributeChildren(path, "", content, applyMap); System.out.println("Finished JSON-Generation. Generating String."); @@ -82,4 +86,5 @@ public String build(Map map) return ehr; } + } diff --git a/src/main/java/de/uksh/medic/etl/openehrmapper/Generator.java b/src/main/java/de/uksh/medic/etl/openehrmapper/Generator.java index e8be27a..6cc8cef 100644 --- a/src/main/java/de/uksh/medic/etl/openehrmapper/Generator.java +++ b/src/main/java/de/uksh/medic/etl/openehrmapper/Generator.java @@ -18,7 +18,6 @@ import com.nedap.archie.rm.datastructures.ItemTree; import com.nedap.archie.rm.datastructures.PointEvent; import com.nedap.archie.rm.datatypes.CodePhrase; -import com.nedap.archie.rm.datavalues.DataValue; import com.nedap.archie.rm.datavalues.DvBoolean; import com.nedap.archie.rm.datavalues.DvCodedText; import com.nedap.archie.rm.datavalues.DvIdentifier; @@ -203,6 +202,7 @@ public static void gen_INSTRUCTION(String path, String name, Object jsonmap, Map instruction.setLanguage(new CodePhrase(new TerminologyId("ISO_639-1"), "de")); instruction.setEncoding(new CodePhrase(new TerminologyId("IANA_character-sets"), "UTF-8")); instruction.setSubject(new PartySelf()); + instruction.setNarrative(new DvText("asdf")); if (map.containsKey(paramName)) { List activities = new ArrayList<>(); @@ -222,7 +222,7 @@ public static void gen_ACTIVITY(String path, String name, Object jsonmap, Map el.setValue(d); - default -> processAttributeChildren(newPath, nodeId, el, map); - } - ((ArrayList) jsonmap).add(el); + String label = getLabel(nodeId, name); + + ((List) map.get(nodeId)).forEach(e -> { + Element el = new Element(); + el.setArchetypeNodeId(nodeId); + el.setNameAsString(label); + Map mo = new HashMap<>(); + mo.put(nodeId, e); + processAttributeChildren(newPath, nodeId, el, mo); + ((ArrayList) jsonmap).add(el); + + }); } // HISTORY Class descriptions @@ -412,15 +415,29 @@ public static void gen_DV_TEXT(String path, String name, Object jsonmap, // CODE_PHRASE public static void gen_DV_CODED_TEXT(String path, String name, Object jsonmap, - Map map) throws Exception { - Coding coding = map.get(name); + Map map) throws Exception { + DvCodedText ct = new DvCodedText(); - ct.setDefiningCode(new CodePhrase( - new TerminologyId("terminology://fhir.hl7.org//ValueSet/$expand?url=" + coding.getSystem(), - coding.getVersion()), - coding.getCode())); - ct.setValue(coding.getCode()); - ((Element) jsonmap).setValue(ct); + switch (map.get(name)) { + case Coding coding -> { + ct.setDefiningCode(new CodePhrase( + new TerminologyId("terminology://fhir.hl7.org//ValueSet/$expand?url=" + coding.getSystem(), + coding.getVersion()), + coding.getCode(), coding.getDisplay())); + ct.setValue(coding.getDisplay()); + ((Element) jsonmap).setValue(ct); + } + case String s -> { + String display = getLocalTerminologyTerm(path, s); + ct.setDefiningCode(new CodePhrase( + new TerminologyId("local_terms"), + s, display)); + ct.setValue(display); + ((Element) jsonmap).setValue(ct); + } + default -> { + } + } } @@ -514,6 +531,16 @@ private static String getTypeLabel(String path, String code) throws Exception { return CACHE.get(newPath); } + private static String getLocalTerminologyTerm(String path, String code) throws Exception { + String newPath = "//term_definitions[@code=\"local_terms::" + code + "\"]/items/text()"; + if (!CACHE.containsKey(newPath)) { + XPathExpression expr = XP.compile(newPath); + CACHE.put(newPath, ((String) expr.evaluate(opt, XPathConstants.STRING)).replaceAll("^* (?m) ", "") + .replaceAll("\\n", " ")); + } + return CACHE.get(newPath); + } + private static String getNodeId(String path) throws Exception { String newPath = path + "/node_id"; if (!CACHE.containsKey(newPath)) { @@ -532,4 +559,69 @@ private static String getArcheTypeId(String path) throws Exception { return CACHE.get(newPath); } + public static Map getDefaultValues() { + Map defaults = new HashMap<>(); + Map current = defaults; + String path = "//constraints/attributes[children/default_value]"; + try { + XPathExpression expr = XP.compile(path); + NodeList nl = (NodeList) expr.evaluate(opt, XPathConstants.NODESET); + for (int i = 1; i <= nl.getLength(); i++) { + XPathExpression exprC = XP.compile(path + "[" + i + "]/children/default_value/value/text()"); + XPathExpression exprP = XP.compile(path + "[" + i + "]/differential_path/text()"); + String value = (String) exprC.evaluate(opt, XPathConstants.STRING); + String differentialPath = ((String) exprP.evaluate(opt, XPathConstants.STRING)).trim(); + List l = List.of(differentialPath.split("/")); + String last = l.getLast().split("(\\[|\\])")[1]; + for (int j = 1; j < l.size() - 1; j++) { + String s = l.get(j); + if (s.contains("description")) { + continue; + } + Map n = new HashMap<>(); + String s2 = s.split("(\\[|\\])")[1]; + current.put(s2, n); + current = n; + } + current.put(last, List.of(value)); + } + } catch (XPathExpressionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return defaults; + } + + public static Map applyDefaults(Map map) { + Map defaults = getDefaultValues(); + deepMerge(defaults, map); + return defaults; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static void deepMerge(Map map1, Map map2) { + for (String key : map2.keySet()) { + Object value2 = map2.get(key); + if (map1.containsKey(key)) { + Object value1 = map1.get(key); + if (value1 instanceof Map && value2 instanceof Map) { + deepMerge((Map) value1, (Map) value2); + } else if (value1 instanceof List && value2 instanceof List) { + map1.put(key, merge((List) value1, (List) value2)); + } else { + map1.put(key, value2); + } + } else { + map1.put(key, value2); + } + } + } + + @SuppressWarnings("rawtypes") + private static List merge(List list1, List list2) { + list2.removeAll(list1); + list1.addAll(list2); + return list1; + } + }