Add JSON enhancements for CDS hooks logical model

This commit is contained in:
Grahame Grieve 2022-10-10 17:05:12 +11:00
parent e1657c66b0
commit a66ca2a197
5 changed files with 57 additions and 16 deletions

View File

@ -355,6 +355,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private boolean wantFixDifferentialFirstElementType; private boolean wantFixDifferentialFirstElementType;
private Set<String> masterSourceFileNames; private Set<String> masterSourceFileNames;
private Map<ElementDefinition, List<ElementDefinition>> childMapCache = new HashMap<>(); private Map<ElementDefinition, List<ElementDefinition>> childMapCache = new HashMap<>();
private List<String> keyRows = new ArrayList<>();
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) { public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) {
super(); super();
@ -1222,7 +1223,7 @@ public class ProfileUtilities extends TranslatingUtilities {
String lid = tail(id); String lid = tail(id);
if (lid.contains("/")) { if (lid.contains("/")) {
// the template comes from the snapshot of the base // the template comes from the snapshot of the base
generateIds(result.getElement(), url, srcSD.getType()); generateIds(result.getElement(), url, srcSD.getType(), srcSD.getUrl());
String baseId = id.substring(0, id.length()-lid.length()) + lid.substring(0, lid.indexOf("/")); // this is wrong if there's more than one reslice (todo: one thing at a time) String baseId = id.substring(0, id.length()-lid.length()) + lid.substring(0, lid.indexOf("/")); // this is wrong if there's more than one reslice (todo: one thing at a time)
template = getById(result.getElement(), baseId); template = getById(result.getElement(), baseId);
@ -3976,12 +3977,23 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!max.isEmpty()) if (!max.isEmpty())
tracker.used = !max.getValue().equals("0"); tracker.used = !max.getValue().equals("0");
String hint = null;
if ("*".equals(max.getValue()) && 0 == min.getValue()) {
if (definition.hasExtension(ToolingExtensions.EXT_JSON_EMPTY)) {
String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_EMPTY);
if ("present".equals(code)) {
hint = "This element is present as a JSON Array even when there are no items in the instance";
} else {
hint = "This element may be present as a JSON Array even when there are no items in the instance";
}
}
}
Cell cell = gen.new Cell(null, null, null, null, null); Cell cell = gen.new Cell(null, null, null, null, null);
row.getCells().add(cell); row.getCells().add(cell);
if (!min.isEmpty() || !max.isEmpty()) { if (!min.isEmpty() || !max.isEmpty()) {
cell.addPiece(checkForNoChange(min, gen.new Piece(null, !min.hasValue() ? "" : Integer.toString(min.getValue()), null))); cell.addPiece(checkForNoChange(min, gen.new Piece(null, !min.hasValue() ? "" : Integer.toString(min.getValue()), hint)));
cell.addPiece(checkForNoChange(min, max, gen.new Piece(null, "..", null))); cell.addPiece(checkForNoChange(min, max, gen.new Piece(null, "..", hint)));
cell.addPiece(checkForNoChange(max, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), null))); cell.addPiece(checkForNoChange(max, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), hint)));
} }
return cell; return cell;
} }
@ -4058,6 +4070,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>(); List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
profiles.add(profile); profiles.add(profile);
keyRows.clear();
genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc, anchorPrefix); genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc, anchorPrefix);
try { try {
@ -4190,6 +4203,9 @@ public class ProfileUtilities extends TranslatingUtilities {
} else if (!hasDef || element.getType().size() == 0) { } else if (!hasDef || element.getType().size() == 0) {
if (root && context.getResourceNames().contains(profile.getType())) { if (root && context.getResourceNames().contains(profile.getType())) {
row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE);
} else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) {
row.setIcon("icon-object-box.png", HierarchicalTableGenerator.TEXT_ICON_OBJECT_BOX);
keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY));
} else { } else {
row.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT); row.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT);
} }
@ -4203,7 +4219,11 @@ public class ProfileUtilities extends TranslatingUtilities {
} else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) { } else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) {
row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE); row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE);
} else if (hasDef && isPrimitive(element.getType().get(0).getWorkingCode())) { } else if (hasDef && isPrimitive(element.getType().get(0).getWorkingCode())) {
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); if (keyRows.contains(element.getId())) {
row.setIcon("icon-key.png", HierarchicalTableGenerator.TEXT_ICON_KEY);
} else {
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
}
} else if (hasDef && element.getType().get(0).hasTarget()) { } else if (hasDef && element.getType().get(0).hasTarget()) {
row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
} else if (hasDef && isDataType(element.getType().get(0).getWorkingCode())) { } else if (hasDef && isDataType(element.getType().get(0).getWorkingCode())) {
@ -4764,7 +4784,22 @@ public class ProfileUtilities extends TranslatingUtilities {
if (root) { if (root) {
if (profile != null && profile.getAbstract()) { if (profile != null && profile.getAbstract()) {
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.addPiece(gen.new Piece(null, "This is an abstract profile", null)); c.addPiece(gen.new Piece(null, "This is an abstract "+(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profile" : "type")+". ", null));
List<StructureDefinition> children = new ArrayList<>();
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
if (sd.hasBaseDefinition() && sd.getBaseDefinition().equals(profile.getUrl())) {
children.add(sd);
}
}
if (!children.isEmpty()) {
c.addPiece(gen.new Piece(null, "Child "+(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profiles" : "types")+": ", null));
boolean first = true;
for (StructureDefinition sd : children) {
if (first) first = false; else c.addPiece(gen.new Piece(null, ", ", null));
c.addPiece(gen.new Piece(sd.getUserString("path"), sd.getType(), null));
}
}
} }
} }
if (definition.getPath().endsWith("url") && definition.hasFixed()) { if (definition.getPath().endsWith("url") && definition.hasFixed()) {
@ -5979,12 +6014,12 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!checkFirst || !sd.hasDifferential() || hasMissingIds(sd.getDifferential().getElement())) { if (!checkFirst || !sd.hasDifferential() || hasMissingIds(sd.getDifferential().getElement())) {
if (!sd.hasDifferential()) if (!sd.hasDifferential())
sd.setDifferential(new StructureDefinitionDifferentialComponent()); sd.setDifferential(new StructureDefinitionDifferentialComponent());
generateIds(sd.getDifferential().getElement(), sd.getUrl(), sd.getType()); generateIds(sd.getDifferential().getElement(), sd.getUrl(), sd.getType(), sd.getUrl());
} }
if (!checkFirst || !sd.hasSnapshot() || hasMissingIds(sd.getSnapshot().getElement())) { if (!checkFirst || !sd.hasSnapshot() || hasMissingIds(sd.getSnapshot().getElement())) {
if (!sd.hasSnapshot()) if (!sd.hasSnapshot())
sd.setSnapshot(new StructureDefinitionSnapshotComponent()); sd.setSnapshot(new StructureDefinitionSnapshotComponent());
generateIds(sd.getSnapshot().getElement(), sd.getUrl(), sd.getType()); generateIds(sd.getSnapshot().getElement(), sd.getUrl(), sd.getType(), sd.getUrl());
} }
} }
@ -6029,7 +6064,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
private void generateIds(List<ElementDefinition> list, String name, String type) throws DefinitionException { private void generateIds(List<ElementDefinition> list, String name, String type, String url) throws DefinitionException {
if (list.isEmpty()) if (list.isEmpty())
return; return;
@ -6075,9 +6110,9 @@ public class ProfileUtilities extends TranslatingUtilities {
if (ed.hasContentReference() && ed.getContentReference().startsWith("#")) { if (ed.hasContentReference() && ed.getContentReference().startsWith("#")) {
String s = ed.getContentReference(); String s = ed.getContentReference();
if (replacedIds.containsKey(s.substring(1))) { if (replacedIds.containsKey(s.substring(1))) {
ed.setContentReference("http://hl7.org/fhir/StructureDefinition/"+type+"#"+replacedIds.get(s.substring(1))); ed.setContentReference(url+"#"+replacedIds.get(s.substring(1)));
} else { } else {
ed.setContentReference("http://hl7.org/fhir/StructureDefinition/"+type+s); ed.setContentReference(url+s);
} }
} }
} }

View File

@ -148,8 +148,8 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
return null; return null;
} }
CanonicalResource cr = context.fetchResource(CanonicalResource.class, url); if (context.hasResource(CanonicalResource.class, url)) {
if (cr != null) { CanonicalResource cr = context.fetchResource(CanonicalResource.class, url);
return cr.getUserString("path"); return cr.getUserString("path");
} }
if (url.equals("http://loinc.org")) { if (url.equals("http://loinc.org")) {

View File

@ -1115,13 +1115,14 @@ public class ValueSetRenderer extends TerminologyRenderer {
// for performance reasons, we do all the fetching in one batch // for performance reasons, we do all the fetching in one batch
definitions = getConceptsForCodes(e, inc); definitions = getConceptsForCodes(e, inc);
XhtmlNode t = li.table("none"); XhtmlNode t = li.table("none");
boolean hasComments = false; boolean hasComments = false;
boolean hasDefinition = false; boolean hasDefinition = false;
for (ConceptReferenceComponent c : inc.getConcept()) { for (ConceptReferenceComponent c : inc.getConcept()) {
hasComments = hasComments || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_VS_COMMENT); hasComments = hasComments || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_VS_COMMENT);
ConceptDefinitionComponent cc = definitions.get(c.getCode()); ConceptDefinitionComponent cc = definitions == null ? null : definitions.get(c.getCode());
hasDefinition = hasDefinition || ((cc != null && cc.hasDefinition()) || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION)); hasDefinition = hasDefinition || ((cc != null && cc.hasDefinition()) || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION));
} }
if (hasComments || hasDefinition) if (hasComments || hasDefinition)
@ -1130,7 +1131,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
for (ConceptReferenceComponent c : inc.getConcept()) { for (ConceptReferenceComponent c : inc.getConcept()) {
XhtmlNode tr = t.tr(); XhtmlNode tr = t.tr();
XhtmlNode td = tr.td(); XhtmlNode td = tr.td();
ConceptDefinitionComponent cc = definitions.get(c.getCode()); ConceptDefinitionComponent cc = definitions == null ? null : definitions.get(c.getCode());
addCodeToTable(false, inc.getSystem(), c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td); addCodeToTable(false, inc.getSystem(), c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
td = tr.td(); td = tr.td();

View File

@ -133,7 +133,6 @@ public class ToolingExtensions {
public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format"; public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format";
public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source"; public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source";
public static final String EXT_IGP_CONTAINED_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/contained-resource-information"; public static final String EXT_IGP_CONTAINED_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/contained-resource-information";
public static final String EXT_PRIVATE_BASE = "http://hl7.org/fhir/tools/";
public static final String EXT_BINARY_FORMAT = "http://hl7.org/fhir/StructureDefinition/implementationguide-resource-format"; public static final String EXT_BINARY_FORMAT = "http://hl7.org/fhir/StructureDefinition/implementationguide-resource-format";
public static final String EXT_IGP_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/resource-information"; public static final String EXT_IGP_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/resource-information";
public static final String EXT_IGP_LOADVERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-loadversion"; public static final String EXT_IGP_LOADVERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-loadversion";
@ -208,7 +207,11 @@ public class ToolingExtensions {
public static final String EXT_SD_DEPENDENCY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-dependencies"; public static final String EXT_SD_DEPENDENCY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-dependencies";
// in the tooling IG // in the tooling IG
public static final String EXT_PRIVATE_BASE = "http://hl7.org/fhir/tools/";
public static final String EXT_BINDING_ADDITIONAL = "http://hl7.org/fhir/tools/StructureDefinition/additional-binding"; public static final String EXT_BINDING_ADDITIONAL = "http://hl7.org/fhir/tools/StructureDefinition/additional-binding";
public static final String EXT_JSON_PROP_KEY = "http://hl7.org/fhir/tools/StructureDefinition/json-property-key";
public static final String EXT_JSON_EMPTY = "http://hl7.org/fhir/tools/StructureDefinition/json-empty-behavior";
// unregistered? - don't know what these are used for // unregistered? - don't know what these are used for
public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix"; public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix";

View File

@ -88,9 +88,11 @@ import org.hl7.fhir.utilities.Utilities;
public class HierarchicalTableGenerator extends TranslatingUtilities { public class HierarchicalTableGenerator extends TranslatingUtilities {
public static final String TEXT_ICON_REFERENCE = "Reference to another Resource"; public static final String TEXT_ICON_REFERENCE = "Reference to another Resource";
public static final String TEXT_ICON_PRIMITIVE = "Primitive Data Type"; public static final String TEXT_ICON_PRIMITIVE = "Primitive Data Type";
public static final String TEXT_ICON_KEY = "JSON Key Value";
public static final String TEXT_ICON_DATATYPE = "Data Type"; public static final String TEXT_ICON_DATATYPE = "Data Type";
public static final String TEXT_ICON_RESOURCE = "Resource"; public static final String TEXT_ICON_RESOURCE = "Resource";
public static final String TEXT_ICON_ELEMENT = "Element"; public static final String TEXT_ICON_ELEMENT = "Element";
public static final String TEXT_ICON_OBJECT_BOX = "Object";
public static final String TEXT_ICON_REUSE = "Reference to another Element"; public static final String TEXT_ICON_REUSE = "Reference to another Element";
public static final String TEXT_ICON_EXTENSION = "Extension"; public static final String TEXT_ICON_EXTENSION = "Extension";
public static final String TEXT_ICON_CHOICE = "Choice of Types"; public static final String TEXT_ICON_CHOICE = "Choice of Types";