More improvements to ConceptMap Infrastructure

This commit is contained in:
Grahame Grieve 2024-03-01 16:40:41 +11:00
parent 7fb2b1ea00
commit a3fb1457a0
2 changed files with 55 additions and 34 deletions

View File

@ -39,8 +39,9 @@ public class ConceptMapRenderer extends TerminologyRenderer {
}
public interface IConceptMapInformationProvider {
public interface IMultiMapRendererAdvisor {
public List<Coding> getMembers(String uri);
public boolean describeMap(ConceptMap map, XhtmlNode x);
public String getLink(String system, String code);
}
@ -723,11 +724,11 @@ public class ConceptMapRenderer extends TerminologyRenderer {
return null;
}
public static XhtmlNode renderMultipleMaps(String start, List<ConceptMap> maps, IConceptMapInformationProvider linker, RenderMultiRowSortPolicy sort) {
public static XhtmlNode renderMultipleMaps(String start, String startLink, List<ConceptMap> maps, IMultiMapRendererAdvisor advisor, RenderMultiRowSortPolicy sort) {
// 1+1 column for each provided map
List<MultipleMappingRow> rowSets = new ArrayList<>();
for (int i = 0; i < maps.size(); i++) {
populateRows(rowSets, maps.get(i), i, linker);
populateRows(rowSets, maps.get(i), i, advisor);
}
collateRows(rowSets);
if (sort != RenderMultiRowSortPolicy.UNSORTED) {
@ -736,16 +737,19 @@ public class ConceptMapRenderer extends TerminologyRenderer {
XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
XhtmlNode tbl = div.table("none").style("text-align: left; border-spacing: 0; padding: 5px");
XhtmlNode tr = tbl.tr();
styleCell(tr.td(), false, true, 5).b().tx(start);
styleCell(tr.td(), false, true, 5).b().ahOrNot(startLink).tx(start);
for (ConceptMap map : maps) {
if (map.hasWebPath()) {
styleCell(tr.td(), false, true, 5).colspan(2).b().ah(map.getWebPath(), map.getVersionedUrl()).tx(map.present());
} else {
styleCell(tr.td(), false, true, 5).colspan(2).b().tx(map.present());
XhtmlNode td = styleCell(tr.td(), false, true, 5).colspan(2);
if (!advisor.describeMap(map, td)) {
if (map.hasWebPath()) {
td.b().ah(map.getWebPath(), map.getVersionedUrl()).tx(map.present());
} else {
td.b().tx(map.present());
}
}
}
for (MultipleMappingRow row : rowSets) {
renderMultiRow(tbl, row, maps, linker);
renderMultiRow(tbl, row, maps, advisor);
}
return div;
}
@ -765,7 +769,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
rowSets.removeAll(toDelete);
}
private static void renderMultiRow(XhtmlNode tbl, MultipleMappingRow rows, List<ConceptMap> maps, IConceptMapInformationProvider linker) {
private static void renderMultiRow(XhtmlNode tbl, MultipleMappingRow rows, List<ConceptMap> maps, IMultiMapRendererAdvisor advisor) {
int rowCounter = 0;
for (MultipleMappingRowItem row : rows.rowSets) {
XhtmlNode tr = tbl.tr();
@ -787,7 +791,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
if (cell.code == null) {
styleCell(tr.td(), rowCounter == 0, true, 5).rowspan(c).style("background-color: #eeeeee");
} else {
String link = linker.getLink(cell.system, cell.code);
String link = advisor.getLink(cell.system, cell.code);
XhtmlNode x = null;
if (link != null) {
x = styleCell(tr.td(), rowCounter == 0, true, 5).attributeNN("title", cell.display).rowspan(c).ah(link);
@ -835,7 +839,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
if (cell.code == null) {
styleCell(tr.td(), rowCounter == 0, true, 5).rowspan(c).style("background-color: #eeeeee");
} else {
String link = linker.getLink(cell.system, cell.code);
String link = advisor.getLink(cell.system, cell.code);
XhtmlNode x = null;
if (link != null) {
x = styleCell(tr.td(), rowCounter == 0, true, 5).attributeNN("title", cell.display).rowspan(c).ah(link);
@ -868,10 +872,10 @@ public class ConceptMapRenderer extends TerminologyRenderer {
return td;
}
private static void populateRows(List<MultipleMappingRow> rowSets, ConceptMap map, int i, IConceptMapInformationProvider linker) {
private static void populateRows(List<MultipleMappingRow> rowSets, ConceptMap map, int i, IMultiMapRendererAdvisor advisor) {
// if we can resolve the value set, we create entries for it
if (map.hasSourceScope()) {
List<Coding> codings = linker.getMembers(map.getSourceScope().primitiveValue());
List<Coding> codings = advisor.getMembers(map.getSourceScope().primitiveValue());
if (codings != null) {
for (Coding c : codings) {
MultipleMappingRow row = i == 0 ? null : findExistingRowBySource(rowSets, c.getSystem(), c.getCode(), i);
@ -931,7 +935,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
}
}
if (map.hasTargetScope()) {
List<Coding> codings = linker.getMembers(map.getTargetScope().primitiveValue());
List<Coding> codings = advisor.getMembers(map.getTargetScope().primitiveValue());
if (codings != null) {
for (Coding c : codings) {
MultipleMappingRow row = findExistingRowByTarget(rowSets, c.getSystem(), c.getCode(), i);

View File

@ -4,8 +4,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalType;
@ -321,7 +323,6 @@ public class ConceptMapUtilities {
}
public static boolean checkReciprocal(ConceptMap left, ConceptMap right, List<String> issues) {
boolean altered = false;
if (!Base.compareDeep(left.getTargetScope(), right.getSourceScope(), true)) {
issues.add("scopes are not reciprocal: "+left.getTargetScope()+" vs "+right.getSourceScope());
}
@ -344,8 +345,7 @@ public class ConceptMapUtilities {
switch (tgtL.getRelationship()) {
case EQUIVALENT:
if (pairs.isEmpty()) {
gr.getOrAddElement(tgtL.getCode()).addTarget().setCode(srcL.getCode()).setRelationship(ConceptMapRelationship.EQUIVALENT);
altered = true;
issues.add("Left map says that "+srcL.getCode()+" is equivalent to "+tgtL.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.EQUIVALENT) {
issues.add("Left map says that "+srcL.getCode()+" is equivalent to "+tgtL.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -354,18 +354,16 @@ public class ConceptMapUtilities {
break;
case RELATEDTO:
if (pairs.isEmpty()) {
gr.getOrAddElement(tgtL.getCode()).addTarget().setCode(srcL.getCode()).setRelationship(ConceptMapRelationship.RELATEDTO);
altered = true;
issues.add("Left map says that "+srcL.getCode()+" is related to "+tgtL.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.EQUIVALENT && pair.tgt.getRelationship() != ConceptMapRelationship.RELATEDTO) {
issues.add("Left map says that "+srcL.getCode()+" is equivalent to "+tgtL.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
issues.add("Left map says that "+srcL.getCode()+" is related to "+tgtL.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
}
}
break;
case SOURCEISBROADERTHANTARGET:
if (pairs.isEmpty()) {
gr.getOrAddElement(tgtL.getCode()).addTarget().setCode(srcL.getCode()).setRelationship(ConceptMapRelationship.SOURCEISNARROWERTHANTARGET);
altered = true;
issues.add("Left map says that "+srcL.getCode()+" is broader than "+tgtL.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.SOURCEISNARROWERTHANTARGET) {
issues.add("Left map says that "+srcL.getCode()+" is broader than "+tgtL.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -374,8 +372,7 @@ public class ConceptMapUtilities {
break;
case SOURCEISNARROWERTHANTARGET:
if (pairs.isEmpty()) {
gr.getOrAddElement(tgtL.getCode()).addTarget().setCode(srcL.getCode()).setRelationship(ConceptMapRelationship.SOURCEISBROADERTHANTARGET);
altered = true;
issues.add("Left map says that "+srcL.getCode()+" is narrower than "+tgtL.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.SOURCEISBROADERTHANTARGET) {
issues.add("Left map says that "+srcL.getCode()+" is narrower than "+tgtL.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -410,8 +407,7 @@ public class ConceptMapUtilities {
switch (tgtR.getRelationship()) {
case EQUIVALENT:
if (pairs.isEmpty()) {
gl.getOrAddElement(tgtR.getCode()).addTarget().setCode(srcR.getCode()).setRelationship(ConceptMapRelationship.EQUIVALENT);
altered = true;
issues.add("Right map says that "+srcR.getCode()+" is equivalent to "+tgtR.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.EQUIVALENT) {
issues.add("Right map says that "+srcR.getCode()+" is equivalent to "+tgtR.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -420,8 +416,7 @@ public class ConceptMapUtilities {
break;
case RELATEDTO:
if (pairs.isEmpty()) {
gl.getOrAddElement(tgtR.getCode()).addTarget().setCode(srcR.getCode()).setRelationship(ConceptMapRelationship.RELATEDTO);
altered = true;
issues.add("Right map says that "+srcR.getCode()+" is related to "+tgtR.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.EQUIVALENT && pair.tgt.getRelationship() != ConceptMapRelationship.RELATEDTO) {
issues.add("Right map says that "+srcR.getCode()+" is equivalent to "+tgtR.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -430,8 +425,7 @@ public class ConceptMapUtilities {
break;
case SOURCEISBROADERTHANTARGET:
if (pairs.isEmpty()) {
gl.getOrAddElement(tgtR.getCode()).addTarget().setCode(srcR.getCode()).setRelationship(ConceptMapRelationship.SOURCEISNARROWERTHANTARGET);
altered = true;
issues.add("Right map says that "+srcR.getCode()+" is broader than "+tgtR.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.SOURCEISNARROWERTHANTARGET) {
issues.add("Right map says that "+srcR.getCode()+" is broader than "+tgtR.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -440,8 +434,7 @@ public class ConceptMapUtilities {
break;
case SOURCEISNARROWERTHANTARGET:
if (pairs.isEmpty()) {
gl.getOrAddElement(tgtR.getCode()).addTarget().setCode(srcR.getCode()).setRelationship(ConceptMapRelationship.SOURCEISBROADERTHANTARGET);
altered = true;
issues.add("Right map says that "+srcR.getCode()+" is narrower than "+tgtR.getCode()+" but there's no reverse relationship");
} else for (ElementMappingPair pair : pairs) {
if (pair.tgt.getRelationship() != ConceptMapRelationship.SOURCEISBROADERTHANTARGET) {
issues.add("Right map says that "+srcR.getCode()+" is narrower than "+tgtR.getCode()+" but the reverse relationship has type "+pair.tgt.getRelationship().toCode());
@ -470,7 +463,7 @@ public class ConceptMapUtilities {
}
}
}
return altered;
return false;
}
private static List<ElementMappingPair> getMappings(ConceptMapGroupComponent g, String source, String target) {
@ -530,4 +523,28 @@ public class ConceptMapUtilities {
return i;
}
public static Set<String> listCodesWithNoMappings(Set<String> set, ConceptMap map) {
Set<String> res = new HashSet<>();
for (String s : set) {
if (s != null) {
boolean found = false;
for (ConceptMapGroupComponent grp : map.getGroup()) {
for (SourceElementComponent src : grp.getElement()) {
if (s.equals(src.getCode())) {
for (TargetElementComponent tgt : src.getTarget()) {
if (tgt.getRelationship() == ConceptMapRelationship.RELATEDTO || tgt.getRelationship() == ConceptMapRelationship.EQUIVALENT || tgt.getRelationship() == ConceptMapRelationship.SOURCEISNARROWERTHANTARGET) {
found = true;
}
}
}
}
}
if (!found) {
res.add(s);
}
}
}
return res;
}
}