Rendering improvements for showing difference analysis (WIP)

This commit is contained in:
Grahame Grieve 2023-08-14 15:34:54 +10:00
parent b45f6caf60
commit 0fc4398dfc
3 changed files with 78 additions and 48 deletions

View File

@ -9,9 +9,12 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode; import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemHierarchyMeaning;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent; import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent; import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
@ -29,6 +32,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.LoincLinker; import org.hl7.fhir.utilities.LoincLinker;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class CodeSystemRenderer extends TerminologyRenderer { public class CodeSystemRenderer extends TerminologyRenderer {
@ -84,12 +88,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang())); tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
for (CodeSystemFilterComponent f : cs.getFilter()) { for (CodeSystemFilterComponent f : cs.getFilter()) {
tr = tbl.tr(); tr = tbl.tr();
tr.td().tx(f.getCode()); VersionComparisonAnnotation.render(f, tr.td()).tx(f.getCode());
tr.td().tx(f.getDescription()); VersionComparisonAnnotation.render(f.getDescriptionElement(), tr.td()).tx(f.getDescription());
XhtmlNode td = tr.td(); XhtmlNode td = tr.td();
for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator()) for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator())
td.tx(t.asStringValue()+" "); VersionComparisonAnnotation.render(t, td).tx(t.asStringValue()+" ");
tr.td().tx(f.getValue()); VersionComparisonAnnotation.render(f.getValueElement(), tr.td()).tx(f.getValue());
} }
} }
} }
@ -125,13 +129,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (hasRendered) { if (hasRendered) {
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement())); tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
} }
tr.td().tx(p.getCode()); VersionComparisonAnnotation.render(p, tr.td()).tx(p.getCode());
if (hasURI) { if (hasURI) {
tr.td().tx(p.getUri()); VersionComparisonAnnotation.render(p.getUriElement(), tr.td()).tx(p.getUri());
} }
tr.td().tx(p.hasType() ? p.getType().toCode() : ""); VersionComparisonAnnotation.render(p.getTypeElement(), tr.td()).tx(p.hasType() ? p.getType().toCode() : "");
if (hasDescription) { if (hasDescription) {
tr.td().tx(p.getDescription()); VersionComparisonAnnotation.render(p.getDescriptionElement(), tr.td()).tx(p.getDescription());
} }
} }
return true; return true;
@ -160,8 +164,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
features = "features"; // ? features = "features"; // ?
} }
return context.getContext().formatMessage(I18nConstants.RND_CS_CONTENT_SUPPLEMENT, features); return context.getContext().formatMessage(I18nConstants.RND_CS_CONTENT_SUPPLEMENT, features);
default:
throw new FHIRException("Unknown CodeSystemContentMode mode");
} }
throw new FHIRException("Unknown CodeSystemContentMode mode");
} }
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps, boolean props) throws FHIRFormatError, DefinitionException, IOException { private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps, boolean props) throws FHIRFormatError, DefinitionException, IOException {
@ -169,7 +174,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Concepts", getContext().getLang())); x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Concepts", getContext().getLang()));
} }
XhtmlNode p = x.para(); XhtmlNode p = x.para();
p.param("cs").code().tx(cs.getUrl()); VersionComparisonAnnotation.render(cs.getUrlElement(), p.param("cs")).code().tx(cs.getUrl());
makeCasedParam(p.param("cased"), cs, cs.getCaseSensitiveElement());
makeHierarchyParam(p.param("h"), cs, cs.getHierarchyMeaningElement());
p.paramValue("code-count", CodeSystemUtilities.countCodes(cs)); p.paramValue("code-count", CodeSystemUtilities.countCodes(cs));
p.sentenceForParams(sentenceForContent(cs.getContent(), cs)); p.sentenceForParams(sentenceForContent(cs.getContent(), cs));
if (cs.getContent() == CodeSystemContentMode.NOTPRESENT) { if (cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
@ -236,6 +244,30 @@ public class CodeSystemRenderer extends TerminologyRenderer {
return hasExtensions; return hasExtensions;
} }
private void makeHierarchyParam(XhtmlNode x, CodeSystem cs, Enumeration<CodeSystemHierarchyMeaning> hm) {
if (hm.hasValue()) {
String s = hm.getValue().getDisplay();
VersionComparisonAnnotation.render(hm, x).tx(" in a "+s+" heirarchy");
} else if (VersionComparisonAnnotation.hasDeleted(cs, "hierarchyMeaning")) {
makeHierarchyParam(x, null, (Enumeration<CodeSystemHierarchyMeaning>) VersionComparisonAnnotation.getDeleted(cs, "hierarchyMeaning").get(0));
} else if (CodeSystemUtilities.hasHierarchy(cs)) {
x.tx(" in an undefined heirarchy");
} else {
x.tx("");
}
}
private void makeCasedParam(XhtmlNode x, CodeSystem cs, BooleanType caseSensitiveElement) {
if (caseSensitiveElement.hasValue()) {
String s = caseSensitiveElement.getValue() == true? "case-sensitive" : "case-insensitive";
VersionComparisonAnnotation.render(caseSensitiveElement, x).tx(s);
} else if (VersionComparisonAnnotation.hasDeleted(cs, "caseSensitive")) {
makeCasedParam(x, null, (BooleanType) VersionComparisonAnnotation.getDeleted(cs, "caseSensitive").get(0));
} else {
x.tx("");
}
}
private void listConceptLanguages(CodeSystem cs, ConceptDefinitionComponent c, List<String> langs) { private void listConceptLanguages(CodeSystem cs, ConceptDefinitionComponent c, List<String> langs) {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) { if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
@ -377,7 +409,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (link != null) { if (link != null) {
td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode()); td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
} else { } else {
td.attribute("style", "white-space:nowrap").addText(c.getCode()); VersionComparisonAnnotation.render(c, td.attribute("style", "white-space:nowrap")).addText(c.getCode());
} }
XhtmlNode a; XhtmlNode a;
if (c.hasCodeElement()) { if (c.hasCodeElement()) {
@ -390,13 +422,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
} }
if (hasDefinitions) { if (hasDefinitions) {
td = tr.td(); td = tr.td();
if (c != null && if (c != null &&c.hasDefinitionElement()) {
c.hasDefinitionElement()) {
if (getContext().getLang() == null) { if (getContext().getLang() == null) {
if (hasMarkdownInDefinitions(cs)) if (hasMarkdownInDefinitions(cs)) {
addMarkdown(td, c.getDefinition()); addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
else } else {
td.addText(c.getDefinition()); VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
}
} else if (getContext().getLang().equals("*")) { } else if (getContext().getLang().equals("*")) {
boolean sl = false; boolean sl = false;
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
@ -404,9 +436,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
sl = true; sl = true;
td.addText((sl ? cs.getLanguage("en")+": " : "")); td.addText((sl ? cs.getLanguage("en")+": " : ""));
if (hasMarkdownInDefinitions(cs)) if (hasMarkdownInDefinitions(cs))
addMarkdown(td, c.getDefinition()); addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
else else
td.addText(c.getDefinition()); VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
td.br(); td.br();
@ -414,7 +446,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
} }
} }
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
td.addText(c.getDefinition()); VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
} else { } else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
@ -591,7 +623,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) { public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
if (c.hasDisplayElement()) { if (c.hasDisplayElement()) {
if (getContext().getLang() == null) { if (getContext().getLang() == null) {
td.addText(c.getDisplay()); VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
} else if (getContext().getLang().equals("*")) { } else if (getContext().getLang().equals("*")) {
boolean sl = false; boolean sl = false;
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
@ -605,7 +637,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
} }
} }
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
td.addText(c.getDisplay()); VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
} else { } else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {

View File

@ -2727,30 +2727,24 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return ed.getPath().substring(ed.getPath().indexOf(".")+1); return ed.getPath().substring(ed.getPath().indexOf(".")+1);
} }
public static String formatTypeSpecifiers(IWorkerContext context, ElementDefinition d) { public XhtmlNode formatTypeSpecifiers(IWorkerContext context, ElementDefinition d) {
StringBuilder b = new StringBuilder(); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean first = true; boolean first = true;
for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) {
if (first) first = false; else b.append("<br/>"); if (first) first = false; else x.br();
String cond = ToolingExtensions.readStringExtension(e, "condition"); String cond = ToolingExtensions.readStringExtension(e, "condition");
String type = ToolingExtensions.readStringExtension(e, "type"); String type = ToolingExtensions.readStringExtension(e, "type");
b.append("If <code>"); x.tx("If ");
b.append(Utilities.escapeXml(cond)); x.code().tx(cond);
b.append("</code> then the type is "); x.tx(" then the type is ");
StructureDefinition sd = context.fetchTypeDefinition(type); StructureDefinition sd = context.fetchTypeDefinition(type);
if (sd == null) { if (sd == null) {
b.append("<code>"); x.code().tx(type);
b.append(Utilities.escapeXml(type));
b.append("</code>");
} else { } else {
b.append("<a href=\""); x.ah(sd.getWebPath()).tx(sd.getTypeName());
b.append(sd.getWebPath());
b.append("\">");
b.append(Utilities.escapeXml(sd.getTypeName()));
b.append("</a>");
} }
} }
return b.toString(); return first ? null : x;
} }
public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc) throws IOException, FHIRException { public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc) throws IOException, FHIRException {

View File

@ -1234,33 +1234,34 @@ public class ValueSetRenderer extends TerminologyRenderer {
li.tx(", "); li.tx(", ");
} }
} }
XhtmlNode wli = VersionComparisonAnnotation.render(f, li);
if (f.getOp() == FilterOperator.EXISTS) { if (f.getOp() == FilterOperator.EXISTS) {
if (f.getValue().equals("true")) { if (f.getValue().equals("true")) {
li.tx(f.getProperty()+" exists"); wli.tx(f.getProperty()+" exists");
} else { } else {
li.tx(f.getProperty()+" doesn't exist"); wli.tx(f.getProperty()+" doesn't exist");
} }
} else { } else {
li.tx(f.getProperty()+" "+describe(f.getOp())+" "); wli.tx(f.getProperty()+" "+describe(f.getOp())+" ");
if (e != null && codeExistsInValueSet(e, f.getValue())) { if (e != null && codeExistsInValueSet(e, f.getValue())) {
String href = getContext().fixReference(getCsRef(e)); String href = getContext().fixReference(getCsRef(e));
if (href.contains("#")) if (href.contains("#"))
href = href + "-"+Utilities.nmtokenize(f.getValue()); href = href + "-"+Utilities.nmtokenize(f.getValue());
else else
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue()); href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
li.ah(href).addText(f.getValue()); wli.ah(href).addText(f.getValue());
} else if ("concept".equals(f.getProperty()) && inc.hasSystem()) { } else if ("concept".equals(f.getProperty()) && inc.hasSystem()) {
li.addText(f.getValue()); wli.addText(f.getValue());
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null); ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null);
if (vr.isOk()) { if (vr.isOk()) {
li.tx(" ("+vr.getDisplay()+")"); wli.tx(" ("+vr.getDisplay()+")");
} }
} }
else else
li.addText(f.getValue()); wli.addText(f.getValue());
String disp = ToolingExtensions.getDisplayHint(f); String disp = ToolingExtensions.getDisplayHint(f);
if (disp != null) if (disp != null)
li.tx(" ("+disp+")"); wli.tx(" ("+disp+")");
} }
} }
} }
@ -1273,7 +1274,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false; first = false;
else else
li.tx(", "); li.tx(", ");
AddVsRef(vs.asStringValue(), li, vsRes); XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
AddVsRef(vs.asStringValue(), wli, vsRes);
} }
} }
if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) { if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) {
@ -1289,12 +1291,14 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false; first = false;
else else
li.tx(", "); li.tx(", ");
AddVsRef(vs.asStringValue(), li, vsRes); XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
AddVsRef(vs.asStringValue(), wli, vsRes);
} }
} else { } else {
XhtmlNode xul = li.ul(); XhtmlNode xul = li.ul();
for (UriType vs : inc.getValueSet()) { for (UriType vs : inc.getValueSet()) {
AddVsRef(vs.asStringValue(), xul.li(), vsRes); XhtmlNode wli = VersionComparisonAnnotation.render(vs, xul.li());
AddVsRef(vs.asStringValue(), wli, vsRes);
} }
} }