From e76c65e6c944dccc8b101a660070651556eacf62 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 21 Apr 2020 10:00:30 +1000 Subject: [PATCH] Fix problem expanding flat code systems --- .../fhir/r5/context/BaseWorkerContext.java | 6 ++- .../r5/terminologies/CodeSystemUtilities.java | 49 +++++++++++++++++++ .../terminologies/ValueSetExpanderSimple.java | 18 +++++-- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index d61c1134c..86208d186 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -81,6 +81,7 @@ import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCode import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent; +import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.TerminologyClient; import org.hl7.fhir.r5.terminologies.ValueSetCheckerSimple; import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass; @@ -265,9 +266,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte structures.see(sd, packageInfo); } else if (r instanceof ValueSet) valueSets.see((ValueSet) m, packageInfo); - else if (r instanceof CodeSystem) + else if (r instanceof CodeSystem) { + CodeSystemUtilities.crossLinkCodeSystem((CodeSystem) r); codeSystems.see((CodeSystem) m, packageInfo); - else if (r instanceof ImplementationGuide) + } else if (r instanceof ImplementationGuide) guides.see((ImplementationGuide) m, packageInfo); else if (r instanceof CapabilityStatement) capstmts.see((CapabilityStatement) m, packageInfo); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java index d07fe0af5..8b28ef2e0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java @@ -49,6 +49,8 @@ import org.hl7.fhir.utilities.Utilities; public class CodeSystemUtilities { + public static final String USER_DATA_CROSS_LINK = "cs.utils.cross.link"; + public static class CodeSystemNavigator { private CodeSystem cs; @@ -344,6 +346,17 @@ public class CodeSystemUtilities { return p; return null; } + + public static List getPropertyValues(ConceptDefinitionComponent concept, String code) { + List res = new ArrayList<>(); + for (ConceptPropertyComponent p : concept.getProperty()) { + if (p.getCode().equals(code)) { + res.add(p); + } + } + return res; + } + // see http://hl7.org/fhir/R4/codesystem.html#hierachy // returns additional parents not in the heirarchy @@ -416,4 +429,40 @@ public class CodeSystemUtilities { return null; } + public static void crossLinkCodeSystem(CodeSystem cs) { + String parent = getPropertyByUrl(cs, "http://hl7.org/fhir/concept-properties#parent"); + if ((parent != null)) { + crossLinkConcepts(cs.getConcept(), cs.getConcept(), parent); + } + } + + private static String getPropertyByUrl(CodeSystem cs, String url) { + for (PropertyComponent pc : cs.getProperty()) { + if (url.equals(pc.getUri())) { + return pc.getCode(); + } + } + return null; + } + + private static void crossLinkConcepts(List root, List focus, String parent) { + for (ConceptDefinitionComponent def : focus) { + List pcl = getPropertyValues(def, parent); + for (ConceptPropertyComponent pc : pcl) { + String code = pc.getValue().primitiveValue(); + ConceptDefinitionComponent tgt = findCode(root, code); + if (!tgt.hasUserData(USER_DATA_CROSS_LINK)) { + tgt.setUserData(USER_DATA_CROSS_LINK, new ArrayList<>()); + } + @SuppressWarnings("unchecked") + List children = (List) tgt.getUserData(USER_DATA_CROSS_LINK); + children.add(def); + } + if (def.hasConcept()) { + crossLinkConcepts(root, def.getConcept(), parent); + } + } + + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java index 8fedc48da..d6a0dc430 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java @@ -116,7 +116,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander { public void setMaxExpansionSize(int theMaxExpansionSize) { maxExpansionSize = theMaxExpansionSize; } - + private ValueSetExpansionContainsComponent addCode(String system, String code, String display, ValueSetExpansionContainsComponent parent, List designations, Parameters expParams, boolean isAbstract, boolean inactive, List filters) { if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code)) @@ -215,11 +215,23 @@ public class ValueSetExpanderSimple implements ValueSetExpander { boolean inc = CodeSystemUtilities.isInactive(cs, def); if (canBeHeirarchy || !abs) np = addCode(system, def.getCode(), def.getDisplay(), parent, def.getDesignation(), expParams, abs, inc, filters); - for (ConceptDefinitionComponent c : def.getConcept()) + for (ConceptDefinitionComponent c : def.getConcept()) { addCodeAndDescendents(cs, system, c, np, expParams, filters, exclusion); + } + if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) { + List children = (List) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK); + for (ConceptDefinitionComponent c : children) + addCodeAndDescendents(cs, system, c, np, expParams, filters, exclusion); + } } else { - for (ConceptDefinitionComponent c : def.getConcept()) + for (ConceptDefinitionComponent c : def.getConcept()) { addCodeAndDescendents(cs, system, c, null, expParams, filters, exclusion); + } + if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) { + List children = (List) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK); + for (ConceptDefinitionComponent c : children) + addCodeAndDescendents(cs, system, c, null, expParams, filters, exclusion); + } } }