From 853b4fd9ca34bab1cb3e8ec6435ba4c4690782ef Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 25 May 2024 04:25:47 -0500 Subject: [PATCH] stable baseline --- .../hl7/fhir/r4b/fhirpath/FHIRPathEngine.java | 2 +- .../fhir/r5/renderers/CodeSystemRenderer.java | 14 +- .../fhir/r5/renderers/ConceptMapRenderer.java | 10 +- .../hl7/fhir/r5/renderers/DataRenderer.java | 3954 ++++--- .../renderers/DiagnosticReportRenderer.java | 974 +- .../hl7/fhir/r5/renderers/ListRenderer.java | 504 +- .../OperationDefinitionRenderer.java | 378 +- .../renderers/OperationOutcomeRenderer.java | 210 +- .../r5/renderers/QuestionnaireRenderer.java | 2308 ++-- .../StructureDefinitionRenderer.java | 9478 ++++++++--------- .../r5/renderers/TerminologyRenderer.java | 21 +- .../fhir/r5/renderers/ValueSetRenderer.java | 20 +- .../i18n/I18nConstantMaintainer.java | 477 +- .../fhir/utilities/i18n/I18nConstants.java | 5 + .../hl7/fhir/utilities/i18n/POGenerator.java | 80 +- .../utilities/i18n/RenderingI18nContext.java | 40 +- .../xhtml/HierarchicalTableGenerator.java | 4 +- .../instance/InstanceValidator.java | 2 +- 18 files changed, 9487 insertions(+), 8994 deletions(-) diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/fhirpath/FHIRPathEngine.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/fhirpath/FHIRPathEngine.java index 15c9b4c7a..3c883d44a 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/fhirpath/FHIRPathEngine.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/fhirpath/FHIRPathEngine.java @@ -6383,7 +6383,7 @@ public class FHIRPathEngine { sd = fetchStructureByType(element, expr); if (sd == null) { - throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, + throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId()); } childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index 18cb5c3d5..a0be76f57 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -110,7 +110,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { x.para().b().tx(formatPhrase(RenderingContext.CODESYSTEM_FILTERS)); XhtmlNode tbl = x.table("grid"); XhtmlNode tr = tbl.tr(); - tr.td().b().tx(formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_FILTER_CODE)); tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_FILTER_DESC)); tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_FILTER_OP)); tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_FILTER_VALUE)); @@ -132,8 +132,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { boolean hasURI = false; boolean hasDescription = false; for (PropertyComponent p : cs.getProperty()) { - String display = getPropertyDisplay(p); - hasRendered = hasRendered || display != null; + hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement())); hasURI = hasURI || p.hasUri(); hasDescription = hasDescription || p.hasDescription(); } @@ -145,7 +144,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { if (hasRendered) { tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_PROP_NAME)); } - tr.td().b().tx(formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_PROP_CODE)); if (hasURI) { tr.td().b().tx(formatPhrase(RenderingContext.CODESYSTEM_PROP_URI)); } @@ -156,8 +155,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { for (PropertyComponent p : cs.getProperty()) { tr = tbl.tr(); if (hasRendered) { - String display = getPropertyDisplay(p); - tr.td().tx(display); + tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement())); } renderStatus(p, tr.td()).tx(p.getCode()); if (hasURI) { @@ -261,10 +259,10 @@ public class CodeSystemRenderer extends TerminologyRenderer { } if (langs.size() >= 2) { Collections.sort(langs); - x.para().b().tx(context.formatPhrase(RenderingContext.GENERAL_ADD_LANG)); + x.para().b().tx(context.formatPhrase(RenderingContext.CODE_SYS_ADD_LANG)); t = x.table("codes"); XhtmlNode tr = t.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.CODE_SYS_CODE)); for (String lang : langs) tr.td().b().addText(describeLang(lang)); for (ConceptDefinitionComponent c : cs.getConcept()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java index f2b2f8d40..461a11e50 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java @@ -405,13 +405,13 @@ public class ConceptMapRenderer extends TerminologyRenderer { if (grp.hasSource()) { renderCanonical(cm, pp, grp.getSource()); } else { - pp.code(context.formatPhrase(RenderingContext.GENERAL_CODE_SYS_UNSPEC)); + pp.code(context.formatPhrase(RenderingContext.CONC_MAP_CODE_SYS_UNSPEC)); } pp.tx(" to "); if (grp.hasTarget()) { renderCanonical(cm, pp, grp.getTarget()); } else { - pp.code(context.formatPhrase(RenderingContext.GENERAL_CODE_SYS_UNSPEC)); + pp.code(context.formatPhrase(RenderingContext.CONC_MAP_CODE_SYS_UNSPEC)); } String display; @@ -484,7 +484,7 @@ public class ConceptMapRenderer extends TerminologyRenderer { String url = sources.get("code").iterator().next(); renderCSDetailsLink(tr, url, true); } else - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.CONC_MAP_CODE)); for (String s : sources.keySet()) { if (s != null && !s.equals("code")) { if (sources.get(s).size() == 1) { @@ -501,7 +501,7 @@ public class ConceptMapRenderer extends TerminologyRenderer { String url = targets.get("code").iterator().next(); renderCSDetailsLink(tr, url, true); } else - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.CONC_MAP_CODE)); for (String s : targets.keySet()) { if (s != null && !s.equals("code")) { if (targets.get(s).size() == 1) { @@ -698,7 +698,7 @@ public class ConceptMapRenderer extends TerminologyRenderer { if (span2) { td.colspan("2"); } - td.b().tx(context.formatPhrase(RenderingContext.GENERAL_CODES)); + td.b().tx(context.formatPhrase(RenderingContext.CONC_MAP_CODES)); td.tx(" " + (context.formatPhrase(RenderingContext.CONC_MAP_FRM) + " ")); if (cs == null) td.tx(url); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index 0f008a8a9..f12d41653 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -1,1987 +1,1981 @@ -package org.hl7.fhir.r5.renderers; - -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.YEAR; - -import java.io.IOException; -import java.math.BigDecimal; -import java.text.NumberFormat; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.FormatStyle; -import java.time.format.SignStyle; -import java.util.Currency; -import java.util.List; - -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.context.ContextUtilities; -import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.elementmodel.Element; -import org.hl7.fhir.r5.model.Address; -import org.hl7.fhir.r5.model.Annotation; -import org.hl7.fhir.r5.model.BackboneType; -import org.hl7.fhir.r5.model.Base; -import org.hl7.fhir.r5.model.Base64BinaryType; -import org.hl7.fhir.r5.model.BaseDateTimeType; -import org.hl7.fhir.r5.model.CanonicalResource; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.CodeSystem; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.CodeableConcept; -import org.hl7.fhir.r5.model.CodeableReference; -import org.hl7.fhir.r5.model.Coding; -import org.hl7.fhir.r5.model.ContactDetail; -import org.hl7.fhir.r5.model.ContactPoint; -import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem; -import org.hl7.fhir.r5.model.DataRequirement; -import org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent; -import org.hl7.fhir.r5.model.DataRequirement.DataRequirementDateFilterComponent; -import org.hl7.fhir.r5.model.DataRequirement.DataRequirementSortComponent; -import org.hl7.fhir.r5.model.DataRequirement.SortDirection; -import org.hl7.fhir.r5.model.DataType; -import org.hl7.fhir.r5.model.DateTimeType; -import org.hl7.fhir.r5.model.DateType; -import org.hl7.fhir.r5.model.ElementDefinition; -import org.hl7.fhir.r5.model.Enumeration; -import org.hl7.fhir.r5.model.Expression; -import org.hl7.fhir.r5.model.Extension; -import org.hl7.fhir.r5.model.ExtensionHelper; -import org.hl7.fhir.r5.model.HumanName; -import org.hl7.fhir.r5.model.HumanName.NameUse; -import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.Identifier; -import org.hl7.fhir.r5.model.MarkdownType; -import org.hl7.fhir.r5.model.Money; -import org.hl7.fhir.r5.model.NamingSystem; -import org.hl7.fhir.r5.model.Period; -import org.hl7.fhir.r5.model.PrimitiveType; -import org.hl7.fhir.r5.model.Quantity; -import org.hl7.fhir.r5.model.Range; -import org.hl7.fhir.r5.model.Reference; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.SampledData; -import org.hl7.fhir.r5.model.StringType; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.model.Timing; -import org.hl7.fhir.r5.model.Timing.EventTiming; -import org.hl7.fhir.r5.model.Timing.TimingRepeatComponent; -import org.hl7.fhir.r5.model.Timing.UnitsOfTime; -import org.hl7.fhir.r5.model.TriggerDefinition; -import org.hl7.fhir.r5.model.UriType; -import org.hl7.fhir.r5.model.UsageContext; -import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; -import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; -import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; -import org.hl7.fhir.r5.terminologies.JurisdictionUtilities; -import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; -import org.hl7.fhir.utilities.xhtml.NodeType; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; -import org.hl7.fhir.utilities.xhtml.XhtmlParser; - -import ca.uhn.fhir.model.api.TemporalPrecisionEnum; - -public class DataRenderer extends Renderer implements CodeResolver { - - // -- 1. context -------------------------------------------------------------- - - public DataRenderer(RenderingContext context) { - super(context); - } - - public DataRenderer(IWorkerContext worker) { - super(worker); - } - - // -- 2. Markdown support ------------------------------------------------------- - - public static String processRelativeUrls(String markdown, String path) { - if (markdown == null) { - return ""; - } - if (!Utilities.isAbsoluteUrl(path)) { - return markdown; - } - String basePath = path.contains("/") ? path.substring(0, path.lastIndexOf("/")+1) : path+"/"; - StringBuilder b = new StringBuilder(); - int i = 0; - while (i < markdown.length()) { - if (i < markdown.length()-3 && markdown.substring(i, i+2).equals("](")) { - int j = i + 2; - while (j < markdown.length() && markdown.charAt(j) != ')') - j++; - if (j < markdown.length()) { - String url = markdown.substring(i+2, j); - if (!Utilities.isAbsoluteUrl(url) && !url.startsWith("..")) { - // it's relative - so it's relative to the base URL - b.append("]("); - b.append(basePath); - } else { - b.append("]("); - } - i = i + 1; - } else - b.append(markdown.charAt(i)); - } else { - b.append(markdown.charAt(i)); - } - i++; - } - return b.toString(); - } - - protected void addMarkdown(XhtmlNode x, String text, String path) throws FHIRFormatError, IOException, DefinitionException { - addMarkdown(x, processRelativeUrls(text, path)); - } - - protected void addMarkdown(XhtmlNode x, String text) throws FHIRFormatError, IOException, DefinitionException { - if (text != null) { - // 1. custom FHIR extensions - while (text.contains("[[[")) { - String left = text.substring(0, text.indexOf("[[[")); - String link = text.substring(text.indexOf("[[[")+3, text.indexOf("]]]")); - String right = text.substring(text.indexOf("]]]")+3); - String path = null; - String url = link; - String[] parts = link.split("\\#"); - if (parts[0].contains(".")) { - path = parts[0]; - parts[0] = parts[0].substring(0, parts[0].indexOf(".")); - } - StructureDefinition p = getContext().getWorker().fetchResource(StructureDefinition.class, parts[0]); - if (p == null) { - p = getContext().getWorker().fetchTypeDefinition(parts[0]); - } - if (context.getTypeMap().containsKey(parts[0])) { - p = getContext().getWorker().fetchTypeDefinition(context.getTypeMap().get(parts[0])); - } - if (p == null) { - p = getContext().getWorker().fetchResource(StructureDefinition.class, link); - } - if (p != null) { - if ("Extension".equals(p.getType())) { - path = null; - } else if (p.hasSnapshot()) { - path = p.getSnapshot().getElementFirstRep().getPath(); - } else if (Utilities.isAbsoluteUrl(path)) { - path = null; - } - url = p.getWebPath(); - if (url == null) { - url = p.getUserString("filename"); - } - } else { - throw new DefinitionException(context.formatPhrase(RenderingContext.DATA_REND_MKDWN_LNK, link) + " "); - } - - text = left+"["+link+"]("+url+(path == null ? "" : "#"+path)+")"+right; - } - - // 2. markdown - String s = getContext().getMarkdown().process(text, "narrative generator"); - XhtmlParser p = new XhtmlParser(); - XhtmlNode m; - try { - m = p.parse("
"+s+"
", "div"); - } catch (org.hl7.fhir.exceptions.FHIRFormatError e) { - throw new FHIRFormatError(e.getMessage(), e); - } - x.getChildNodes().addAll(m.getChildNodes()); - } - } - - protected void smartAddText(XhtmlNode p, String text) { - if (text == null) - return; - - String[] lines = text.split("\\r\\n"); - for (int i = 0; i < lines.length; i++) { - if (i > 0) - p.br(); - p.addText(lines[i]); - } - } +package org.hl7.fhir.r5.renderers; - // -- 3. General Purpose Terminology Support ----------------------------------------- - - private static String snMonth(String m) { - switch (m) { - case "1" : return "Jan"; - case "2" : return "Feb"; - case "3" : return "Mar"; - case "4" : return "Apr"; - case "5" : return "May"; - case "6" : return "Jun"; - case "7" : return "Jul"; - case "8" : return "Aug"; - case "9" : return "Sep"; - case "10" : return "Oct"; - case "11" : return "Nov"; - case "12" : return "Dec"; - default: return null; - } - } - - public static String describeVersion(String version) { - if (version.startsWith("http://snomed.info/sct")) { - String[] p = version.split("\\/"); - String ed = null; - String dt = ""; - - if (p[p.length-2].equals("version")) { - ed = p[p.length-3]; - String y = p[p.length-3].substring(4, 8); - String m = p[p.length-3].substring(2, 4); - dt = " rel. "+snMonth(m)+" "+y; - } else { - ed = p[p.length-1]; - } - switch (ed) { - case "900000000000207008": return "Intl"+dt; - case "731000124108": return "US"+dt; - case "32506021000036107": return "AU"+dt; - case "449081005": return "ES"+dt; - case "554471000005108": return "DK"+dt; - case "11000146104": return "NL"+dt; - case "45991000052106": return "SE"+dt; - case "999000041000000102": return "UK"+dt; - case "20611000087101": return "CA"+dt; - case "11000172109": return "BE"+dt; - default: return "??"+dt; - } - } else { - return version; - } - } - - public String displaySystem(String system) { - if (system == null) - return (context.formatPhrase(RenderingContext.DATA_REND_NOT_STAT)); - if (system.equals("http://loinc.org")) - return (context.formatPhrase(RenderingContext.DATA_REND_LOINC)); - if (system.startsWith("http://snomed.info")) - return (context.formatPhrase(RenderingContext.DATA_REND_SNOMED)); - if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm")) - return (context.formatPhrase(RenderingContext.DATA_REND_RXNORM)); - if (system.equals("http://hl7.org/fhir/sid/icd-9")) - return (context.formatPhrase(RenderingContext.DATA_REND_ICD)); - if (system.equals("http://dicom.nema.org/resources/ontology/DCM")) - return (context.formatPhrase(RenderingContext.DATA_REND_DICOM)); - if (system.equals("http://unitsofmeasure.org")) - return (context.formatPhrase(RenderingContext.DATA_REND_UCUM)); - - CodeSystem cs = context.getContext().fetchCodeSystem(system); - if (cs != null) { - return crPresent(cs); - } - return tails(system); - } - - private String crPresent(CanonicalResource cr) { - if (cr.hasUserData("presentation")) { - return cr.getUserString("presentation"); - } - if (cr.hasTitle()) - return context.getTranslated(cr.getTitleElement()); - if (cr.hasName()) - return context.getTranslated(cr.getNameElement()); - return cr.toString(); - } - - private String tails(String system) { - if (system.contains("/")) { - return system.substring(system.lastIndexOf("/")+1); - } else { - return (context.formatPhrase(RenderingContext.DATA_REND_UNKNWN)); - } - } - - protected String makeAnchor(String codeSystem, String code) { - String s = codeSystem+'-'+code; - StringBuilder b = new StringBuilder(); - for (char c : s.toCharArray()) { - if (Character.isAlphabetic(c) || Character.isDigit(c) || c == '.') - b.append(c); - else - b.append('-'); - } - return b.toString(); - } - - private String lookupCode(String system, String version, String code) { - if (JurisdictionUtilities.isJurisdiction(system)) { - return JurisdictionUtilities.displayJurisdiction(system+"#"+code); - } - ValidationResult t = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions().withLanguage(context.getLocale().toString().replace("_", "-")).withVersionFlexible(true), system, version, code, null); - - if (t != null && t.getDisplay() != null) - return t.getDisplay(); - else - return code; - } - - protected String describeLang(String lang) { - // special cases: - if ("fr-CA".equals(lang)) { - return "French (Canadian)"; // this one was omitted from the value set - } - ValueSet v = getContext().getWorker().findTxResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages"); - if (v != null) { - ConceptReferenceComponent l = null; - for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { - if (cc.getCode().equals(lang)) - l = cc; - } - if (l == null) { - if (lang.contains("-")) { - lang = lang.substring(0, lang.indexOf("-")); - } - for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { - if (cc.getCode().equals(lang)) { - l = cc; - break; - } - } - if (l == null) { - for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { - if (cc.getCode().startsWith(lang+"-")) { - l = cc; - break; - } - } - } - } - if (l != null) { - if (lang.contains("-")) - lang = lang.substring(0, lang.indexOf("-")); - String en = l.getDisplay(); - String nativelang = null; - for (ConceptReferenceDesignationComponent cd : l.getDesignation()) { - if (cd.getLanguage().equals(lang)) - nativelang = cd.getValue(); - } - if (nativelang == null) - return en+" ("+lang+")"; - else - return nativelang+" ("+en+", "+lang+")"; - } - } - return lang; - } - - private boolean isCanonical(String path) { - if (!path.endsWith(".url")) - return false; - String t = path.substring(0, path.length()-4); - StructureDefinition sd = getContext().getWorker().fetchTypeDefinition(t); - if (sd == null) - return false; - if (VersionUtilities.getCanonicalResourceNames(getContext().getWorker().getVersion()).contains(t)) { - return true; - } - if (Utilities.existsInList(t, - "ActivityDefinition", "CapabilityStatement", "ChargeItemDefinition", "Citation", "CodeSystem", - "CompartmentDefinition", "ConceptMap", "ConditionDefinition", "EventDefinition", "Evidence", "EvidenceReport", "EvidenceVariable", - "ExampleScenario", "GraphDefinition", "ImplementationGuide", "Library", "Measure", "MessageDefinition", "NamingSystem", "PlanDefinition" - )) - return true; - return false; - } - - // -- 4. Language support ------------------------------------------------------ - - public String gt(@SuppressWarnings("rawtypes") PrimitiveType value) { - return context.getTranslated(value); - } - - // -- 6. General purpose extension rendering ---------------------------------------------- - - public boolean hasRenderableExtensions(DataType element) { - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - return true; - } - } - return false; - } - - public boolean hasRenderableExtensions(BackboneType element) { - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - return true; - } - } - return element.hasModifierExtension(); - } - - private String getExtensionLabel(Extension ext) { - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, ext.getUrl()); - if (sd != null && ext.hasValue() && ext.getValue().isPrimitive() && sd.hasSnapshot()) { - for (ElementDefinition ed : sd.getSnapshot().getElement()) { - if (Utilities.existsInList(ed.getPath(), "Extension", "Extension.value[x]") && ed.hasLabel()) { - return context.getTranslated(ed.getLabelElement()); - } - } - } - return null; - } - - private boolean canRender(Extension ext) { - return getExtensionLabel(ext) != null; - } - - public void renderExtensionsInList(XhtmlNode ul, DataType element) throws FHIRFormatError, DefinitionException, IOException { - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - String lbl = getExtensionLabel(ext); - XhtmlNode li = ul.li(); - li.tx(lbl); - li.tx(": "); - render(li, ext.getValue()); - } - } - } - - public void renderExtensionsInList(XhtmlNode ul, BackboneType element) throws FHIRFormatError, DefinitionException, IOException { - for (Extension ext : element.getModifierExtension()) { - if (canRender(ext)) { - String lbl = getExtensionLabel(ext); - XhtmlNode li = ul.li(); - li = li.b(); - li.tx(lbl); - li.tx(": "); - render(li, ext.getValue()); - } else { - // somehow have to do better than this - XhtmlNode li = ul.li(); - li.b().tx(context.formatPhrase(RenderingContext.DATA_REND_UNRD_EX)); - } - } - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - String lbl = getExtensionLabel(ext); - XhtmlNode li = ul.li(); - li.tx(lbl); - li.tx(": "); - render(li, ext.getValue()); - } - } - } - - public void renderExtensionsInText(XhtmlNode div, DataType element, String sep) throws FHIRFormatError, DefinitionException, IOException { - boolean first = true; - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - if (first) { - first = false; - } else { - div.tx(sep); - div.tx(" "); - } - - String lbl = getExtensionLabel(ext); - div.tx(lbl); - div.tx(": "); - render(div, ext.getValue()); - } - } - } - - public void renderExtensionsInList(XhtmlNode div, BackboneType element, String sep) throws FHIRFormatError, DefinitionException, IOException { - boolean first = true; - for (Extension ext : element.getModifierExtension()) { - if (first) { - first = false; - } else { - div.tx(sep); - div.tx(" "); - } - if (canRender(ext)) { - String lbl = getExtensionLabel(ext); - XhtmlNode b = div.b(); - b.tx(lbl); - b.tx(": "); - render(div, ext.getValue()); - } else { - // somehow have to do better than this - div.b().tx(context.formatPhrase(RenderingContext.DATA_REND_UNRD_EX)); - } - } - for (Extension ext : element.getExtension()) { - if (canRender(ext)) { - if (first) { - first = false; - } else { - div.tx(sep); - div.tx(" "); - } - - String lbl = getExtensionLabel(ext); - div.tx(lbl); - div.tx(": "); - render(div, ext.getValue()); - } - } - - } - - // -- 6. Data type Rendering ---------------------------------------------- - - public static String display(IWorkerContext context, DataType type) { - return new DataRenderer(new RenderingContext(context, null, null, "http://hl7.org/fhir/R4", "", null, ResourceRendererMode.END_USER, GenerationRules.VALID_RESOURCE)).display(type); - } - - public String displayBase(Base b) { - if (b instanceof DataType) { - return display((DataType) b); - } else { - return (context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, b.fhirType()) + " "); - } - } - - public String display(DataType type) { - if (type == null || type.isEmpty()) { - return ""; - } +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; + +import java.io.IOException; +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.format.SignStyle; +import java.util.Currency; +import java.util.List; + +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.context.ContextUtilities; +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.model.Address; +import org.hl7.fhir.r5.model.Annotation; +import org.hl7.fhir.r5.model.BackboneType; +import org.hl7.fhir.r5.model.Base; +import org.hl7.fhir.r5.model.Base64BinaryType; +import org.hl7.fhir.r5.model.BaseDateTimeType; +import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.CodeableReference; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.ContactDetail; +import org.hl7.fhir.r5.model.ContactPoint; +import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem; +import org.hl7.fhir.r5.model.DataRequirement; +import org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent; +import org.hl7.fhir.r5.model.DataRequirement.DataRequirementDateFilterComponent; +import org.hl7.fhir.r5.model.DataRequirement.DataRequirementSortComponent; +import org.hl7.fhir.r5.model.DataRequirement.SortDirection; +import org.hl7.fhir.r5.model.DataType; +import org.hl7.fhir.r5.model.DateTimeType; +import org.hl7.fhir.r5.model.DateType; +import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.Enumeration; +import org.hl7.fhir.r5.model.Expression; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.ExtensionHelper; +import org.hl7.fhir.r5.model.HumanName; +import org.hl7.fhir.r5.model.HumanName.NameUse; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.Identifier; +import org.hl7.fhir.r5.model.MarkdownType; +import org.hl7.fhir.r5.model.Money; +import org.hl7.fhir.r5.model.NamingSystem; +import org.hl7.fhir.r5.model.Period; +import org.hl7.fhir.r5.model.PrimitiveType; +import org.hl7.fhir.r5.model.Quantity; +import org.hl7.fhir.r5.model.Range; +import org.hl7.fhir.r5.model.Reference; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.SampledData; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.Timing; +import org.hl7.fhir.r5.model.Timing.EventTiming; +import org.hl7.fhir.r5.model.Timing.TimingRepeatComponent; +import org.hl7.fhir.r5.model.Timing.UnitsOfTime; +import org.hl7.fhir.r5.model.TriggerDefinition; +import org.hl7.fhir.r5.model.UriType; +import org.hl7.fhir.r5.model.UsageContext; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; +import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; +import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; +import org.hl7.fhir.r5.terminologies.JurisdictionUtilities; +import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; +import org.hl7.fhir.utilities.xhtml.NodeType; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; +import org.hl7.fhir.utilities.xhtml.XhtmlParser; + +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; + +public class DataRenderer extends Renderer implements CodeResolver { + + // -- 1. context -------------------------------------------------------------- + + public DataRenderer(RenderingContext context) { + super(context); + } + + public DataRenderer(IWorkerContext worker) { + super(worker); + } + + // -- 2. Markdown support ------------------------------------------------------- - if (type instanceof Coding) { - return displayCoding((Coding) type); - } else if (type instanceof CodeableConcept) { - return displayCodeableConcept((CodeableConcept) type); - } else if (type instanceof Identifier) { - return displayIdentifier((Identifier) type); - } else if (type instanceof HumanName) { - return displayHumanName((HumanName) type); - } else if (type instanceof Address) { - return displayAddress((Address) type); - } else if (type instanceof ContactPoint) { - return displayContactPoint((ContactPoint) type); - } else if (type instanceof Quantity) { - return displayQuantity((Quantity) type); - } else if (type instanceof Range) { - return displayRange((Range) type); - } else if (type instanceof Period) { - return displayPeriod((Period) type); - } else if (type instanceof Timing) { - return displayTiming((Timing) type); - } else if (type instanceof SampledData) { - return displaySampledData((SampledData) type); - } else if (type instanceof ContactDetail) { - return displayContactDetail((ContactDetail) type); - } else if (type.isDateTime()) { - return displayDateTime((BaseDateTimeType) type); - } else if (type.isPrimitive()) { - return context.getTranslated((PrimitiveType) type); - } else { - return (context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, type.fhirType()) + " "); - } - } - - protected String displayDateTime(BaseDateTimeType type) { - if (!type.hasPrimitiveValue()) { - return ""; - } - - // relevant inputs in rendering context: - // timeZone, dateTimeFormat, locale, mode - // timezone - application specified timezone to use. - // null = default to the time of the date/time itself - // dateTimeFormat - application specified format for date times - // null = default to ... depends on mode - // mode - if rendering mode is technical, format defaults to XML format - // locale - otherwise, format defaults to SHORT for the Locale (which defaults to default Locale) - if (isOnlyDate(type.getPrecision())) { - - DateTimeFormatter fmt = getDateFormatForPrecision(type); - LocalDate date = LocalDate.of(type.getYear(), type.getMonth()+1, type.getDay()); - return fmt.format(date); - } - - DateTimeFormatter fmt = context.getDateTimeFormat(); - if (fmt == null) { - if (context.isTechnicalMode()) { - fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME; - } else { - fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(context.getLocale()); - } - } - ZonedDateTime zdt = ZonedDateTime.parse(type.primitiveValue()); - ZoneId zone = context.getTimeZoneId(); - if (zone != null) { - zdt = zdt.withZoneSameInstant(zone); - } - return fmt.format(zdt); - } - - private DateTimeFormatter getDateFormatForPrecision(BaseDateTimeType type) { - DateTimeFormatter fmt = getContextDateFormat(type); - if (fmt != null) { - return fmt; - } - if (context.isTechnicalMode()) { - switch (type.getPrecision()) { - case YEAR: - return new DateTimeFormatterBuilder().appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD).toFormatter(); - case MONTH: - return new DateTimeFormatterBuilder().appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD).appendLiteral('-').appendValue(MONTH_OF_YEAR, 2).toFormatter(); - default: - return DateTimeFormatter.ISO_DATE; - } - } else { - switch (type.getPrecision()) { - case YEAR: - return DateTimeFormatter.ofPattern("uuuu"); - case MONTH: - return DateTimeFormatter.ofPattern("MMM uuuu"); - default: - return DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(context.getLocale()); - } - } - } - - private DateTimeFormatter getContextDateFormat(BaseDateTimeType type) { - switch (type.getPrecision()) { - case YEAR: - return context.getDateYearFormat(); - case MONTH: - return context.getDateYearMonthFormat(); - default: - return context.getDateFormat(); - } - } - - private boolean isOnlyDate(TemporalPrecisionEnum temporalPrecisionEnum) { - return temporalPrecisionEnum == TemporalPrecisionEnum.YEAR || temporalPrecisionEnum == TemporalPrecisionEnum.MONTH || temporalPrecisionEnum == TemporalPrecisionEnum.DAY; - } - - public String display(BaseWrapper type) { - return (context.formatPhrase(RenderingContext.DATA_REND_TO_DO)); - } - - public void render(XhtmlNode x, BaseWrapper type) throws FHIRFormatError, DefinitionException, IOException { - Base base = null; - try { - base = type.getBase(); - } catch (FHIRException | IOException e) { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_ERROR, e.getMessage()) + " "); // this shouldn't happen - it's an error in the library itself - return; - } - if (base instanceof DataType) { - render(x, (DataType) base); - } else { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_TO_DO, base.fhirType())); - } - } - - public void renderBase(XhtmlNode x, Base b) throws FHIRFormatError, DefinitionException, IOException { - if (b instanceof DataType) { - render(x, (DataType) b); - } else { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, b.fhirType()) + " "); - } - } - - public void render(XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException { - if (type instanceof BaseDateTimeType) { - x.tx(displayDateTime((BaseDateTimeType) type)); - } else if (type instanceof UriType) { - renderUri(x, (UriType) type); - } else if (type instanceof Annotation) { - renderAnnotation(x, (Annotation) type); - } else if (type instanceof Coding) { - renderCodingWithDetails(x, (Coding) type); - } else if (type instanceof CodeableConcept) { - renderCodeableConcept(x, (CodeableConcept) type); - } else if (type instanceof Identifier) { - renderIdentifier(x, (Identifier) type); - } else if (type instanceof HumanName) { - renderHumanName(x, (HumanName) type); - } else if (type instanceof Address) { - renderAddress(x, (Address) type); - } else if (type instanceof Expression) { - renderExpression(x, (Expression) type); - } else if (type instanceof Money) { - renderMoney(x, (Money) type); - } else if (type instanceof ContactPoint) { - renderContactPoint(x, (ContactPoint) type); - } else if (type instanceof Quantity) { - renderQuantity(x, (Quantity) type); - } else if (type instanceof Range) { - renderRange(x, (Range) type); - } else if (type instanceof Period) { - renderPeriod(x, (Period) type); - } else if (type instanceof Timing) { - renderTiming(x, (Timing) type); - } else if (type instanceof SampledData) { - renderSampledData(x, (SampledData) type); - } else if (type instanceof Reference) { - renderReference(x, (Reference) type); - } else if (type instanceof UsageContext) { - renderUsageContext(x, (UsageContext) type); - } else if (type instanceof CodeableReference) { - CodeableReference cr = (CodeableReference) type; - if (cr.hasConcept()) { - renderCodeableConcept(x, cr.getConcept()); + public static String processRelativeUrls(String markdown, String path) { + if (markdown == null) { + return ""; + } + if (!Utilities.isAbsoluteUrl(path)) { + return markdown; + } + String basePath = path.contains("/") ? path.substring(0, path.lastIndexOf("/")+1) : path+"/"; + StringBuilder b = new StringBuilder(); + int i = 0; + while (i < markdown.length()) { + if (i < markdown.length()-3 && markdown.substring(i, i+2).equals("](")) { + int j = i + 2; + while (j < markdown.length() && markdown.charAt(j) != ')') + j++; + if (j < markdown.length()) { + String url = markdown.substring(i+2, j); + if (!Utilities.isAbsoluteUrl(url) && !url.startsWith("..")) { + // it's relative - so it's relative to the base URL + b.append("]("); + b.append(basePath); + } else { + b.append("]("); + } + i = i + 1; + } else + b.append(markdown.charAt(i)); } else { - renderReference(x, cr.getReference()); - } - } else if (type instanceof MarkdownType) { - addMarkdown(x, context.getTranslated((MarkdownType) type)); - } else if (type instanceof Base64BinaryType) { - Base64BinaryType b64 = (Base64BinaryType) type; - x.tx(context.formatPhrase(RenderingContext.DATA_REND_BASE64, (b64.getValue() == null ? "0" : b64.getValue().length))); - } else if (type.isPrimitive()) { - x.tx(context.getTranslated((PrimitiveType) type)); - } else { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, type.fhirType()) + " "); - } - } - - protected void renderReference(XhtmlNode x, Reference ref) { - if (ref.hasDisplay()) { - x.tx(context.getTranslated(ref.getDisplayElement())); - } else if (ref.hasReference()) { - x.tx(ref.getReference()); - } else { - x.tx("??"); - } - } - - public void renderDateTime(XhtmlNode x, Base e) { - if (e.hasPrimitiveValue()) { - x.addText(displayDateTime((DateTimeType) e)); - } - } - - public void renderDate(XhtmlNode x, Base e) { - if (e.hasPrimitiveValue()) { - x.addText(displayDateTime((DateType) e)); - } - } - - public void renderDateTime(XhtmlNode x, String s) { - if (s != null) { - DateTimeType dt = new DateTimeType(s); - x.addText(displayDateTime(dt)); - } - } - - protected void renderUri(XhtmlNode x, UriType uri) { - if (uri.getValue().startsWith("mailto:")) { - x.ah(uri.getValue()).addText(uri.getValue().substring(7)); - } else { - Resource r = context.getContext().fetchResource(Resource.class, uri.getValue()); - if (r != null && r.getWebPath() != null) { - if (r instanceof CanonicalResource) { - x.ah(r.getWebPath()).addText(crPresent((CanonicalResource) r)); - } else { - x.ah(r.getWebPath()).addText(uri.getValue()); - } - } else { - String url = context.getResolver() != null ? context.getResolver().resolveUri(context, uri.getValue()) : null; - if (url != null) { - x.ah(url).addText(uri.getValue()); - } else if (Utilities.isAbsoluteUrlLinkable(uri.getValue()) && !(uri instanceof IdType)) { - x.ah(uri.getValue()).addText(uri.getValue()); - } else { - x.addText(uri.getValue()); - } - } - } - } + b.append(markdown.charAt(i)); + } + i++; + } + return b.toString(); + } + + protected void addMarkdown(XhtmlNode x, String text, String path) throws FHIRFormatError, IOException, DefinitionException { + addMarkdown(x, processRelativeUrls(text, path)); + } + + protected void addMarkdown(XhtmlNode x, String text) throws FHIRFormatError, IOException, DefinitionException { + if (text != null) { + // 1. custom FHIR extensions + while (text.contains("[[[")) { + String left = text.substring(0, text.indexOf("[[[")); + String link = text.substring(text.indexOf("[[[")+3, text.indexOf("]]]")); + String right = text.substring(text.indexOf("]]]")+3); + String path = null; + String url = link; + String[] parts = link.split("\\#"); + if (parts[0].contains(".")) { + path = parts[0]; + parts[0] = parts[0].substring(0, parts[0].indexOf(".")); + } + StructureDefinition p = getContext().getWorker().fetchResource(StructureDefinition.class, parts[0]); + if (p == null) { + p = getContext().getWorker().fetchTypeDefinition(parts[0]); + } + if (context.getTypeMap().containsKey(parts[0])) { + p = getContext().getWorker().fetchTypeDefinition(context.getTypeMap().get(parts[0])); + } + if (p == null) { + p = getContext().getWorker().fetchResource(StructureDefinition.class, link); + } + if (p != null) { + if ("Extension".equals(p.getType())) { + path = null; + } else if (p.hasSnapshot()) { + path = p.getSnapshot().getElementFirstRep().getPath(); + } else if (Utilities.isAbsoluteUrl(path)) { + path = null; + } + url = p.getWebPath(); + if (url == null) { + url = p.getUserString("filename"); + } + } else { + throw new DefinitionException(context.formatPhrase(RenderingContext.DATA_REND_MKDWN_LNK, link) + " "); + } + + text = left+"["+link+"]("+url+(path == null ? "" : "#"+path)+")"+right; + } + + // 2. markdown + String s = getContext().getMarkdown().process(text, "narrative generator"); + XhtmlParser p = new XhtmlParser(); + XhtmlNode m; + try { + m = p.parse("
"+s+"
", "div"); + } catch (org.hl7.fhir.exceptions.FHIRFormatError e) { + throw new FHIRFormatError(e.getMessage(), e); + } + x.getChildNodes().addAll(m.getChildNodes()); + } + } + + protected void smartAddText(XhtmlNode p, String text) { + if (text == null) + return; + + String[] lines = text.split("\\r\\n"); + for (int i = 0; i < lines.length; i++) { + if (i > 0) + p.br(); + p.addText(lines[i]); + } + } - protected void renderUri(XhtmlNode x, UriType uriD, String path, String id, Resource src) { - String uri = uriD.getValue(); - if (isCanonical(path)) { - x.code().tx(uri); - } else { - if (uri == null) { - x.b().tx(uri); - } else if (uri.startsWith("mailto:")) { - x.ah(uri).addText(uri.substring(7)); - } else { - Resource target = context.getContext().fetchResource(Resource.class, uri, src); - if (target != null && target.hasWebPath()) { - String title = target instanceof CanonicalResource ? crPresent((CanonicalResource) target) : uri; - x.ah(target.getWebPath()).addText(title); - } else { - String url = context.getResolver() != null ? context.getResolver().resolveUri(context, uri) : null; - if (url != null) { - x.ah(url).addText(uri); - } else if (uri.contains("|")) { - x.ah(uri.substring(0, uri.indexOf("|"))).addText(uri); - } else if (uri.startsWith("http:") || uri.startsWith("https:") || uri.startsWith("ftp:")) { - x.ah(uri).addText(uri); - } else { - x.code().addText(uri); - } - } - } - } - } - - protected void renderAnnotation(XhtmlNode x, Annotation annot) { - renderAnnotation(x, annot, false); - } - - protected void renderAnnotation(XhtmlNode x, Annotation a, boolean showCodeDetails) throws FHIRException { - StringBuilder b = new StringBuilder(); - if (a.hasText()) { - b.append(context.getTranslated(a.getTextElement())); - } - - if (a.hasText() && (a.hasAuthor() || a.hasTimeElement())) { - b.append(" ("); - } - - if (a.hasAuthor()) { - b.append(context.formatPhrase(RenderingContext.DATA_REND_BY) + " "); - if (a.hasAuthorReference()) { - b.append(a.getAuthorReference().getReference()); - } else if (a.hasAuthorStringType()) { - b.append(context.getTranslated(a.getAuthorStringType())); - } - } - - - if (a.hasTimeElement()) { - if (b.length() > 0) { - b.append(" "); - } - b.append("@").append(a.getTimeElement().toHumanDisplay()); - } - if (a.hasText() && (a.hasAuthor() || a.hasTimeElement())) { - b.append(")"); - } - - - x.addText(b.toString()); - } - - public String displayCoding(Coding c) { - String s = ""; - if (context.isTechnicalMode()) { - s = context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(s)) { - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - } - if (Utilities.noString(s)) { - s = displayCodeTriple(c.getSystem(), c.getVersion(), c.getCode()); - } else if (c.hasSystem()) { - s = s + " ("+displayCodeTriple(c.getSystem(), c.getVersion(), c.getCode())+")"; - } else if (c.hasCode()) { - s = s + " ("+c.getCode()+")"; - } - } else { - if (c.hasDisplayElement()) - return context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(s)) - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - if (Utilities.noString(s)) - s = c.getCode(); - } - return s; - } - - private String displayCodeSource(String system, String version) { - String s = displaySystem(system); - if (version != null) { - s = s + "["+describeVersion(version)+"]"; - } - return s; - } - - private String displayCodeTriple(String system, String version, String code) { - if (system == null) { - if (code == null) { - return ""; - } else { - return "#"+code; - } - } else { - String s = displayCodeSource(system, version); - if (code != null) { - s = s + "#"+code; - } - return s; - } - } - - public String displayCoding(List list) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (Coding c : list) { - b.append(displayCoding(c)); - } - return b.toString(); - } - - protected void renderCoding(XhtmlNode x, Coding c) { - renderCoding(x, c, false); - } - - protected void renderCoding(HierarchicalTableGenerator gen, List pieces, Coding c) { - if (c.isEmpty()) { - return; - } - - String url = getLinkForSystem(c.getSystem(), c.getVersion()); - String name = displayCodeSource(c.getSystem(), c.getVersion()); - if (!Utilities.noString(url)) { - pieces.add(gen.new Piece(url, name, c.getSystem()+(c.hasVersion() ? "#"+c.getVersion() : ""))); + // -- 3. General Purpose Terminology Support ----------------------------------------- + + private static String snMonth(String m) { + switch (m) { + case "1" : return "Jan"; + case "2" : return "Feb"; + case "3" : return "Mar"; + case "4" : return "Apr"; + case "5" : return "May"; + case "6" : return "Jun"; + case "7" : return "Jul"; + case "8" : return "Aug"; + case "9" : return "Sep"; + case "10" : return "Oct"; + case "11" : return "Nov"; + case "12" : return "Dec"; + default: return null; + } + } + + public static String describeVersion(String version) { + if (version.startsWith("http://snomed.info/sct")) { + String[] p = version.split("\\/"); + String ed = null; + String dt = ""; + + if (p[p.length-2].equals("version")) { + ed = p[p.length-3]; + String y = p[p.length-3].substring(4, 8); + String m = p[p.length-3].substring(2, 4); + dt = " rel. "+snMonth(m)+" "+y; + } else { + ed = p[p.length-1]; + } + switch (ed) { + case "900000000000207008": return "Intl"+dt; + case "731000124108": return "US"+dt; + case "32506021000036107": return "AU"+dt; + case "449081005": return "ES"+dt; + case "554471000005108": return "DK"+dt; + case "11000146104": return "NL"+dt; + case "45991000052106": return "SE"+dt; + case "999000041000000102": return "UK"+dt; + case "20611000087101": return "CA"+dt; + case "11000172109": return "BE"+dt; + default: return "??"+dt; + } } else { - pieces.add(gen.new Piece(null, name, c.getSystem()+(c.hasVersion() ? "#"+c.getVersion() : ""))); - } - pieces.add(gen.new Piece(null, "#"+c.getCode(), null)); - String s = context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(s)) { - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - } - if (!Utilities.noString(s)) { - pieces.add(gen.new Piece(null, " \""+s+"\"", null)); - } - } - - private String getLinkForSystem(String system, String version) { - if ("http://snomed.info/sct".equals(system)) { - return "https://browser.ihtsdotools.org/"; - } else if ("http://loinc.org".equals(system)) { - return "https://loinc.org/"; - } else if ("http://unitsofmeasure.org".equals(system)) { - return "http://ucum.org"; - } else { - String url = system; - if (version != null) { - url = url + "|"+version; - } - CodeSystem cs = context.getWorker().fetchCodeSystem(url); - if (cs != null && cs.hasWebPath()) { - return cs.getWebPath(); - } - return null; - } - } - - protected String getLinkForCode(String system, String version, String code) { - if ("http://snomed.info/sct".equals(system)) { - if (!Utilities.noString(code)) { - return "http://snomed.info/id/"+code; - } else { - return "https://browser.ihtsdotools.org/"; - } - } else if ("http://loinc.org".equals(system)) { - if (!Utilities.noString(code)) { - return "https://loinc.org/"+code; - } else { - return "https://loinc.org/"; - } - } else if ("http://www.nlm.nih.gov/research/umls/rxnorm".equals(system)) { - if (!Utilities.noString(code)) { - return "https://mor.nlm.nih.gov/RxNav/search?searchBy=RXCUI&searchTerm="+code; - } else { - return "https://www.nlm.nih.gov/research/umls/rxnorm/index.html"; - } - } else if ("urn:iso:std:iso:3166".equals(system)) { - if (!Utilities.noString(code)) { - return "https://en.wikipedia.org/wiki/ISO_3166-2:"+code; - } else { - return "https://en.wikipedia.org/wiki/ISO_3166-2"; - } - } else { - CodeSystem cs = context.getWorker().fetchCodeSystem(system, version); - if (cs != null && cs.hasWebPath()) { - if (!Utilities.noString(code)) { - return cs.getWebPath()+"#"+cs.getId()+"-"+Utilities.nmtokenize(code); - } else { - return cs.getWebPath(); - } - } - } - return null; - } - - public CodeResolution resolveCode(String system, String code) { - return resolveCode(new Coding().setSystem(system).setCode(code)); - } - - public CodeResolution resolveCode(Coding c) { - String systemName; - String systemLink; - String link; - String display = null; - String hint; - - if (c.hasDisplayElement()) - display = context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(display)) - display = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - if (Utilities.noString(display)) { - display = c.getCode(); - } - - CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem()); - systemLink = cs != null ? cs.getWebPath() : null; - systemName = cs != null ? crPresent(cs) : displaySystem(c.getSystem()); - link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode()); - - hint = systemName+": "+display+(c.hasVersion() ? " "+ context.formatPhrase(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")") : ""); - return new CodeResolution(systemName, systemLink, link, display, hint); - } - - public CodeResolution resolveCode(CodeableConcept code) { - if (code.hasCoding()) { - return resolveCode(code.getCodingFirstRep()); - } else { - return new CodeResolution(null, null, null, code.getText(), code.getText()); - } - } - protected void renderCodingWithDetails(XhtmlNode x, Coding c) { - String s = ""; - if (c.hasDisplayElement()) - s = context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(s)) - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - - CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem()); - - String sn = cs != null ? crPresent(cs) : displaySystem(c.getSystem()); - String link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode()); - if (link != null) { - x.ah(link).tx(sn); - } else { - x.tx(sn); - } - - x.tx(" "); - x.tx(c.getCode()); - if (!Utilities.noString(s)) { - x.tx(": "); - x.tx(s); - } - if (c.hasVersion()) { - x.tx(" "+context.formatPhrase(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")")); - } - } - - protected void renderCoding(XhtmlNode x, Coding c, boolean showCodeDetails) { - String s = ""; - if (c.hasDisplayElement()) - s = context.getTranslated(c.getDisplayElement()); - if (Utilities.noString(s)) - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - - if (Utilities.noString(s)) - s = c.getCode(); - - if (showCodeDetails) { - x.addText(s+" "+context.formatPhrase(RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.getSystem()), c.getCode(), " = '", lookupCode(c.getSystem(), c.getVersion(), c.getCode()), c.getDisplay(), "')")); - } else - x.span(null, "{"+c.getSystem()+" "+c.getCode()+"}").addText(s); - } - - public String displayCodeableConcept(CodeableConcept cc) { - String s = context.getTranslated(cc.getTextElement()); - if (Utilities.noString(s)) { - for (Coding c : cc.getCoding()) { - if (c.hasDisplayElement()) { - s = context.getTranslated(c.getDisplayElement()); - break; - } - } - } - if (Utilities.noString(s)) { - // still? ok, let's try looking it up - for (Coding c : cc.getCoding()) { - if (c.hasCode() && c.hasSystem()) { - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - if (!Utilities.noString(s)) - break; - } - } - } - - if (Utilities.noString(s)) { - if (cc.getCoding().isEmpty()) - s = ""; - else - s = cc.getCoding().get(0).getCode(); - } - return s; - } - - protected void renderCodeableConcept(XhtmlNode x, CodeableConcept cc) throws FHIRFormatError, DefinitionException, IOException { - renderCodeableConcept(x, cc, false); - } - - protected void renderCodeableReference(XhtmlNode x, CodeableReference e, boolean showCodeDetails) throws FHIRFormatError, DefinitionException, IOException { - if (e.hasConcept()) { - renderCodeableConcept(x, e.getConcept(), showCodeDetails); - } - if (e.hasReference()) { - renderReference(x, e.getReference()); - } - } - - protected void renderCodeableConcept(XhtmlNode x, CodeableConcept cc, boolean showCodeDetails) throws FHIRFormatError, DefinitionException, IOException { - if (cc.isEmpty()) { - return; - } - - String s = context.getTranslated(cc.getTextElement()); - if (Utilities.noString(s)) { - for (Coding c : cc.getCoding()) { - if (c.hasDisplayElement()) { - s = context.getTranslated(c.getDisplayElement()); - break; - } - } - } - if (Utilities.noString(s)) { - // still? ok, let's try looking it up - for (Coding c : cc.getCoding()) { - if (c.hasCodeElement() && c.hasSystemElement()) { - s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); - if (!Utilities.noString(s)) - break; - } - } - } - - if (Utilities.noString(s)) { - if (cc.getCoding().isEmpty()) - s = ""; - else - s = cc.getCoding().get(0).getCode(); - } - - if (showCodeDetails) { - x.addText(s+" "); - XhtmlNode sp = x.span("background: LightGoldenRodYellow; margin: 4px; border: 1px solid khaki", null); - sp.tx(" ("); - boolean first = true; - for (Coding c : cc.getCoding()) { - if (first) { - first = false; - } else { - sp.tx("; "); - } - String url = getLinkForSystem(c.getSystem(), c.getVersion()); - if (url != null) { - sp.ah(url).tx(displayCodeSource(c.getSystem(), c.getVersion())); - } else { - sp.tx(displayCodeSource(c.getSystem(), c.getVersion())); - } - if (c.hasCode()) { - sp.tx("#"+c.getCode()); - } - if (c.hasDisplay() && !s.equals(c.getDisplay())) { - sp.tx(" \""+context.getTranslated(c.getDisplayElement())+"\""); - } - } - if (hasRenderableExtensions(cc)) { - if (!first) { - sp.tx("; "); - } - renderExtensionsInText(sp, cc, ";"); - } - sp.tx(")"); - } else { - - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (Coding c : cc.getCoding()) { - if (c.hasCodeElement() && c.hasSystemElement()) { - b.append("{"+c.getSystem()+" "+c.getCode()+"}"); - } - } - - x.span(null, context.formatPhrase(RenderingContext.GENERAL_CODES) +b.toString()).addText(s); - } - } - - protected String displayIdentifier(Identifier ii) { - String s = Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue(); - if ("urn:ietf:rfc:3986".equals(ii.getSystem()) && s.startsWith("urn:oid:")) { - s = "OID:"+s.substring(8); - } else if ("urn:ietf:rfc:3986".equals(ii.getSystem()) && s.startsWith("urn:uuid:")) { - s = "UUID:"+s.substring(9); + return version; + } + } + + public String displaySystem(String system) { + if (system == null) + return (context.formatPhrase(RenderingContext.DATA_REND_NOT_STAT)); + if (system.equals("http://loinc.org")) + return (context.formatPhrase(RenderingContext.DATA_REND_LOINC)); + if (system.startsWith("http://snomed.info")) + return (context.formatPhrase(RenderingContext.DATA_REND_SNOMED)); + if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm")) + return (context.formatPhrase(RenderingContext.DATA_REND_RXNORM)); + if (system.equals("http://hl7.org/fhir/sid/icd-9")) + return (context.formatPhrase(RenderingContext.DATA_REND_ICD)); + if (system.equals("http://dicom.nema.org/resources/ontology/DCM")) + return (context.formatPhrase(RenderingContext.DATA_REND_DICOM)); + if (system.equals("http://unitsofmeasure.org")) + return (context.formatPhrase(RenderingContext.DATA_REND_UCUM)); + + CodeSystem cs = context.getContext().fetchCodeSystem(system); + if (cs != null) { + return crPresent(cs); + } + return tails(system); + } + + private String crPresent(CanonicalResource cr) { + if (cr.hasUserData("presentation")) { + return cr.getUserString("presentation"); + } + if (cr.hasTitle()) + return context.getTranslated(cr.getTitleElement()); + if (cr.hasName()) + return context.getTranslated(cr.getNameElement()); + return cr.toString(); + } + + private String tails(String system) { + if (system.contains("/")) { + return system.substring(system.lastIndexOf("/")+1); } else { - NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem()); - if (ns != null) { - s = crPresent(ns)+"#"+s; - } - if (ii.hasType()) { - if (ii.getType().hasText()) - s = context.getTranslated(ii.getType().getTextElement())+":\u00A0"+s; - else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay()) - s = context.getTranslated(ii.getType().getCoding().get(0).getDisplayElement())+": "+s; - else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode()) - s = lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())+": "+s; - } else if (ii.hasSystem()) { - s = ii.getSystem()+"#"+s; - } - } - - if (ii.hasUse() || ii.hasPeriod()) { - s = s + "\u00A0("; - if (ii.hasUse()) { - s = s + "use:\u00A0"+ii.getUse().toCode(); - } - if (ii.hasUse() && ii.hasPeriod()) { - s = s + ",\u00A0"; - } - if (ii.hasPeriod()) { - s = s + "period:\u00A0"+displayPeriod(ii.getPeriod()); - } - s = s + ")"; - } - return s; - } - - protected void renderIdentifier(XhtmlNode x, Identifier ii) { - boolean pfx = true; - if (ii.hasType()) { - if (ii.getType().hasText()) { - x.tx(context.getTranslated(ii.getType().getTextElement())); - } else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay()) { - x.tx(context.getTranslated(ii.getType().getCoding().get(0).getDisplayElement())); - } else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode()) { - x.tx(lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())); - } else { - pfx = false; - } - } else if (ii.hasSystem()) { - NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem()); - if (ns != null) { - if (ns.hasWebPath()) { - x.ah(ns.getWebPath(), ns.getDescription()).tx(crPresent(ns)); - } else { - x.tx(crPresent(ns)); - } - } else { - switch (ii.getSystem()) { - case "urn:oid:2.51.1.3": - x.ah("https://www.gs1.org/standards/id-keys/gln", context.formatPhrase(RenderingContext.DATA_REND_GLN)).tx("GLN"); - break; - default: - x.code(ii.getSystem()); - } - } - } - if (!Utilities.noString(ii.getValue())) { - if (pfx) { - x.tx("/"); - } - x.tx(ii.getValue()); - } - - if (ii.hasUse() || ii.hasPeriod()) { - x.nbsp(); - x.tx("("); - if (ii.hasUse()) { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_USE)); - x.nbsp(); - x.tx(ii.getUse().toCode()); - } - if (ii.hasUse() && ii.hasPeriod()) { - x.tx(","); - x.nbsp(); - } - if (ii.hasPeriod()) { - x.tx(context.formatPhrase(RenderingContext.DATA_REND_PERIOD)); - x.nbsp(); - x.tx(displayPeriod(ii.getPeriod())); - } - x.tx(")"); - } - } - - public static String displayHumanName(HumanName name) { - StringBuilder s = new StringBuilder(); - if (name.hasText()) - s.append(name.getText()); - else { - for (StringType p : name.getGiven()) { - s.append(p.getValue()); - s.append(" "); - } - if (name.hasFamily()) { - s.append(name.getFamily()); - s.append(" "); - } - } - if (name.hasUse() && name.getUse() != NameUse.USUAL) - s.append("("+name.getUse().toString()+")"); - return s.toString(); - } - - - protected void renderHumanName(XhtmlNode x, HumanName name) { - StringBuilder s = new StringBuilder(); - if (name.hasText()) - s.append(context.getTranslated(name.getTextElement())); - else { - for (StringType p : name.getGiven()) { - s.append(context.getTranslated(p)); - s.append(" "); - } - if (name.hasFamily()) { - s.append(context.getTranslated(name.getFamilyElement())); - s.append(" "); - } - } - if (name.hasUse() && name.getUse() != NameUse.USUAL) - s.append("("+context.getTranslatedCode(name.getUseElement(), "http://hl7.org/fhir/name-use")+")"); - - x.addText(s.toString()); - } - - private String displayAddress(Address address) { - StringBuilder s = new StringBuilder(); - if (address.hasText()) - s.append(context.getTranslated(address.getTextElement())); - else { - for (StringType p : address.getLine()) { - s.append(context.getTranslated(p)); - s.append(" "); - } - if (address.hasCity()) { - s.append(context.getTranslated(address.getCityElement())); - s.append(" "); - } - if (address.hasState()) { - s.append(context.getTranslated(address.getStateElement())); - s.append(" "); - } - - if (address.hasPostalCode()) { - s.append(context.getTranslated(address.getPostalCodeElement())); - s.append(" "); - } - - if (address.hasCountry()) { - s.append(context.getTranslated(address.getCountryElement())); - s.append(" "); - } - } - if (address.hasUse()) - s.append("("+address.getUse().toCode()+")"); - return s.toString(); - } - - protected void renderAddress(XhtmlNode x, Address address) { - x.addText(displayAddress(address)); - } - - - public static String displayContactPoint(ContactPoint contact) { - StringBuilder s = new StringBuilder(); - s.append(describeSystem(contact.getSystem())); - if (Utilities.noString(contact.getValue())) - s.append("-unknown-"); - else - s.append(contact.getValue()); - if (contact.hasUse()) - s.append("("+contact.getUse().toString()+")"); - return s.toString(); - } - - public static String displayContactDetail(ContactDetail contact) { - CommaSeparatedStringBuilder s = new CommaSeparatedStringBuilder(); - for (ContactPoint cp : contact.getTelecom()) { - s.append(displayContactPoint(cp)); - } - return contact.getName()+(s.length() == 0 ? "" : " ("+s.toString()+")"); - } - - protected String getLocalizedBigDecimalValue(BigDecimal input, Currency c) { - NumberFormat numberFormat = NumberFormat.getNumberInstance(context.getLocale()); - numberFormat.setGroupingUsed(true); - numberFormat.setMaximumFractionDigits(c.getDefaultFractionDigits()); - numberFormat.setMinimumFractionDigits(c.getDefaultFractionDigits()); - return numberFormat.format(input); -} - - protected void renderMoney(XhtmlNode x, Money money) { - if (x.getName().equals("blockquote")) { - x = x.para(); - } - Currency c = money.hasCurrency() ? Currency.getInstance(money.getCurrency()) : null; - if (c != null) { - XhtmlNode s = x.span(null, c.getDisplayName()); - s.tx(c.getSymbol(context.getLocale())); - s.tx(getLocalizedBigDecimalValue(money.getValue(), c)); - x.tx(" ("+c.getCurrencyCode()+")"); - } else { - if (money.getCurrency() != null) { - x.tx(money.getCurrency()); - } - x.tx(money.getValue().toPlainString()); - } - } - - protected void renderExpression(XhtmlNode x, Expression expr) { - // there's two parts: what the expression is, and how it's described. - // we start with what it is, and then how it's described - XhtmlNode p = x; - if (p.getName().equals("blockquote")) { - p = p.para(); - } - if (expr.hasExpression()) { - if (expr.hasReference()) { - p = x.ah(expr.getReference()); - } - XhtmlNode c = p; - if (expr.hasLanguage()) { - c = c.span(null, expr.getLanguage()); - } - c.code().tx(expr.getExpression()); - } else if (expr.hasReference()) { - p.ah(expr.getReference()).tx(context.formatPhrase(RenderingContext.DATA_REND_SOURCE)); - } - if (expr.hasName() || expr.hasDescription()) { - p.tx("("); - if (expr.hasName()) { - p.b().tx(expr.getName()); - } - if (expr.hasDescription()) { - p.tx("\""); - p.tx(context.getTranslated(expr.getDescriptionElement())); - p.tx("\""); - } - p.tx(")"); - } - } - - - protected void renderContactPoint(XhtmlNode x, ContactPoint contact) { - if (contact != null) { - if (!contact.hasSystem()) { - x.addText(displayContactPoint(contact)); - } else { - switch (contact.getSystem()) { - case EMAIL: - x.ah("mailto:"+contact.getValue()).tx(contact.getValue()); - break; - case FAX: - x.addText(displayContactPoint(contact)); - break; - case NULL: - x.addText(displayContactPoint(contact)); - break; - case OTHER: - x.addText(displayContactPoint(contact)); - break; - case PAGER: - x.addText(displayContactPoint(contact)); - break; - case PHONE: - if (contact.hasValue() && contact.getValue().startsWith("+")) { - x.ah("tel:"+contact.getValue().replace(" ", "")).tx(contact.getValue()); - } else { - x.addText(displayContactPoint(contact)); - } - break; - case SMS: - x.addText(displayContactPoint(contact)); - break; - case URL: - x.ah(contact.getValue()).tx(contact.getValue()); - break; - default: - break; - } - } - } - } - - protected void displayContactPoint(XhtmlNode p, ContactPoint c) { - if (c != null) { - if (c.getSystem() == ContactPointSystem.PHONE) { - p.tx(context.formatPhrase(RenderingContext.DATA_REND_PHONE, c.getValue()) + " "); - } else if (c.getSystem() == ContactPointSystem.FAX) { - p.tx(context.formatPhrase(RenderingContext.DATA_REND_FAX, c.getValue()) + " "); - } else if (c.getSystem() == ContactPointSystem.EMAIL) { - p.tx(c.getValue()); - } else if (c.getSystem() == ContactPointSystem.URL) { - if (c.getValue().length() > 30) { - p.addText(c.getValue().substring(0, 30)+"..."); - } else { - p.addText(c.getValue()); - } - } - } - } - - protected void addTelecom(XhtmlNode p, ContactPoint c) { - if (c.getSystem() == ContactPointSystem.PHONE) { - p.tx(context.formatPhrase(RenderingContext.DATA_REND_PHONE, c.getValue()) + " "); - } else if (c.getSystem() == ContactPointSystem.FAX) { - p.tx(context.formatPhrase(RenderingContext.DATA_REND_FAX, c.getValue()) + " "); - } else if (c.getSystem() == ContactPointSystem.EMAIL) { - p.ah("mailto:"+c.getValue()).addText(c.getValue()); - } else if (c.getSystem() == ContactPointSystem.URL) { - if (c.getValue().length() > 30) - p.ah(c.getValue()).addText(c.getValue().substring(0, 30)+"..."); - else - p.ah(c.getValue()).addText(c.getValue()); - } - } - private static String describeSystem(ContactPointSystem system) { - if (system == null) - return ""; - switch (system) { - case PHONE: return "ph: "; - case FAX: return "fax: "; - default: - return ""; - } - } - - protected String displayQuantity(Quantity q) { - StringBuilder s = new StringBuilder(); - - s.append(q.hasValue() ? q.getValue() : "?"); - if (q.hasUnit()) - s.append(" ").append(q.getUnit()); - else if (q.hasCode()) - s.append(" ").append(q.getCode()); - - return s.toString(); - } - - protected void renderQuantity(XhtmlNode x, Quantity q) { - renderQuantity(x, q, false); - } - - protected void renderQuantity(XhtmlNode x, Quantity q, boolean showCodeDetails) { - if (q.hasComparator()) - x.addText(q.getComparator().toCode()); - if (q.hasValue()) { - x.addText(context.getTranslated(q.getValueElement())); - } - if (q.hasUnit()) - x.tx(" "+context.getTranslated(q.getUnitElement())); - else if (q.hasCode() && q.hasSystem()) { - // if there's a code there *shall* be a system, so if we've got one and not the other, things are invalid and we won't bother trying to render - if (q.hasSystem() && q.getSystem().equals("http://unitsofmeasure.org")) - x.tx(" "+q.getCode()); - else - x.tx("(unit "+q.getCode()+" from "+q.getSystem()+")"); - } - if (showCodeDetails && q.hasCode()) { - x.span("background: LightGoldenRodYellow", null).tx(" "+ (context.formatPhrase(RenderingContext.DATA_REND_DETAILS, displaySystem(q.getSystem()))) +q.getCode()+" = '"+lookupCode(q.getSystem(), null, q.getCode())+"')"); - } - } - - - protected void renderQuantity(HierarchicalTableGenerator gen, List pieces, Quantity q, boolean showCodeDetails) { - pieces.add(gen.new Piece(null, displayQuantity(q), null)); - } - - public String displayRange(Range q) { - if (!q.hasLow() && !q.hasHigh()) - return "?"; - - StringBuilder b = new StringBuilder(); - - boolean sameUnits = (q.getLow().hasUnit() && q.getHigh().hasUnit() && q.getLow().getUnit().equals(q.getHigh().getUnit())) - || (q.getLow().hasCode() && q.getHigh().hasCode() && q.getLow().getCode().equals(q.getHigh().getCode())); - String low = "?"; - if (q.hasLow() && q.getLow().hasValue()) - low = sameUnits ? q.getLow().getValue().toString() : displayQuantity(q.getLow()); - String high = displayQuantity(q.getHigh()); - if (high.isEmpty()) - high = "?"; - b.append(low).append("\u00A0to\u00A0").append(high); - return b.toString(); - } - - protected void renderRange(XhtmlNode x, Range q) { - if (q.hasLow()) - x.addText(q.getLow().getValue().toString()); - else - x.tx("?"); - x.tx("-"); - if (q.hasHigh()) - x.addText(q.getHigh().getValue().toString()); - else - x.tx("?"); - if (q.getLow().hasUnit()) - x.tx(" "+q.getLow().getUnit()); - } - - public String displayPeriod(Period p) { - String s = !p.hasStart() ? "(?)" : displayDateTime(p.getStartElement()); - s = s + " --> "; - return s + (!p.hasEnd() ? context.formatPhrase(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); - } - - public void renderPeriod(XhtmlNode x, Period p) { - x.addText(!p.hasStart() ? "??" : displayDateTime(p.getStartElement())); - x.tx(" --> "); - x.addText(!p.hasEnd() ? context.formatPhrase(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); - } - - public void renderUsageContext(XhtmlNode x, UsageContext u) throws FHIRFormatError, DefinitionException, IOException { - renderCoding(x, u.getCode()); - x.tx(": "); - render(x, u.getValue()); - } - - - public void renderTriggerDefinition(XhtmlNode x, TriggerDefinition td) throws FHIRFormatError, DefinitionException, IOException { - if (x.isPara()) { - x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); - x.tx(": "); - x.tx(td.getType().getDisplay()); - - if (td.hasName()) { - x.tx(", "); - x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_NAME)); - x.tx(": "); - x.tx(context.getTranslated(td.getNameElement())); - } - if (td.hasCode()) { - x.tx(", "); - x.b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); - x.tx(": "); - renderCodeableConcept(x, td.getCode()); - } - if (td.hasTiming()) { - x.tx(", "); - x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TIMING)); - x.tx(": "); - render(x, td.getTiming()); - } - if (td.hasCondition()) { - x.tx(", "); - x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_COND)); - x.tx(": "); - renderExpression(x, td.getCondition()); - } - } else { - XhtmlNode tbl = x.table("grid"); - - XhtmlNode tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); - tr.td().tx(td.getType().getDisplay()); - - if (td.hasName()) { - tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_NAME)); - tr.td().tx(context.getTranslated(td.getNameElement())); - } - if (td.hasCode()) { - tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); - renderCodeableConcept(tr.td(), td.getCode()); - } - if (td.hasTiming()) { - tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_TIMING)); - render(tr.td(), td.getTiming()); - } - if (td.hasCondition()) { - tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_COND)); - renderExpression(tr.td(), td.getCondition()); - } - } - } - - public void renderDataRequirement(XhtmlNode x, DataRequirement dr) throws FHIRFormatError, DefinitionException, IOException { - XhtmlNode tbl = x.table("grid"); - XhtmlNode tr = tbl.tr(); - XhtmlNode td = tr.td().colspan("2"); - td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); - td.tx(": "); - StructureDefinition sd = context.getWorker().fetchTypeDefinition(dr.getType().toCode()); - if (sd != null && sd.hasWebPath()) { - td.ah(sd.getWebPath()).tx(dr.getType().toCode()); - } else { - td.tx(dr.getType().toCode()); - } - if (dr.hasProfile()) { - td.tx(" ("); - boolean first = true; - for (CanonicalType p : dr.getProfile()) { - if (first) first = false; else td.tx(" | "); - sd = context.getWorker().fetchResource(StructureDefinition.class, p.getValue()); - if (sd != null && sd.hasWebPath()) { - td.ah(sd.getWebPath()).tx(crPresent(sd)); - } else { - td.tx(p.asStringValue()); - } - } - td.tx(")"); - } - if (dr.hasSubject()) { - tr = tbl.tr(); - td = tr.td().colspan("2"); - td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_SUB)); - if (dr.hasSubjectReference()) { - renderReference(td, dr.getSubjectReference()); - } else { - renderCodeableConcept(td, dr.getSubjectCodeableConcept()); - } - } - if (dr.hasCodeFilter() || dr.hasDateFilter()) { - tr = tbl.tr().backgroundColor("#efefef"); - tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_FILT)); - tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_VALUE)); - } - for (DataRequirementCodeFilterComponent cf : dr.getCodeFilter()) { - tr = tbl.tr(); - if (cf.hasPath()) { - tr.td().tx(cf.getPath()); - } else { - tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_SEARCH, cf.getSearchParam()) + " "); - } - if (cf.hasValueSet()) { - td = tr.td(); - td.tx(context.formatPhrase(RenderingContext.DATA_REND_VALUESET) + " "); - render(td, cf.getValueSetElement()); - } else { - boolean first = true; - td = tr.td(); - td.tx(context.formatPhrase(RenderingContext.DATA_REND_THESE_CODES) + " "); - for (Coding c : cf.getCode()) { - if (first) first = false; else td.tx(", "); - render(td, c); - } - } - } - for (DataRequirementDateFilterComponent cf : dr.getDateFilter()) { - tr = tbl.tr(); - if (cf.hasPath()) { - tr.td().tx(cf.getPath()); - } else { - tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_SEARCH, cf.getSearchParam()) + " "); - } - render(tr.td(), cf.getValue()); - } - if (dr.hasSort() || dr.hasLimit()) { - tr = tbl.tr(); - td = tr.td().colspan("2"); - if (dr.hasLimit()) { - td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_LIMIT)); - td.tx(": "); - td.tx(dr.getLimit()); - if (dr.hasSort()) { - td.tx(", "); - } - } - if (dr.hasSort()) { - td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_SORT)); - td.tx(": "); - boolean first = true; - for (DataRequirementSortComponent p : dr.getSort()) { - if (first) first = false; else td.tx(" | "); - td.tx(p.getDirection() == SortDirection.ASCENDING ? "+" : "-"); - td.tx(p.getPath()); - } - } - } - } - - - private String displayTiming(Timing s) throws FHIRException { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - if (s.hasCode()) - b.append(context.formatPhrase(RenderingContext.GENERAL_CODE, displayCodeableConcept(s.getCode())) + " "); - - if (s.getEvent().size() > 0) { - CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder(); - for (DateTimeType p : s.getEvent()) { - if (p.hasValue()) { - c.append(displayDateTime(p)); - } else if (!renderExpression(c, p)) { - c.append("??"); - } - } - b.append(context.formatPhrase(RenderingContext.DATA_REND_EVENTS, c.toString()) + " "); - } - - if (s.hasRepeat()) { - TimingRepeatComponent rep = s.getRepeat(); - if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_STARTING, displayDateTime(rep.getBoundsPeriod().getStartElement())) + " "); - if (rep.hasCount()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_COUNT, Integer.toString(rep.getCount())) + " " + " times"); - if (rep.hasDuration()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_DURATION, rep.getDuration().toPlainString()+displayTimeUnits(rep.getPeriodUnit())) + " "); - - if (rep.hasWhen()) { - String st = ""; - if (rep.hasOffset()) { - st = Integer.toString(rep.getOffset())+"min "; - } - b.append(st); - for (Enumeration wh : rep.getWhen()) - b.append(displayEventCode(wh.getValue())); - } else { - String st = ""; - if (!rep.hasFrequency() || (!rep.hasFrequencyMax() && rep.getFrequency() == 1) ) - st = context.formatPhrase(RenderingContext.DATA_REND_ONCE); - else { - st = Integer.toString(rep.getFrequency()); - if (rep.hasFrequencyMax()) - st = st + "-"+Integer.toString(rep.getFrequency()); - } - if (rep.hasPeriod()) { - st = st + " "+ (context.formatPhrase(RenderingContext.DATA_REND_PER))+rep.getPeriod().toPlainString(); - if (rep.hasPeriodMax()) - st = st + "-"+rep.getPeriodMax().toPlainString(); - st = st + " "+displayTimeUnits(rep.getPeriodUnit()); - } - b.append(st); - } - if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_UNTIL, displayDateTime(rep.getBoundsPeriod().getEndElement())) + " "); - } - return b.toString(); - } - - private boolean renderExpression(CommaSeparatedStringBuilder c, PrimitiveType p) { - Extension exp = p.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/cqf-expression"); - if (exp == null) { - return false; - } - c.append(exp.getValueExpression().getExpression()); - return true; - } - - private String displayEventCode(EventTiming when) { - switch (when) { - case C: return (context.formatPhrase(RenderingContext.DATA_REND_MEALS)); - case CD: return (context.formatPhrase(RenderingContext.DATA_REND_ATLUNCH)); - case CM: return (context.formatPhrase(RenderingContext.DATA_REND_ATBKFST)); - case CV: return (context.formatPhrase(RenderingContext.DATA_REND_ATDINR)); - case AC: return (context.formatPhrase(RenderingContext.DATA_REND_BFMEALS)); - case ACD: return (context.formatPhrase(RenderingContext.DATA_REND_BFLUNCH)); - case ACM: return (context.formatPhrase(RenderingContext.DATA_REND_BFBKFST)); - case ACV: return (context.formatPhrase(RenderingContext.DATA_REND_BFDINR)); - case HS: return (context.formatPhrase(RenderingContext.DATA_REND_BFSLEEP)); - case PC: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRMEALS)); - case PCD: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRLUNCH)); - case PCM: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRBKFST)); - case PCV: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRDINR)); - case WAKE: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRWKNG)); - default: return "?ngen-6?"; - } - } - - private String displayTimeUnits(UnitsOfTime units) { - if (units == null) - return "?ngen-7?"; - switch (units) { - case A: return "years"; - case D: return "days"; - case H: return "hours"; - case MIN: return "minutes"; - case MO: return "months"; - case S: return "seconds"; - case WK: return "weeks"; - default: return "?ngen-8?"; - } - } - - protected void renderTiming(XhtmlNode x, Timing s) throws FHIRException { - x.addText(displayTiming(s)); - } - - - private String displaySampledData(SampledData s) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - if (s.hasOrigin()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_ORIGIN, displayQuantity(s.getOrigin())) + " "); - - if (s.hasInterval()) { - b.append(context.formatPhrase(RenderingContext.DATA_REND_INT, s.getInterval().toString()) + " "); - - if (s.hasIntervalUnit()) - b.append(s.getIntervalUnit().toString()); - } - - if (s.hasFactor()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_FACT, s.getFactor().toString()) + " "); - - if (s.hasLowerLimit()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_LOWER, s.getLowerLimit().toString()) + " "); - - if (s.hasUpperLimit()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_UP, s.getUpperLimit().toString()) + " "); - - if (s.hasDimensions()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_DIM, s.getDimensions()) + " "); - - if (s.hasData()) - b.append(context.formatPhrase(RenderingContext.DATA_REND_DATA, s.getData()) + " "); - - return b.toString(); - } - - protected void renderSampledData(XhtmlNode x, SampledData sampledData) { - x.addText(displaySampledData(sampledData)); - } - - public RenderingContext getContext() { - return context; - } - - - public XhtmlNode makeExceptionXhtml(Exception e, String function) { - XhtmlNode xn; - xn = new XhtmlNode(NodeType.Element, "div"); - XhtmlNode p = xn.para(); - p.b().tx((context.formatPhrase(RenderingContext.DATA_REND_EXCEPTION)) +function+": "+e.getMessage()); - p.addComment(getStackTrace(e)); - return xn; - } - - private String getStackTrace(Exception e) { - StringBuilder b = new StringBuilder(); - b.append("\r\n"); - for (StackTraceElement t : e.getStackTrace()) { - b.append(t.getClassName()+"."+t.getMethodName()+" ("+t.getFileName()+":"+t.getLineNumber()); - b.append("\r\n"); - } - return b.toString(); - } - - protected String versionFromCanonical(String system) { - if (system == null) { - return null; - } else if (system.contains("|")) { - return system.substring(0, system.indexOf("|")); - } else { - return null; - } - } - - protected String systemFromCanonical(String system) { - if (system == null) { - return null; - } else if (system.contains("|")) { - return system.substring(system.indexOf("|")+1); - } else { - return system; - } - } - - + return (context.formatPhrase(RenderingContext.DATA_REND_UNKNWN)); + } + } + + protected String makeAnchor(String codeSystem, String code) { + String s = codeSystem+'-'+code; + StringBuilder b = new StringBuilder(); + for (char c : s.toCharArray()) { + if (Character.isAlphabetic(c) || Character.isDigit(c) || c == '.') + b.append(c); + else + b.append('-'); + } + return b.toString(); + } + + private String lookupCode(String system, String version, String code) { + if (JurisdictionUtilities.isJurisdiction(system)) { + return JurisdictionUtilities.displayJurisdiction(system+"#"+code); + } + ValidationResult t = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions().withLanguage(context.getLocale().toString().replace("_", "-")).withVersionFlexible(true), system, version, code, null); + + if (t != null && t.getDisplay() != null) + return t.getDisplay(); + else + return code; + } + + protected String describeLang(String lang) { + // special cases: + if ("fr-CA".equals(lang)) { + return "French (Canadian)"; // this one was omitted from the value set + } + ValueSet v = getContext().getWorker().findTxResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages"); + if (v != null) { + ConceptReferenceComponent l = null; + for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { + if (cc.getCode().equals(lang)) + l = cc; + } + if (l == null) { + if (lang.contains("-")) { + lang = lang.substring(0, lang.indexOf("-")); + } + for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { + if (cc.getCode().equals(lang)) { + l = cc; + break; + } + } + if (l == null) { + for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { + if (cc.getCode().startsWith(lang+"-")) { + l = cc; + break; + } + } + } + } + if (l != null) { + if (lang.contains("-")) + lang = lang.substring(0, lang.indexOf("-")); + String en = l.getDisplay(); + String nativelang = null; + for (ConceptReferenceDesignationComponent cd : l.getDesignation()) { + if (cd.getLanguage().equals(lang)) + nativelang = cd.getValue(); + } + if (nativelang == null) + return en+" ("+lang+")"; + else + return nativelang+" ("+en+", "+lang+")"; + } + } + return lang; + } + + private boolean isCanonical(String path) { + if (!path.endsWith(".url")) + return false; + String t = path.substring(0, path.length()-4); + StructureDefinition sd = getContext().getWorker().fetchTypeDefinition(t); + if (sd == null) + return false; + if (VersionUtilities.getCanonicalResourceNames(getContext().getWorker().getVersion()).contains(t)) { + return true; + } + if (Utilities.existsInList(t, + "ActivityDefinition", "CapabilityStatement", "ChargeItemDefinition", "Citation", "CodeSystem", + "CompartmentDefinition", "ConceptMap", "ConditionDefinition", "EventDefinition", "Evidence", "EvidenceReport", "EvidenceVariable", + "ExampleScenario", "GraphDefinition", "ImplementationGuide", "Library", "Measure", "MessageDefinition", "NamingSystem", "PlanDefinition" + )) + return true; + return false; + } + + // -- 4. Language support ------------------------------------------------------ + + public String gt(@SuppressWarnings("rawtypes") PrimitiveType value) { + return context.getTranslated(value); + } + + // -- 6. General purpose extension rendering ---------------------------------------------- + + public boolean hasRenderableExtensions(DataType element) { + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + return true; + } + } + return false; + } + + public boolean hasRenderableExtensions(BackboneType element) { + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + return true; + } + } + return element.hasModifierExtension(); + } + + private String getExtensionLabel(Extension ext) { + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, ext.getUrl()); + if (sd != null && ext.hasValue() && ext.getValue().isPrimitive() && sd.hasSnapshot()) { + for (ElementDefinition ed : sd.getSnapshot().getElement()) { + if (Utilities.existsInList(ed.getPath(), "Extension", "Extension.value[x]") && ed.hasLabel()) { + return context.getTranslated(ed.getLabelElement()); + } + } + } + return null; + } + + private boolean canRender(Extension ext) { + return getExtensionLabel(ext) != null; + } + + public void renderExtensionsInList(XhtmlNode ul, DataType element) throws FHIRFormatError, DefinitionException, IOException { + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + String lbl = getExtensionLabel(ext); + XhtmlNode li = ul.li(); + li.tx(lbl); + li.tx(": "); + render(li, ext.getValue()); + } + } + } + + public void renderExtensionsInList(XhtmlNode ul, BackboneType element) throws FHIRFormatError, DefinitionException, IOException { + for (Extension ext : element.getModifierExtension()) { + if (canRender(ext)) { + String lbl = getExtensionLabel(ext); + XhtmlNode li = ul.li(); + li = li.b(); + li.tx(lbl); + li.tx(": "); + render(li, ext.getValue()); + } else { + // somehow have to do better than this + XhtmlNode li = ul.li(); + li.b().tx(context.formatPhrase(RenderingContext.DATA_REND_UNRD_EX)); + } + } + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + String lbl = getExtensionLabel(ext); + XhtmlNode li = ul.li(); + li.tx(lbl); + li.tx(": "); + render(li, ext.getValue()); + } + } + } + + public void renderExtensionsInText(XhtmlNode div, DataType element, String sep) throws FHIRFormatError, DefinitionException, IOException { + boolean first = true; + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + if (first) { + first = false; + } else { + div.tx(sep); + div.tx(" "); + } + + String lbl = getExtensionLabel(ext); + div.tx(lbl); + div.tx(": "); + render(div, ext.getValue()); + } + } + } + + public void renderExtensionsInList(XhtmlNode div, BackboneType element, String sep) throws FHIRFormatError, DefinitionException, IOException { + boolean first = true; + for (Extension ext : element.getModifierExtension()) { + if (first) { + first = false; + } else { + div.tx(sep); + div.tx(" "); + } + if (canRender(ext)) { + String lbl = getExtensionLabel(ext); + XhtmlNode b = div.b(); + b.tx(lbl); + b.tx(": "); + render(div, ext.getValue()); + } else { + // somehow have to do better than this + div.b().tx(context.formatPhrase(RenderingContext.DATA_REND_UNRD_EX)); + } + } + for (Extension ext : element.getExtension()) { + if (canRender(ext)) { + if (first) { + first = false; + } else { + div.tx(sep); + div.tx(" "); + } + + String lbl = getExtensionLabel(ext); + div.tx(lbl); + div.tx(": "); + render(div, ext.getValue()); + } + } + + } + + // -- 6. Data type Rendering ---------------------------------------------- + + public static String display(IWorkerContext context, DataType type) { + return new DataRenderer(new RenderingContext(context, null, null, "http://hl7.org/fhir/R4", "", null, ResourceRendererMode.END_USER, GenerationRules.VALID_RESOURCE)).display(type); + } + + public String displayBase(Base b) { + if (b instanceof DataType) { + return display((DataType) b); + } else { + return (context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, b.fhirType()) + " "); + } + } + + public String display(DataType type) { + if (type == null || type.isEmpty()) { + return ""; + } + + if (type instanceof Coding) { + return displayCoding((Coding) type); + } else if (type instanceof CodeableConcept) { + return displayCodeableConcept((CodeableConcept) type); + } else if (type instanceof Identifier) { + return displayIdentifier((Identifier) type); + } else if (type instanceof HumanName) { + return displayHumanName((HumanName) type); + } else if (type instanceof Address) { + return displayAddress((Address) type); + } else if (type instanceof ContactPoint) { + return displayContactPoint((ContactPoint) type); + } else if (type instanceof Quantity) { + return displayQuantity((Quantity) type); + } else if (type instanceof Range) { + return displayRange((Range) type); + } else if (type instanceof Period) { + return displayPeriod((Period) type); + } else if (type instanceof Timing) { + return displayTiming((Timing) type); + } else if (type instanceof SampledData) { + return displaySampledData((SampledData) type); + } else if (type instanceof ContactDetail) { + return displayContactDetail((ContactDetail) type); + } else if (type.isDateTime()) { + return displayDateTime((BaseDateTimeType) type); + } else if (type.isPrimitive()) { + return context.getTranslated((PrimitiveType) type); + } else { + return (context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, type.fhirType()) + " "); + } + } + + protected String displayDateTime(BaseDateTimeType type) { + if (!type.hasPrimitiveValue()) { + return ""; + } + + // relevant inputs in rendering context: + // timeZone, dateTimeFormat, locale, mode + // timezone - application specified timezone to use. + // null = default to the time of the date/time itself + // dateTimeFormat - application specified format for date times + // null = default to ... depends on mode + // mode - if rendering mode is technical, format defaults to XML format + // locale - otherwise, format defaults to SHORT for the Locale (which defaults to default Locale) + if (isOnlyDate(type.getPrecision())) { + + DateTimeFormatter fmt = getDateFormatForPrecision(type); + LocalDate date = LocalDate.of(type.getYear(), type.getMonth()+1, type.getDay()); + return fmt.format(date); + } + + DateTimeFormatter fmt = context.getDateTimeFormat(); + if (fmt == null) { + if (context.isTechnicalMode()) { + fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + } else { + fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(context.getLocale()); + } + } + ZonedDateTime zdt = ZonedDateTime.parse(type.primitiveValue()); + ZoneId zone = context.getTimeZoneId(); + if (zone != null) { + zdt = zdt.withZoneSameInstant(zone); + } + return fmt.format(zdt); + } + + private DateTimeFormatter getDateFormatForPrecision(BaseDateTimeType type) { + DateTimeFormatter fmt = getContextDateFormat(type); + if (fmt != null) { + return fmt; + } + if (context.isTechnicalMode()) { + switch (type.getPrecision()) { + case YEAR: + return new DateTimeFormatterBuilder().appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD).toFormatter(); + case MONTH: + return new DateTimeFormatterBuilder().appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD).appendLiteral('-').appendValue(MONTH_OF_YEAR, 2).toFormatter(); + default: + return DateTimeFormatter.ISO_DATE; + } + } else { + switch (type.getPrecision()) { + case YEAR: + return DateTimeFormatter.ofPattern("uuuu"); + case MONTH: + return DateTimeFormatter.ofPattern("MMM uuuu"); + default: + return DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(context.getLocale()); + } + } + } + + private DateTimeFormatter getContextDateFormat(BaseDateTimeType type) { + switch (type.getPrecision()) { + case YEAR: + return context.getDateYearFormat(); + case MONTH: + return context.getDateYearMonthFormat(); + default: + return context.getDateFormat(); + } + } + + private boolean isOnlyDate(TemporalPrecisionEnum temporalPrecisionEnum) { + return temporalPrecisionEnum == TemporalPrecisionEnum.YEAR || temporalPrecisionEnum == TemporalPrecisionEnum.MONTH || temporalPrecisionEnum == TemporalPrecisionEnum.DAY; + } + + public String display(BaseWrapper type) { + return (context.formatPhrase(RenderingContext.DATA_REND_TO_DO)); + } + + public void render(XhtmlNode x, BaseWrapper type) throws FHIRFormatError, DefinitionException, IOException { + Base base = null; + try { + base = type.getBase(); + } catch (FHIRException | IOException e) { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_ERROR, e.getMessage()) + " "); // this shouldn't happen - it's an error in the library itself + return; + } + if (base instanceof DataType) { + render(x, (DataType) base); + } else { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_TO_DO, base.fhirType())); + } + } + + public void renderBase(XhtmlNode x, Base b) throws FHIRFormatError, DefinitionException, IOException { + if (b instanceof DataType) { + render(x, (DataType) b); + } else { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, b.fhirType()) + " "); + } + } + + public void render(XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException { + if (type instanceof BaseDateTimeType) { + x.tx(displayDateTime((BaseDateTimeType) type)); + } else if (type instanceof UriType) { + renderUri(x, (UriType) type); + } else if (type instanceof Annotation) { + renderAnnotation(x, (Annotation) type); + } else if (type instanceof Coding) { + renderCodingWithDetails(x, (Coding) type); + } else if (type instanceof CodeableConcept) { + renderCodeableConcept(x, (CodeableConcept) type); + } else if (type instanceof Identifier) { + renderIdentifier(x, (Identifier) type); + } else if (type instanceof HumanName) { + renderHumanName(x, (HumanName) type); + } else if (type instanceof Address) { + renderAddress(x, (Address) type); + } else if (type instanceof Expression) { + renderExpression(x, (Expression) type); + } else if (type instanceof Money) { + renderMoney(x, (Money) type); + } else if (type instanceof ContactPoint) { + renderContactPoint(x, (ContactPoint) type); + } else if (type instanceof Quantity) { + renderQuantity(x, (Quantity) type); + } else if (type instanceof Range) { + renderRange(x, (Range) type); + } else if (type instanceof Period) { + renderPeriod(x, (Period) type); + } else if (type instanceof Timing) { + renderTiming(x, (Timing) type); + } else if (type instanceof SampledData) { + renderSampledData(x, (SampledData) type); + } else if (type instanceof Reference) { + renderReference(x, (Reference) type); + } else if (type instanceof UsageContext) { + renderUsageContext(x, (UsageContext) type); + } else if (type instanceof CodeableReference) { + CodeableReference cr = (CodeableReference) type; + if (cr.hasConcept()) { + renderCodeableConcept(x, cr.getConcept()); + } else { + renderReference(x, cr.getReference()); + } + } else if (type instanceof MarkdownType) { + addMarkdown(x, context.getTranslated((MarkdownType) type)); + } else if (type instanceof Base64BinaryType) { + Base64BinaryType b64 = (Base64BinaryType) type; + x.tx(context.formatPhrase(RenderingContext.DATA_REND_BASE64, (b64.getValue() == null ? "0" : b64.getValue().length))); + } else if (type.isPrimitive()) { + x.tx(context.getTranslated((PrimitiveType) type)); + } else { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_NO_DISP, type.fhirType()) + " "); + } + } + + protected void renderReference(XhtmlNode x, Reference ref) { + if (ref.hasDisplay()) { + x.tx(context.getTranslated(ref.getDisplayElement())); + } else if (ref.hasReference()) { + x.tx(ref.getReference()); + } else { + x.tx("??"); + } + } + + public void renderDateTime(XhtmlNode x, Base e) { + if (e.hasPrimitiveValue()) { + x.addText(displayDateTime((DateTimeType) e)); + } + } + + public void renderDate(XhtmlNode x, Base e) { + if (e.hasPrimitiveValue()) { + x.addText(displayDateTime((DateType) e)); + } + } + + public void renderDateTime(XhtmlNode x, String s) { + if (s != null) { + DateTimeType dt = new DateTimeType(s); + x.addText(displayDateTime(dt)); + } + } + + protected void renderUri(XhtmlNode x, UriType uri) { + if (uri.getValue().startsWith("mailto:")) { + x.ah(uri.getValue()).addText(uri.getValue().substring(7)); + } else { + Resource r = context.getContext().fetchResource(Resource.class, uri.getValue()); + if (r != null && r.getWebPath() != null) { + if (r instanceof CanonicalResource) { + x.ah(r.getWebPath()).addText(crPresent((CanonicalResource) r)); + } else { + x.ah(r.getWebPath()).addText(uri.getValue()); + } + } else { + String url = context.getResolver() != null ? context.getResolver().resolveUri(context, uri.getValue()) : null; + if (url != null) { + x.ah(url).addText(uri.getValue()); + } else if (Utilities.isAbsoluteUrlLinkable(uri.getValue()) && !(uri instanceof IdType)) { + x.ah(uri.getValue()).addText(uri.getValue()); + } else { + x.addText(uri.getValue()); + } + } + } + } + + protected void renderUri(XhtmlNode x, UriType uriD, String path, String id, Resource src) { + String uri = uriD.getValue(); + if (isCanonical(path)) { + x.code().tx(uri); + } else { + if (uri == null) { + x.b().tx(uri); + } else if (uri.startsWith("mailto:")) { + x.ah(uri).addText(uri.substring(7)); + } else { + Resource target = context.getContext().fetchResource(Resource.class, uri, src); + if (target != null && target.hasWebPath()) { + String title = target instanceof CanonicalResource ? crPresent((CanonicalResource) target) : uri; + x.ah(target.getWebPath()).addText(title); + } else { + String url = context.getResolver() != null ? context.getResolver().resolveUri(context, uri) : null; + if (url != null) { + x.ah(url).addText(uri); + } else if (uri.contains("|")) { + x.ah(uri.substring(0, uri.indexOf("|"))).addText(uri); + } else if (uri.startsWith("http:") || uri.startsWith("https:") || uri.startsWith("ftp:")) { + x.ah(uri).addText(uri); + } else { + x.code().addText(uri); + } + } + } + } + } + + protected void renderAnnotation(XhtmlNode x, Annotation annot) { + renderAnnotation(x, annot, false); + } + + protected void renderAnnotation(XhtmlNode x, Annotation a, boolean showCodeDetails) throws FHIRException { + StringBuilder b = new StringBuilder(); + if (a.hasText()) { + b.append(context.getTranslated(a.getTextElement())); + } + + if (a.hasText() && (a.hasAuthor() || a.hasTimeElement())) { + b.append(" ("); + } + + if (a.hasAuthor()) { + b.append(context.formatPhrase(RenderingContext.DATA_REND_BY) + " "); + if (a.hasAuthorReference()) { + b.append(a.getAuthorReference().getReference()); + } else if (a.hasAuthorStringType()) { + b.append(context.getTranslated(a.getAuthorStringType())); + } + } + + + if (a.hasTimeElement()) { + if (b.length() > 0) { + b.append(" "); + } + b.append("@").append(a.getTimeElement().toHumanDisplay()); + } + if (a.hasText() && (a.hasAuthor() || a.hasTimeElement())) { + b.append(")"); + } + + + x.addText(b.toString()); + } + + public String displayCoding(Coding c) { + String s = ""; + if (context.isTechnicalMode()) { + s = context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(s)) { + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + } + if (Utilities.noString(s)) { + s = displayCodeTriple(c.getSystem(), c.getVersion(), c.getCode()); + } else if (c.hasSystem()) { + s = s + " ("+displayCodeTriple(c.getSystem(), c.getVersion(), c.getCode())+")"; + } else if (c.hasCode()) { + s = s + " ("+c.getCode()+")"; + } + } else { + if (c.hasDisplayElement()) + return context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(s)) + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + if (Utilities.noString(s)) + s = c.getCode(); + } + return s; + } + + private String displayCodeSource(String system, String version) { + String s = displaySystem(system); + if (version != null) { + s = s + "["+describeVersion(version)+"]"; + } + return s; + } + + private String displayCodeTriple(String system, String version, String code) { + if (system == null) { + if (code == null) { + return ""; + } else { + return "#"+code; + } + } else { + String s = displayCodeSource(system, version); + if (code != null) { + s = s + "#"+code; + } + return s; + } + } + + public String displayCoding(List list) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (Coding c : list) { + b.append(displayCoding(c)); + } + return b.toString(); + } + + protected void renderCoding(XhtmlNode x, Coding c) { + renderCoding(x, c, false); + } + + protected void renderCoding(HierarchicalTableGenerator gen, List pieces, Coding c) { + if (c.isEmpty()) { + return; + } + + String url = getLinkForSystem(c.getSystem(), c.getVersion()); + String name = displayCodeSource(c.getSystem(), c.getVersion()); + if (!Utilities.noString(url)) { + pieces.add(gen.new Piece(url, name, c.getSystem()+(c.hasVersion() ? "#"+c.getVersion() : ""))); + } else { + pieces.add(gen.new Piece(null, name, c.getSystem()+(c.hasVersion() ? "#"+c.getVersion() : ""))); + } + pieces.add(gen.new Piece(null, "#"+c.getCode(), null)); + String s = context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(s)) { + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + } + if (!Utilities.noString(s)) { + pieces.add(gen.new Piece(null, " \""+s+"\"", null)); + } + } + + private String getLinkForSystem(String system, String version) { + if ("http://snomed.info/sct".equals(system)) { + return "https://browser.ihtsdotools.org/"; + } else if ("http://loinc.org".equals(system)) { + return "https://loinc.org/"; + } else if ("http://unitsofmeasure.org".equals(system)) { + return "http://ucum.org"; + } else { + String url = system; + if (version != null) { + url = url + "|"+version; + } + CodeSystem cs = context.getWorker().fetchCodeSystem(url); + if (cs != null && cs.hasWebPath()) { + return cs.getWebPath(); + } + return null; + } + } + + protected String getLinkForCode(String system, String version, String code) { + if ("http://snomed.info/sct".equals(system)) { + if (!Utilities.noString(code)) { + return "http://snomed.info/id/"+code; + } else { + return "https://browser.ihtsdotools.org/"; + } + } else if ("http://loinc.org".equals(system)) { + if (!Utilities.noString(code)) { + return "https://loinc.org/"+code; + } else { + return "https://loinc.org/"; + } + } else if ("http://www.nlm.nih.gov/research/umls/rxnorm".equals(system)) { + if (!Utilities.noString(code)) { + return "https://mor.nlm.nih.gov/RxNav/search?searchBy=RXCUI&searchTerm="+code; + } else { + return "https://www.nlm.nih.gov/research/umls/rxnorm/index.html"; + } + } else if ("urn:iso:std:iso:3166".equals(system)) { + if (!Utilities.noString(code)) { + return "https://en.wikipedia.org/wiki/ISO_3166-2:"+code; + } else { + return "https://en.wikipedia.org/wiki/ISO_3166-2"; + } + } else { + CodeSystem cs = context.getWorker().fetchCodeSystem(system, version); + if (cs != null && cs.hasWebPath()) { + if (!Utilities.noString(code)) { + return cs.getWebPath()+"#"+cs.getId()+"-"+Utilities.nmtokenize(code); + } else { + return cs.getWebPath(); + } + } + } + return null; + } + + public CodeResolution resolveCode(String system, String code) { + return resolveCode(new Coding().setSystem(system).setCode(code)); + } + + public CodeResolution resolveCode(Coding c) { + String systemName; + String systemLink; + String link; + String display = null; + String hint; + + if (c.hasDisplayElement()) + display = context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(display)) + display = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + if (Utilities.noString(display)) { + display = c.getCode(); + } + + CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem()); + systemLink = cs != null ? cs.getWebPath() : null; + systemName = cs != null ? crPresent(cs) : displaySystem(c.getSystem()); + link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode()); + + hint = systemName+": "+display+(c.hasVersion() ? " "+ context.formatPhrase(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")") : ""); + return new CodeResolution(systemName, systemLink, link, display, hint); + } + + public CodeResolution resolveCode(CodeableConcept code) { + if (code.hasCoding()) { + return resolveCode(code.getCodingFirstRep()); + } else { + return new CodeResolution(null, null, null, code.getText(), code.getText()); + } + } + protected void renderCodingWithDetails(XhtmlNode x, Coding c) { + String s = ""; + if (c.hasDisplayElement()) + s = context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(s)) + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + + CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem()); + + String sn = cs != null ? crPresent(cs) : displaySystem(c.getSystem()); + String link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode()); + if (link != null) { + x.ah(link).tx(sn); + } else { + x.tx(sn); + } + + x.tx(" "); + x.tx(c.getCode()); + if (!Utilities.noString(s)) { + x.tx(": "); + x.tx(s); + } + if (c.hasVersion()) { + x.tx(" "+context.formatPhrase(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")")); + } + } + + protected void renderCoding(XhtmlNode x, Coding c, boolean showCodeDetails) { + String s = ""; + if (c.hasDisplayElement()) + s = context.getTranslated(c.getDisplayElement()); + if (Utilities.noString(s)) + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + + if (Utilities.noString(s)) + s = c.getCode(); + + if (showCodeDetails) { + x.addText(s+" "+context.formatPhrase(RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.getSystem()), c.getCode(), " = '", lookupCode(c.getSystem(), c.getVersion(), c.getCode()), c.getDisplay(), "')")); + } else + x.span(null, "{"+c.getSystem()+" "+c.getCode()+"}").addText(s); + } + + public String displayCodeableConcept(CodeableConcept cc) { + String s = context.getTranslated(cc.getTextElement()); + if (Utilities.noString(s)) { + for (Coding c : cc.getCoding()) { + if (c.hasDisplayElement()) { + s = context.getTranslated(c.getDisplayElement()); + break; + } + } + } + if (Utilities.noString(s)) { + // still? ok, let's try looking it up + for (Coding c : cc.getCoding()) { + if (c.hasCode() && c.hasSystem()) { + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + if (!Utilities.noString(s)) + break; + } + } + } + + if (Utilities.noString(s)) { + if (cc.getCoding().isEmpty()) + s = ""; + else + s = cc.getCoding().get(0).getCode(); + } + return s; + } + + protected void renderCodeableConcept(XhtmlNode x, CodeableConcept cc) throws FHIRFormatError, DefinitionException, IOException { + renderCodeableConcept(x, cc, false); + } + + protected void renderCodeableReference(XhtmlNode x, CodeableReference e, boolean showCodeDetails) throws FHIRFormatError, DefinitionException, IOException { + if (e.hasConcept()) { + renderCodeableConcept(x, e.getConcept(), showCodeDetails); + } + if (e.hasReference()) { + renderReference(x, e.getReference()); + } + } + + protected void renderCodeableConcept(XhtmlNode x, CodeableConcept cc, boolean showCodeDetails) throws FHIRFormatError, DefinitionException, IOException { + if (cc.isEmpty()) { + return; + } + + String s = context.getTranslated(cc.getTextElement()); + if (Utilities.noString(s)) { + for (Coding c : cc.getCoding()) { + if (c.hasDisplayElement()) { + s = context.getTranslated(c.getDisplayElement()); + break; + } + } + } + if (Utilities.noString(s)) { + // still? ok, let's try looking it up + for (Coding c : cc.getCoding()) { + if (c.hasCodeElement() && c.hasSystemElement()) { + s = lookupCode(c.getSystem(), c.getVersion(), c.getCode()); + if (!Utilities.noString(s)) + break; + } + } + } + + if (Utilities.noString(s)) { + if (cc.getCoding().isEmpty()) + s = ""; + else + s = cc.getCoding().get(0).getCode(); + } + + if (showCodeDetails) { + x.addText(s+" "); + XhtmlNode sp = x.span("background: LightGoldenRodYellow; margin: 4px; border: 1px solid khaki", null); + sp.tx(" ("); + boolean first = true; + for (Coding c : cc.getCoding()) { + if (first) { + first = false; + } else { + sp.tx("; "); + } + String url = getLinkForSystem(c.getSystem(), c.getVersion()); + if (url != null) { + sp.ah(url).tx(displayCodeSource(c.getSystem(), c.getVersion())); + } else { + sp.tx(displayCodeSource(c.getSystem(), c.getVersion())); + } + if (c.hasCode()) { + sp.tx("#"+c.getCode()); + } + if (c.hasDisplay() && !s.equals(c.getDisplay())) { + sp.tx(" \""+context.getTranslated(c.getDisplayElement())+"\""); + } + } + if (hasRenderableExtensions(cc)) { + if (!first) { + sp.tx("; "); + } + renderExtensionsInText(sp, cc, ";"); + } + sp.tx(")"); + } else { + + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (Coding c : cc.getCoding()) { + if (c.hasCodeElement() && c.hasSystemElement()) { + b.append("{"+c.getSystem()+" "+c.getCode()+"}"); + } + } + + x.span(null, context.formatPhrase(RenderingContext.DATA_REND_CODES) +b.toString()).addText(s); + } + } + + protected String displayIdentifier(Identifier ii) { + String s = Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue(); + if ("urn:ietf:rfc:3986".equals(ii.getSystem()) && s.startsWith("urn:oid:")) { + s = "OID:"+s.substring(8); + } else if ("urn:ietf:rfc:3986".equals(ii.getSystem()) && s.startsWith("urn:uuid:")) { + s = "UUID:"+s.substring(9); + } else { + NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem()); + if (ns != null) { + s = crPresent(ns)+"#"+s; + } + if (ii.hasType()) { + if (ii.getType().hasText()) + s = context.getTranslated(ii.getType().getTextElement())+":\u00A0"+s; + else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay()) + s = context.getTranslated(ii.getType().getCoding().get(0).getDisplayElement())+": "+s; + else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode()) + s = lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())+": "+s; + } else if (ii.hasSystem()) { + s = ii.getSystem()+"#"+s; + } + } + + if (ii.hasUse() || ii.hasPeriod()) { + s = s + "\u00A0("; + if (ii.hasUse()) { + s = s + "use:\u00A0"+ii.getUse().toCode(); + } + if (ii.hasUse() && ii.hasPeriod()) { + s = s + ",\u00A0"; + } + if (ii.hasPeriod()) { + s = s + "period:\u00A0"+displayPeriod(ii.getPeriod()); + } + s = s + ")"; + } + return s; + } + + protected void renderIdentifier(XhtmlNode x, Identifier ii) { + if (ii.hasType()) { + if (ii.getType().hasText()) { + x.tx(context.getTranslated(ii.getType().getTextElement())); + } else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay()) { + x.tx(context.getTranslated(ii.getType().getCoding().get(0).getDisplayElement())); + } else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasCode()) { + x.tx(lookupCode(ii.getType().getCoding().get(0).getSystem(), ii.getType().getCoding().get(0).getVersion(), ii.getType().getCoding().get(0).getCode())); + } + x.tx("/"); + } else if (ii.hasSystem()) { + NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem()); + if (ns != null) { + if (ns.hasWebPath()) { + x.ah(ns.getWebPath(), ns.getDescription()).tx(crPresent(ns)); + } else { + x.tx(crPresent(ns)); + } + } else { + switch (ii.getSystem()) { + case "urn:oid:2.51.1.3": + x.ah("https://www.gs1.org/standards/id-keys/gln", context.formatPhrase(RenderingContext.DATA_REND_GLN)).tx("GLN"); + break; + default: + x.code(ii.getSystem()); + } + } + x.tx("/"); + } + x.tx(Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue()); + + if (ii.hasUse() || ii.hasPeriod()) { + x.nbsp(); + x.tx("("); + if (ii.hasUse()) { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_USE)); + x.nbsp(); + x.tx(ii.getUse().toCode()); + } + if (ii.hasUse() && ii.hasPeriod()) { + x.tx(","); + x.nbsp(); + } + if (ii.hasPeriod()) { + x.tx(context.formatPhrase(RenderingContext.DATA_REND_PERIOD)); + x.nbsp(); + x.tx(displayPeriod(ii.getPeriod())); + } + x.tx(")"); + } + } + + public static String displayHumanName(HumanName name) { + StringBuilder s = new StringBuilder(); + if (name.hasText()) + s.append(name.getText()); + else { + for (StringType p : name.getGiven()) { + s.append(p.getValue()); + s.append(" "); + } + if (name.hasFamily()) { + s.append(name.getFamily()); + s.append(" "); + } + } + if (name.hasUse() && name.getUse() != NameUse.USUAL) + s.append("("+name.getUse().toString()+")"); + return s.toString(); + } + + + protected void renderHumanName(XhtmlNode x, HumanName name) { + StringBuilder s = new StringBuilder(); + if (name.hasText()) + s.append(context.getTranslated(name.getTextElement())); + else { + for (StringType p : name.getGiven()) { + s.append(context.getTranslated(p)); + s.append(" "); + } + if (name.hasFamily()) { + s.append(context.getTranslated(name.getFamilyElement())); + s.append(" "); + } + } + if (name.hasUse() && name.getUse() != NameUse.USUAL) + s.append("("+context.getTranslatedCode(name.getUseElement(), "http://hl7.org/fhir/name-use")+")"); + + x.addText(s.toString()); + } + + private String displayAddress(Address address) { + StringBuilder s = new StringBuilder(); + if (address.hasText()) + s.append(context.getTranslated(address.getTextElement())); + else { + for (StringType p : address.getLine()) { + s.append(context.getTranslated(p)); + s.append(" "); + } + if (address.hasCity()) { + s.append(context.getTranslated(address.getCityElement())); + s.append(" "); + } + if (address.hasState()) { + s.append(context.getTranslated(address.getStateElement())); + s.append(" "); + } + + if (address.hasPostalCode()) { + s.append(context.getTranslated(address.getPostalCodeElement())); + s.append(" "); + } + + if (address.hasCountry()) { + s.append(context.getTranslated(address.getCountryElement())); + s.append(" "); + } + } + if (address.hasUse()) + s.append("("+address.getUse().toCode()+")"); + return s.toString(); + } + + protected void renderAddress(XhtmlNode x, Address address) { + x.addText(displayAddress(address)); + } + + + public static String displayContactPoint(ContactPoint contact) { + StringBuilder s = new StringBuilder(); + s.append(describeSystem(contact.getSystem())); + if (Utilities.noString(contact.getValue())) + s.append("-unknown-"); + else + s.append(contact.getValue()); + if (contact.hasUse()) + s.append("("+contact.getUse().toString()+")"); + return s.toString(); + } + + public static String displayContactDetail(ContactDetail contact) { + CommaSeparatedStringBuilder s = new CommaSeparatedStringBuilder(); + for (ContactPoint cp : contact.getTelecom()) { + s.append(displayContactPoint(cp)); + } + return contact.getName()+(s.length() == 0 ? "" : " ("+s.toString()+")"); + } + + protected String getLocalizedBigDecimalValue(BigDecimal input, Currency c) { + NumberFormat numberFormat = NumberFormat.getNumberInstance(context.getLocale()); + numberFormat.setGroupingUsed(true); + numberFormat.setMaximumFractionDigits(c.getDefaultFractionDigits()); + numberFormat.setMinimumFractionDigits(c.getDefaultFractionDigits()); + return numberFormat.format(input); +} + + protected void renderMoney(XhtmlNode x, Money money) { + if (x.getName().equals("blockquote")) { + x = x.para(); + } + Currency c = money.hasCurrency() ? Currency.getInstance(money.getCurrency()) : null; + if (c != null) { + XhtmlNode s = x.span(null, c.getDisplayName()); + s.tx(c.getSymbol(context.getLocale())); + s.tx(getLocalizedBigDecimalValue(money.getValue(), c)); + x.tx(" ("+c.getCurrencyCode()+")"); + } else { + if (money.getCurrency() != null) { + x.tx(money.getCurrency()); + } + x.tx(money.getValue().toPlainString()); + } + } + + protected void renderExpression(XhtmlNode x, Expression expr) { + // there's two parts: what the expression is, and how it's described. + // we start with what it is, and then how it's described + XhtmlNode p = x; + if (p.getName().equals("blockquote")) { + p = p.para(); + } + if (expr.hasExpression()) { + if (expr.hasReference()) { + p = x.ah(expr.getReference()); + } + XhtmlNode c = p; + if (expr.hasLanguage()) { + c = c.span(null, expr.getLanguage()); + } + c.code().tx(expr.getExpression()); + } else if (expr.hasReference()) { + p.ah(expr.getReference()).tx(context.formatPhrase(RenderingContext.DATA_REND_SOURCE)); + } + if (expr.hasName() || expr.hasDescription()) { + p.tx("("); + if (expr.hasName()) { + p.b().tx(expr.getName()); + } + if (expr.hasDescription()) { + p.tx("\""); + p.tx(context.getTranslated(expr.getDescriptionElement())); + p.tx("\""); + } + p.tx(")"); + } + } + + + protected void renderContactPoint(XhtmlNode x, ContactPoint contact) { + if (contact != null) { + if (!contact.hasSystem()) { + x.addText(displayContactPoint(contact)); + } else { + switch (contact.getSystem()) { + case EMAIL: + x.ah("mailto:"+contact.getValue()).tx(contact.getValue()); + break; + case FAX: + x.addText(displayContactPoint(contact)); + break; + case NULL: + x.addText(displayContactPoint(contact)); + break; + case OTHER: + x.addText(displayContactPoint(contact)); + break; + case PAGER: + x.addText(displayContactPoint(contact)); + break; + case PHONE: + if (contact.hasValue() && contact.getValue().startsWith("+")) { + x.ah("tel:"+contact.getValue().replace(" ", "")).tx(contact.getValue()); + } else { + x.addText(displayContactPoint(contact)); + } + break; + case SMS: + x.addText(displayContactPoint(contact)); + break; + case URL: + x.ah(contact.getValue()).tx(contact.getValue()); + break; + default: + break; + } + } + } + } + + protected void displayContactPoint(XhtmlNode p, ContactPoint c) { + if (c != null) { + if (c.getSystem() == ContactPointSystem.PHONE) { + p.tx(context.formatPhrase(RenderingContext.DATA_REND_PHONE, c.getValue()) + " "); + } else if (c.getSystem() == ContactPointSystem.FAX) { + p.tx(context.formatPhrase(RenderingContext.DATA_REND_FAX, c.getValue()) + " "); + } else if (c.getSystem() == ContactPointSystem.EMAIL) { + p.tx(c.getValue()); + } else if (c.getSystem() == ContactPointSystem.URL) { + if (c.getValue().length() > 30) { + p.addText(c.getValue().substring(0, 30)+"..."); + } else { + p.addText(c.getValue()); + } + } + } + } + + protected void addTelecom(XhtmlNode p, ContactPoint c) { + if (c.getSystem() == ContactPointSystem.PHONE) { + p.tx(context.formatPhrase(RenderingContext.DATA_REND_PHONE, c.getValue()) + " "); + } else if (c.getSystem() == ContactPointSystem.FAX) { + p.tx(context.formatPhrase(RenderingContext.DATA_REND_FAX, c.getValue()) + " "); + } else if (c.getSystem() == ContactPointSystem.EMAIL) { + p.ah("mailto:"+c.getValue()).addText(c.getValue()); + } else if (c.getSystem() == ContactPointSystem.URL) { + if (c.getValue().length() > 30) + p.ah(c.getValue()).addText(c.getValue().substring(0, 30)+"..."); + else + p.ah(c.getValue()).addText(c.getValue()); + } + } + private static String describeSystem(ContactPointSystem system) { + if (system == null) + return ""; + switch (system) { + case PHONE: return "ph: "; + case FAX: return "fax: "; + default: + return ""; + } + } + + protected String displayQuantity(Quantity q) { + StringBuilder s = new StringBuilder(); + + s.append(q.hasValue() ? q.getValue() : "?"); + if (q.hasUnit()) + s.append(" ").append(q.getUnit()); + else if (q.hasCode()) + s.append(" ").append(q.getCode()); + + return s.toString(); + } + + protected void renderQuantity(XhtmlNode x, Quantity q) { + renderQuantity(x, q, false); + } + + protected void renderQuantity(XhtmlNode x, Quantity q, boolean showCodeDetails) { + if (q.hasComparator()) + x.addText(q.getComparator().toCode()); + if (q.hasValue()) { + x.addText(context.getTranslated(q.getValueElement())); + } + if (q.hasUnit()) + x.tx(" "+context.getTranslated(q.getUnitElement())); + else if (q.hasCode() && q.hasSystem()) { + // if there's a code there *shall* be a system, so if we've got one and not the other, things are invalid and we won't bother trying to render + if (q.hasSystem() && q.getSystem().equals("http://unitsofmeasure.org")) + x.tx(" "+q.getCode()); + else + x.tx("(unit "+q.getCode()+" from "+q.getSystem()+")"); + } + if (showCodeDetails && q.hasCode()) { + x.span("background: LightGoldenRodYellow", null).tx(" "+ (context.formatPhrase(RenderingContext.DATA_REND_DETAILS, displaySystem(q.getSystem()))) +q.getCode()+" = '"+lookupCode(q.getSystem(), null, q.getCode())+"')"); + } + } + + + protected void renderQuantity(HierarchicalTableGenerator gen, List pieces, Quantity q, boolean showCodeDetails) { + pieces.add(gen.new Piece(null, displayQuantity(q), null)); + } + + public String displayRange(Range q) { + if (!q.hasLow() && !q.hasHigh()) + return "?"; + + StringBuilder b = new StringBuilder(); + + boolean sameUnits = (q.getLow().hasUnit() && q.getHigh().hasUnit() && q.getLow().getUnit().equals(q.getHigh().getUnit())) + || (q.getLow().hasCode() && q.getHigh().hasCode() && q.getLow().getCode().equals(q.getHigh().getCode())); + String low = "?"; + if (q.hasLow() && q.getLow().hasValue()) + low = sameUnits ? q.getLow().getValue().toString() : displayQuantity(q.getLow()); + String high = displayQuantity(q.getHigh()); + if (high.isEmpty()) + high = "?"; + b.append(low).append("\u00A0to\u00A0").append(high); + return b.toString(); + } + + protected void renderRange(XhtmlNode x, Range q) { + if (q.hasLow()) + x.addText(q.getLow().getValue().toString()); + else + x.tx("?"); + x.tx("-"); + if (q.hasHigh()) + x.addText(q.getHigh().getValue().toString()); + else + x.tx("?"); + if (q.getLow().hasUnit()) + x.tx(" "+q.getLow().getUnit()); + } + + public String displayPeriod(Period p) { + String s = !p.hasStart() ? "(?)" : displayDateTime(p.getStartElement()); + s = s + " --> "; + return s + (!p.hasEnd() ? context.formatPhrase(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); + } + + public void renderPeriod(XhtmlNode x, Period p) { + x.addText(!p.hasStart() ? "??" : displayDateTime(p.getStartElement())); + x.tx(" --> "); + x.addText(!p.hasEnd() ? context.formatPhrase(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); + } + + public void renderUsageContext(XhtmlNode x, UsageContext u) throws FHIRFormatError, DefinitionException, IOException { + renderCoding(x, u.getCode()); + x.tx(": "); + render(x, u.getValue()); + } + + + public void renderTriggerDefinition(XhtmlNode x, TriggerDefinition td) throws FHIRFormatError, DefinitionException, IOException { + if (x.isPara()) { + x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); + x.tx(": "); + x.tx(td.getType().getDisplay()); + + if (td.hasName()) { + x.tx(", "); + x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_NAME)); + x.tx(": "); + x.tx(context.getTranslated(td.getNameElement())); + } + if (td.hasCode()) { + x.tx(", "); + x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_CODE)); + x.tx(": "); + renderCodeableConcept(x, td.getCode()); + } + if (td.hasTiming()) { + x.tx(", "); + x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TIMING)); + x.tx(": "); + render(x, td.getTiming()); + } + if (td.hasCondition()) { + x.tx(", "); + x.b().tx(context.formatPhrase(RenderingContext.DATA_REND_COND)); + x.tx(": "); + renderExpression(x, td.getCondition()); + } + } else { + XhtmlNode tbl = x.table("grid"); + + XhtmlNode tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); + tr.td().tx(td.getType().getDisplay()); + + if (td.hasName()) { + tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_NAME)); + tr.td().tx(context.getTranslated(td.getNameElement())); + } + if (td.hasCode()) { + tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_CODE)); + renderCodeableConcept(tr.td(), td.getCode()); + } + if (td.hasTiming()) { + tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_TIMING)); + render(tr.td(), td.getTiming()); + } + if (td.hasCondition()) { + tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DATA_REND_COND)); + renderExpression(tr.td(), td.getCondition()); + } + } + } + + public void renderDataRequirement(XhtmlNode x, DataRequirement dr) throws FHIRFormatError, DefinitionException, IOException { + XhtmlNode tbl = x.table("grid"); + XhtmlNode tr = tbl.tr(); + XhtmlNode td = tr.td().colspan("2"); + td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_TYPE)); + td.tx(": "); + StructureDefinition sd = context.getWorker().fetchTypeDefinition(dr.getType().toCode()); + if (sd != null && sd.hasWebPath()) { + td.ah(sd.getWebPath()).tx(dr.getType().toCode()); + } else { + td.tx(dr.getType().toCode()); + } + if (dr.hasProfile()) { + td.tx(" ("); + boolean first = true; + for (CanonicalType p : dr.getProfile()) { + if (first) first = false; else td.tx(" | "); + sd = context.getWorker().fetchResource(StructureDefinition.class, p.getValue()); + if (sd != null && sd.hasWebPath()) { + td.ah(sd.getWebPath()).tx(crPresent(sd)); + } else { + td.tx(p.asStringValue()); + } + } + td.tx(")"); + } + if (dr.hasSubject()) { + tr = tbl.tr(); + td = tr.td().colspan("2"); + td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_SUB)); + if (dr.hasSubjectReference()) { + renderReference(td, dr.getSubjectReference()); + } else { + renderCodeableConcept(td, dr.getSubjectCodeableConcept()); + } + } + if (dr.hasCodeFilter() || dr.hasDateFilter()) { + tr = tbl.tr().backgroundColor("#efefef"); + tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_FILT)); + tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_VALUE)); + } + for (DataRequirementCodeFilterComponent cf : dr.getCodeFilter()) { + tr = tbl.tr(); + if (cf.hasPath()) { + tr.td().tx(cf.getPath()); + } else { + tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_SEARCH, cf.getSearchParam()) + " "); + } + if (cf.hasValueSet()) { + td = tr.td(); + td.tx(context.formatPhrase(RenderingContext.DATA_REND_VALUESET) + " "); + render(td, cf.getValueSetElement()); + } else { + boolean first = true; + td = tr.td(); + td.tx(context.formatPhrase(RenderingContext.DATA_REND_THESE_CODES) + " "); + for (Coding c : cf.getCode()) { + if (first) first = false; else td.tx(", "); + render(td, c); + } + } + } + for (DataRequirementDateFilterComponent cf : dr.getDateFilter()) { + tr = tbl.tr(); + if (cf.hasPath()) { + tr.td().tx(cf.getPath()); + } else { + tr.td().tx(context.formatPhrase(RenderingContext.DATA_REND_SEARCH, cf.getSearchParam()) + " "); + } + render(tr.td(), cf.getValue()); + } + if (dr.hasSort() || dr.hasLimit()) { + tr = tbl.tr(); + td = tr.td().colspan("2"); + if (dr.hasLimit()) { + td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_LIMIT)); + td.tx(": "); + td.tx(dr.getLimit()); + if (dr.hasSort()) { + td.tx(", "); + } + } + if (dr.hasSort()) { + td.b().tx(context.formatPhrase(RenderingContext.DATA_REND_SORT)); + td.tx(": "); + boolean first = true; + for (DataRequirementSortComponent p : dr.getSort()) { + if (first) first = false; else td.tx(" | "); + td.tx(p.getDirection() == SortDirection.ASCENDING ? "+" : "-"); + td.tx(p.getPath()); + } + } + } + } + + + private String displayTiming(Timing s) throws FHIRException { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + if (s.hasCode()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_GETCODE, displayCodeableConcept(s.getCode())) + " "); + + if (s.getEvent().size() > 0) { + CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder(); + for (DateTimeType p : s.getEvent()) { + if (p.hasValue()) { + c.append(displayDateTime(p)); + } else if (!renderExpression(c, p)) { + c.append("??"); + } + } + b.append(context.formatPhrase(RenderingContext.DATA_REND_EVENTS, c.toString()) + " "); + } + + if (s.hasRepeat()) { + TimingRepeatComponent rep = s.getRepeat(); + if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_STARTING, displayDateTime(rep.getBoundsPeriod().getStartElement())) + " "); + if (rep.hasCount()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_COUNT, Integer.toString(rep.getCount())) + " " + " times"); + if (rep.hasDuration()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_DURATION, rep.getDuration().toPlainString()+displayTimeUnits(rep.getPeriodUnit())) + " "); + + if (rep.hasWhen()) { + String st = ""; + if (rep.hasOffset()) { + st = Integer.toString(rep.getOffset())+"min "; + } + b.append(st); + for (Enumeration wh : rep.getWhen()) + b.append(displayEventCode(wh.getValue())); + } else { + String st = ""; + if (!rep.hasFrequency() || (!rep.hasFrequencyMax() && rep.getFrequency() == 1) ) + st = context.formatPhrase(RenderingContext.DATA_REND_ONCE); + else { + st = Integer.toString(rep.getFrequency()); + if (rep.hasFrequencyMax()) + st = st + "-"+Integer.toString(rep.getFrequency()); + } + if (rep.hasPeriod()) { + st = st + " "+ (context.formatPhrase(RenderingContext.DATA_REND_PER))+rep.getPeriod().toPlainString(); + if (rep.hasPeriodMax()) + st = st + "-"+rep.getPeriodMax().toPlainString(); + st = st + " "+displayTimeUnits(rep.getPeriodUnit()); + } + b.append(st); + } + if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_UNTIL, displayDateTime(rep.getBoundsPeriod().getEndElement())) + " "); + } + return b.toString(); + } + + private boolean renderExpression(CommaSeparatedStringBuilder c, PrimitiveType p) { + Extension exp = p.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/cqf-expression"); + if (exp == null) { + return false; + } + c.append(exp.getValueExpression().getExpression()); + return true; + } + + private String displayEventCode(EventTiming when) { + switch (when) { + case C: return (context.formatPhrase(RenderingContext.DATA_REND_MEALS)); + case CD: return (context.formatPhrase(RenderingContext.DATA_REND_ATLUNCH)); + case CM: return (context.formatPhrase(RenderingContext.DATA_REND_ATBKFST)); + case CV: return (context.formatPhrase(RenderingContext.DATA_REND_ATDINR)); + case AC: return (context.formatPhrase(RenderingContext.DATA_REND_BFMEALS)); + case ACD: return (context.formatPhrase(RenderingContext.DATA_REND_BFLUNCH)); + case ACM: return (context.formatPhrase(RenderingContext.DATA_REND_BFBKFST)); + case ACV: return (context.formatPhrase(RenderingContext.DATA_REND_BFDINR)); + case HS: return (context.formatPhrase(RenderingContext.DATA_REND_BFSLEEP)); + case PC: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRMEALS)); + case PCD: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRLUNCH)); + case PCM: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRBKFST)); + case PCV: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRDINR)); + case WAKE: return (context.formatPhrase(RenderingContext.DATA_REND_AFTRWKNG)); + default: return "?ngen-6?"; + } + } + + private String displayTimeUnits(UnitsOfTime units) { + if (units == null) + return "?ngen-7?"; + switch (units) { + case A: return "years"; + case D: return "days"; + case H: return "hours"; + case MIN: return "minutes"; + case MO: return "months"; + case S: return "seconds"; + case WK: return "weeks"; + default: return "?ngen-8?"; + } + } + + protected void renderTiming(XhtmlNode x, Timing s) throws FHIRException { + x.addText(displayTiming(s)); + } + + + private String displaySampledData(SampledData s) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + if (s.hasOrigin()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_ORIGIN, displayQuantity(s.getOrigin())) + " "); + + if (s.hasInterval()) { + b.append(context.formatPhrase(RenderingContext.DATA_REND_INT, s.getInterval().toString()) + " "); + + if (s.hasIntervalUnit()) + b.append(s.getIntervalUnit().toString()); + } + + if (s.hasFactor()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_FACT, s.getFactor().toString()) + " "); + + if (s.hasLowerLimit()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_LOWER, s.getLowerLimit().toString()) + " "); + + if (s.hasUpperLimit()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_UP, s.getUpperLimit().toString()) + " "); + + if (s.hasDimensions()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_DIM, s.getDimensions()) + " "); + + if (s.hasData()) + b.append(context.formatPhrase(RenderingContext.DATA_REND_DATA, s.getData()) + " "); + + return b.toString(); + } + + protected void renderSampledData(XhtmlNode x, SampledData sampledData) { + x.addText(displaySampledData(sampledData)); + } + + public RenderingContext getContext() { + return context; + } + + + public XhtmlNode makeExceptionXhtml(Exception e, String function) { + XhtmlNode xn; + xn = new XhtmlNode(NodeType.Element, "div"); + XhtmlNode p = xn.para(); + p.b().tx((context.formatPhrase(RenderingContext.DATA_REND_EXCEPTION)) +function+": "+e.getMessage()); + p.addComment(getStackTrace(e)); + return xn; + } + + private String getStackTrace(Exception e) { + StringBuilder b = new StringBuilder(); + b.append("\r\n"); + for (StackTraceElement t : e.getStackTrace()) { + b.append(t.getClassName()+"."+t.getMethodName()+" ("+t.getFileName()+":"+t.getLineNumber()); + b.append("\r\n"); + } + return b.toString(); + } + + protected String versionFromCanonical(String system) { + if (system == null) { + return null; + } else if (system.contains("|")) { + return system.substring(0, system.indexOf("|")); + } else { + return null; + } + } + + protected String systemFromCanonical(String system) { + if (system == null) { + return null; + } else if (system.contains("|")) { + return system.substring(system.indexOf("|")+1); + } else { + return system; + } + } + + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java index 175d2ebc3..8c85a5a01 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java @@ -1,488 +1,488 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; - -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.model.Base; -import org.hl7.fhir.r5.model.DataType; -import org.hl7.fhir.r5.model.DiagnosticReport; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; -import org.hl7.fhir.r5.renderers.utils.DirectWrappers; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; -import org.hl7.fhir.r5.utils.EOperationOutcome; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; - -public class DiagnosticReportRenderer extends ResourceRenderer { - - public class ObservationNode { - private String ref; - private ResourceWithReference obs; - private List contained; - } - - - public DiagnosticReportRenderer(RenderingContext context) { - super(context); - } - - public DiagnosticReportRenderer(RenderingContext context, ResourceContext rcontext) { - super(context, rcontext); - } - - public boolean render(XhtmlNode x, Resource dr) throws IOException, FHIRException, EOperationOutcome { - return render(x, (DiagnosticReport) dr); - } - - public boolean render(XhtmlNode x, ResourceWrapper dr) throws IOException, FHIRException, EOperationOutcome { - XhtmlNode h2 = x.h2(); - render(h2, getProperty(dr, "code").value()); - h2.tx(" "); - PropertyWrapper pw = getProperty(dr, "category"); - if (valued(pw)) { - h2.tx("("); - boolean first = true; - for (BaseWrapper b : pw.getValues()) { - if (first) first = false; else h2.tx(", "); - render(h2, b); - } - h2.tx(") "); - } - XhtmlNode tbl = x.table("grid"); - XhtmlNode tr; - if (dr.has("subject")) { - tr = tbl.tr(); - tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_SUB)); - populateSubjectSummary(tr.td(), getProperty(dr, "subject").value()); - } - - DataType eff = null; - DataType iss = null; - - if (dr.has("effective[x]")) { - tr = tbl.tr(); - tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN)); - eff = (DataType) getProperty(dr, "effective[x]").value().getBase(); - render(tr.td(), eff); - } - if (dr.has("issued")) { - tr = tbl.tr(); - tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP)); - eff = (DataType) getProperty(dr, "issued").value().getBase(); - render(tr.td(), getProperty(dr, "issued").value()); - } - - pw = getProperty(dr, "perfomer"); - if (valued(pw)) { - tr = tbl.tr(); - tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_PER)), pw.getValues().size())); - XhtmlNode tdr = tr.td(); - for (BaseWrapper v : pw.getValues()) { - tdr.tx(" "); - render(tdr, v); - } - } - pw = getProperty(dr, "identifier"); - if (valued(pw)) { - tr = tbl.tr(); - tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_IDENTIFIER)), pw.getValues().size())+":"); - XhtmlNode tdr = tr.td(); - for (BaseWrapper v : pw.getValues()) { - tdr.tx(" "); - render(tdr, v); - } - } - pw = getProperty(dr, "request"); - if (valued(pw)) { - tr = tbl.tr(); - tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_REQUEST)), pw.getValues().size())+":"); - XhtmlNode tdr = tr.td(); - for (BaseWrapper v : pw.getValues()) { - tdr.tx(" "); - render(tdr, v); - } - tdr.br(); - } - - - x.para().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REPDET)); - - pw = getProperty(dr, "result"); - if (valued(pw)) { - List observations = fetchObservations(pw.getValues(), dr); - buildObservationsTable(x, observations, eff, iss); - } - - pw = getProperty(dr, "conclusion"); - if (valued(pw)) { - if (pw.fhirType().equals("markdown")) { - render(x, pw.value()); - } else { - render(x.para(), pw.value()); - } - } - - pw = getProperty(dr, "conclusionCode"); - if (!valued(pw)) { - pw = getProperty(dr, "codedDiagnosis"); - } - if (valued(pw)) { - XhtmlNode p = x.para(); - p.b().tx(context.formatPhrase(RenderingContext.GENERAL_CODECON)); - XhtmlNode ul = x.ul(); - for (BaseWrapper v : pw.getValues()) { - render(ul.li(), v); - } - } - return false; - } - - public boolean render(XhtmlNode x, DiagnosticReport dr) throws IOException, FHIRException, EOperationOutcome { - render(x, new DirectWrappers.ResourceWrapperDirect(this.context, dr)); - - return true; - } - - public void describe(XhtmlNode x, DiagnosticReport dr) { - x.tx(display(dr)); - } - - public String display(DiagnosticReport dr) { - return display(dr.getCode()); - } - - @Override - public String display(Resource r) throws UnsupportedEncodingException, IOException { - return display((DiagnosticReport) r); - } - - @Override - public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { - return "Not done yet"; - } - - private void populateSubjectSummary(XhtmlNode container, BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException, EOperationOutcome { - ResourceWrapper r = fetchResource(subject); - if (r == null) - container.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_UNABLE)); - else if (r.getName().equals("Patient")) - generatePatientSummary(container, r); - else - container.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTDONE)); - } - - private void generatePatientSummary(XhtmlNode c, ResourceWrapper r) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome { - new PatientRenderer(context).describe(c, r); - } - - private List fetchObservations(List list, ResourceWrapper rw) throws UnsupportedEncodingException, FHIRException, IOException { - List res = new ArrayList(); - for (BaseWrapper b : list) { - if (b.has("reference")) { - ObservationNode obs = new ObservationNode(); - obs.ref = b.get("reference").primitiveValue(); - obs.obs = resolveReference(rw, obs.ref); - if (obs.obs != null && obs.obs.getResource() != null) { - PropertyWrapper t = getProperty(obs.obs.getResource(), "contained"); - if (t != null && t.hasValues()) { - obs.contained = fetchObservations(t.getValues(), rw); - } - } - res.add(obs); - } - } - return res; - } - - private void buildObservationsTable(XhtmlNode root, List observations, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { - XhtmlNode tbl = root.table("grid"); - boolean refRange = scanObsForRefRange(observations); - boolean flags = scanObsForFlags(observations); - boolean note = scanObsForNote(observations); - boolean effectiveTime = scanObsForEffective(observations, eff); - boolean issued = scanObsForIssued(observations, iss); - int cs = 2; - if (refRange) cs++; - if (flags) cs++; - if (note) cs++; - if (issued) cs++; - if (effectiveTime) cs++; - XhtmlNode tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_VALUE)); - if (refRange) { - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REFRAN)); - } - if (flags) { - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_FLAG)); - } - if (note) { - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTE)); - } - if (effectiveTime) { - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN)); - } - if (issued) { - tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP)); - } - for (ObservationNode o : observations) { - addObservationToTable(tbl, o, 0, Integer.toString(cs), refRange, flags, note, effectiveTime, issued, eff, iss); - } - } - - private boolean scanObsForRefRange(List observations) { - for (ObservationNode o : observations) { - if (o.obs != null && o.obs.getResource() != null) { - PropertyWrapper pw = getProperty(o.obs.getResource(), "referenceRange"); - if (valued(pw)) { - return true; - } - } - if (o.contained != null) { - if (scanObsForRefRange(o.contained)) { - return true; - } - } - } - return false; - } - - private boolean scanObsForNote(List observations) { - for (ObservationNode o : observations) { - if (o.obs != null && o.obs.getResource() != null) { - PropertyWrapper pw = getProperty(o.obs.getResource(), "note"); - if (valued(pw)) { - return true; - } - } - if (o.contained != null) { - if (scanObsForNote(o.contained)) { - return true; - } - } - } - return false; - } - - private boolean scanObsForIssued(List observations, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { - for (ObservationNode o : observations) { - if (o.obs != null && o.obs.getResource() != null) { - PropertyWrapper pw = getProperty(o.obs.getResource(), "issued"); - if (valued(pw)) { - if (!Base.compareDeep(pw.value().getBase(), iss, true)) { - return true; - } - } - } - if (o.contained != null) { - if (scanObsForIssued(o.contained, iss)) { - return true; - } - } - } - return false; - } - - private boolean scanObsForEffective(List observations, DataType eff) throws UnsupportedEncodingException, FHIRException, IOException { - for (ObservationNode o : observations) { - if (o.obs != null && o.obs.getResource() != null) { - PropertyWrapper pw = getProperty(o.obs.getResource(), "effective[x]"); - if (valued(pw)) { - if (!Base.compareDeep(pw.value().getBase(), eff, true)) { - return true; - } - } - } - if (o.contained != null) { - if (scanObsForEffective(o.contained, eff)) { - return true; - } - } - } - return false; - } - - private boolean scanObsForFlags(List observations) throws UnsupportedEncodingException, FHIRException, IOException { - for (ObservationNode o : observations) { - if (o.obs != null && o.obs.getResource() != null) { - PropertyWrapper pw = getProperty(o.obs.getResource(), "interpretation"); - if (valued(pw)) { - return true; - } - pw = getProperty(o.obs.getResource(), "status"); - if (valued(pw)) { - if (!pw.value().getBase().primitiveValue().equals("final")) { - return true; - } - } - - } - if (o.contained != null) { - if (scanObsForFlags(o.contained)) { - return true; - } - } - } - return false; - } - - private void addObservationToTable(XhtmlNode tbl, ObservationNode o, int i, String cs, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { - XhtmlNode tr = tbl.tr(); - if (o.obs != null && o.obs.getReference() == null) { - XhtmlNode td = tr.td().colspan(cs); - td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTRES)); - } else { - if (o.obs != null && o.obs.getResource() != null) { - addObservationToTable(tr, o.obs.getResource(), i, o.obs.getReference(), refRange, flags, note, effectiveTime, issued, eff, iss); - } else { - XhtmlNode td = tr.td().colspan(cs); - td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_OBS)); - } - if (o.contained != null) { - for (ObservationNode c : o.contained) { - addObservationToTable(tbl, c, i+1, cs, refRange, flags, note, effectiveTime, issued, eff, iss); - } - } +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.model.Base; +import org.hl7.fhir.r5.model.DataType; +import org.hl7.fhir.r5.model.DiagnosticReport; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; +import org.hl7.fhir.r5.renderers.utils.DirectWrappers; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; +import org.hl7.fhir.r5.utils.EOperationOutcome; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +public class DiagnosticReportRenderer extends ResourceRenderer { + + public class ObservationNode { + private String ref; + private ResourceWithReference obs; + private List contained; + } + + + public DiagnosticReportRenderer(RenderingContext context) { + super(context); + } + + public DiagnosticReportRenderer(RenderingContext context, ResourceContext rcontext) { + super(context, rcontext); + } + + public boolean render(XhtmlNode x, Resource dr) throws IOException, FHIRException, EOperationOutcome { + return render(x, (DiagnosticReport) dr); + } + + public boolean render(XhtmlNode x, ResourceWrapper dr) throws IOException, FHIRException, EOperationOutcome { + XhtmlNode h2 = x.h2(); + render(h2, getProperty(dr, "code").value()); + h2.tx(" "); + PropertyWrapper pw = getProperty(dr, "category"); + if (valued(pw)) { + h2.tx("("); + boolean first = true; + for (BaseWrapper b : pw.getValues()) { + if (first) first = false; else h2.tx(", "); + render(h2, b); + } + h2.tx(") "); } - } - - private void addObservationToTable(XhtmlNode tr, ResourceWrapper obs, int i, String ref, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { - - // code (+bodysite) - XhtmlNode td = tr.td(); - PropertyWrapper pw = getProperty(obs, "code"); - if (valued(pw)) { - render(td.ah(ref), pw.value()); - } - pw = getProperty(obs, "bodySite"); - if (valued(pw)) { - td.tx(" ("); - render(td, pw.value()); - td.tx(")"); - } - - // value / dataAbsentReason (in red) - td = tr.td(); - pw = getProperty(obs, "value[x]"); - if (valued(pw)) { - render(td, pw.value()); - } else { - pw = getProperty(obs, "dataAbsentReason"); - if (valued(pw)) { - XhtmlNode span = td.span("color: maroon", "Error"); - span.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_ERR) + " "); - render(span.b(), pw.value()); - } - } - if (refRange) { - // reference range - td = tr.td(); - pw = getProperty(obs, "referenceRange"); - if (valued(pw)) { - boolean first = true; - for (BaseWrapper v : pw.getValues()) { - if (first) first = false; else td.br(); - PropertyWrapper pwr = getProperty(v, "type"); - if (valued(pwr)) { - render(td, pwr.value()); - td.tx(": "); - } - PropertyWrapper pwt = getProperty(v, "text"); - if (valued(pwt)) { - render(td, pwt.value()); - } else { - PropertyWrapper pwl = getProperty(v, "low"); - PropertyWrapper pwh = getProperty(v, "high"); - if (valued(pwl) && valued(pwh)) { - render(td, pwl.value()); - td.tx(" - "); - render(td, pwh.value()); - } else if (valued(pwl)) { - td.tx(">"); - render(td, pwl.value()); - } else if (valued(pwh)) { - td.tx("<"); - render(td, pwh.value()); - } else { - td.tx("??"); - } - } - pwr = getProperty(v, "appliesTo"); - PropertyWrapper pwrA = getProperty(v, "age"); - if (valued(pwr) || valued(pwrA)) { - boolean firstA = true; - td.tx(" "+ (context.formatPhrase(RenderingContext.DIAG_REP_REND_FOR)) + " "); - if (valued(pwr)) { - for (BaseWrapper va : pwr.getValues()) { - if (firstA) firstA = false; else td.tx(", "); - render(td, va); - } - } - if (valued(pwrA)) { - if (firstA) firstA = false; else td.tx(", "); - td.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_AGE) + " "); - render(td, pwrA.value()); - } - } - } - } - } - if (flags) { - // flags (status other than F, interpretation, ) - td = tr.td(); - boolean first = true; - pw = getProperty(obs, "status"); - if (valued(pw)) { - if (!pw.value().getBase().primitiveValue().equals("final")) { - if (first) first = false; else td.br(); - render(td, pw.value()); - } - } - pw = getProperty(obs, "interpretation"); - if (valued(pw)) { - for (BaseWrapper v : pw.getValues()) { - if (first) first = false; else td.br(); - render(td, v); - } - } - } - - if (note) { - td = tr.td(); - pw = getProperty(obs, "note"); - if (valued(pw)) { - render(td, pw.value()); - } - } - if (effectiveTime) { - // effective if different to DR - td = tr.td(); - pw = getProperty(obs, "effective[x]"); - if (valued(pw)) { - if (!Base.compareDeep(pw.value().getBase(), eff, true)) { - render(td, pw.value()); - } - } - } - if (issued) { - // issued if different to DR - td = tr.td(); - pw = getProperty(obs, "issued"); - if (valued(pw)) { - if (!Base.compareDeep(pw.value().getBase(), eff, true)) { - render(td, pw.value()); - } - } - } - } -} + XhtmlNode tbl = x.table("grid"); + XhtmlNode tr; + if (dr.has("subject")) { + tr = tbl.tr(); + tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_SUB)); + populateSubjectSummary(tr.td(), getProperty(dr, "subject").value()); + } + + DataType eff = null; + DataType iss = null; + + if (dr.has("effective[x]")) { + tr = tbl.tr(); + tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN)); + eff = (DataType) getProperty(dr, "effective[x]").value().getBase(); + render(tr.td(), eff); + } + if (dr.has("issued")) { + tr = tbl.tr(); + tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP)); + eff = (DataType) getProperty(dr, "issued").value().getBase(); + render(tr.td(), getProperty(dr, "issued").value()); + } + + pw = getProperty(dr, "perfomer"); + if (valued(pw)) { + tr = tbl.tr(); + tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_PER)), pw.getValues().size())); + XhtmlNode tdr = tr.td(); + for (BaseWrapper v : pw.getValues()) { + tdr.tx(" "); + render(tdr, v); + } + } + pw = getProperty(dr, "identifier"); + if (valued(pw)) { + tr = tbl.tr(); + tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_IDENTIFIER)), pw.getValues().size())+":"); + XhtmlNode tdr = tr.td(); + for (BaseWrapper v : pw.getValues()) { + tdr.tx(" "); + render(tdr, v); + } + } + pw = getProperty(dr, "request"); + if (valued(pw)) { + tr = tbl.tr(); + tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.DIAG_REP_REND_REQUEST)), pw.getValues().size())+":"); + XhtmlNode tdr = tr.td(); + for (BaseWrapper v : pw.getValues()) { + tdr.tx(" "); + render(tdr, v); + } + tdr.br(); + } + + + x.para().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REPDET)); + + pw = getProperty(dr, "result"); + if (valued(pw)) { + List observations = fetchObservations(pw.getValues(), dr); + buildObservationsTable(x, observations, eff, iss); + } + + pw = getProperty(dr, "conclusion"); + if (valued(pw)) { + if (pw.fhirType().equals("markdown")) { + render(x, pw.value()); + } else { + render(x.para(), pw.value()); + } + } + + pw = getProperty(dr, "conclusionCode"); + if (!valued(pw)) { + pw = getProperty(dr, "codedDiagnosis"); + } + if (valued(pw)) { + XhtmlNode p = x.para(); + p.b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_CODECON)); + XhtmlNode ul = x.ul(); + for (BaseWrapper v : pw.getValues()) { + render(ul.li(), v); + } + } + return false; + } + + public boolean render(XhtmlNode x, DiagnosticReport dr) throws IOException, FHIRException, EOperationOutcome { + render(x, new DirectWrappers.ResourceWrapperDirect(this.context, dr)); + + return true; + } + + public void describe(XhtmlNode x, DiagnosticReport dr) { + x.tx(display(dr)); + } + + public String display(DiagnosticReport dr) { + return display(dr.getCode()); + } + + @Override + public String display(Resource r) throws UnsupportedEncodingException, IOException { + return display((DiagnosticReport) r); + } + + @Override + public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { + return "Not done yet"; + } + + private void populateSubjectSummary(XhtmlNode container, BaseWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException, EOperationOutcome { + ResourceWrapper r = fetchResource(subject); + if (r == null) + container.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_UNABLE)); + else if (r.getName().equals("Patient")) + generatePatientSummary(container, r); + else + container.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTDONE)); + } + + private void generatePatientSummary(XhtmlNode c, ResourceWrapper r) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome { + new PatientRenderer(context).describe(c, r); + } + + private List fetchObservations(List list, ResourceWrapper rw) throws UnsupportedEncodingException, FHIRException, IOException { + List res = new ArrayList(); + for (BaseWrapper b : list) { + if (b.has("reference")) { + ObservationNode obs = new ObservationNode(); + obs.ref = b.get("reference").primitiveValue(); + obs.obs = resolveReference(rw, obs.ref); + if (obs.obs != null && obs.obs.getResource() != null) { + PropertyWrapper t = getProperty(obs.obs.getResource(), "contained"); + if (t != null && t.hasValues()) { + obs.contained = fetchObservations(t.getValues(), rw); + } + } + res.add(obs); + } + } + return res; + } + + private void buildObservationsTable(XhtmlNode root, List observations, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { + XhtmlNode tbl = root.table("grid"); + boolean refRange = scanObsForRefRange(observations); + boolean flags = scanObsForFlags(observations); + boolean note = scanObsForNote(observations); + boolean effectiveTime = scanObsForEffective(observations, eff); + boolean issued = scanObsForIssued(observations, iss); + int cs = 2; + if (refRange) cs++; + if (flags) cs++; + if (note) cs++; + if (issued) cs++; + if (effectiveTime) cs++; + XhtmlNode tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_VALUE)); + if (refRange) { + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REFRAN)); + } + if (flags) { + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_FLAG)); + } + if (note) { + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTE)); + } + if (effectiveTime) { + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN)); + } + if (issued) { + tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP)); + } + for (ObservationNode o : observations) { + addObservationToTable(tbl, o, 0, Integer.toString(cs), refRange, flags, note, effectiveTime, issued, eff, iss); + } + } + + private boolean scanObsForRefRange(List observations) { + for (ObservationNode o : observations) { + if (o.obs != null && o.obs.getResource() != null) { + PropertyWrapper pw = getProperty(o.obs.getResource(), "referenceRange"); + if (valued(pw)) { + return true; + } + } + if (o.contained != null) { + if (scanObsForRefRange(o.contained)) { + return true; + } + } + } + return false; + } + + private boolean scanObsForNote(List observations) { + for (ObservationNode o : observations) { + if (o.obs != null && o.obs.getResource() != null) { + PropertyWrapper pw = getProperty(o.obs.getResource(), "note"); + if (valued(pw)) { + return true; + } + } + if (o.contained != null) { + if (scanObsForNote(o.contained)) { + return true; + } + } + } + return false; + } + + private boolean scanObsForIssued(List observations, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { + for (ObservationNode o : observations) { + if (o.obs != null && o.obs.getResource() != null) { + PropertyWrapper pw = getProperty(o.obs.getResource(), "issued"); + if (valued(pw)) { + if (!Base.compareDeep(pw.value().getBase(), iss, true)) { + return true; + } + } + } + if (o.contained != null) { + if (scanObsForIssued(o.contained, iss)) { + return true; + } + } + } + return false; + } + + private boolean scanObsForEffective(List observations, DataType eff) throws UnsupportedEncodingException, FHIRException, IOException { + for (ObservationNode o : observations) { + if (o.obs != null && o.obs.getResource() != null) { + PropertyWrapper pw = getProperty(o.obs.getResource(), "effective[x]"); + if (valued(pw)) { + if (!Base.compareDeep(pw.value().getBase(), eff, true)) { + return true; + } + } + } + if (o.contained != null) { + if (scanObsForEffective(o.contained, eff)) { + return true; + } + } + } + return false; + } + + private boolean scanObsForFlags(List observations) throws UnsupportedEncodingException, FHIRException, IOException { + for (ObservationNode o : observations) { + if (o.obs != null && o.obs.getResource() != null) { + PropertyWrapper pw = getProperty(o.obs.getResource(), "interpretation"); + if (valued(pw)) { + return true; + } + pw = getProperty(o.obs.getResource(), "status"); + if (valued(pw)) { + if (!pw.value().getBase().primitiveValue().equals("final")) { + return true; + } + } + + } + if (o.contained != null) { + if (scanObsForFlags(o.contained)) { + return true; + } + } + } + return false; + } + + private void addObservationToTable(XhtmlNode tbl, ObservationNode o, int i, String cs, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { + XhtmlNode tr = tbl.tr(); + if (o.obs != null && o.obs.getReference() == null) { + XhtmlNode td = tr.td().colspan(cs); + td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTRES)); + } else { + if (o.obs != null && o.obs.getResource() != null) { + addObservationToTable(tr, o.obs.getResource(), i, o.obs.getReference(), refRange, flags, note, effectiveTime, issued, eff, iss); + } else { + XhtmlNode td = tr.td().colspan(cs); + td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_OBS)); + } + if (o.contained != null) { + for (ObservationNode c : o.contained) { + addObservationToTable(tbl, c, i+1, cs, refRange, flags, note, effectiveTime, issued, eff, iss); + } + } + } + } + + private void addObservationToTable(XhtmlNode tr, ResourceWrapper obs, int i, String ref, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, DataType eff, DataType iss) throws UnsupportedEncodingException, FHIRException, IOException { + + // code (+bodysite) + XhtmlNode td = tr.td(); + PropertyWrapper pw = getProperty(obs, "code"); + if (valued(pw)) { + render(td.ah(ref), pw.value()); + } + pw = getProperty(obs, "bodySite"); + if (valued(pw)) { + td.tx(" ("); + render(td, pw.value()); + td.tx(")"); + } + + // value / dataAbsentReason (in red) + td = tr.td(); + pw = getProperty(obs, "value[x]"); + if (valued(pw)) { + render(td, pw.value()); + } else { + pw = getProperty(obs, "dataAbsentReason"); + if (valued(pw)) { + XhtmlNode span = td.span("color: maroon", "Error"); + span.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_ERR) + " "); + render(span.b(), pw.value()); + } + } + if (refRange) { + // reference range + td = tr.td(); + pw = getProperty(obs, "referenceRange"); + if (valued(pw)) { + boolean first = true; + for (BaseWrapper v : pw.getValues()) { + if (first) first = false; else td.br(); + PropertyWrapper pwr = getProperty(v, "type"); + if (valued(pwr)) { + render(td, pwr.value()); + td.tx(": "); + } + PropertyWrapper pwt = getProperty(v, "text"); + if (valued(pwt)) { + render(td, pwt.value()); + } else { + PropertyWrapper pwl = getProperty(v, "low"); + PropertyWrapper pwh = getProperty(v, "high"); + if (valued(pwl) && valued(pwh)) { + render(td, pwl.value()); + td.tx(" - "); + render(td, pwh.value()); + } else if (valued(pwl)) { + td.tx(">"); + render(td, pwl.value()); + } else if (valued(pwh)) { + td.tx("<"); + render(td, pwh.value()); + } else { + td.tx("??"); + } + } + pwr = getProperty(v, "appliesTo"); + PropertyWrapper pwrA = getProperty(v, "age"); + if (valued(pwr) || valued(pwrA)) { + boolean firstA = true; + td.tx(" "+ (context.formatPhrase(RenderingContext.DIAG_REP_REND_FOR)) + " "); + if (valued(pwr)) { + for (BaseWrapper va : pwr.getValues()) { + if (firstA) firstA = false; else td.tx(", "); + render(td, va); + } + } + if (valued(pwrA)) { + if (firstA) firstA = false; else td.tx(", "); + td.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_AGE) + " "); + render(td, pwrA.value()); + } + } + } + } + } + if (flags) { + // flags (status other than F, interpretation, ) + td = tr.td(); + boolean first = true; + pw = getProperty(obs, "status"); + if (valued(pw)) { + if (!pw.value().getBase().primitiveValue().equals("final")) { + if (first) first = false; else td.br(); + render(td, pw.value()); + } + } + pw = getProperty(obs, "interpretation"); + if (valued(pw)) { + for (BaseWrapper v : pw.getValues()) { + if (first) first = false; else td.br(); + render(td, v); + } + } + } + + if (note) { + td = tr.td(); + pw = getProperty(obs, "note"); + if (valued(pw)) { + render(td, pw.value()); + } + } + if (effectiveTime) { + // effective if different to DR + td = tr.td(); + pw = getProperty(obs, "effective[x]"); + if (valued(pw)) { + if (!Base.compareDeep(pw.value().getBase(), eff, true)) { + render(td, pw.value()); + } + } + } + if (issued) { + // issued if different to DR + td = tr.td(); + pw = getProperty(obs, "issued"); + if (valued(pw)) { + if (!Base.compareDeep(pw.value().getBase(), eff, true)) { + render(td, pw.value()); + } + } + } + } +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ListRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ListRenderer.java index 272babc68..998454b5f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ListRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ListRenderer.java @@ -1,253 +1,253 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.model.Annotation; -import org.hl7.fhir.r5.model.Base; -import org.hl7.fhir.r5.model.ListResource; -import org.hl7.fhir.r5.model.ListResource.ListResourceEntryComponent; -import org.hl7.fhir.r5.model.Reference; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; - -public class ListRenderer extends ResourceRenderer { - - public ListRenderer(RenderingContext context) { - super(context); - } - - public ListRenderer(RenderingContext context, ResourceContext rcontext) { - super(context, rcontext); - } - - public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { - return render(x, (ListResource) dr); - } - - public boolean render(XhtmlNode x, ResourceWrapper list) throws FHIRFormatError, DefinitionException, IOException { - if (list.has("title")) { - x.h2().tx(list.get("title").primitiveValue()); - } - XhtmlNode t = x.table("clstu"); - XhtmlNode tr = t.tr(); - XhtmlNode td = tr.td(); - if (list.has("date")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_DATE, displayDateTime(list.get("date").dateTimeValue()))+" "); +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.model.Annotation; +import org.hl7.fhir.r5.model.Base; +import org.hl7.fhir.r5.model.ListResource; +import org.hl7.fhir.r5.model.ListResource.ListResourceEntryComponent; +import org.hl7.fhir.r5.model.Reference; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +public class ListRenderer extends ResourceRenderer { + + public ListRenderer(RenderingContext context) { + super(context); + } + + public ListRenderer(RenderingContext context, ResourceContext rcontext) { + super(context, rcontext); + } + + public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { + return render(x, (ListResource) dr); + } + + public boolean render(XhtmlNode x, ResourceWrapper list) throws FHIRFormatError, DefinitionException, IOException { + if (list.has("title")) { + x.h2().tx(list.get("title").primitiveValue()); } - if (list.has("mode")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_MODE, list.get("mode").primitiveValue())+" "); - } - if (list.has("status")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_STAT, list.get("status").primitiveValue())+" "); - } - if (list.has("code")) { - td.tx(context.formatPhrase(RenderingContext.GENERAL_CODE, displayBase(list.get("code")))+" "); - } - tr = t.tr(); - td = tr.td(); - if (list.has("subject")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_SUB)+" "); - shortForRef(td, list.get("subject")); - } - if (list.has("encounter")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_ENC)+" "); - shortForRef(td, list.get("encounter")); - } - if (list.has("source")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_SRC)+" "); - shortForRef(td, list.get("encounter")); - } - if (list.has("orderedBy")) { - td.tx(context.formatPhrase(RenderingContext.LIST_REND_ORD, displayBase(list.get("orderedBy")))+" "); - } - // for (Annotation a : list.getNote()) { - // renderAnnotation(a, x); - // } - boolean flag = false; - boolean deleted = false; - boolean date = false; - for (BaseWrapper e : list.children("entry")) { - flag = flag || e.has("flag"); - deleted = deleted || e.has("deleted"); - date = date || e.has("date"); - } - t = x.table("grid"); - tr = t.tr().style("backgound-color: #eeeeee"); - tr.td().b().tx(context.formatPhrase(RenderingContext.LIST_REND_ITEM)); - if (date) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DAT)); - } - if (flag) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_FLAG)); - } - if (deleted) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DEL)); - } - for (BaseWrapper e : list.children("entry")) { - tr = t.tr(); - shortForRef(tr.td(), e.get("item")); - if (date) { - tr.td().tx(e.has("date") ? e.get("date").dateTimeValue().toHumanDisplay() : ""); - } - if (flag) { - tr.td().tx(e.has("flag") ? displayBase(e.get("flag")) : ""); - } - if (deleted) { - tr.td().tx(e.has("deleted") ? e.get("deleted").primitiveValue() : ""); - } - } - return false; - } - public boolean render(XhtmlNode x, ListResource list) throws FHIRFormatError, DefinitionException, IOException { - if (list.hasTitle()) { - x.h2().tx(list.getTitle()); - } - XhtmlNode t = x.table("clstu"); - XhtmlNode tr = t.tr(); - if (list.hasDate()) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DATE, displayDateTime(list.getDateElement()))+" "); - } - if (list.hasMode()) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_MODE, list.getMode().getDisplay())+" "); - } - if (list.hasStatus()) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_STAT, list.getStatus().getDisplay())+" "); - } - if (list.hasCode()) { - tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_CODE, display(list.getCode()))+" "); - } - tr = t.tr(); - if (list.hasSubject()) { - if (list.getSubject().size() == 1) { - shortForRef(tr.td().txN("Subject: "), list.getSubjectFirstRep()); - } else { - XhtmlNode td = tr.td(); - td.txN(context.formatPhrase(RenderingContext.LIST_REND_SUB)+" "); - int i = 0; - for (Reference subj : list.getSubject()) { - if (i == list.getSubject().size() - 1) { - td.tx(" and "); - } else if (i > 0) { - td.tx(", "); - } - shortForRef(td, subj); - } - } - } - if (list.hasEncounter()) { - shortForRef(tr.td().txN(context.formatPhrase(RenderingContext.LIST_REND_ENC)+" "), list.getEncounter()); - } - if (list.hasSource()) { - shortForRef(tr.td().txN(context.formatPhrase(RenderingContext.LIST_REND_SRC)+" "), list.getEncounter()); - } - if (list.hasOrderedBy()) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_ORD, display(list.getOrderedBy()))+" "); - } - for (Annotation a : list.getNote()) { - renderAnnotation(x, a); - } - boolean flag = false; - boolean deleted = false; - boolean date = false; - for (ListResourceEntryComponent e : list.getEntry()) { - flag = flag || e.hasFlag(); - deleted = deleted || e.hasDeleted(); - date = date || e.hasDate(); - } - t = x.table("grid"); - tr = t.tr().style("backgound-color: #eeeeee"); - tr.td().b().tx(context.formatPhrase(RenderingContext.LIST_REND_ITEM)); - if (date) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DAT)); - } - if (flag) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_FLAG)); - } - if (deleted) { - tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DEL)); - } - for (ListResourceEntryComponent e : list.getEntry()) { - tr = t.tr(); - shortForRef(tr.td(), e.getItem()); - if (date) { - tr.td().tx(e.hasDate() ? e.getDate().toLocaleString() : ""); - } - if (flag) { - tr.td().tx(e.hasFlag() ? display(e.getFlag()) : ""); - } - if (deleted) { - tr.td().tx(e.hasDeleted() ? Boolean.toString(e.getDeleted()) : ""); - } - } - return false; - } - - public void describe(XhtmlNode x, ListResource list) { - x.tx(display(list)); - } - - public String display(ListResource list) { - return list.getTitle(); - } - - @Override - public String display(Resource r) throws UnsupportedEncodingException, IOException { - return ((ListResource) r).getTitle(); - } - - @Override - public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { - if (r.has("title")) { - return r.children("title").get(0).getBase().primitiveValue(); - } - return "??"; - } - - private void shortForRef(XhtmlNode x, Reference ref) throws UnsupportedEncodingException, IOException { - ResourceWithReference r = context.getResolver() == null ? null : context.getResolver().resolve(context, ref.getReference()); - if (r == null) { - x.tx(display(ref)); - } else { - RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, ref); - } - } - - private XhtmlNode shortForRef(XhtmlNode x, Base ref) throws UnsupportedEncodingException, IOException { - if (ref == null) { - x.tx("(null)"); - } else { - String disp = ref.getChildByName("display") != null && ref.getChildByName("display").hasValues() ? ref.getChildByName("display").getValues().get(0).primitiveValue() : null; - if (ref.getChildByName("reference").hasValues()) { - String url = ref.getChildByName("reference").getValues().get(0).primitiveValue(); - if (url.startsWith("#")) { - x.tx("?ngen-16a?"); - } else { - ResourceWithReference r = context.getResolver().resolve(context, url); - if (r == null) { - if (disp == null) { - disp = url; - } - x.tx(disp); - } else if (r.getResource() != null) { - RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, (Reference) ref); - } else { - x.ah(r.getReference()).tx(url); - } - } - } else if (disp != null) { - x.tx(disp); - } else { - x.tx("?ngen-16?"); - } - } - return x; - } -} + XhtmlNode t = x.table("clstu"); + XhtmlNode tr = t.tr(); + XhtmlNode td = tr.td(); + if (list.has("date")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_DATE, displayDateTime(list.get("date").dateTimeValue()))+" "); + } + if (list.has("mode")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_MODE, list.get("mode").primitiveValue())+" "); + } + if (list.has("status")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_STAT, list.get("status").primitiveValue())+" "); + } + if (list.has("code")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_CODE, displayBase(list.get("code")))+" "); + } + tr = t.tr(); + td = tr.td(); + if (list.has("subject")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_SUB)+" "); + shortForRef(td, list.get("subject")); + } + if (list.has("encounter")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_ENC)+" "); + shortForRef(td, list.get("encounter")); + } + if (list.has("source")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_SRC)+" "); + shortForRef(td, list.get("encounter")); + } + if (list.has("orderedBy")) { + td.tx(context.formatPhrase(RenderingContext.LIST_REND_ORD, displayBase(list.get("orderedBy")))+" "); + } + // for (Annotation a : list.getNote()) { + // renderAnnotation(a, x); + // } + boolean flag = false; + boolean deleted = false; + boolean date = false; + for (BaseWrapper e : list.children("entry")) { + flag = flag || e.has("flag"); + deleted = deleted || e.has("deleted"); + date = date || e.has("date"); + } + t = x.table("grid"); + tr = t.tr().style("backgound-color: #eeeeee"); + tr.td().b().tx(context.formatPhrase(RenderingContext.LIST_REND_ITEM)); + if (date) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DAT)); + } + if (flag) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_FLAG)); + } + if (deleted) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DEL)); + } + for (BaseWrapper e : list.children("entry")) { + tr = t.tr(); + shortForRef(tr.td(), e.get("item")); + if (date) { + tr.td().tx(e.has("date") ? e.get("date").dateTimeValue().toHumanDisplay() : ""); + } + if (flag) { + tr.td().tx(e.has("flag") ? displayBase(e.get("flag")) : ""); + } + if (deleted) { + tr.td().tx(e.has("deleted") ? e.get("deleted").primitiveValue() : ""); + } + } + return false; + } + public boolean render(XhtmlNode x, ListResource list) throws FHIRFormatError, DefinitionException, IOException { + if (list.hasTitle()) { + x.h2().tx(list.getTitle()); + } + XhtmlNode t = x.table("clstu"); + XhtmlNode tr = t.tr(); + if (list.hasDate()) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DATE, displayDateTime(list.getDateElement()))+" "); + } + if (list.hasMode()) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_MODE, list.getMode().getDisplay())+" "); + } + if (list.hasStatus()) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_STAT, list.getStatus().getDisplay())+" "); + } + if (list.hasCode()) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_CODE, display(list.getCode()))+" "); + } + tr = t.tr(); + if (list.hasSubject()) { + if (list.getSubject().size() == 1) { + shortForRef(tr.td().txN("Subject: "), list.getSubjectFirstRep()); + } else { + XhtmlNode td = tr.td(); + td.txN(context.formatPhrase(RenderingContext.LIST_REND_SUB)+" "); + int i = 0; + for (Reference subj : list.getSubject()) { + if (i == list.getSubject().size() - 1) { + td.tx(" and "); + } else if (i > 0) { + td.tx(", "); + } + shortForRef(td, subj); + } + } + } + if (list.hasEncounter()) { + shortForRef(tr.td().txN(context.formatPhrase(RenderingContext.LIST_REND_ENC)+" "), list.getEncounter()); + } + if (list.hasSource()) { + shortForRef(tr.td().txN(context.formatPhrase(RenderingContext.LIST_REND_SRC)+" "), list.getEncounter()); + } + if (list.hasOrderedBy()) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_ORD, display(list.getOrderedBy()))+" "); + } + for (Annotation a : list.getNote()) { + renderAnnotation(x, a); + } + boolean flag = false; + boolean deleted = false; + boolean date = false; + for (ListResourceEntryComponent e : list.getEntry()) { + flag = flag || e.hasFlag(); + deleted = deleted || e.hasDeleted(); + date = date || e.hasDate(); + } + t = x.table("grid"); + tr = t.tr().style("backgound-color: #eeeeee"); + tr.td().b().tx(context.formatPhrase(RenderingContext.LIST_REND_ITEM)); + if (date) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DAT)); + } + if (flag) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_FLAG)); + } + if (deleted) { + tr.td().tx(context.formatPhrase(RenderingContext.LIST_REND_DEL)); + } + for (ListResourceEntryComponent e : list.getEntry()) { + tr = t.tr(); + shortForRef(tr.td(), e.getItem()); + if (date) { + tr.td().tx(e.hasDate() ? e.getDate().toLocaleString() : ""); + } + if (flag) { + tr.td().tx(e.hasFlag() ? display(e.getFlag()) : ""); + } + if (deleted) { + tr.td().tx(e.hasDeleted() ? Boolean.toString(e.getDeleted()) : ""); + } + } + return false; + } + + public void describe(XhtmlNode x, ListResource list) { + x.tx(display(list)); + } + + public String display(ListResource list) { + return list.getTitle(); + } + + @Override + public String display(Resource r) throws UnsupportedEncodingException, IOException { + return ((ListResource) r).getTitle(); + } + + @Override + public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { + if (r.has("title")) { + return r.children("title").get(0).getBase().primitiveValue(); + } + return "??"; + } + + private void shortForRef(XhtmlNode x, Reference ref) throws UnsupportedEncodingException, IOException { + ResourceWithReference r = context.getResolver() == null ? null : context.getResolver().resolve(context, ref.getReference()); + if (r == null) { + x.tx(display(ref)); + } else { + RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, ref); + } + } + + private XhtmlNode shortForRef(XhtmlNode x, Base ref) throws UnsupportedEncodingException, IOException { + if (ref == null) { + x.tx("(null)"); + } else { + String disp = ref.getChildByName("display") != null && ref.getChildByName("display").hasValues() ? ref.getChildByName("display").getValues().get(0).primitiveValue() : null; + if (ref.getChildByName("reference").hasValues()) { + String url = ref.getChildByName("reference").getValues().get(0).primitiveValue(); + if (url.startsWith("#")) { + x.tx("?ngen-16a?"); + } else { + ResourceWithReference r = context.getResolver().resolve(context, url); + if (r == null) { + if (disp == null) { + disp = url; + } + x.tx(disp); + } else if (r.getResource() != null) { + RendererFactory.factory(r.getResource().getName(), context).renderReference(r.getResource(), x, (Reference) ref); + } else { + x.ah(r.getReference()).tx(url); + } + } + } else if (disp != null) { + x.tx(disp); + } else { + x.tx("?ngen-16?"); + } + } + return x; + } +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java index 1f25f277f..b5d55413e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java @@ -1,189 +1,189 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.Enumeration; -import org.hl7.fhir.r5.model.Enumerations.FHIRTypes; -import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll; -import org.hl7.fhir.r5.model.Extension; -import org.hl7.fhir.r5.model.OperationDefinition; -import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent; -import org.hl7.fhir.r5.model.OperationDefinition.OperationParameterScope; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; -import org.hl7.fhir.r5.utils.EOperationOutcome; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.StandardsStatus; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; - -public class OperationDefinitionRenderer extends TerminologyRenderer { - - public OperationDefinitionRenderer(RenderingContext context) { - super(context); - } - - public OperationDefinitionRenderer(RenderingContext context, ResourceContext rcontext) { - super(context, rcontext); - } - - public boolean render(XhtmlNode x, Resource dr) throws IOException, FHIRException, EOperationOutcome { - return render(x, (OperationDefinition) dr); - } - - public boolean render(XhtmlNode x, OperationDefinition opd) throws IOException, FHIRException, EOperationOutcome { - if (context.isHeader()) { - x.h2().addText(opd.getName()); - x.para().addText(Utilities.capitalize(opd.getKind().toString())+": "+opd.getName()); - x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_OFFIC)+" "); - x.pre().tx(opd.getUrl()); - addMarkdown(x, opd.getDescription());} - - if (opd.getSystem()) - x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URLS, opd.getCode())); - for (Enumeration c : opd.getResource()) { - if (opd.getType()) - x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/$"+opd.getCode())); - if (opd.getInstance()) - x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]/$"+opd.getCode())); - } - - if (opd.hasInputProfile()) { - XhtmlNode p = x.para(); - p.tx(context.formatPhrase(RenderingContext.OP_DEF_INPAR)); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile(), opd); - if (sd == null) { - p.pre().tx(opd.getInputProfile()); - } else { - p.ah(sd.getWebPath()).tx(sd.present()); - } - } - if (opd.hasOutputProfile()) { - XhtmlNode p = x.para(); - p.tx(context.formatPhrase(RenderingContext.OP_DEF_OUTPAR)); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile(), opd); - if (sd == null) { - p.pre().tx(opd.getOutputProfile()); - } else { - p.ah(sd.getWebPath()).tx(sd.present()); - } - } - x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_PAR)); - XhtmlNode tbl = x.table( "grid"); - XhtmlNode tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_USE)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_NAME)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_SCO)); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CARDINALITY)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_TYPE)); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_BINDING)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_DOC)); - for (OperationDefinitionParameterComponent p : opd.getParameter()) { - genOpParam(tbl, "", p, opd); - } - addMarkdown(x, opd.getComment()); - return true; - } - - public void describe(XhtmlNode x, OperationDefinition opd) { - x.tx(display(opd)); - } - - public String display(OperationDefinition opd) { - return opd.present(); - } - - @Override - public String display(Resource r) throws UnsupportedEncodingException, IOException { - return ((OperationDefinition) r).present(); - } - - private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p, Resource opd) throws EOperationOutcome, FHIRException, IOException { - XhtmlNode tr; - tr = tbl.tr(); - tr.td().addText(p.getUse().toString()); - XhtmlNode td = tr.td(); - td.addText(path+p.getName()); - StandardsStatus ss = ToolingExtensions.getStandardsStatus(p); - genStandardsStatus(td, ss); - td = tr.td(); - if (p.hasScope()) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (Enumeration s : p.getScope()) { - b.append(s.getCode()); - } - td.tx(b.toString()); - } - tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax()); - td = tr.td(); - String actualType = translateTypeToVersion(p.getTypeElement()); - StructureDefinition sd = actualType != null ? context.getWorker().fetchTypeDefinition(actualType) : null; - if (sd == null) - td.tx(p.hasType() ? actualType : ""); - else if (sd.getAbstract() && p.hasExtension(ToolingExtensions.EXT_ALLOWED_TYPE)) { - boolean first = true; - for (Extension ex : p.getExtensionsByUrl(ToolingExtensions.EXT_ALLOWED_TYPE)) { - if (first) first = false; else td.tx(" | "); - String s = ex.getValue().primitiveValue(); - StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s); - if (sdt == null) - td.tx(p.hasType() ? actualType : ""); - else - td.ah(sdt.getWebPath()).tx(s); - } - } else - td.ah(sd.getWebPath()).tx(actualType); - if (p.hasTargetProfile()) { - td.tx(" ("); - boolean first = true; - for (CanonicalType tp : p.getTargetProfile()) { - if (first) { first = false;} else {td.tx(", ");}; - StructureDefinition sdt = context.getWorker().fetchTypeDefinition(tp.asStringValue()); - if (sdt == null || !sdt.hasWebPath()) { - td.code().tx(tp.asStringValue()); - } else { - td.ah(sdt.getWebPath(), tp.asStringValue()).tx(sdt.present()); - } - } - td.tx(")"); - } - if (p.hasSearchType()) { - td.br(); - td.tx("("); - td.ah( context.getLink(KnownLinkType.SPEC) == null ? "search.html#"+p.getSearchType().toCode() : Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "search.html#"+p.getSearchType().toCode())).tx(p.getSearchType().toCode()); - td.tx(")"); - } - td = tr.td(); - if (p.hasBinding() && p.getBinding().hasValueSet()) { - AddVsRef(p.getBinding().getValueSet(), td, opd); - td.tx(" ("+p.getBinding().getStrength().getDisplay()+")"); - } - addMarkdown(tr.td(), p.getDocumentation()); - if (!p.hasType()) { - for (OperationDefinitionParameterComponent pp : p.getPart()) { - genOpParam(tbl, path+p.getName()+".", pp, opd); - } - } - } - - public static final String EXT_OPDEF_ORIGINAL_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-OperationDefinition.parameter.type"; - - private String translateTypeToVersion(Enumeration src) { - if (src.hasExtension(EXT_OPDEF_ORIGINAL_TYPE)) { - return src.getExtensionString(EXT_OPDEF_ORIGINAL_TYPE); - } else { - return src.asStringValue(); - } - } - - -} +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.Enumeration; +import org.hl7.fhir.r5.model.Enumerations.FHIRTypes; +import org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.OperationDefinition; +import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent; +import org.hl7.fhir.r5.model.OperationDefinition.OperationParameterScope; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; +import org.hl7.fhir.r5.utils.EOperationOutcome; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.StandardsStatus; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +public class OperationDefinitionRenderer extends TerminologyRenderer { + + public OperationDefinitionRenderer(RenderingContext context) { + super(context); + } + + public OperationDefinitionRenderer(RenderingContext context, ResourceContext rcontext) { + super(context, rcontext); + } + + public boolean render(XhtmlNode x, Resource dr) throws IOException, FHIRException, EOperationOutcome { + return render(x, (OperationDefinition) dr); + } + + public boolean render(XhtmlNode x, OperationDefinition opd) throws IOException, FHIRException, EOperationOutcome { + if (context.isHeader()) { + x.h2().addText(opd.getName()); + x.para().addText(Utilities.capitalize(opd.getKind().toString())+": "+opd.getName()); + x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_OFFIC)+" "); + x.pre().tx(opd.getUrl()); + addMarkdown(x, opd.getDescription());} + + if (opd.getSystem()) + x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URLS, opd.getCode())); + for (Enumeration c : opd.getResource()) { + if (opd.getType()) + x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/$"+opd.getCode())); + if (opd.getInstance()) + x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_URL, c.getCode()+"/[id]/$"+opd.getCode())); + } + + if (opd.hasInputProfile()) { + XhtmlNode p = x.para(); + p.tx(context.formatPhrase(RenderingContext.OP_DEF_INPAR)); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile(), opd); + if (sd == null) { + p.pre().tx(opd.getInputProfile()); + } else { + p.ah(sd.getWebPath()).tx(sd.present()); + } + } + if (opd.hasOutputProfile()) { + XhtmlNode p = x.para(); + p.tx(context.formatPhrase(RenderingContext.OP_DEF_OUTPAR)); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile(), opd); + if (sd == null) { + p.pre().tx(opd.getOutputProfile()); + } else { + p.ah(sd.getWebPath()).tx(sd.present()); + } + } + x.para().tx(context.formatPhrase(RenderingContext.OP_DEF_PAR)); + XhtmlNode tbl = x.table( "grid"); + XhtmlNode tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_USE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_NAME)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_SCO)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_CARD)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_TYPE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_BIND)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_DEF_DOC)); + for (OperationDefinitionParameterComponent p : opd.getParameter()) { + genOpParam(tbl, "", p, opd); + } + addMarkdown(x, opd.getComment()); + return true; + } + + public void describe(XhtmlNode x, OperationDefinition opd) { + x.tx(display(opd)); + } + + public String display(OperationDefinition opd) { + return opd.present(); + } + + @Override + public String display(Resource r) throws UnsupportedEncodingException, IOException { + return ((OperationDefinition) r).present(); + } + + private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p, Resource opd) throws EOperationOutcome, FHIRException, IOException { + XhtmlNode tr; + tr = tbl.tr(); + tr.td().addText(p.getUse().toString()); + XhtmlNode td = tr.td(); + td.addText(path+p.getName()); + StandardsStatus ss = ToolingExtensions.getStandardsStatus(p); + genStandardsStatus(td, ss); + td = tr.td(); + if (p.hasScope()) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (Enumeration s : p.getScope()) { + b.append(s.getCode()); + } + td.tx(b.toString()); + } + tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax()); + td = tr.td(); + String actualType = translateTypeToVersion(p.getTypeElement()); + StructureDefinition sd = actualType != null ? context.getWorker().fetchTypeDefinition(actualType) : null; + if (sd == null) + td.tx(p.hasType() ? actualType : ""); + else if (sd.getAbstract() && p.hasExtension(ToolingExtensions.EXT_ALLOWED_TYPE)) { + boolean first = true; + for (Extension ex : p.getExtensionsByUrl(ToolingExtensions.EXT_ALLOWED_TYPE)) { + if (first) first = false; else td.tx(" | "); + String s = ex.getValue().primitiveValue(); + StructureDefinition sdt = context.getWorker().fetchTypeDefinition(s); + if (sdt == null) + td.tx(p.hasType() ? actualType : ""); + else + td.ah(sdt.getWebPath()).tx(s); + } + } else + td.ah(sd.getWebPath()).tx(actualType); + if (p.hasTargetProfile()) { + td.tx(" ("); + boolean first = true; + for (CanonicalType tp : p.getTargetProfile()) { + if (first) { first = false;} else {td.tx(", ");}; + StructureDefinition sdt = context.getWorker().fetchTypeDefinition(tp.asStringValue()); + if (sdt == null || !sdt.hasWebPath()) { + td.code().tx(tp.asStringValue()); + } else { + td.ah(sdt.getWebPath(), tp.asStringValue()).tx(sdt.present()); + } + } + td.tx(")"); + } + if (p.hasSearchType()) { + td.br(); + td.tx("("); + td.ah( context.getLink(KnownLinkType.SPEC) == null ? "search.html#"+p.getSearchType().toCode() : Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "search.html#"+p.getSearchType().toCode())).tx(p.getSearchType().toCode()); + td.tx(")"); + } + td = tr.td(); + if (p.hasBinding() && p.getBinding().hasValueSet()) { + AddVsRef(p.getBinding().getValueSet(), td, opd); + td.tx(" ("+p.getBinding().getStrength().getDisplay()+")"); + } + addMarkdown(tr.td(), p.getDocumentation()); + if (!p.hasType()) { + for (OperationDefinitionParameterComponent pp : p.getPart()) { + genOpParam(tbl, path+p.getName()+".", pp, opd); + } + } + } + + public static final String EXT_OPDEF_ORIGINAL_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-OperationDefinition.parameter.type"; + + private String translateTypeToVersion(Enumeration src) { + if (src.hasExtension(EXT_OPDEF_ORIGINAL_TYPE)) { + return src.getExtensionString(EXT_OPDEF_ORIGINAL_TYPE); + } else { + return src.asStringValue(); + } + } + + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationOutcomeRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationOutcomeRenderer.java index 25d125e15..5ddf14bdd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationOutcomeRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationOutcomeRenderer.java @@ -1,105 +1,105 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.model.Extension; -import org.hl7.fhir.r5.model.ExtensionHelper; -import org.hl7.fhir.r5.model.OperationOutcome; -import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity; -import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.StringType; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; - -public class OperationOutcomeRenderer extends ResourceRenderer { - - public OperationOutcomeRenderer(RenderingContext context) { - super(context); - } - - public OperationOutcomeRenderer(RenderingContext context, ResourceContext rcontext) { - super(context, rcontext); - } - - public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { - return render(x, (OperationOutcome) dr); - } - - public boolean render(XhtmlNode x, OperationOutcome op) throws FHIRFormatError, DefinitionException, IOException { - boolean hasSource = false; - boolean success = true; - for (OperationOutcomeIssueComponent i : op.getIssue()) { - success = success && i.getSeverity() == IssueSeverity.INFORMATION; - hasSource = hasSource || ExtensionHelper.hasExtension(i, ToolingExtensions.EXT_ISSUE_SOURCE); - } - if (success) - x.para().tx(context.formatPhrase(RenderingContext.OP_OUT_OK)); - if (op.getIssue().size() > 0) { - XhtmlNode tbl = x.table("grid"); // on the basis that we'll most likely be rendered using the standard fhir css, but it doesn't really matter - XhtmlNode tr = tbl.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_SEV)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_LOC)); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_DET)); - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_DIAG)); - if (hasSource) - tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_SRC)); - for (OperationOutcomeIssueComponent i : op.getIssue()) { - tr = tbl.tr(); - tr.td().addText(i.getSeverity().toString()); - XhtmlNode td = tr.td(); - boolean d = false; - for (StringType s : i.hasExpression() ? i.getExpression() : i.getLocation()) { - if (d) - td.tx(", "); - else - d = true; - td.addText(s.getValue()); - } - tr.td().addText(i.getCode().getDisplay()); - tr.td().addText(display(i.getDetails())); - smartAddText(tr.td(), i.getDiagnostics()); - if (hasSource) { - Extension ext = ExtensionHelper.getExtension(i, ToolingExtensions.EXT_ISSUE_SOURCE); - tr.td().addText(ext == null ? "" : display(ext)); - } - } - } - return true; - - } - - public void describe(XhtmlNode x, OperationOutcome oo) { - x.tx(display(oo)); - } - - public String display(OperationOutcome oo) { - return (context.formatPhrase(RenderingContext.OP_OUT_TODO)); - } - - @Override - public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { - return (context.formatPhrase(RenderingContext.OP_OUT_NOT)); - } - - @Override - public String display(Resource r) throws UnsupportedEncodingException, IOException { - return display((OperationOutcome) r); - } - - public static String toString(OperationOutcome oo) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (OperationOutcomeIssueComponent issue : oo.getIssue()) { - b.append(issue.getSeverity().toCode()+": "+issue.getDetails().getText()); - } - return b.toString(); - } -} +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.ExtensionHelper; +import org.hl7.fhir.r5.model.OperationOutcome; +import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity; +import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +public class OperationOutcomeRenderer extends ResourceRenderer { + + public OperationOutcomeRenderer(RenderingContext context) { + super(context); + } + + public OperationOutcomeRenderer(RenderingContext context, ResourceContext rcontext) { + super(context, rcontext); + } + + public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { + return render(x, (OperationOutcome) dr); + } + + public boolean render(XhtmlNode x, OperationOutcome op) throws FHIRFormatError, DefinitionException, IOException { + boolean hasSource = false; + boolean success = true; + for (OperationOutcomeIssueComponent i : op.getIssue()) { + success = success && i.getSeverity() == IssueSeverity.INFORMATION; + hasSource = hasSource || ExtensionHelper.hasExtension(i, ToolingExtensions.EXT_ISSUE_SOURCE); + } + if (success) + x.para().tx(context.formatPhrase(RenderingContext.OP_OUT_OK)); + if (op.getIssue().size() > 0) { + XhtmlNode tbl = x.table("grid"); // on the basis that we'll most likely be rendered using the standard fhir css, but it doesn't really matter + XhtmlNode tr = tbl.tr(); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_SEV)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_LOC)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_DET)); + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_DIAG)); + if (hasSource) + tr.td().b().tx(context.formatPhrase(RenderingContext.OP_OUT_SRC)); + for (OperationOutcomeIssueComponent i : op.getIssue()) { + tr = tbl.tr(); + tr.td().addText(i.getSeverity().toString()); + XhtmlNode td = tr.td(); + boolean d = false; + for (StringType s : i.hasExpression() ? i.getExpression() : i.getLocation()) { + if (d) + td.tx(", "); + else + d = true; + td.addText(s.getValue()); + } + tr.td().addText(i.getCode().getDisplay()); + tr.td().addText(display(i.getDetails())); + smartAddText(tr.td(), i.getDiagnostics()); + if (hasSource) { + Extension ext = ExtensionHelper.getExtension(i, ToolingExtensions.EXT_ISSUE_SOURCE); + tr.td().addText(ext == null ? "" : display(ext)); + } + } + } + return true; + + } + + public void describe(XhtmlNode x, OperationOutcome oo) { + x.tx(display(oo)); + } + + public String display(OperationOutcome oo) { + return (context.formatPhrase(RenderingContext.OP_OUT_TODO)); + } + + @Override + public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { + return (context.formatPhrase(RenderingContext.OP_OUT_NOT)); + } + + @Override + public String display(Resource r) throws UnsupportedEncodingException, IOException { + return display((OperationOutcome) r); + } + + public static String toString(OperationOutcome oo) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (OperationOutcomeIssueComponent issue : oo.getIssue()) { + b.append(issue.getSeverity().toCode()+": "+issue.getDetails().getText()); + } + return b.toString(); + } +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java index d9b37e5a2..f0099f407 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java @@ -1,1160 +1,1160 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; - -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.context.ContextUtilities; -import org.hl7.fhir.r5.model.CanonicalResource; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.CodeableConcept; -import org.hl7.fhir.r5.model.Coding; -import org.hl7.fhir.r5.model.Expression; -import org.hl7.fhir.r5.model.Extension; -import org.hl7.fhir.r5.model.Questionnaire; -import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemAnswerOptionComponent; -import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent; -import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemEnableWhenComponent; -import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemInitialComponent; -import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemType; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; -import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; -import org.hl7.fhir.utilities.xhtml.NodeType; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; - -import javax.annotation.Nonnull; - -public class QuestionnaireRenderer extends TerminologyRenderer { - public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type"; - - public QuestionnaireRenderer(RenderingContext context) { - super(context); - } - - public boolean render(XhtmlNode x, Resource q) throws UnsupportedEncodingException, IOException { - return render(x, (Questionnaire) q); - } - - public boolean render(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { - switch (context.getQuestionnaireMode()) { - case FORM: return renderForm(x, q); - case LINKS: return renderLinks(x, q); - case LOGIC: return renderLogic(x, q); - case DEFNS: return renderDefns(x, q); - case TREE: return renderTree(x, q); - default: - throw new Error("Unknown Questionnaire Renderer Mode"); - } - } - - public boolean renderTree(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { - boolean hasFlags = checkForFlags(q.getItem()); - boolean doOpts = context.getDefinitionsTarget() == null && hasAnyOptions(q.getItem()); - - if (doOpts) { - x.b().tx(context.formatPhrase(RenderingContext.QUEST_STRUCT)); - } - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); - TableModel model = gen.new TableModel("qtree="+q.getId(), context.getRules() == GenerationRules.IG_PUBLISHER); - model.setAlternating(true); - if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { - model.setDocoImg(HierarchicalTableGenerator.help16AsData()); - } else { - model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); - } - model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_LINKID)), (context.formatPhrase(RenderingContext.QUEST_LINK)), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_TEXT)), (context.formatPhrase(RenderingContext.QUEST_TEXTFOR)), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.GENERAL_CARDINALITY)), (context.formatPhrase(RenderingContext.QUEST_TIMES)), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_TYPE)), (context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM)), null, 0)); - if (hasFlags) { - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_FLAG)), (context.formatPhrase(RenderingContext.QUEST_ATTRIBUTES)), null, 0)); - } - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_DESC)), (context.formatPhrase(RenderingContext.QUEST_ADD_INFO)), null, 0)); - - boolean hasExt = false; - // first we add a root for the questionaire itself - Row row = addTreeRoot(gen, model.getRows(), q, hasFlags); - for (QuestionnaireItemComponent i : q.getItem()) { - hasExt = renderTreeItem(gen, row.getSubRows(), q, i, hasFlags) || hasExt; - } - XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); - x.getChildNodes().add(xn); - if (doOpts) { - renderOptions(q, x); - } - return hasExt; - } - - private void renderOptions(Questionnaire q, XhtmlNode x) { - if (hasAnyOptions(q.getItem())) { - x.hr(); - x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_OPT)); - renderOptions(q.getItem(), x); - } - } - - private void renderOptions(List items, XhtmlNode x) { - for (QuestionnaireItemComponent i : items) { - renderItemOptions(x, i); - renderOptions(i.getItem(), x); - } - } - - public void renderItemOptions(XhtmlNode x, QuestionnaireItemComponent i) { - if (i.hasAnswerOption()) { - boolean useSelect = false; - for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { - useSelect = useSelect || opt.getInitialSelected(); - } - x.an("opt-item."+i.getLinkId()); - x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_ANSW, i.getLinkId())+" "); - XhtmlNode ul = x.ul(); - for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { - XhtmlNode li = ul.li(); - li.style("font-size: 11px"); - if (useSelect) { - if (opt.getInitialSelected()) { - li.img("icon-selected.png", "icon"); - } else { - li.img("icon-not-selected.png", "icon"); - } - } - if (opt.getValue().isPrimitive()) { - li.tx(opt.getValue().primitiveValue()); - } else if (opt.getValue() instanceof Coding) { - Coding c = (Coding) opt.getValue(); - String link = c.hasSystem() ? new ContextUtilities(context.getWorker()).getLinkForUrl(context.getLink(KnownLinkType.SPEC), c.getSystem()) : null; - if (link == null) { - li.tx(c.getSystem()+"#"+c.getCode()); - } else { - li.ah(link).tx(displaySystem(c.getSystem())); - li.tx(": "+c.getCode()); - } - if (c.hasDisplay()) { - li.tx(" (\""+c.getDisplay()+"\")"); - } - } else { - li.tx("??"); - } - } - } - } - - private boolean hasAnyOptions(List items) { - for (QuestionnaireItemComponent i : items) { - if (i.hasAnswerOption()) { - return true; - } - if (hasAnyOptions(i.getItem())) { - return true; - } - } - return false; - } - - private boolean checkForFlags(List items) { - for (QuestionnaireItemComponent i : items) { - if (checkForFlags(i)) { - return true; - } - } - return false; - } - - private boolean checkForFlags(QuestionnaireItemComponent i) { - if (i.getReadOnly()) { - return true; - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_IS_SUBJ)) { - return true; - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { - return true; - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { - return true; - } - if (i.hasExtension(ToolingExtensions.EXT_O_LINK_PERIOD)) { - return true; - } - if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { - return true; - } - if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { - return true; - } - return checkForFlags(i.getItem()); - } - - - - private Row addTreeRoot(HierarchicalTableGenerator gen, List rows, Questionnaire q, boolean hasFlags) throws IOException { - Row r = gen.new Row(); - rows.add(r); - - r.setIcon("icon_q_root.gif", context.formatPhrase(RenderingContext.QUEST_ROOT)); - r.getCells().add(gen.new Cell(null, null, q.getName(), null, null)); - r.getCells().add(gen.new Cell(null, null, q.getDescription(), null, null)); - r.getCells().add(gen.new Cell(null, null, "", null, null)); - r.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.QUEST_QUEST), null, null)); - if (hasFlags) { - r.getCells().add(gen.new Cell(null, null, "", null, null)); - } - r.getCells().add(gen.new Cell(null, null, q.hasUrl() ? q.hasVersion() ? q.getUrl()+"#"+q.getVersion() : q.getUrl() : "", null, null)); - return r; - } - - private String getSpecLink(String path) { - return Utilities.pathURL(context.getLink(KnownLinkType.SPEC), path); - } - - private String getSDCLink(String url, String path) { - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, url); - if (sd == null) { - sd = context.getContext().fetchResource(StructureDefinition.class, path); - } - if (sd != null && sd.hasWebPath()) { - return sd.getWebPath(); - } else if (Utilities.isAbsoluteUrl(path)) { - return path.replace("StructureDefinition/", "StructureDefinition-")+".html"; - } else { - return Utilities.pathURL("http://hl7.org/fhir/uv/sdc", path); // for now? - } - } - - private boolean renderTreeItem(HierarchicalTableGenerator gen, List rows, Questionnaire q, QuestionnaireItemComponent i, boolean hasFlags) throws IOException { - Row r = gen.new Row(); - rows.add(r); - boolean hasExt = false; - - r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); - Cell c1 = gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null); - c1.setId("item."+i.getLinkId()); - r.getCells().add(c1); - String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText(); - r.getCells().add(gen.new Cell(null, null, txt, null, null)); - r.getCells().add(gen.new Cell(null, null, (i.getRequired() ? "1" : "0")+".."+(i.getRepeats() ? "*" : "1"), null, null)); - if (i.getTypeElement().hasExtension(EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL)) { - String t = i.getTypeElement().getExtensionString(EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL); - r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+t, t, null, null)); - } else { - r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+i.getType().toCode(), i.getType().toCode(), null, null)); - } - - if (hasFlags) { - // flags: - Cell flags = gen.new Cell(); - r.getCells().add(flags); - if (i.getReadOnly()) { - flags.addPiece(gen.new Piece(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, context.formatPhrase(RenderingContext.QUEST_READONLY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-readonly.png")))); - } - if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { - flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), null, context.formatPhrase(RenderingContext.QUEST_SUBJECT)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-subject.png")))); - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { - flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, context.formatPhrase(RenderingContext.QUEST_HIDDEN)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-hidden.png")))); - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { - flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, context.formatPhrase(RenderingContext.QUEST_DISPLAY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-optional.png")))); - } - if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { - flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), null, context.formatPhrase(RenderingContext.QUEST_LINKED)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-observation.png")))); - } - if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { - String code = ToolingExtensions.readStringExtension(i, ToolingExtensions.EXT_Q_CHOICE_ORIENT); - flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, context.formatPhrase(RenderingContext.QUEST_ORIENTATION, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); - } - if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { - CodeableConcept cc = i.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValueCodeableConcept(); - String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); - flags.addPiece(gen.new Piece("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", null, context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); - } - } - Cell defn = gen.new Cell(); - r.getCells().add(defn); - - if (i.hasMaxLength()) { - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_MAX)+" "), null)); - defn.getPieces().add(gen.new Piece(null, Integer.toString(i.getMaxLength()), null)); - } - if (i.hasDefinition()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_DEF)+" "), null)); - genDefinitionLink(gen, i, defn, q); - } - if (i.hasEnableWhen()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - Piece p = gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null); - defn.getPieces().add(p); - if (i.getEnableWhen().size() == 1) { - XhtmlNode x = new XhtmlNode(NodeType.Element, "span"); - p.getChildren().add(x); - renderEnableWhen(x, i.getEnableWhenFirstRep()); - } else { - XhtmlNode x = new XhtmlNode(NodeType.Element, "ul"); - p.getChildren().add(x); - for (QuestionnaireItemEnableWhenComponent qi : i.getEnableWhen()) { - renderEnableWhen(x.li(), qi); - } - } - } - if (i.hasAnswerValueSet()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); - if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { - ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); - if (vs == null) { - defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); - } else { - defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); - } - } else { - ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); - if (vs == null || !vs.hasWebPath()) { - defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); - } else { - defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); - } - } - } - if (i.hasAnswerOption()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); - if (context.getDefinitionsTarget() == null) { - // if we don't have a definitions target, we'll add them below. - defn.getPieces().add(gen.new Piece("#opt-item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); - } else { - defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); - } - } - if (i.hasInitial()) { - for (QuestionnaireItemInitialComponent v : i.getInitial()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); - defn.getPieces().add(gen.new Piece(null, v.getValue().fhirType(), null)); - defn.getPieces().add(gen.new Piece(null, " = ", null)); - if (v.getValue().isPrimitive()) { - defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null)); - } else if (v.hasValueCoding()) { - renderCoding(gen, defn.getPieces(), v.getValueCoding()); - } else if (v.hasValueQuantity()) { - renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false); - } else if (v.hasValueReference()) { - renderReference(q, gen, defn.getPieces(), v.getValueReference(), true); - } else if (v.hasValueAttachment()) { - // renderAttachment(gen, defn.getPieces(), v.getValueAttachment()); - } - } - } - // still todo - -// -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn -// -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-width -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod -//http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl -//http://hl7.org/fhir/StructureDefinition/questionnaire-sliderStepValue - - if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); - Piece p = gen.new Piece("ul"); - defn.getPieces().add(p); - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); - } - } - - for (QuestionnaireItemComponent c : i.getItem()) { - hasExt = renderTreeItem(gen, r.getSubRows(), q, c, hasFlags) || hasExt; - } - return hasExt; - } - - public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireItemComponent i, Cell defn, Questionnaire q) { - // can we resolve the definition? - String path = null; - String d = i.getDefinition(); - if (d.contains("#")) { - path = d.substring(d.indexOf("#")+1); - d = d.substring(0, d.indexOf("#")); - } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); - if (sd != null) { - String url = sd.getWebPath(); - if (url != null) { - defn.getPieces().add(gen.new Piece(url+"#"+path, path, null)); - } else { - defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); - } - } else { - defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); - } - } - - public void genDefinitionLink(XhtmlNode x, QuestionnaireItemComponent i, Questionnaire q) { - // can we resolve the definition? - String path = null; - String d = i.getDefinition(); - if (d.contains("#")) { - path = d.substring(d.indexOf("#")+1); - d = d.substring(0, d.indexOf("#")); - } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); - if (sd != null) { - String url = sd.getWebPath(); - if (url != null) { - x.ah(url+"#"+path).tx(path); - } else { - x.tx(i.getDefinition()); - } - } else { - x.tx(i.getDefinition()); - } - } - - private void addExpression(Piece p, Expression exp, String label, String url) { - XhtmlNode x = new XhtmlNode(NodeType.Element, "li").style("font-size: 11px"); - p.addHtml(x); - CanonicalResource cr = (CanonicalResource) context.getContext().fetchResource(Resource.class, url); - if (cr != null && cr.hasWebPath()) { - x.ah(cr.getWebPath()).tx(label); - } else { - x.ah(url).tx(label); - } - x.tx(": "); - x.code(exp.getExpression()); - } - - private boolean renderLogic(XhtmlNode x, Questionnaire q) throws FHIRException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); - TableModel model = gen.new TableModel("qtree="+q.getId(), true); - model.setAlternating(true); - if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { - model.setDocoImg(HierarchicalTableGenerator.help16AsData()); - } else { - model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); - } - model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_LINKID), context.formatPhrase(RenderingContext.QUEST_LINK), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_DESC), context.formatPhrase(RenderingContext.QUEST_ADD_INFO), null, 0)); - - boolean hasExt = false; - if (!q.hasItem()) { - gen.emptyRow(model, 2); - } else { - for (QuestionnaireItemComponent i : q.getItem()) { - hasExt = renderLogicItem(gen, model.getRows(), q, i) || hasExt; - } - } - XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); - x.getChildNodes().add(xn); - return hasExt; - } - - private boolean renderLogicItem(HierarchicalTableGenerator gen, List rows, Questionnaire q, QuestionnaireItemComponent i) throws IOException { - Row r = gen.new Row(); - rows.add(r); - boolean hasExt = false; - - r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); - r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); - Cell defn = gen.new Cell(); - r.getCells().add(defn); - - if (i.hasMaxLength()) { - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_MAX)+" "), null)); - defn.getPieces().add(gen.new Piece(null, Integer.toString(i.getMaxLength()), null)); - } - if (i.hasDefinition()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_DEF)+" "), null)); - genDefinitionLink(gen, i, defn, q); - } - if (i.hasEnableWhen()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null)); - defn.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.QUEST_TODO), null)); - } - if (i.hasAnswerValueSet()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); - if (Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { - ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); - if (vs == null) { - defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); - } else { - defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); - } - } else { - ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); - if (vs == null || !vs.hasWebPath()) { - defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); - } else { - defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); - } - } - } - if (i.hasAnswerOption()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); - defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); - } - if (i.hasInitial()) { - for (QuestionnaireItemInitialComponent v : i.getInitial()) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); - defn.getPieces().add(gen.new Piece(null, v.getValue().fhirType(), null)); - defn.getPieces().add(gen.new Piece(null, " = ", null)); - if (v.getValue().isPrimitive()) { - defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null)); - } else if (v.hasValueCoding()) { - renderCoding(gen, defn.getPieces(), v.getValueCoding()); - } else if (v.hasValueQuantity()) { - renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false); - } else if (v.hasValueReference()) { - renderReference(q, gen, defn.getPieces(), v.getValueReference(), false); -// } else if (v.hasValueAttachment()) { -// renderAttachment(gen, defn.getPieces(), v.getValueAttachment()); - } - } - } - // still todo - -// -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn -// -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-width -//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod -//http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl -//http://hl7.org/fhir/StructureDefinition/questionnaire-sliderStepValue - - if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { - if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); - defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); - Piece p = gen.new Piece("ul"); - defn.getPieces().add(p); - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); - } - for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { - addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); - } - } - - for (QuestionnaireItemComponent c : i.getItem()) { - hasExt = renderLogicItem(gen, r.getSubRows(), q, c) || hasExt; - } - return hasExt; - - } - - - public boolean renderForm(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { - boolean hasExt = false; - XhtmlNode d = x.div(); - boolean hasPrefix = false; - for (QuestionnaireItemComponent c : q.getItem()) { - hasPrefix = hasPrefix || doesItemHavePrefix(c); - } - int i = 1; - for (QuestionnaireItemComponent c : q.getItem()) { - hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt; - i++; - } - return hasExt; - } - - private boolean doesItemHavePrefix(QuestionnaireItemComponent i) { - if (i.hasPrefix()) { - return true; - } - for (QuestionnaireItemComponent c : i.getItem()) { - if (doesItemHavePrefix(c)) { - return true; - } - } - return false; - } - - private boolean renderFormItem(XhtmlNode x, Questionnaire q, QuestionnaireItemComponent i, String pfx, int indent) throws IOException { - boolean hasExt = false; - XhtmlNode d = x.div().style("width: "+Integer.toString(900-indent*10)+"px; border-top: 1px #eeeeee solid"); - if (indent > 0) { - d.style("margin-left: "+Integer.toString(10*indent)+"px"); - } - XhtmlNode display = d.div().style("display: inline-block; width: "+Integer.toString(500-indent*10)+"px"); - XhtmlNode details = d.div().style("border: 1px #ccccff solid; padding: 2px; display: inline-block; background-color: #fefce7; width: 380px"); - XhtmlNode p = display.para(); - if (i.getType() == QuestionnaireItemType.GROUP) { - p = p.b(); - } - if (i.hasPrefix()) { - p.tx(i.getPrefix()); - p.tx(": "); - } - p.span(null, "linkId: "+i.getLinkId()).tx(i.getText()); - if (i.getRequired()) { - p.span("color: red", context.formatPhrase(RenderingContext.QUEST_MAND)).tx("*"); - } - - XhtmlNode input = null; - switch (i.getType()) { - case STRING: - p.tx(" "); - input = p.input(i.getLinkId(), "text", i.getType().getDisplay(), 60); - break; - case ATTACHMENT: - break; - case BOOLEAN: - p.tx(" "); - input = p.input(i.getLinkId(), "checkbox", i.getType().getDisplay(), 1); - break; - case CODING: - input = p.select(i.getLinkId()); - listOptions(q, i, input); - break; - case DATE: - p.tx(" "); - input = p.input(i.getLinkId(), "date", i.getType().getDisplay(), 10); - break; - case DATETIME: - p.tx(" "); - input = p.input(i.getLinkId(), "datetime-local", i.getType().getDisplay(), 25); - break; - case DECIMAL: - p.tx(" "); - input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 15); - break; - case DISPLAY: - break; - case GROUP: - - break; - case INTEGER: - p.tx(" "); - input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 10); - break; - case QUANTITY: - p.tx(" "); - input = p.input(i.getLinkId(), "number", "value", 15); - p.tx(" "); - input = p.input(i.getLinkId(), "unit", "unit", 10); - break; - case QUESTION: - break; - case REFERENCE: - break; - case TEXT: - break; - case TIME: - break; - case URL: - break; - default: - break; - } - if (input != null) { - if (i.getReadOnly()) { - input.attribute("readonly", "1"); - input.style("background-color: #eeeeee"); - } - } - -// if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { -// String code = ToolingExtensions.readStringExtension(i, ToolingExtensions.EXT_Q_CHOICE_ORIENT); -// flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); -//} - - - XhtmlNode ul = details.ul(); - boolean hasFlag = false; - XhtmlNode flags = item(ul, "Flags"); - item(ul, "linkId", i.getLinkId()); - - if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { - hasFlag = true; - flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), context.formatPhrase(RenderingContext.QUEST_SUBJECT)).img(getImgPath("icon-qi-subject.png"), "icon"); - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { - hasFlag = true; - flags.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "extension-questionnaire-hidden.html"), context.formatPhrase(RenderingContext.QUEST_HIDDEN)).img(getImgPath("icon-qi-hidden.png"), "icon"); - d.style("background-color: #eeeeee"); - } - if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { - hasFlag = true; - flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), context.formatPhrase(RenderingContext.QUEST_DISPLAY)).img(getImgPath("icon-qi-optional.png"), "icon"); - } - if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { - hasFlag = true; - flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), context.formatPhrase(RenderingContext.QUEST_LINKED)).img(getImgPath("icon-qi-observation.png"), "icon"); - } - if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { - CodeableConcept cc = i.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValueCodeableConcept(); - String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); - hasFlag = true; - flags.ah("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", (context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ")).img(getImgPath("icon-qi-" + code + ".png"), "icon"); - } - - if (i.hasMaxLength()) { - item(ul, context.formatPhrase(RenderingContext.QUEST_MAX), Integer.toString(i.getMaxLength())); - } - if (i.hasDefinition()) { - genDefinitionLink(item(ul, context.formatPhrase(RenderingContext.QUEST_DEF)), i, q); - } - if (i.hasEnableWhen()) { - item(ul, context.formatPhrase(RenderingContext.QUEST_EN), "todo"); - } - if (i.hasAnswerValueSet()) { - XhtmlNode ans = item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS)); - if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { - ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); - if (vs == null || !vs.hasWebPath()) { - ans.tx(i.getAnswerValueSet()); - } else { - ans.ah(vs.getWebPath()).tx(vs.present()); - } - } else { - ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); - if (vs == null || !vs.hasWebPath()) { - ans.tx(i.getAnswerValueSet()); - } else { - ans.ah(vs.getWebPath()).tx(vs.present()); - } - } - } - if (i.hasAnswerOption()) { - item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#item."+i.getLinkId()); - } - if (i.hasInitial()) { - XhtmlNode vi = item(ul, context.formatPhrase(RenderingContext.QUEST_INT)); - boolean first = true; - for (QuestionnaireItemInitialComponent v : i.getInitial()) { - if (first) first = false; else vi.tx(", "); - if (v.getValue().isPrimitive()) { - vi.tx(v.getValue().primitiveValue()); - } else if (v.hasValueCoding()) { - renderCoding(vi, v.getValueCoding(), true); - } else if (v.hasValueReference()) { - renderReference(vi, v.getValueReference()); - } else if (v.hasValueQuantity()) { - renderQuantity(vi, v.getValueQuantity()); -// } else if (v.hasValueAttachment()) { -// renderAttachment(vi, v.getValueAttachment()); - } - } - } - if (!hasFlag) { - ul.remove(flags); - } -// if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { -// if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); -// defn.getPieces().add(gen.new Piece(null, "Expressions: ", null)); -// Piece p = gen.new Piece("ul"); -// defn.getPieces().add(p); -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { -// addExpression(p, e.getValueExpression(), "Initial Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); -// } -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { -// addExpression(p, e.getValueExpression(), "Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); -// } -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { -// addExpression(p, e.getValueExpression(), "Item Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); -// } -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { -// addExpression(p, e.getValueExpression(), "Enable When", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); -// } -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { -// addExpression(p, e.getValueExpression(), "Calculated Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); -// } -// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { -// addExpression(p, e.getValueExpression(), "Candidates", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); -// } -// } -// - - int t = 1; - for (QuestionnaireItemComponent c : i.getItem()) { - hasExt = renderFormItem(x, q, c, pfx == null ? null : pfx+"."+Integer.toString(t), indent+1) || hasExt; - t++; - } - return hasExt; - } - - @Nonnull - private String getImgPath(String code) throws IOException { - return context.getLocalPrefix().length() > 0 - ? Utilities.path(context.getLocalPrefix(), code) - : Utilities.path(code); - } - - private void item(XhtmlNode ul, String name, String value, String valueLink) { - if (!Utilities.noString(value)) { - ul.li().style("font-size: 10px").ah(valueLink).tx(name+": "+value); - } - } - - private void item(XhtmlNode ul, String name, String value) { - if (!Utilities.noString(value)) { - ul.li().style("font-size: 10px").tx(name+": "+value); - } - } - private XhtmlNode item(XhtmlNode ul, String name) { - XhtmlNode li = ul.li(); - li.style("font-size: 10px").tx(name+": "); - return li; - } - - - private void listOptions(Questionnaire q, QuestionnaireItemComponent i, XhtmlNode select) { - if (i.hasAnswerValueSet()) { - ValueSet vs = null; - if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { - vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); - if (vs != null && !vs.hasUrl()) { - vs = vs.copy(); - vs.setUrl(q.getUrl()+"--"+q.getContained(i.getAnswerValueSet().substring(1))); - } - } else { - vs = context.getContext().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); - } - if (vs != null) { - ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false); - if (exp.getValueset() != null) { - for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) { - select.option(cc.getCode(), cc.hasDisplay() ? cc.getDisplay() : cc.getCode(), false); - } - return; - } - } - } else if (i.hasAnswerOption()) { - renderItemOptions(select, i); +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.context.ContextUtilities; +import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.Expression; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.Questionnaire; +import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemAnswerOptionComponent; +import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent; +import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemEnableWhenComponent; +import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemInitialComponent; +import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemType; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; +import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; +import org.hl7.fhir.utilities.xhtml.NodeType; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +import javax.annotation.Nonnull; + +public class QuestionnaireRenderer extends TerminologyRenderer { + public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type"; + + public QuestionnaireRenderer(RenderingContext context) { + super(context); + } + + public boolean render(XhtmlNode x, Resource q) throws UnsupportedEncodingException, IOException { + return render(x, (Questionnaire) q); + } + + public boolean render(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { + switch (context.getQuestionnaireMode()) { + case FORM: return renderForm(x, q); + case LINKS: return renderLinks(x, q); + case LOGIC: return renderLogic(x, q); + case DEFNS: return renderDefns(x, q); + case TREE: return renderTree(x, q); + default: + throw new Error("Unknown Questionnaire Renderer Mode"); } - select.option("a", "??", false); - } - - public String display(Resource dr) throws UnsupportedEncodingException, IOException { - return display((Questionnaire) dr); - } - - public String display(Questionnaire q) throws UnsupportedEncodingException, IOException { - return context.formatPhrase(RenderingContext.QUEST_QUESTIONNAIRE, q.present())+" "; - } + } + + public boolean renderTree(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { + boolean hasFlags = checkForFlags(q.getItem()); + boolean doOpts = context.getDefinitionsTarget() == null && hasAnyOptions(q.getItem()); - private boolean renderLinks(XhtmlNode x, Questionnaire q) { - x.para().tx(context.formatPhrase(RenderingContext.QUEST_TRY)); - XhtmlNode ul = x.ul(); - ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatPhrase(RenderingContext.QUEST_NLM)); - return false; - } - - private boolean renderDefns(XhtmlNode x, Questionnaire q) throws IOException { - XhtmlNode tbl = x.table("dict"); - boolean ext = false; - ext = renderRootDefinition(tbl, q, new ArrayList<>()) || ext; - for (QuestionnaireItemComponent qi : q.getItem()) { - ext = renderDefinition(tbl, q, qi, new ArrayList<>()) || ext; - } - return ext; - } - - private boolean renderRootDefinition(XhtmlNode tbl, Questionnaire q, List parents) throws IOException { - boolean ext = false; - XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); - td.an(q.getId()); - td.img(getImgPath("icon_q_root.gif"), "icon"); - td.tx(" "+(context.formatPhrase(RenderingContext.QUEST_QUEST)+" ")); - td.b().tx(q.getId()); - - // general information - defn(tbl, context.formatPhrase(RenderingContext.QUEST_URL), q.getUrl()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_VERSION), q.getVersion()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_NAME), q.getName()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_TITLE), q.getTitle()); - if (q.hasDerivedFrom()) { - td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_DERIVED)); - boolean first = true; - for (CanonicalType c : q.getDerivedFrom()) { - if (first) first = false; else td.tx(", "); - td.tx(c.asStringValue()); // todo: make these a reference - } - } - defn(tbl, context.formatPhrase(RenderingContext.QUEST_STATUS), q.getStatus().getDisplay()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_EXPER), q.getExperimental()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_PUB), q.getDateElement().primitiveValue()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_APP), q.getApprovalDateElement().primitiveValue()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_REV_DATE), q.getLastReviewDateElement().primitiveValue()); - if (q.hasEffectivePeriod()) { - renderPeriod(defn(tbl, context.formatPhrase(RenderingContext.QUEST_EFF_PERIOD)), q.getEffectivePeriod()); - } - - if (q.hasSubjectType()) { - td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_SUB_TYPE)); - boolean first = true; - for (CodeType c : q.getSubjectType()) { - if (first) first = false; else td.tx(", "); - td.tx(c.asStringValue()); - } - } - defn(tbl, context.formatPhrase(RenderingContext.QUEST_DESCRIPTION), q.getDescription()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_PURPOSE), q.getPurpose()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_COPYRIGHT), q.getCopyright()); - if (q.hasCode()) { - td = defn(tbl, Utilities.pluralize("Code", q.getCode().size())); - boolean first = true; - for (Coding c : q.getCode()) { - if (first) first = false; else td.tx(", "); - renderCodingWithDetails(td, c); - } - } - return false; - } - - private boolean renderDefinition(XhtmlNode tbl, Questionnaire q, QuestionnaireItemComponent qi, List parents) throws IOException { - boolean ext = false; - XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); - td.an("item."+qi.getLinkId()); - for (QuestionnaireItemComponent p : parents) { - td.ah("#item."+p.getLinkId()).img(getImgPath("icon_q_item.png"), "icon"); - td.tx(" > "); - } - td.img(getImgPath("icon_q_item.png"), "icon"); - td.tx(" Item "); - td.b().tx(qi.getLinkId()); - - // general information - defn(tbl, context.formatPhrase(RenderingContext.QUEST_ID), qi.getLinkId()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_PREFIX), qi.getPrefix()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_TEXT), qi.getText()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_TYPE), qi.getType().getDisplay()); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_REQ), qi.getRequired(), true); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_REP), qi.getRepeats(), true); - defn(tbl, context.formatPhrase(RenderingContext.QUEST_READ_ONLY), qi.getReadOnly(), false); - if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_SUB), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "This element changes who the subject of the question is", null); - } - - // content control - defn(tbl, context.formatPhrase(RenderingContext.QUEST_MAX_LENGTH), qi.getMaxLength()); - if (qi.hasAnswerValueSet()) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_VALUE_SET), qi.getDefinition(), context.getWorker().findTxResource(ValueSet.class, qi.getAnswerValueSet(), q)); - } - if (qi.hasAnswerOption()) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(context.formatPhrase(RenderingContext.QUEST_ALLOWED)); - XhtmlNode ul = tr.td().ul(); - for (QuestionnaireItemAnswerOptionComponent ans : qi.getAnswerOption()) { - XhtmlNode li = ul.li(); - render(li, ans.getValue()); - if (ans.getInitialSelected()) { - li.tx(" "+(context.formatPhrase(RenderingContext.QUEST_INITIALLY))); - } - } - } - if (qi.hasInitial()) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.QUEST_INITIAL_ANSWER)), qi.getInitial().size())); - if (qi.getInitial().size() == 1) { - render(tr.td(), qi.getInitialFirstRep().getValue()); - } else { - XhtmlNode ul = tr.td().ul(); - for (QuestionnaireItemInitialComponent ans : qi.getInitial()) { - XhtmlNode li = ul.li(); - render(li, ans.getValue()); - } - } - } - - // appearance - if (qi.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { - XhtmlNode tr = tbl.tr(); - tr.td().ah(ToolingExtensions.EXT_Q_DISPLAY_CAT).tx("Display Category"); - render(tr.td(), qi.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValue()); - } - if (ToolingExtensions.readBoolExtension(qi, ToolingExtensions.EXT_Q_HIDDEN)) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_DISPLAY_CAT, "This item is a hidden question", null); - } - if (ToolingExtensions.readBoolExtension(qi, ToolingExtensions.EXT_Q_OTP_DISP)) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_OTP_DISP, "This item is optional to display", null); - } - - // formal definitions - if (qi.hasDefinition()) { - genDefinitionLink(defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION)), qi, q); - } - - if (qi.hasCode()) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(context.formatPhrase(RenderingContext.GENERAL_CODE), qi.getCode().size())); - XhtmlNode ul = tr.td().ul(); - for (Coding c : qi.getCode()) { - renderCodingWithDetails(ul.li(), c); - } - } - if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { - XhtmlNode tr = tbl.tr(); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, ToolingExtensions.EXT_O_LINK_PERIOD); - if (sd != null && sd.hasWebPath()) { - tr.td().ah(sd.getWebPath()).tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); - } else { - tr.td().ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod").tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); - } - render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod").getValue()); - } - - // dynamic management - if (qi.hasEnableWhen()) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(context.formatPhrase(RenderingContext.QUEST_EN)); - td = tr.td(); - if (qi.getEnableWhen().size() == 1) { - renderEnableWhen(td, qi.getEnableWhen().get(0)); - } else { - if (qi.hasEnableBehavior()) { - td.tx(qi.getEnableBehavior().getDisplay()+" "+(context.formatPhrase(RenderingContext.QUEST_TRUE))); - } else { - td.tx(context.formatPhrase(RenderingContext.QUEST_ARE_TRUE)); - } - XhtmlNode ul = td.ul(); - for (QuestionnaireItemEnableWhenComponent ew : qi.getEnableWhen()) { - renderEnableWhen(ul.li(), ew); - } - } - } - - - // other stuff - - - - List curr = new ArrayList<>(); - curr.addAll(parents); - curr.add(qi); - for (QuestionnaireItemComponent qic : qi.getItem()) { - ext = renderDefinition(tbl, q, qic, curr) || ext; - } - return ext; - } - - private void defn(XhtmlNode tbl, String name, String url, Resource res) throws UnsupportedEncodingException, IOException { - if (res != null && res.hasWebPath()) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), RendererFactory.factory(res, context).display(res), res.getWebPath()); - } else if (Utilities.isAbsoluteUrlLinkable(url)) { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), url, url); - } { - defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), url); - } + if (doOpts) { + x.b().tx(context.formatPhrase(RenderingContext.QUEST_STRUCT)); + } + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + TableModel model = gen.new TableModel("qtree="+q.getId(), context.getRules() == GenerationRules.IG_PUBLISHER); + model.setAlternating(true); + if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { + model.setDocoImg(HierarchicalTableGenerator.help16AsData()); + } else { + model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); + } + model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_LINKID)), (context.formatPhrase(RenderingContext.QUEST_LINK)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_TEXT)), (context.formatPhrase(RenderingContext.QUEST_TEXTFOR)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_CARD)), (context.formatPhrase(RenderingContext.QUEST_TIMES)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_TYPE)), (context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM)), null, 0)); + if (hasFlags) { + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_FLAG)), (context.formatPhrase(RenderingContext.QUEST_ATTRIBUTES)), null, 0)); + } + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.QUEST_DESC)), (context.formatPhrase(RenderingContext.QUEST_ADD_INFO)), null, 0)); - } - - private void renderEnableWhen(XhtmlNode x, QuestionnaireItemEnableWhenComponent ew) { - x.ah("#item."+ew.getQuestion()).tx(ew.getQuestion()); - x.tx(" "); - x.tx(ew.getOperator().toCode()); - x.tx(" "); - x.tx(display(ew.getAnswer())); - } - - private XhtmlNode defn(XhtmlNode tbl, String name) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - return tr.td(); - } - - private void defn(XhtmlNode tbl, String name, int value) { - if (value > 0) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - tr.td().tx(value); - } - } + boolean hasExt = false; + // first we add a root for the questionaire itself + Row row = addTreeRoot(gen, model.getRows(), q, hasFlags); + for (QuestionnaireItemComponent i : q.getItem()) { + hasExt = renderTreeItem(gen, row.getSubRows(), q, i, hasFlags) || hasExt; + } + XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); + x.getChildNodes().add(xn); + if (doOpts) { + renderOptions(q, x); + } + return hasExt; + } - - private void defn(XhtmlNode tbl, String name, boolean value) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - tr.td().tx(Boolean.toString(value)); - } + private void renderOptions(Questionnaire q, XhtmlNode x) { + if (hasAnyOptions(q.getItem())) { + x.hr(); + x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_OPT)); + renderOptions(q.getItem(), x); + } + } - private void defn(XhtmlNode tbl, String name, String value) { - if (!Utilities.noString(value)) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - tr.td().tx(value); - } - } + private void renderOptions(List items, XhtmlNode x) { + for (QuestionnaireItemComponent i : items) { + renderItemOptions(x, i); + renderOptions(i.getItem(), x); + } + } + + public void renderItemOptions(XhtmlNode x, QuestionnaireItemComponent i) { + if (i.hasAnswerOption()) { + boolean useSelect = false; + for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { + useSelect = useSelect || opt.getInitialSelected(); + } + x.an("opt-item."+i.getLinkId()); + x.para().b().tx(context.formatPhrase(RenderingContext.QUEST_ANSW, i.getLinkId())+" "); + XhtmlNode ul = x.ul(); + for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { + XhtmlNode li = ul.li(); + li.style("font-size: 11px"); + if (useSelect) { + if (opt.getInitialSelected()) { + li.img("icon-selected.png", "icon"); + } else { + li.img("icon-not-selected.png", "icon"); + } + } + if (opt.getValue().isPrimitive()) { + li.tx(opt.getValue().primitiveValue()); + } else if (opt.getValue() instanceof Coding) { + Coding c = (Coding) opt.getValue(); + String link = c.hasSystem() ? new ContextUtilities(context.getWorker()).getLinkForUrl(context.getLink(KnownLinkType.SPEC), c.getSystem()) : null; + if (link == null) { + li.tx(c.getSystem()+"#"+c.getCode()); + } else { + li.ah(link).tx(displaySystem(c.getSystem())); + li.tx(": "+c.getCode()); + } + if (c.hasDisplay()) { + li.tx(" (\""+c.getDisplay()+"\")"); + } + } else { + li.tx("??"); + } + } + } + } + + private boolean hasAnyOptions(List items) { + for (QuestionnaireItemComponent i : items) { + if (i.hasAnswerOption()) { + return true; + } + if (hasAnyOptions(i.getItem())) { + return true; + } + } + return false; + } + + private boolean checkForFlags(List items) { + for (QuestionnaireItemComponent i : items) { + if (checkForFlags(i)) { + return true; + } + } + return false; + } + + private boolean checkForFlags(QuestionnaireItemComponent i) { + if (i.getReadOnly()) { + return true; + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_IS_SUBJ)) { + return true; + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { + return true; + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { + return true; + } + if (i.hasExtension(ToolingExtensions.EXT_O_LINK_PERIOD)) { + return true; + } + if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { + return true; + } + if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { + return true; + } + return checkForFlags(i.getItem()); + } + + + + private Row addTreeRoot(HierarchicalTableGenerator gen, List rows, Questionnaire q, boolean hasFlags) throws IOException { + Row r = gen.new Row(); + rows.add(r); + + r.setIcon("icon_q_root.gif", context.formatPhrase(RenderingContext.QUEST_ROOT)); + r.getCells().add(gen.new Cell(null, null, q.getName(), null, null)); + r.getCells().add(gen.new Cell(null, null, q.getDescription(), null, null)); + r.getCells().add(gen.new Cell(null, null, "", null, null)); + r.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.QUEST_QUEST), null, null)); + if (hasFlags) { + r.getCells().add(gen.new Cell(null, null, "", null, null)); + } + r.getCells().add(gen.new Cell(null, null, q.hasUrl() ? q.hasVersion() ? q.getUrl()+"#"+q.getVersion() : q.getUrl() : "", null, null)); + return r; + } + + private String getSpecLink(String path) { + return Utilities.pathURL(context.getLink(KnownLinkType.SPEC), path); + } + + private String getSDCLink(String url, String path) { + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, url); + if (sd == null) { + sd = context.getContext().fetchResource(StructureDefinition.class, path); + } + if (sd != null && sd.hasWebPath()) { + return sd.getWebPath(); + } else if (Utilities.isAbsoluteUrl(path)) { + return path.replace("StructureDefinition/", "StructureDefinition-")+".html"; + } else { + return Utilities.pathURL("http://hl7.org/fhir/uv/sdc", path); // for now? + } + } + + private boolean renderTreeItem(HierarchicalTableGenerator gen, List rows, Questionnaire q, QuestionnaireItemComponent i, boolean hasFlags) throws IOException { + Row r = gen.new Row(); + rows.add(r); + boolean hasExt = false; + + r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); + Cell c1 = gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null); + c1.setId("item."+i.getLinkId()); + r.getCells().add(c1); + String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText(); + r.getCells().add(gen.new Cell(null, null, txt, null, null)); + r.getCells().add(gen.new Cell(null, null, (i.getRequired() ? "1" : "0")+".."+(i.getRepeats() ? "*" : "1"), null, null)); + if (i.getTypeElement().hasExtension(EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL)) { + String t = i.getTypeElement().getExtensionString(EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL); + r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+t, t, null, null)); + } else { + r.getCells().add(gen.new Cell(null, context.getLink(KnownLinkType.SPEC)+"codesystem-item-type.html#item-type-"+i.getType().toCode(), i.getType().toCode(), null, null)); + } + + if (hasFlags) { + // flags: + Cell flags = gen.new Cell(); + r.getCells().add(flags); + if (i.getReadOnly()) { + flags.addPiece(gen.new Piece(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, context.formatPhrase(RenderingContext.QUEST_READONLY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-readonly.png")))); + } + if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { + flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), null, context.formatPhrase(RenderingContext.QUEST_SUBJECT)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-subject.png")))); + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { + flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, context.formatPhrase(RenderingContext.QUEST_HIDDEN)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-hidden.png")))); + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { + flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, context.formatPhrase(RenderingContext.QUEST_DISPLAY)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-optional.png")))); + } + if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { + flags.addPiece(gen.new Piece(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), null, context.formatPhrase(RenderingContext.QUEST_LINKED)).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-observation.png")))); + } + if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { + String code = ToolingExtensions.readStringExtension(i, ToolingExtensions.EXT_Q_CHOICE_ORIENT); + flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, context.formatPhrase(RenderingContext.QUEST_ORIENTATION, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); + } + if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { + CodeableConcept cc = i.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValueCodeableConcept(); + String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); + flags.addPiece(gen.new Piece("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", null, context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", getImgPath("icon-qi-" + code + ".png")))); + } + } + Cell defn = gen.new Cell(); + r.getCells().add(defn); + + if (i.hasMaxLength()) { + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_MAX)+" "), null)); + defn.getPieces().add(gen.new Piece(null, Integer.toString(i.getMaxLength()), null)); + } + if (i.hasDefinition()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_DEF)+" "), null)); + genDefinitionLink(gen, i, defn, q); + } + if (i.hasEnableWhen()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + Piece p = gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null); + defn.getPieces().add(p); + if (i.getEnableWhen().size() == 1) { + XhtmlNode x = new XhtmlNode(NodeType.Element, "span"); + p.getChildren().add(x); + renderEnableWhen(x, i.getEnableWhenFirstRep()); + } else { + XhtmlNode x = new XhtmlNode(NodeType.Element, "ul"); + p.getChildren().add(x); + for (QuestionnaireItemEnableWhenComponent qi : i.getEnableWhen()) { + renderEnableWhen(x.li(), qi); + } + } + } + if (i.hasAnswerValueSet()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); + if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { + ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); + if (vs == null) { + defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); + } else { + defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); + } + } else { + ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); + if (vs == null || !vs.hasWebPath()) { + defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); + } else { + defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); + } + } + } + if (i.hasAnswerOption()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); + if (context.getDefinitionsTarget() == null) { + // if we don't have a definitions target, we'll add them below. + defn.getPieces().add(gen.new Piece("#opt-item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + } else { + defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + } + } + if (i.hasInitial()) { + for (QuestionnaireItemInitialComponent v : i.getInitial()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); + defn.getPieces().add(gen.new Piece(null, v.getValue().fhirType(), null)); + defn.getPieces().add(gen.new Piece(null, " = ", null)); + if (v.getValue().isPrimitive()) { + defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null)); + } else if (v.hasValueCoding()) { + renderCoding(gen, defn.getPieces(), v.getValueCoding()); + } else if (v.hasValueQuantity()) { + renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false); + } else if (v.hasValueReference()) { + renderReference(q, gen, defn.getPieces(), v.getValueReference(), true); + } else if (v.hasValueAttachment()) { + // renderAttachment(gen, defn.getPieces(), v.getValueAttachment()); + } + } + } + // still todo + +// +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn +// +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-width +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod +//http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl +//http://hl7.org/fhir/StructureDefinition/questionnaire-sliderStepValue + + if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); + Piece p = gen.new Piece("ul"); + defn.getPieces().add(p); + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); + } + } + + for (QuestionnaireItemComponent c : i.getItem()) { + hasExt = renderTreeItem(gen, r.getSubRows(), q, c, hasFlags) || hasExt; + } + return hasExt; + } + + public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireItemComponent i, Cell defn, Questionnaire q) { + // can we resolve the definition? + String path = null; + String d = i.getDefinition(); + if (d.contains("#")) { + path = d.substring(d.indexOf("#")+1); + d = d.substring(0, d.indexOf("#")); + } + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); + if (sd != null) { + String url = sd.getWebPath(); + if (url != null) { + defn.getPieces().add(gen.new Piece(url+"#"+path, path, null)); + } else { + defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); + } + } else { + defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); + } + } + + public void genDefinitionLink(XhtmlNode x, QuestionnaireItemComponent i, Questionnaire q) { + // can we resolve the definition? + String path = null; + String d = i.getDefinition(); + if (d.contains("#")) { + path = d.substring(d.indexOf("#")+1); + d = d.substring(0, d.indexOf("#")); + } + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); + if (sd != null) { + String url = sd.getWebPath(); + if (url != null) { + x.ah(url+"#"+path).tx(path); + } else { + x.tx(i.getDefinition()); + } + } else { + x.tx(i.getDefinition()); + } + } + + private void addExpression(Piece p, Expression exp, String label, String url) { + XhtmlNode x = new XhtmlNode(NodeType.Element, "li").style("font-size: 11px"); + p.addHtml(x); + CanonicalResource cr = (CanonicalResource) context.getContext().fetchResource(Resource.class, url); + if (cr != null && cr.hasWebPath()) { + x.ah(cr.getWebPath()).tx(label); + } else { + x.ah(url).tx(label); + } + x.tx(": "); + x.code(exp.getExpression()); + } + + private boolean renderLogic(XhtmlNode x, Questionnaire q) throws FHIRException, IOException { + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + TableModel model = gen.new TableModel("qtree="+q.getId(), true); + model.setAlternating(true); + if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { + model.setDocoImg(HierarchicalTableGenerator.help16AsData()); + } else { + model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); + } + model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_LINKID), context.formatPhrase(RenderingContext.QUEST_LINK), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_DESC), context.formatPhrase(RenderingContext.QUEST_ADD_INFO), null, 0)); + + boolean hasExt = false; + if (!q.hasItem()) { + gen.emptyRow(model, 2); + } else { + for (QuestionnaireItemComponent i : q.getItem()) { + hasExt = renderLogicItem(gen, model.getRows(), q, i) || hasExt; + } + } + XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); + x.getChildNodes().add(xn); + return hasExt; + } + + private boolean renderLogicItem(HierarchicalTableGenerator gen, List rows, Questionnaire q, QuestionnaireItemComponent i) throws IOException { + Row r = gen.new Row(); + rows.add(r); + boolean hasExt = false; + + r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); + r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); + Cell defn = gen.new Cell(); + r.getCells().add(defn); + + if (i.hasMaxLength()) { + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_MAX)+" "), null)); + defn.getPieces().add(gen.new Piece(null, Integer.toString(i.getMaxLength()), null)); + } + if (i.hasDefinition()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_DEF)+" "), null)); + genDefinitionLink(gen, i, defn, q); + } + if (i.hasEnableWhen()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_ENABLE)+" "), null)); + defn.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.QUEST_TODO), null)); + } + if (i.hasAnswerValueSet()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_VALUE)+" "), null)); + if (Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { + ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); + if (vs == null) { + defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); + } else { + defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); + } + } else { + ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); + if (vs == null || !vs.hasWebPath()) { + defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); + } else { + defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null)); + } + } + } + if (i.hasAnswerOption()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null)); + defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + } + if (i.hasInitial()) { + for (QuestionnaireItemInitialComponent v : i.getInitial()) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_INITIAL)+" "), null)); + defn.getPieces().add(gen.new Piece(null, v.getValue().fhirType(), null)); + defn.getPieces().add(gen.new Piece(null, " = ", null)); + if (v.getValue().isPrimitive()) { + defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null)); + } else if (v.hasValueCoding()) { + renderCoding(gen, defn.getPieces(), v.getValueCoding()); + } else if (v.hasValueQuantity()) { + renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false); + } else if (v.hasValueReference()) { + renderReference(q, gen, defn.getPieces(), v.getValueReference(), false); +// } else if (v.hasValueAttachment()) { +// renderAttachment(gen, defn.getPieces(), v.getValueAttachment()); + } + } + } + // still todo + +// +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn +// +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-width +//http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod +//http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl +//http://hl7.org/fhir/StructureDefinition/questionnaire-sliderStepValue + + if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { + if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); + defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_EXP)+" "), null)); + Piece p = gen.new Piece("ul"); + defn.getPieces().add(p); + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_INT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_ITEM_CONT), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_EN), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CALC), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); + } + for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { + addExpression(p, e.getValueExpression(), context.formatPhrase(RenderingContext.QUEST_CAND), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); + } + } + + for (QuestionnaireItemComponent c : i.getItem()) { + hasExt = renderLogicItem(gen, r.getSubRows(), q, c) || hasExt; + } + return hasExt; + + } + + + public boolean renderForm(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { + boolean hasExt = false; + XhtmlNode d = x.div(); + boolean hasPrefix = false; + for (QuestionnaireItemComponent c : q.getItem()) { + hasPrefix = hasPrefix || doesItemHavePrefix(c); + } + int i = 1; + for (QuestionnaireItemComponent c : q.getItem()) { + hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt; + i++; + } + return hasExt; + } + + private boolean doesItemHavePrefix(QuestionnaireItemComponent i) { + if (i.hasPrefix()) { + return true; + } + for (QuestionnaireItemComponent c : i.getItem()) { + if (doesItemHavePrefix(c)) { + return true; + } + } + return false; + } + + private boolean renderFormItem(XhtmlNode x, Questionnaire q, QuestionnaireItemComponent i, String pfx, int indent) throws IOException { + boolean hasExt = false; + XhtmlNode d = x.div().style("width: "+Integer.toString(900-indent*10)+"px; border-top: 1px #eeeeee solid"); + if (indent > 0) { + d.style("margin-left: "+Integer.toString(10*indent)+"px"); + } + XhtmlNode display = d.div().style("display: inline-block; width: "+Integer.toString(500-indent*10)+"px"); + XhtmlNode details = d.div().style("border: 1px #ccccff solid; padding: 2px; display: inline-block; background-color: #fefce7; width: 380px"); + XhtmlNode p = display.para(); + if (i.getType() == QuestionnaireItemType.GROUP) { + p = p.b(); + } + if (i.hasPrefix()) { + p.tx(i.getPrefix()); + p.tx(": "); + } + p.span(null, "linkId: "+i.getLinkId()).tx(i.getText()); + if (i.getRequired()) { + p.span("color: red", context.formatPhrase(RenderingContext.QUEST_MAND)).tx("*"); + } + + XhtmlNode input = null; + switch (i.getType()) { + case STRING: + p.tx(" "); + input = p.input(i.getLinkId(), "text", i.getType().getDisplay(), 60); + break; + case ATTACHMENT: + break; + case BOOLEAN: + p.tx(" "); + input = p.input(i.getLinkId(), "checkbox", i.getType().getDisplay(), 1); + break; + case CODING: + input = p.select(i.getLinkId()); + listOptions(q, i, input); + break; + case DATE: + p.tx(" "); + input = p.input(i.getLinkId(), "date", i.getType().getDisplay(), 10); + break; + case DATETIME: + p.tx(" "); + input = p.input(i.getLinkId(), "datetime-local", i.getType().getDisplay(), 25); + break; + case DECIMAL: + p.tx(" "); + input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 15); + break; + case DISPLAY: + break; + case GROUP: + + break; + case INTEGER: + p.tx(" "); + input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 10); + break; + case QUANTITY: + p.tx(" "); + input = p.input(i.getLinkId(), "number", "value", 15); + p.tx(" "); + input = p.input(i.getLinkId(), "unit", "unit", 10); + break; + case QUESTION: + break; + case REFERENCE: + break; + case TEXT: + break; + case TIME: + break; + case URL: + break; + default: + break; + } + if (input != null) { + if (i.getReadOnly()) { + input.attribute("readonly", "1"); + input.style("background-color: #eeeeee"); + } + } + +// if (i.hasExtension(ToolingExtensions.EXT_Q_CHOICE_ORIENT)) { +// String code = ToolingExtensions.readStringExtension(i, ToolingExtensions.EXT_Q_CHOICE_ORIENT); +// flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); +//} + + + XhtmlNode ul = details.ul(); + boolean hasFlag = false; + XhtmlNode flags = item(ul, "Flags"); + item(ul, "linkId", i.getLinkId()); + + if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { + hasFlag = true; + flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "StructureDefinition-sdc-questionnaire-isSubject.html"), context.formatPhrase(RenderingContext.QUEST_SUBJECT)).img(getImgPath("icon-qi-subject.png"), "icon"); + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_HIDDEN)) { + hasFlag = true; + flags.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "extension-questionnaire-hidden.html"), context.formatPhrase(RenderingContext.QUEST_HIDDEN)).img(getImgPath("icon-qi-hidden.png"), "icon"); + d.style("background-color: #eeeeee"); + } + if (ToolingExtensions.readBoolExtension(i, ToolingExtensions.EXT_Q_OTP_DISP)) { + hasFlag = true; + flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "StructureDefinition-sdc-questionnaire-optionalDisplay.html"), context.formatPhrase(RenderingContext.QUEST_DISPLAY)).img(getImgPath("icon-qi-optional.png"), "icon"); + } + if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { + hasFlag = true; + flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), context.formatPhrase(RenderingContext.QUEST_LINKED)).img(getImgPath("icon-qi-observation.png"), "icon"); + } + if (i.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { + CodeableConcept cc = i.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValueCodeableConcept(); + String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); + hasFlag = true; + flags.ah("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", (context.formatPhrase(RenderingContext.QUEST_CAT, code)+" ")).img(getImgPath("icon-qi-" + code + ".png"), "icon"); + } + + if (i.hasMaxLength()) { + item(ul, context.formatPhrase(RenderingContext.QUEST_MAX), Integer.toString(i.getMaxLength())); + } + if (i.hasDefinition()) { + genDefinitionLink(item(ul, context.formatPhrase(RenderingContext.QUEST_DEF)), i, q); + } + if (i.hasEnableWhen()) { + item(ul, context.formatPhrase(RenderingContext.QUEST_EN), "todo"); + } + if (i.hasAnswerValueSet()) { + XhtmlNode ans = item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS)); + if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { + ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); + if (vs == null || !vs.hasWebPath()) { + ans.tx(i.getAnswerValueSet()); + } else { + ans.ah(vs.getWebPath()).tx(vs.present()); + } + } else { + ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); + if (vs == null || !vs.hasWebPath()) { + ans.tx(i.getAnswerValueSet()); + } else { + ans.ah(vs.getWebPath()).tx(vs.present()); + } + } + } + if (i.hasAnswerOption()) { + item(ul, context.formatPhrase(RenderingContext.QUEST_ANSWERS), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#item."+i.getLinkId()); + } + if (i.hasInitial()) { + XhtmlNode vi = item(ul, context.formatPhrase(RenderingContext.QUEST_INT)); + boolean first = true; + for (QuestionnaireItemInitialComponent v : i.getInitial()) { + if (first) first = false; else vi.tx(", "); + if (v.getValue().isPrimitive()) { + vi.tx(v.getValue().primitiveValue()); + } else if (v.hasValueCoding()) { + renderCoding(vi, v.getValueCoding(), true); + } else if (v.hasValueReference()) { + renderReference(vi, v.getValueReference()); + } else if (v.hasValueQuantity()) { + renderQuantity(vi, v.getValueQuantity()); +// } else if (v.hasValueAttachment()) { +// renderAttachment(vi, v.getValueAttachment()); + } + } + } + if (!hasFlag) { + ul.remove(flags); + } +// if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { +// if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); +// defn.getPieces().add(gen.new Piece(null, "Expressions: ", null)); +// Piece p = gen.new Piece("ul"); +// defn.getPieces().add(p); +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression")) { +// addExpression(p, e.getValueExpression(), "Initial Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"); +// } +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression")) { +// addExpression(p, e.getValueExpression(), "Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression"); +// } +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext")) { +// addExpression(p, e.getValueExpression(), "Item Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemContext"); +// } +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression")) { +// addExpression(p, e.getValueExpression(), "Enable When", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); +// } +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression")) { +// addExpression(p, e.getValueExpression(), "Calculated Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression"); +// } +// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression")) { +// addExpression(p, e.getValueExpression(), "Candidates", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression"); +// } +// } +// + + int t = 1; + for (QuestionnaireItemComponent c : i.getItem()) { + hasExt = renderFormItem(x, q, c, pfx == null ? null : pfx+"."+Integer.toString(t), indent+1) || hasExt; + t++; + } + return hasExt; + } + + @Nonnull + private String getImgPath(String code) throws IOException { + return context.getLocalPrefix().length() > 0 + ? Utilities.path(context.getLocalPrefix(), code) + : Utilities.path(code); + } + + private void item(XhtmlNode ul, String name, String value, String valueLink) { + if (!Utilities.noString(value)) { + ul.li().style("font-size: 10px").ah(valueLink).tx(name+": "+value); + } + } + + private void item(XhtmlNode ul, String name, String value) { + if (!Utilities.noString(value)) { + ul.li().style("font-size: 10px").tx(name+": "+value); + } + } + private XhtmlNode item(XhtmlNode ul, String name) { + XhtmlNode li = ul.li(); + li.style("font-size: 10px").tx(name+": "); + return li; + } + + + private void listOptions(Questionnaire q, QuestionnaireItemComponent i, XhtmlNode select) { + if (i.hasAnswerValueSet()) { + ValueSet vs = null; + if (!Utilities.noString(i.getAnswerValueSet()) && i.getAnswerValueSet().startsWith("#")) { + vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); + if (vs != null && !vs.hasUrl()) { + vs = vs.copy(); + vs.setUrl(q.getUrl()+"--"+q.getContained(i.getAnswerValueSet().substring(1))); + } + } else { + vs = context.getContext().findTxResource(ValueSet.class, i.getAnswerValueSet(), q); + } + if (vs != null) { + ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false); + if (exp.getValueset() != null) { + for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) { + select.option(cc.getCode(), cc.hasDisplay() ? cc.getDisplay() : cc.getCode(), false); + } + return; + } + } + } else if (i.hasAnswerOption()) { + renderItemOptions(select, i); + } + select.option("a", "??", false); + } + + public String display(Resource dr) throws UnsupportedEncodingException, IOException { + return display((Questionnaire) dr); + } + + public String display(Questionnaire q) throws UnsupportedEncodingException, IOException { + return context.formatPhrase(RenderingContext.QUEST_QUESTIONNAIRE, q.present())+" "; + } - private void defn(XhtmlNode tbl, String name, String value, String url) { - if (!Utilities.noString(value)) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - tr.td().ah(url).tx(value); - } - } - - private void defn(XhtmlNode tbl, String name, String nurl, String value, String url) { - if (!Utilities.noString(value)) { - XhtmlNode tr = tbl.tr(); - tr.td().ah(nurl).tx(name); - if (url != null) { - tr.td().ah(url).tx(value); - } else { - tr.td().tx(value); - } - } - } - - private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) { - if (ifFalse || value) { - XhtmlNode tr = tbl.tr(); - tr.td().tx(name); - tr.td().tx(Boolean.toString(value)); - } - } - -} + private boolean renderLinks(XhtmlNode x, Questionnaire q) { + x.para().tx(context.formatPhrase(RenderingContext.QUEST_TRY)); + XhtmlNode ul = x.ul(); + ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatPhrase(RenderingContext.QUEST_NLM)); + return false; + } + + private boolean renderDefns(XhtmlNode x, Questionnaire q) throws IOException { + XhtmlNode tbl = x.table("dict"); + boolean ext = false; + ext = renderRootDefinition(tbl, q, new ArrayList<>()) || ext; + for (QuestionnaireItemComponent qi : q.getItem()) { + ext = renderDefinition(tbl, q, qi, new ArrayList<>()) || ext; + } + return ext; + } + + private boolean renderRootDefinition(XhtmlNode tbl, Questionnaire q, List parents) throws IOException { + boolean ext = false; + XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); + td.an(q.getId()); + td.img(getImgPath("icon_q_root.gif"), "icon"); + td.tx(" "+(context.formatPhrase(RenderingContext.QUEST_QUEST)+" ")); + td.b().tx(q.getId()); + + // general information + defn(tbl, context.formatPhrase(RenderingContext.QUEST_URL), q.getUrl()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_VERSION), q.getVersion()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_NAME), q.getName()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_TITLE), q.getTitle()); + if (q.hasDerivedFrom()) { + td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_DERIVED)); + boolean first = true; + for (CanonicalType c : q.getDerivedFrom()) { + if (first) first = false; else td.tx(", "); + td.tx(c.asStringValue()); // todo: make these a reference + } + } + defn(tbl, context.formatPhrase(RenderingContext.QUEST_STATUS), q.getStatus().getDisplay()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_EXPER), q.getExperimental()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_PUB), q.getDateElement().primitiveValue()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_APP), q.getApprovalDateElement().primitiveValue()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_REV_DATE), q.getLastReviewDateElement().primitiveValue()); + if (q.hasEffectivePeriod()) { + renderPeriod(defn(tbl, context.formatPhrase(RenderingContext.QUEST_EFF_PERIOD)), q.getEffectivePeriod()); + } + + if (q.hasSubjectType()) { + td = defn(tbl, context.formatPhrase(RenderingContext.QUEST_SUB_TYPE)); + boolean first = true; + for (CodeType c : q.getSubjectType()) { + if (first) first = false; else td.tx(", "); + td.tx(c.asStringValue()); + } + } + defn(tbl, context.formatPhrase(RenderingContext.QUEST_DESCRIPTION), q.getDescription()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_PURPOSE), q.getPurpose()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_COPYRIGHT), q.getCopyright()); + if (q.hasCode()) { + td = defn(tbl, Utilities.pluralize("Code", q.getCode().size())); + boolean first = true; + for (Coding c : q.getCode()) { + if (first) first = false; else td.tx(", "); + renderCodingWithDetails(td, c); + } + } + return false; + } + + private boolean renderDefinition(XhtmlNode tbl, Questionnaire q, QuestionnaireItemComponent qi, List parents) throws IOException { + boolean ext = false; + XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); + td.an("item."+qi.getLinkId()); + for (QuestionnaireItemComponent p : parents) { + td.ah("#item."+p.getLinkId()).img(getImgPath("icon_q_item.png"), "icon"); + td.tx(" > "); + } + td.img(getImgPath("icon_q_item.png"), "icon"); + td.tx(" Item "); + td.b().tx(qi.getLinkId()); + + // general information + defn(tbl, context.formatPhrase(RenderingContext.QUEST_ID), qi.getLinkId()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_PREFIX), qi.getPrefix()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_TEXT), qi.getText()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_TYPE), qi.getType().getDisplay()); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_REQ), qi.getRequired(), true); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_REP), qi.getRepeats(), true); + defn(tbl, context.formatPhrase(RenderingContext.QUEST_READ_ONLY), qi.getReadOnly(), false); + if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_SUB), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "This element changes who the subject of the question is", null); + } + + // content control + defn(tbl, context.formatPhrase(RenderingContext.QUEST_MAX_LENGTH), qi.getMaxLength()); + if (qi.hasAnswerValueSet()) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_VALUE_SET), qi.getDefinition(), context.getWorker().findTxResource(ValueSet.class, qi.getAnswerValueSet(), q)); + } + if (qi.hasAnswerOption()) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(context.formatPhrase(RenderingContext.QUEST_ALLOWED)); + XhtmlNode ul = tr.td().ul(); + for (QuestionnaireItemAnswerOptionComponent ans : qi.getAnswerOption()) { + XhtmlNode li = ul.li(); + render(li, ans.getValue()); + if (ans.getInitialSelected()) { + li.tx(" "+(context.formatPhrase(RenderingContext.QUEST_INITIALLY))); + } + } + } + if (qi.hasInitial()) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(Utilities.pluralize((context.formatPhrase(RenderingContext.QUEST_INITIAL_ANSWER)), qi.getInitial().size())); + if (qi.getInitial().size() == 1) { + render(tr.td(), qi.getInitialFirstRep().getValue()); + } else { + XhtmlNode ul = tr.td().ul(); + for (QuestionnaireItemInitialComponent ans : qi.getInitial()) { + XhtmlNode li = ul.li(); + render(li, ans.getValue()); + } + } + } + + // appearance + if (qi.hasExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT)) { + XhtmlNode tr = tbl.tr(); + tr.td().ah(ToolingExtensions.EXT_Q_DISPLAY_CAT).tx("Display Category"); + render(tr.td(), qi.getExtensionByUrl(ToolingExtensions.EXT_Q_DISPLAY_CAT).getValue()); + } + if (ToolingExtensions.readBoolExtension(qi, ToolingExtensions.EXT_Q_HIDDEN)) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_DISPLAY_CAT, "This item is a hidden question", null); + } + if (ToolingExtensions.readBoolExtension(qi, ToolingExtensions.EXT_Q_OTP_DISP)) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_HIDDEN_ITEM), ToolingExtensions.EXT_Q_OTP_DISP, "This item is optional to display", null); + } + + // formal definitions + if (qi.hasDefinition()) { + genDefinitionLink(defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION)), qi, q); + } + + if (qi.hasCode()) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(Utilities.pluralize(context.formatPhrase(RenderingContext.QUEST_CODE), qi.getCode().size())); + XhtmlNode ul = tr.td().ul(); + for (Coding c : qi.getCode()) { + renderCodingWithDetails(ul.li(), c); + } + } + if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { + XhtmlNode tr = tbl.tr(); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, ToolingExtensions.EXT_O_LINK_PERIOD); + if (sd != null && sd.hasWebPath()) { + tr.td().ah(sd.getWebPath()).tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); + } else { + tr.td().ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod").tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); + } + render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod").getValue()); + } + + // dynamic management + if (qi.hasEnableWhen()) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(context.formatPhrase(RenderingContext.QUEST_EN)); + td = tr.td(); + if (qi.getEnableWhen().size() == 1) { + renderEnableWhen(td, qi.getEnableWhen().get(0)); + } else { + if (qi.hasEnableBehavior()) { + td.tx(qi.getEnableBehavior().getDisplay()+" "+(context.formatPhrase(RenderingContext.QUEST_TRUE))); + } else { + td.tx(context.formatPhrase(RenderingContext.QUEST_ARE_TRUE)); + } + XhtmlNode ul = td.ul(); + for (QuestionnaireItemEnableWhenComponent ew : qi.getEnableWhen()) { + renderEnableWhen(ul.li(), ew); + } + } + } + + + // other stuff + + + + List curr = new ArrayList<>(); + curr.addAll(parents); + curr.add(qi); + for (QuestionnaireItemComponent qic : qi.getItem()) { + ext = renderDefinition(tbl, q, qic, curr) || ext; + } + return ext; + } + + private void defn(XhtmlNode tbl, String name, String url, Resource res) throws UnsupportedEncodingException, IOException { + if (res != null && res.hasWebPath()) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), RendererFactory.factory(res, context).display(res), res.getWebPath()); + } else if (Utilities.isAbsoluteUrlLinkable(url)) { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), url, url); + } { + defn(tbl, context.formatPhrase(RenderingContext.QUEST_DEFINITION), url); + } + + } + + private void renderEnableWhen(XhtmlNode x, QuestionnaireItemEnableWhenComponent ew) { + x.ah("#item."+ew.getQuestion()).tx(ew.getQuestion()); + x.tx(" "); + x.tx(ew.getOperator().toCode()); + x.tx(" "); + x.tx(display(ew.getAnswer())); + } + + private XhtmlNode defn(XhtmlNode tbl, String name) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + return tr.td(); + } + + private void defn(XhtmlNode tbl, String name, int value) { + if (value > 0) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + tr.td().tx(value); + } + } + + + private void defn(XhtmlNode tbl, String name, boolean value) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + tr.td().tx(Boolean.toString(value)); + } + + private void defn(XhtmlNode tbl, String name, String value) { + if (!Utilities.noString(value)) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + tr.td().tx(value); + } + } + + private void defn(XhtmlNode tbl, String name, String value, String url) { + if (!Utilities.noString(value)) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + tr.td().ah(url).tx(value); + } + } + + private void defn(XhtmlNode tbl, String name, String nurl, String value, String url) { + if (!Utilities.noString(value)) { + XhtmlNode tr = tbl.tr(); + tr.td().ah(nurl).tx(name); + if (url != null) { + tr.td().ah(url).tx(value); + } else { + tr.td().tx(value); + } + } + } + + private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) { + if (ifFalse || value) { + XhtmlNode tr = tbl.tr(); + tr.td().tx(name); + tr.td().tx(Boolean.toString(value)); + } + } + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index 07198f468..14a3feac9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -1,4754 +1,4754 @@ -package org.hl7.fhir.r5.renderers; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Stack; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.exceptions.DefinitionException; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.exceptions.FHIRFormatError; -import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation; -import org.hl7.fhir.r5.conformance.profile.BindingResolution; -import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; -import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ElementChoiceGroup; -import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ExtensionContext; -import org.hl7.fhir.r5.formats.IParser; -import org.hl7.fhir.r5.formats.IParser.OutputStyle; -import org.hl7.fhir.r5.formats.JsonParser; -import org.hl7.fhir.r5.formats.XmlParser; -import org.hl7.fhir.r5.model.ActorDefinition; -import org.hl7.fhir.r5.model.Base; -import org.hl7.fhir.r5.model.BooleanType; -import org.hl7.fhir.r5.model.CanonicalResource; -import org.hl7.fhir.r5.model.CanonicalType; -import org.hl7.fhir.r5.model.CodeSystem; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.CodeableConcept; -import org.hl7.fhir.r5.model.Coding; -import org.hl7.fhir.r5.model.DataType; -import org.hl7.fhir.r5.model.DecimalType; -import org.hl7.fhir.r5.model.Element; -import org.hl7.fhir.r5.model.ElementDefinition; -import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS; -import org.hl7.fhir.r5.model.ElementDefinition.AggregationMode; -import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionExampleComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingComponent; -import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent; -import org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation; -import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules; -import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; -import org.hl7.fhir.r5.model.Enumeration; -import org.hl7.fhir.r5.model.Enumerations.BindingStrength; -import org.hl7.fhir.r5.model.Extension; -import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.IntegerType; -import org.hl7.fhir.r5.model.MarkdownType; -import org.hl7.fhir.r5.model.PrimitiveType; -import org.hl7.fhir.r5.model.Quantity; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.StringType; -import org.hl7.fhir.r5.model.StructureDefinition; -import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; -import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent; -import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; -import org.hl7.fhir.r5.model.UriType; -import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; -import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.InternalMarkdownProcessor; -import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.RenderStyle; -import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.SourcedElementDefinition; -import org.hl7.fhir.r5.renderers.utils.RenderingContext; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.FixedValueFormat; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; -import org.hl7.fhir.r5.renderers.utils.RenderingContext.StructureDefinitionRendererMode; -import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; -import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; -import org.hl7.fhir.r5.utils.PublicationHacker; -import org.hl7.fhir.r5.utils.ToolingExtensions; -import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.MarkDownProcessor; -import org.hl7.fhir.utilities.StandardsStatus; -import org.hl7.fhir.utilities.TextFile; -import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.i18n.I18nConstants; -import org.hl7.fhir.utilities.i18n.RenderingI18nContext; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableGenerationMode; -import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; -import org.hl7.fhir.utilities.xhtml.NodeType; -import org.hl7.fhir.utilities.xhtml.XhtmlNode; -import org.hl7.fhir.utilities.xhtml.XhtmlNodeList; -import org.hl7.fhir.utilities.xhtml.XhtmlParser; - -public class StructureDefinitionRenderer extends ResourceRenderer { - - public enum RenderStyle { - - } - - public class SourcedElementDefinition { - private StructureDefinition profile; - private ElementDefinition definition; - - - protected SourcedElementDefinition(StructureDefinition profile, ElementDefinition definition) { - super(); - this.profile = profile; - this.definition = definition; - } - public StructureDefinition getProfile() { - return profile; - } - public ElementDefinition getDefinition() { - return definition; - } - - } - - public class InternalMarkdownProcessor implements IMarkdownProcessor { - - @Override - public String processMarkdown(String location, PrimitiveType md) throws FHIRException { - return context.getMarkdown().process(md.primitiveValue(), location); - } - - @Override - public String processMarkdown(String location, String text) throws FHIRException { - return context.getMarkdown().process(text, location); - } - } - - private enum ListItemStatus { New, Unchanged, Removed}; - - private abstract class ItemWithStatus { - ListItemStatus status = ListItemStatus.New; // new, unchanged, removed - - protected abstract void renderDetails(XhtmlNode f) throws IOException; - protected abstract boolean matches(ItemWithStatus other); - - public void render(XhtmlNode x) throws IOException { - XhtmlNode f = x; - if (status == ListItemStatus.Unchanged) { - f = unchanged(f); - } else if (status == ListItemStatus.Removed) { - f = removed(f); - } - renderDetails(f); - } - } - - protected class StatusList extends ArrayList implements List { - - public boolean merge(T item) { - if (item == null) { - return false; - } - boolean found = false; - for (T t : this) { - if (t.matches(item)) { - found = true; - t.status = ListItemStatus.Unchanged; - } - } - if (!found) { - item.status = ListItemStatus.Removed; - return add(item); - } else { - return false; - } - } - - public boolean add(T item) { - if (item != null) { - return super.add(item); - } else { - return false; - } - } - } - - private class ResolvedCanonical extends ItemWithStatus { - String url; // what we used to resolve - CanonicalResource cr; // what we resolved - - public ResolvedCanonical(String url, CanonicalResource cr) { - this.url = url; - this.cr = cr; - } - public void renderDetails(XhtmlNode f) { - if (cr != null && cr.hasWebPath()) { - f.ah(cr.getWebPath()).tx(cr.present()); - } else { - f.code().tx(url); - } - } - protected boolean matches(ItemWithStatus other) { - return ((ResolvedCanonical) other).url.equals(url); - } - } - - private class InvariantWithStatus extends ItemWithStatus { - ElementDefinitionConstraintComponent value; - protected InvariantWithStatus(ElementDefinitionConstraintComponent value) { - this.value = value; - } - - protected boolean matches(ItemWithStatus other) { - return ((InvariantWithStatus) other).value.equalsDeep(value); - } - - public void renderDetails(XhtmlNode f) { - f = renderStatus(value, f); - f.b().attribute("title", context.formatPhrase(RenderingContext.STRUC_DEF_FII)).tx(value.getKey()); - f.tx(": "); - if (value.hasHuman()) { - renderStatus(value.getHumanElement(), f).tx(value.getHuman()); - } else if (VersionComparisonAnnotation.hasDeleted(value, "human")) { - Base b =VersionComparisonAnnotation.getDeletedItem(value, "human"); - renderStatus(b, f).tx(b.primitiveValue()); - } - f.tx(" ("); - if (status == ListItemStatus.New) { - if (value.hasExpression()) { - renderStatus(value.getExpressionElement(), f).code().tx(value.getExpression()); - } else if (VersionComparisonAnnotation.hasDeleted(value, "expression")) { - Base b = VersionComparisonAnnotation.getDeletedItem(value, "expression"); - renderStatus(b, f).code().tx(b.primitiveValue()); - } - } else { - renderStatus(value.getExpressionElement(), f).tx(value.getExpression()); - } - f.tx(")"); - } - } - - private class DiscriminatorWithStatus extends ItemWithStatus { - ElementDefinitionSlicingDiscriminatorComponent value; - protected DiscriminatorWithStatus(ElementDefinitionSlicingDiscriminatorComponent value) { - this.value = value; - } - - protected boolean matches(ItemWithStatus other) { - return ((DiscriminatorWithStatus) other).value.equalsDeep(value); - } - - public void renderDetails(XhtmlNode f) { - f.tx(value.getType().toCode()); - f.tx(" @ "); - f.tx(value.getPath()); - } - } - - private class ValueWithStatus extends ItemWithStatus { - PrimitiveType value; - protected ValueWithStatus(PrimitiveType value) { - this.value = value; - } - - protected boolean matches(ItemWithStatus other) { - return ((ValueWithStatus) other).value.equalsDeep(value); - } - - public void renderDetails(XhtmlNode f) { - if (value.hasUserData("render.link")) { - f = f.ah(value.getUserString("render.link")); - } - f.tx(value.asStringValue()); - } - - } - - private class DataValueWithStatus extends ItemWithStatus { - DataType value; - protected DataValueWithStatus(DataType value) { - this.value = value; - } - - protected boolean matches(ItemWithStatus other) { - return ((ValueWithStatus) other).value.equalsDeep(value); - } - - public void renderDetails(XhtmlNode f) throws IOException { - - if (value.hasUserData("render.link")) { - f = f.ah(value.getUserString("render.link")); - } - f.tx(summarize(value)); - } - - } - - - private List keyRows = new ArrayList<>(); - private Map> sdMapCache = new HashMap<>(); - private IMarkdownProcessor hostMd; - - public StructureDefinitionRenderer(RenderingContext context) { - super(context); - hostMd = new InternalMarkdownProcessor(); - corePath = context.getContext().getSpecUrl(); - } - - public StructureDefinitionRenderer(RenderingContext context, ResourceContext rcontext) { - super(context, rcontext); - } - - - public Map> getSdMapCache() { - return sdMapCache; - } - - public void setSdMapCache(Map> sdMapCache) { - this.sdMapCache = sdMapCache; - } - - public IMarkdownProcessor getHostMd() { - return hostMd; - } - - public void setHostMd(IMarkdownProcessor hostMd) { - this.hostMd = hostMd; - } - - public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { - return render(x, (StructureDefinition) dr); - } - - public boolean render(XhtmlNode x, StructureDefinition sd) throws FHIRFormatError, DefinitionException, IOException { - if (context.getStructureMode() == StructureDefinitionRendererMode.DATA_DICT) { - renderDict(sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, ""); - } else { - x.getChildNodes().add(generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, - context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context, "")); - } - return true; - } - - public void describe(XhtmlNode x, StructureDefinition sd) { - x.tx(display(sd)); - } - - public String display(StructureDefinition sd) { - return sd.present(); - } - - @Override - public String display(Resource r) throws UnsupportedEncodingException, IOException { - return ((StructureDefinition) r).present(); - } - - public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { - if (r.has("title")) { - return r.children("title").get(0).getBase().primitiveValue(); - } - if (r.has("name")) { - return r.children("name").get(0).getBase().primitiveValue(); - } - return "??"; - } - - - // private static final int AGG_NONE = 0; - // private static final int AGG_IND = 1; - // private static final int AGG_GR = 2; - // private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false; - public static final String CONSTRAINT_CHAR = "C"; - public static final String CONSTRAINT_STYLE = "padding-left: 3px; padding-right: 3px; border: 1px maroon solid; font-weight: bold; color: #301212; background-color: #fdf4f4;"; - public static final int GEN_MODE_SNAP = 1; - public static final int GEN_MODE_DIFF = 2; - public static final int GEN_MODE_MS = 3; - public static final int GEN_MODE_KEY = 4; - public static final String RIM_MAPPING = "http://hl7.org/v3"; - public static final String v2_MAPPING = "http://hl7.org/v2"; - public static final String LOINC_MAPPING = "http://loinc.org"; - public static final String SNOMED_MAPPING = "http://snomed.info"; - - private final boolean ADD_REFERENCE_TO_TABLE = true; - - private boolean useTableForFixedValues = true; - private String corePath; - - public static class UnusedTracker { - private boolean used; - } - - private class SpanEntry { - private List children = new ArrayList(); - private boolean profile; - private String id; - private String name; - private String resType; - private String cardinality; - private String description; - private String profileLink; - private String resLink; - private String type; - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - public String getResType() { - return resType; - } - public void setResType(String resType) { - this.resType = resType; - } - public String getCardinality() { - return cardinality; - } - public void setCardinality(String cardinality) { - this.cardinality = cardinality; - } - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - public String getProfileLink() { - return profileLink; - } - public void setProfileLink(String profileLink) { - this.profileLink = profileLink; - } - public String getResLink() { - return resLink; - } - public void setResLink(String resLink) { - this.resLink = resLink; - } - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } - public boolean isProfile() { - return profile; - } - public void setProfile(boolean profile) { - this.profile = profile; - } - public List getChildren() { - return children; - } - public String getType() { - return type; - } - public void setType(String type) { - this.type = type; - } - - } - - private class ElementInStructure { - - private StructureDefinition source; - private ElementDefinition element; - - public ElementInStructure(StructureDefinition source, ElementDefinition ed) { - this.source = source; - this.element = ed; - } - - public StructureDefinition getSource() { - return source; - } - - public ElementDefinition getElement() { - return element; - } - - } - private ElementInStructure getElementByName(List elements, String contentReference, StructureDefinition source) { - if (contentReference.contains("#")) { - String url = contentReference.substring(0, contentReference.indexOf("#")); - contentReference = contentReference.substring(contentReference.indexOf("#")); - if (Utilities.noString(url)) { - url = source.getUrl(); - } - if (!url.equals(source.getUrl())) { - source = context.getWorker().fetchResource(StructureDefinition.class, url, source); - if (source == null) { - throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_REND_UNABLE_RES, url, contentReference)); - } - elements = source.getSnapshot().getElement(); - } +package org.hl7.fhir.r5.renderers; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Stack; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation; +import org.hl7.fhir.r5.conformance.profile.BindingResolution; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ElementChoiceGroup; +import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ExtensionContext; +import org.hl7.fhir.r5.formats.IParser; +import org.hl7.fhir.r5.formats.IParser.OutputStyle; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.ActorDefinition; +import org.hl7.fhir.r5.model.Base; +import org.hl7.fhir.r5.model.BooleanType; +import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.DataType; +import org.hl7.fhir.r5.model.DecimalType; +import org.hl7.fhir.r5.model.Element; +import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS; +import org.hl7.fhir.r5.model.ElementDefinition.AggregationMode; +import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionExampleComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingComponent; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent; +import org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation; +import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules; +import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; +import org.hl7.fhir.r5.model.Enumeration; +import org.hl7.fhir.r5.model.Enumerations.BindingStrength; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.IntegerType; +import org.hl7.fhir.r5.model.MarkdownType; +import org.hl7.fhir.r5.model.PrimitiveType; +import org.hl7.fhir.r5.model.Quantity; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent; +import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; +import org.hl7.fhir.r5.model.UriType; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; +import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.InternalMarkdownProcessor; +import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.RenderStyle; +import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer.SourcedElementDefinition; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.FixedValueFormat; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.StructureDefinitionRendererMode; +import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext; +import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; +import org.hl7.fhir.r5.utils.PublicationHacker; +import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.MarkDownProcessor; +import org.hl7.fhir.utilities.StandardsStatus; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.i18n.RenderingI18nContext; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableGenerationMode; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; +import org.hl7.fhir.utilities.xhtml.NodeType; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; +import org.hl7.fhir.utilities.xhtml.XhtmlNodeList; +import org.hl7.fhir.utilities.xhtml.XhtmlParser; + +public class StructureDefinitionRenderer extends ResourceRenderer { + + public enum RenderStyle { + + } + + public class SourcedElementDefinition { + private StructureDefinition profile; + private ElementDefinition definition; + + + protected SourcedElementDefinition(StructureDefinition profile, ElementDefinition definition) { + super(); + this.profile = profile; + this.definition = definition; } - for (ElementDefinition ed : elements) { - if (("#"+ed.getPath()).equals(contentReference)) { - return new ElementInStructure(source, ed); - } - if (("#"+ed.getId()).equals(contentReference)) { - return new ElementInStructure(source, ed); - } - } - throw new Error(context.formatPhrase(RenderingContext.STRUC_DEF_CANT_FIND, contentReference, elements.toString(), source.getUrl())); - // return null; - } - - public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set outputTracker) throws IOException, FHIRException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); - TableModel model = gen.initGridTable(corePath, profile.getId()); - List list = profile.getSnapshot().getElement(); - List profiles = new ArrayList(); - profiles.add(profile); - genGridElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, true, profileBaseFileName, null, corePath, imagePath, true, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list)); - try { - return gen.generate(model, imagePath, 1, outputTracker); - } catch (org.hl7.fhir.exceptions.FHIRException e) { - throw new FHIRException(e.getMessage(), e); - } - } - - - private static class Column { - String id; - String title; - String hint; - private String link; - - protected Column(String id, String title, String hint) { - super(); - this.id = id; - this.title = title; - this.hint = hint; - } - protected Column(String id, String title, String hint, String link) { - super(); - this.id = id; - this.title = title; - this.hint = hint; - this.link = link; - } - - } - - public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, - boolean logicalModel, boolean allInvariants, Set outputTracker, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { - assert(diff != snapshot);// check it's ok to get rid of one of these - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); - - List list; - if (diff) - list = supplementMissingDiffElements(profile); - else { - list = new ArrayList<>(); - list.addAll(profile.getSnapshot().getElement()); - } - - List columns = new ArrayList<>(); - TableModel model; - switch (context.getStructureMode()) { - case BINDINGS: - scanBindings(columns, list); - model = initCustomTable(gen, corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, columns); - break; - case OBLIGATIONS: - scanObligations(columns, list); - model = initCustomTable(gen, corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, columns); - break; - case SUMMARY: - model = gen.initNormalTable(corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, rc.getRules() == GenerationRules.IG_PUBLISHER ? TableGenerationMode.XHTML : TableGenerationMode.XML); - break; - default: - throw new Error(context.formatPhrase(RenderingContext.STRUC_DEF_ERROR)); - } - - List profiles = new ArrayList(); - 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, profile, columns); - try { - return gen.generate(model, imagePath, 0, outputTracker); - } catch (org.hl7.fhir.exceptions.FHIRException e) { - throw new FHIRException(context.getWorker().formatMessage(I18nConstants.ERROR_GENERATING_TABLE_FOR_PROFILE__, profile.getUrl(), e.getMessage()), e); - } - } - - private void scanBindings(List columns, List list) { - Set cols = new HashSet<>(); - scanBindings(cols, list, list.get(0)); - if (cols.contains("required")) { - columns.add(new Column("required", context.formatPhrase(RenderingContext.STRUC_DEF_REQ), context.formatPhrase(RenderingContext.STRUC_DEF_CONC_SET))); - } - if (cols.contains("extensible")) { - columns.add(new Column("extensible", context.formatPhrase(RenderingContext.STRUC_DEF_EXT), context.formatPhrase(RenderingContext.STRUC_DEF_APPROP_CON))); - } - if (cols.contains("maximum")) { - columns.add(new Column("maximum", context.formatPhrase(RenderingContext.STRUC_DEF_MAX), context.formatPhrase(RenderingContext.STRUC_DEF_REQ_BIND))); - } - if (cols.contains("minimum")) { - columns.add(new Column("minimum", context.formatPhrase(RenderingContext.STRUC_DEF_MIN), context.formatPhrase(RenderingContext.STRUC_DEF_MIN_ALLOW))); - } - if (cols.contains("candidate")) { - columns.add(new Column("candidate", context.formatPhrase(RenderingContext.STRUC_DEF_CAND), context.formatPhrase(RenderingContext.STRUC_DEF_CAND_SUB))); - } - if (cols.contains("current")) { - columns.add(new Column("current", context.formatPhrase(RenderingContext.STRUC_DEF_CURR), context.formatPhrase(RenderingContext.STRUC_DEF_CURR_RULE))); - } - if (cols.contains("preferred")) { - columns.add(new Column("preferred", context.formatPhrase(RenderingContext.STRUC_DEF_PREF), context.formatPhrase(RenderingContext.STRUC_DEF_PREF_CONT))); - } - if (cols.contains("ui")) { - columns.add(new Column("ui", context.formatPhrase(RenderingContext.STRUC_DEF_UI), context.formatPhrase(RenderingContext.STRUC_DEF_UI_CONT))); - } - if (cols.contains("starter")) { - columns.add(new Column("starter", context.formatPhrase(RenderingContext.STRUC_DEF_START), context.formatPhrase(RenderingContext.STRUC_DEF_START_DEF))); - } - if (cols.contains("component")) { - columns.add(new Column("component", context.formatPhrase(RenderingContext.STRUC_DEF_COMP), context.formatPhrase(RenderingContext.STRUC_DEF_COMP_DOC))); - } - if (cols.contains("example")) { - columns.add(new Column("example", context.formatPhrase(RenderingContext.STRUC_DEF_EX), context.formatPhrase(RenderingContext.STRUC_DEF_EX_DESC))); - } - } - - public void scanBindings(Set cols, List list, ElementDefinition ed) { - if (ed.hasBinding()) { - if (ed.getBinding().hasValueSet() && ed.getBinding().hasStrength()) { - switch (ed.getBinding().getStrength()) { - case EXAMPLE: - cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_EXAM)); - break; - case EXTENSIBLE: - cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_EXTENSIBLE)); - break; - case PREFERRED: - cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_PREFERRED)); - break; - case REQUIRED: - cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_REQUIRED)); - break; - default: - break; - } - } - for (ElementDefinitionBindingAdditionalComponent ab : ed.getBinding().getAdditional()) { - cols.add(ab.getPurpose().toCode()); - } - for (Extension ext : ed.getBinding().getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { - cols.add(ext.getExtensionString("purpose")); - } - } - - List children = getChildren(list, ed); - for (ElementDefinition element : children) { - scanBindings(cols, list, element); - } - } - - private void scanObligations(List columns, List list) { - Set cols = new HashSet<>(); - scanObligations(cols, list, list.get(0)); - - if (cols.contains("$all")) { - columns.add(new Column("$all", context.formatPhrase(RenderingContext.STRUC_DEF_ALL_ACTORS), context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ALL))); - } - for (String col : cols) { - if (!"$all".equals(col)) { - ActorDefinition actor = context.getWorker().fetchResource(ActorDefinition.class, col); - if (actor == null) { - columns.add(new Column(col, tail(col), context.formatPhrase(RenderingContext.STRUC_DEF_UNDEF_ACT, col, col)+" ")); - } else { - columns.add(new Column(col, actor.getName(), context.formatPhrase(RenderingContext.STRUC_DEF_ACT, actor.present(), actor.getWebPath())+" ")); - } - } - } - } - - private void scanObligations(Set cols, List list, ElementDefinition ed) { - - for (Extension ob : ed.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { - if (ob.hasExtension("actor", "actorId")) { - for (Extension a : ob.getExtensionsByUrl("actor", "actorId")) { - cols.add(a.getValueCanonicalType().primitiveValue()); - } - } else - cols.add("$all"); - } - - List children = getChildren(list, ed); - for (ElementDefinition element : children) { - scanObligations(cols, list, element); - } - } - - public TableModel initCustomTable(HierarchicalTableGenerator gen, String prefix, boolean isLogical, boolean alternating, String id, boolean isActive, List columns) throws IOException { - TableModel model = gen.new TableModel(id, isActive); - - model.setAlternating(alternating); - if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { - model.setDocoImg(HierarchicalTableGenerator.help16AsData()); - } else { - model.setDocoImg(Utilities.pathURL(prefix, "help16.png")); - } - model.setDocoRef(Utilities.pathURL("https://build.fhir.org/ig/FHIR/ig-guidance", "readingIgs.html#table-views")); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.STRUC_DEF_NAME)), (context.formatPhrase(RenderingContext.STRUC_DEF_LOGIC_NAME)), null, 0)); - for (Column col : columns) { - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (col.title), (col.hint), null, 0)); - } - return model; - } - - private Row genElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, - boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc, String anchorPrefix, Resource srcSD, List columns) throws IOException, FHIRException { - Row originalRow = slicingRow; - StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); - Row typesRow = null; - - List children = getChildren(all, element); - // if (!snapshot && isExtension && extensions != null && extensions != isExtension) - // return; - - if (!onlyInformationIsMapping(all, element)) { - Row row = gen.new Row(); - row.setId(element.getPath()); - row.setAnchor(element.getPath()); - row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); - if (element.hasSlicing()) - row.setLineColor(1); - else if (element.hasSliceName()) - row.setLineColor(2); - else - row.setLineColor(0); - boolean hasDef = element != null; - boolean ext = false; - if (tail(element.getPath()).equals("extension") && isExtension(element)) { - if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) - row.setIcon("icon_extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); - else - row.setIcon("icon_extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); - ext = true; - } else if (tail(element.getPath()).equals("modifierExtension")) { - if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) - row.setIcon("icon_modifier_extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); - else - row.setIcon("icon_modifier_extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); - } else if (!hasDef || element.getType().size() == 0) { - if (root && profile != null && context.getWorker().getResourceNames().contains(profile.getType())) { - row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); - } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { - row.setIcon("icon-object-box.png", context.formatPhrase(RenderingContext.TEXT_ICON_OBJECT_BOX)); - keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); - } else { - row.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); - } - } else if (hasDef && element.getType().size() > 1) { - if (allAreReference(element.getType())) { - row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); - } else if (element.hasExtension(ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { - row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); - } else { - row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); - typesRow = row; - } - } else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) { - row.setIcon("icon_reuse.png", context.formatPhrase(RenderingContext.TEXT_ICON_REUSE)); - } else if (hasDef && context.getContext().isPrimitiveType(element.getType().get(0).getWorkingCode())) { - if (keyRows.contains(element.getId())) { - row.setIcon("icon-key.png", context.formatPhrase(RenderingContext.TEXT_ICON_KEY)); - } else { - row.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); - } - } else if (hasDef && element.getType().get(0).hasTarget()) { - row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); - } else if (hasDef && context.getContext().isDataType(element.getType().get(0).getWorkingCode())) { - row.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); - } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { - row.setIcon("icon-object-box.png", context.formatPhrase(RenderingContext.TEXT_ICON_OBJECT_BOX)); - keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); - } else if (hasDef && Utilities.existsInList(element.getType().get(0).getWorkingCode(), "Base", "Element", "BackboneElement")) { - row.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); - } else { - row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); - } - if (element.hasUserData("render.opaque")) { - row.setOpacity("0.5"); - } - UnusedTracker used = new UnusedTracker(); - String ref = defPath == null ? null : defPath + anchorPrefix + element.getId(); - String sName = tail(element.getPath()); - if (element.hasSliceName()) { - sName = sName +":"+element.getSliceName(); - } - used.used = true; - if (logicalModel) { - if (element.hasRepresentation(PropertyRepresentation.XMLATTR)) { - sName = "@"+sName; - } else if (element.hasUserData("derived.pointer")) { - ElementDefinition drv = (ElementDefinition) element.getUserData("derived.pointer"); - if (drv.hasRepresentation(PropertyRepresentation.XMLATTR)) { - sName = "@"+sName; - } - } - } - Cell nc = genElementNameCell(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, all); - switch (context.getStructureMode()) { - case BINDINGS: - genElementBindings(gen, element, columns, row, profile, corePath); - break; - case OBLIGATIONS: - genElementObligations(gen, element, columns, row, corePath, profile); - break; - case SUMMARY: - genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport, true, rc, children.size() > 0); - break; - } - if (element.hasSlicing()) { - if (standardExtensionSlicing(element)) { - used.used = true; // doesn't matter whether we have a type, we're used if we're setting up slicing ... element.hasType() && element.getType().get(0).hasProfile(); - showMissing = false; //? - slicingRow = row; - } else { - row.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); - slicingRow = row; - for (Cell cell : row.getCells()) - for (Piece p : cell.getPieces()) { - p.addStyle("font-style: italic"); - } - } - } else if (element.hasSliceName()) { - row.setIcon("icon_slice_item.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE_ITEM)); - } - if (used.used || showMissing) - rows.add(row); - if (!used.used && !element.hasSlicing()) { - for (Cell cell : row.getCells()) - for (Piece p : cell.getPieces()) { - p.setStyle("text-decoration:line-through"); - p.setReference(null); - } - } else { - if (slicingRow != originalRow && !children.isEmpty()) { - // we've entered a slice; we're going to create a holder row for the slice children - Row hrow = gen.new Row(); - hrow.setId(element.getPath()); - hrow.setAnchor(element.getPath()); - hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); - hrow.setLineColor(1); - hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); - hrow.getCells().add(gen.new Cell(null, null, sName+ (context.formatPhrase(RenderingContext.STRUC_DEF_ALL_SLICES)), "", null)); - switch (context.getStructureMode()) { - case BINDINGS: - case OBLIGATIONS: - for (Column col : columns) { - hrow.getCells().add(gen.new Cell()); - } - break; - case SUMMARY: - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_RULE), "", null)); - break; - } - row.getSubRows().add(hrow); - row = hrow; - } - if (typesRow != null && !children.isEmpty()) { - // we've entered a typing slice; we're going to create a holder row for the all types children - Row hrow = gen.new Row(); - hrow.setId(element.getPath()); - hrow.setAnchor(element.getPath()); - hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); - hrow.setLineColor(1); - hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); - hrow.getCells().add(gen.new Cell(null, null, sName+ context.formatPhrase(RenderingContext.STRUC_DEF_ALL_TYPES), "", null)); - switch (context.getStructureMode()) { - case BINDINGS: - case OBLIGATIONS: - for (Column col : columns) { - hrow.getCells().add(gen.new Cell()); - } - break; - case SUMMARY: - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell()); - hrow.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_TYPE), "", null)); - } - row.getSubRows().add(hrow); - row = hrow; - } - - Row slicer = null; - List groups = readChoices(element, children); - boolean isExtension = Utilities.existsInList(tail(element.getPath()), "extension", "modifierExtension"); - if (!element.prohibited()) { - for (ElementDefinition child : children) { - Row parent = null; - if (child.hasSliceName()) { - // ok, we're a slice - if (slicer == null || !slicer.getId().equals(child.getPath())) { - parent = gen.new Row(); - parent.setId(child.getPath()); - parent.setAnchor(child.getPath()); - parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); - parent.setLineColor(1); - parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); - parent.getCells().add(gen.new Cell(null, null, "Slices for "+ child.getName(), "", null)); - switch (context.getStructureMode()) { - case BINDINGS: - case OBLIGATIONS: - for (Column col : columns) { - parent.getCells().add(gen.new Cell()); - } - break; - case SUMMARY: - parent.getCells().add(gen.new Cell()); - parent.getCells().add(gen.new Cell()); - parent.getCells().add(gen.new Cell()); - parent.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_RULE), "", null)); - break; - } - row.getSubRows().add(parent); - slicer = parent; - } else { - parent = slicer; - } - } else { - parent = chooseChildRowByGroup(gen, row, groups, child, element, isConstraintMode); - } - - if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) { - slicer = genElement(defPath, gen, parent.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, slicer, mustSupport, rc, anchorPrefix, srcSD, columns); - } - } - } - // if (!snapshot && (extensions == null || !extensions)) - // for (ElementDefinition child : children) - // if (child.getPath().endsWith(".extension") || child.getPath().endsWith(".modifierExtension")) - // genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants); - } - if (typesRow != null && !element.prohibited() && context.getStructureMode() == StructureDefinitionRendererMode.SUMMARY) { - makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport, srcSD); - } - } - return slicingRow; - } - - private boolean isTypeSlice(ElementDefinition child) { - ElementDefinition derived = (ElementDefinition) child.getUserData("derived.pointer"); - return derived != null && derived.getBase().getPath().endsWith("[x]"); - } - - private boolean isExtension(ElementDefinition element) { - if (element.getType().isEmpty()) { - return true; - } - String type = element.getTypeFirstRep().getWorkingCode(); - return "Extension".equals(type); - } - - private void genElementObligations(HierarchicalTableGenerator gen, ElementDefinition element, List columns, Row row, String corePath, StructureDefinition profile) throws IOException { - for (Column col : columns) { - Cell gc = gen.new Cell(); - row.getCells().add(gc); - ObligationsRenderer obr = new ObligationsRenderer(corePath, profile, element.getPath(), context, null, this); - obr.seeObligations(element, col.id); - obr.renderList(gen, gc); - } - } - - private String displayForUsage(Coding c) { - if (c.hasDisplay()) { - return c.getDisplay(); - } - if ("http://terminology.hl7.org/CodeSystem/usage-context-type".equals(c.getSystem())) { - return c.getCode(); - } - return c.getCode(); - } - - private void genElementBindings(HierarchicalTableGenerator gen, ElementDefinition element, List columns, Row row, StructureDefinition profile, String corepath) { - for (Column col : columns) { - Cell gc = gen.new Cell(); - row.getCells().add(gc); - List bindings = collectBindings(element, col.id); - if (bindings.size() > 0) { - Piece p = gen.new Piece(null); - gc.addPiece(p); - new AdditionalBindingsRenderer(context.getPkp(), corepath, profile, element.getPath(), context, null, this).render(p.getChildren(), bindings); - } - } - } - - private List collectBindings(ElementDefinition element, String type) { - List res = new ArrayList<>(); - if (element.hasBinding()) { - ElementDefinitionBindingComponent b = element.getBinding(); - if (b.hasStrength() && type.equals(b.getStrength().toCode())) { - ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); - res.add(ab.setAny(false).setDocumentation(b.getDescription()).setValueSet(b.getValueSet())); - } - if ("maximum".equals(type) && b.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { - ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); - res.add(ab.setAny(false).setValueSet(ToolingExtensions.readStringExtension(b, ToolingExtensions.EXT_MAX_VALUESET))); - } - if ("minimum".equals(type) && b.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { - ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); - res.add(ab.setAny(false).setValueSet(ToolingExtensions.readStringExtension(b, ToolingExtensions.EXT_MIN_VALUESET))); - } - for (ElementDefinitionBindingAdditionalComponent t : b.getAdditional()) { - if (type.equals(t.getPurpose().toCode())) { - res.add(t); - } - } - for (Extension ext : b.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { - if (type.equals(ext.getExtensionString("purpose"))) { - ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); - if (ext.hasExtension("any")) { - ab.setAny(ToolingExtensions.readBooleanExtension(ext, "any")); - } - if (ext.hasExtension("purpose")) { - ab.setPurpose(AdditionalBindingPurposeVS.fromCode(ToolingExtensions.readStringExtension(ext, "purpose"))); - } - if (ext.hasExtension("documentation")) { - ab.setDocumentation(ToolingExtensions.readStringExtension(ext, "documentation")); - } - if (ext.hasExtension("shortDoco")) { - ab.setShortDoco(ToolingExtensions.readStringExtension(ext, "shortDoco")); - } - if (ToolingExtensions.hasExtension(ext, "usage")) { - ab.addUsage(ext.getExtensionByUrl("usage").getValueUsageContext()); - } - if (ext.hasExtension("valueSet")) { - ab.setValueSet(ToolingExtensions.readStringExtension(ext, "valueSet")); - } - res.add(ab); - } - } - } - return res; - } - - public Cell genElementNameCell(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, - String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, - boolean ext, UnusedTracker used, String ref, String sName, List elements) throws IOException { - String hint = ""; - hint = checkAdd(hint, element.hasSliceName() ? context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_PAR, element.getSliceName()) : ""); - if (hasDef && element.hasDefinition()) { - hint = checkAdd(hint, (hasDef && element.hasSliceName() ? ": " : "")); - hint = checkAdd(hint, !hasDef ? null : gt(element.getDefinitionElement())); - } - if (element.hasSlicing() && slicesExist(elements, element)) { // some elements set up slicing but don't actually slice, so we don't augment the name - sName = context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_FOR, sName); - } - Cell left = gen.new Cell(null, ref, sName, hint, null); - row.getCells().add(left); - return left; - } - - public List genElementCells(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, - String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, - boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport, boolean allowSubRows, RenderingContext rc, boolean walksIntoThis) throws IOException { - List res = new ArrayList<>(); - Cell gc = gen.new Cell(); - row.getCells().add(gc); - res.add(gc); - if (element != null && element.getIsModifier()) { - checkForNoChange(element.getIsModifierElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_MOD)), "?!", null, null, null, false)); - } - if (element != null) { - if (element.getMustSupport() && element.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { - checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_SUPP)), "SO", "white", "red", null, false)); - } else if (element.getMustSupport()) { - checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_SUPP)), "S", "white", "red", null, false)); - } else if (element != null && element.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { - checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG)), "O", "white", "red", null, false)); - } - } - if (element != null && element.getIsSummary()) { - checkForNoChange(element.getIsSummaryElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_SUMM)), "\u03A3", null, null, null, false)); - } - if (element != null && element.getMustHaveValue()) { - checkForNoChange(element.getMustHaveValueElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_ELE)), "V", "maroon", null, null, true)); - } - if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) { - Piece p = gc.addText(CONSTRAINT_CHAR); - p.setHint((context.formatPhrase(RenderingContext.STRUC_DEF_ELE_AFFECTED, listConstraintsAndConditions(element), ")"))); - p.addStyle(CONSTRAINT_STYLE); - p.setReference(Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()), "conformance-rules.html#constraints")); - } - if (element != null && element.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { - StandardsStatus ss = StandardsStatus.fromCode(element.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); - gc.addStyledText(context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STATUS) +ss.toDisplay(), ss.getAbbrev(), context.formatPhrase(RenderingContext.STRUC_DEF_BLACK), ss.getColor(), context.getWorker().getSpecUrl()+"versions.html#std-process", true); - } - - ExtensionContext extDefn = null; - if (ext) { - if (element != null) { - if (element.getType().size() == 1 && element.getType().get(0).hasProfile()) { - String eurl = element.getType().get(0).getProfile().get(0).getValue(); - extDefn = locateExtension(StructureDefinition.class, eurl); - if (extDefn == null) { - res.add(genCardinality(gen, element, row, hasDef, used, null)); - res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null))); - res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); - } else { - String name = element.hasSliceName() ? element.getSliceName() : urltail(eurl); - nameCell.getPieces().get(0).setText(name); - // left.getPieces().get(0).setReference((String) extDefn.getExtensionStructure().getTag("filename")); - nameCell.getPieces().get(0).setHint((context.formatPhrase(RenderingContext.STRUC_DEF_EX_URL, extDefn.getUrl()))); - res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement())); - ElementDefinition valueDefn = walksIntoThis ? null : extDefn.getExtensionValueDefinition(); - if (valueDefn != null && !"0".equals(valueDefn.getMax())) - res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); - else // if it's complex, we just call it nothing - // genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile); - res.add(addCell(row, gen.new Cell(null, null, "("+(context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEX))+")", null, null))); - res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport, allowSubRows, rc)); - } - } else { - res.add(genCardinality(gen, element, row, hasDef, used, null)); - if ("0".equals(element.getMax())) - res.add(addCell(row, gen.new Cell())); - else - res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); - res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); - } - } - } else if (element != null) { - res.add(genCardinality(gen, element, row, hasDef, used, null)); - if (hasDef && !"0".equals(element.getMax()) && typesRow == null) - res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); - else - res.add(addCell(row, gen.new Cell())); - res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); - } - return res; - } - - private Cell genCardinality(HierarchicalTableGenerator gen, ElementDefinition definition, Row row, boolean hasDef, UnusedTracker tracker, ElementDefinition fallback) { - IntegerType min = !hasDef ? new IntegerType() : definition.hasMinElement() ? definition.getMinElement() : new IntegerType(); - StringType max = !hasDef ? new StringType() : definition.hasMaxElement() ? definition.getMaxElement() : new StringType(); - if (min.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { - ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); - if (base.hasMinElement()) { - min = base.getMinElement().copy(); - min.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); - } - } - if (max.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { - ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); - if (base.hasMaxElement()) { - max = base.getMaxElement().copy(); - max.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); - } - } - if (min.isEmpty() && fallback != null) - min = fallback.getMinElement(); - if (max.isEmpty() && fallback != null) - max = fallback.getMaxElement(); - - if (!max.isEmpty()) - tracker.used = !max.getValue().equals("0"); - - String hint = null; - if (max.hasValue() && min.hasValue() && "*".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 = context.formatPhrase(RenderingContext.STRUC_DEF_JSON_IS); - } else { - hint = context.formatPhrase(RenderingContext.STRUC_DEF_JSON_MAY); - } - } - } - Cell cell = gen.new Cell(null, null, null, null, null); - row.getCells().add(cell); - if (!min.isEmpty() || !max.isEmpty()) { - cell.addPiece(checkForNoChange(min, gen.new Piece(null, !min.hasValue() ? "" : Integer.toString(min.getValue()), hint))); - cell.addPiece(checkForNoChange(min, max, gen.new Piece(null, "..", hint))); - cell.addPiece(checkForNoChange(max, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), hint))); - } - return cell; - } - - public List supplementMissingDiffElements(StructureDefinition profile) { - List list = new ArrayList<>(); - list.addAll(profile.getDifferential().getElement()); - if (list.isEmpty()) { - ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); - root.setId(profile.getTypeName()); - list.add(root); - } else { - if (list.get(0).getPath().contains(".")) { - ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); - root.setId(profile.getTypeName()); - list.add(0, root); - } - } - insertMissingSparseElements(list); - return list; - } - - private boolean usesMustSupport(List list) { - for (ElementDefinition ed : list) - if (ed.hasMustSupport() && ed.getMustSupport()) - return true; - return false; - } - - - - private Row chooseChildRowByGroup(HierarchicalTableGenerator gen, Row row, List groups, ElementDefinition element, ElementDefinition parent, boolean isConstraintMode) { - String name = tail(element.getPath()); - for (ElementChoiceGroup grp : groups) { - if (grp.getElements().contains(name)) { - if (grp.getRow() == null) { - grp.setRow(makeChoiceElementRow(gen, row, grp, parent, isConstraintMode)); - } - return grp.getRow(); - } - } - return row; - } - - private Row makeChoiceElementRow(HierarchicalTableGenerator gen, Row prow, ElementChoiceGroup grp, ElementDefinition parent, boolean isConstraintMode) { - if (context.getStructureMode() != StructureDefinitionRendererMode.SUMMARY) { - return prow; - } - Row row = gen.new Row(); - row.setId(parent.getPath()+"-"+grp.getName()); - row.setAnchor(parent.getPath()+"-"+grp.getName()); - row.setColor(context.getProfileUtilities().getRowColor(parent, isConstraintMode)); - row.setLineColor(1); - row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); - row.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE), "", null)); - row.getCells().add(gen.new Cell()); - row.getCells().add(gen.new Cell(null, null, (grp.isMandatory() ? "1" : "0")+"..1", "", null)); - row.getCells().add(gen.new Cell()); - row.getCells().add(gen.new Cell()); - prow.getSubRows().add(row); - return row; - } - - - private void insertMissingSparseElements(List list) { - int i = 1; - while (i < list.size()) { - String[] pathCurrent = list.get(i).getPath().split("\\."); - String[] pathLast = list.get(i-1).getPath().split("\\."); - int firstDiff = 0; // the first entry must be a match - while (firstDiff < pathCurrent.length && firstDiff < pathLast.length && pathCurrent[firstDiff].equals(pathLast[firstDiff])) { - firstDiff++; - } - if (!(isSibling(pathCurrent, pathLast, firstDiff) || isChild(pathCurrent, pathLast, firstDiff))) { - // now work backwards down to lastMatch inserting missing path nodes - ElementDefinition parent = findParent(list, i, list.get(i).getPath()); - int parentDepth = Utilities.charCount(parent.getPath(), '.')+1; - int childDepth = Utilities.charCount(list.get(i).getPath(), '.')+1; - if (childDepth > parentDepth + 1) { - String basePath = parent.getPath(); - String baseId = parent.getId(); - for (int index = parentDepth; index >= firstDiff; index--) { - String mtail = makeTail(pathCurrent, parentDepth, index); - ElementDefinition root = new ElementDefinition().setPath(basePath+"."+mtail); - root.setId(baseId+"."+mtail); - list.add(i, root); - } - } + public StructureDefinition getProfile() { + return profile; + } + public ElementDefinition getDefinition() { + return definition; + } + + } + + public class InternalMarkdownProcessor implements IMarkdownProcessor { + + @Override + public String processMarkdown(String location, PrimitiveType md) throws FHIRException { + return context.getMarkdown().process(md.primitiveValue(), location); + } + + @Override + public String processMarkdown(String location, String text) throws FHIRException { + return context.getMarkdown().process(text, location); + } + } + + private enum ListItemStatus { New, Unchanged, Removed}; + + private abstract class ItemWithStatus { + ListItemStatus status = ListItemStatus.New; // new, unchanged, removed + + protected abstract void renderDetails(XhtmlNode f) throws IOException; + protected abstract boolean matches(ItemWithStatus other); + + public void render(XhtmlNode x) throws IOException { + XhtmlNode f = x; + if (status == ListItemStatus.Unchanged) { + f = unchanged(f); + } else if (status == ListItemStatus.Removed) { + f = removed(f); } - i++; - } - } - - - private String urltail(String path) { - if (path.contains("#")) - return path.substring(path.lastIndexOf('#')+1); - if (path.contains("/")) - return path.substring(path.lastIndexOf('/')+1); - else - return path; - - } - - private boolean standardExtensionSlicing(ElementDefinition element) { - String t = tail(element.getPath()); - return (t.equals("extension") || t.equals("modifierExtension")) - && element.getSlicing().getRules() != SlicingRules.CLOSED && element.getSlicing().getDiscriminator().size() == 1 && element.getSlicing().getDiscriminator().get(0).getPath().equals("url") && element.getSlicing().getDiscriminator().get(0).getType().equals(DiscriminatorType.VALUE); - } - - public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { - return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows, rc); - } - - public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { - Cell c = gen.new Cell(); - row.getCells().add(c); - - if (used) { - if (logicalModel && ToolingExtensions.hasAnyOfExtensions(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { - if (root) { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); - } else if (!root && ToolingExtensions.hasAnyOfExtensions(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) && - !ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED).equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED))) { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); - } - } - if (root) { - if (profile != null && profile.getAbstract()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ABSTRACT) +(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profile" : "type")+". ", null)); - - List children = new ArrayList<>(); - for (StructureDefinition sd : context.getWorker().fetchResourcesByType(StructureDefinition.class)) { - if (sd.hasBaseDefinition() && sd.getBaseDefinition().equals(profile.getUrl())) { - children.add(sd); - } - } - if (!children.isEmpty()) { - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_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.getWebPath(), sd.getName(), null)); - } - } - } - if (logicalModel) { - List ancestors = new ArrayList<>(); - getAncestorElements(profile, ancestors); - if (ancestors.size() > 0) { - c.addPiece(gen.new Piece("br")); - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ELEMENTS), null)); - boolean first = true; - for (SourcedElementDefinition ed : ancestors) { - if (first) - first = false; - else - c.addPiece(gen.new Piece(null, ", ", null)); - c.addPiece(gen.new Piece(ed.getProfile().getWebPath(), (isAttr(ed) ? "@" : "")+ed.getDefinition().getName(), ed.getDefinition().getDefinition())); - } - } - } - } - if (definition.getPath().endsWith("url") && definition.hasFixed()) { - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen"))); - } else { - if (definition != null && definition.hasShort()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(checkForNoChange(definition.getShortElement(), gen.new Piece(null, gt(definition.getShortElement()), null))); - } else if (fallback != null && fallback.hasShort()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, gt(fallback.getShortElement()), null).addStyle("opacity: 0.5")); - } - if (url != null) { - if (!c.getPieces().isEmpty()) - c.addPiece(gen.new Piece("br")); - String fullUrl = url.startsWith("#") ? baseURL+url : url; - StructureDefinition ed = context.getWorker().fetchResource(StructureDefinition.class, url, profile); - String ref = null; - String ref2 = null; - String fixedUrl = null; - if (ed != null) { - ref = ed.getWebPath(); - fixedUrl = getFixedUrl(ed); - if (fixedUrl != null) {// if its null, we guess that it's not a profiled extension? - if (fixedUrl.equals(url)) - fixedUrl = null; - else { - StructureDefinition ed2 = context.getWorker().fetchResource(StructureDefinition.class, fixedUrl); - if (ed2 != null) { - String p2 = ed2.getWebPath(); - if (p2 != null) { - ref2 = p2.startsWith("http:") || context.getRules() == GenerationRules.IG_PUBLISHER ? p2 : Utilities.pathURL(corePath, p2); - } - } - } - } - } - if (fixedUrl == null) { - if (!Utilities.noString(fullUrl)) { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_URL))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(ref, fullUrl, null)); - } - } else { - // reference to a profile take on the extension show the base URL - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_URL))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(ref2, fixedUrl, null)); - c.getPieces().add(gen.new Piece(null, (" "+context.formatPhrase(RenderingContext.STRUC_DEF_PROFILED)+" ")+" ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(ref, fullUrl, null)); - - } - } - - if (definition.hasSlicing()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_SLICE))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); - } - if (!definition.getPath().contains(".") && ToolingExtensions.hasExtension(profile, ToolingExtensions.EXT_BINDING_STYLE)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SET)+" "), null)); - c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_BINDING_STYLE), null)); - c.getPieces().add(gen.new Piece(null, " "+context.formatPhrase(RenderingContext.STRUC_DEF_BINDING_STYLE), null)); - } - if (definition.hasValueAlternatives()) { - addCanonicalList(gen, c, definition.getValueAlternatives(), "The primitive value may be replaced by the extension", true); - } - if (definition.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_ELE_READ)+" "), null)); - Piece piece = gen.new Piece("code"); - piece.addHtml(new XhtmlNode(NodeType.Text).setContent(ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_IMPLIED_PREFIX))); - c.getPieces().add(piece); - c.getPieces().add(gen.new Piece(null, " "+ (context.formatPhrase(RenderingContext.STRUC_DEF_PREFIXED)), null)); - } - - if (definition.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - String es = definition.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); - if ("named-elements".equals(es)) { - if (rc.hasLink(KnownLinkType.JSON_NAMES)) { - c.getPieces().add(gen.new Piece(rc.getLink(KnownLinkType.JSON_NAMES), context.formatPhrase(RenderingContext.STRUC_DEF_EXT_JSON), null)); - } else { - c.getPieces().add(gen.new Piece(ToolingExtensions.WEB_EXTENSION_STYLE, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_JSON), null)); - } - } - } - if (definition.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) { - String df = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_DATE_FORMAT); - if (df != null) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_DATE, df)+" "), null)); - } - } - if (definition.hasExtension(ToolingExtensions.EXT_ID_EXPECTATION)) { - String ide = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_ID_EXPECTATION); - if (ide.equals("optional")) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_IS), null)); - } else if (ide.equals("required")) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_MAY), null)); - } else if (ide.equals("required")) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_NOT_ALLOW), null)); - } - } - if (definition.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_GRP))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT), null)); - } - if (definition.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED), null)); - c.getPieces().add(gen.new Piece(null, " (", null)); - c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); - c.getPieces().add(gen.new Piece(null, ")", null)); - } else { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_ELE))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED), null)); - } - } else if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); - } - if (definition.hasExtension(ToolingExtensions.EXT_JSON_EMPTY)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_EMPTY); - if ("present".equals(code)) { - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_INFERRED), null)); - } else { - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ARRAY), null)); - } - } - String jn = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED); - if (!Utilities.noString(jn)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - if (definition.getPath().contains(".")) { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NAME))+": ", null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, jn, null)); - } else { - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_JSON_TYPE))+": ", null).addStyle("font-weight:bold")); - Piece piece = gen.new Piece("code"); - piece.addHtml(new XhtmlNode(NodeType.Text).setContent(jn)); - c.getPieces().add(piece); - } - } - - if (ToolingExtensions.readBoolExtension(definition, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_INFERRED), null)); - } - if (ToolingExtensions.readBoolExtension(definition, ToolingExtensions.EXT_JSON_NULLABLE)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NULL), null)); - } - if (definition.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_PROP_KEY); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SINGLE_JSON_OBJECTS, code), null)); - } - if (definition.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { - for (Extension e : definition.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - String cond = ToolingExtensions.readStringExtension(e, "condition"); - String type = ToolingExtensions.readStringExtension(e, "type"); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_IF), null)); - Piece piece = gen.new Piece("code"); - piece.addHtml(new XhtmlNode(NodeType.Text).setContent(cond)); - c.getPieces().add(piece); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_THEN_TYPE), null)); - StructureDefinition sd = context.getWorker().fetchTypeDefinition(type); - if (sd == null) { - c.getPieces().add(gen.new Piece("")); - c.getPieces().add(gen.new Piece(null, type, null)); - c.getPieces().add(gen.new Piece("")); - } else { - c.getPieces().add(gen.new Piece(sd.getWebPath(), sd.getTypeName(), null)); - } - } - } - if (root) { - if (ToolingExtensions.readBoolExtension(profile, ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ADD), null).addStyle("font-weight:bold")); - } - addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_INHERITS), "This profile picks up obligations and additional bindings from the profile", true); - addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE), "This profile also imposes the profile", true); - addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE), "This profile also complies with the profile", true); - - if (profile.getKind() == StructureDefinitionKind.LOGICAL) { - Extension lt = ToolingExtensions.getExtension(profile, ToolingExtensions.EXT_LOGICAL_TARGET); - if (lt == null || !lt.hasValueBooleanType()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARK), null).addStyle("font-weight:bold")); ; - } else if (lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { - } else if (!lt.getValueBooleanType().hasValue()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); ; - } else if (lt.getValueBooleanType().booleanValue()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); - } else { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); - } - String ps = ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE); - if (ps != null) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - if ("cda".equals(ps)) { - c.addPiece(gen.new Piece(null,context.formatPhrase(RenderingContext.STRUC_DEF_TEMPLATEID), null).addStyle("font-weight:bold")); - } else { - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_VALID_UNKNOWN, ps)+" ", null).addStyle("font-weight:bold")); - } - } - Extension lc = ToolingExtensions.getExtension(profile, ToolingExtensions.EXT_LOGICAL_CONTAINER); - if (lc != null && lc.hasValueUriType()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_LOGIC))+": ", context.formatPhrase(RenderingContext.STRUC_DEF_ROOT)).addStyle("font-weight:bold")); - - String uri = lc.getValue().primitiveValue(); - StructureDefinition lct = context.getContext().fetchTypeDefinition(uri); - if (lct != null) { - c.addPiece(gen.new Piece(lct.getWebPath(), lct.present(), null)); - } else { - c.addPiece(gen.new Piece(null, uri, null)); - } - } - } - } - if (definition != null) { - ElementDefinitionBindingComponent binding = null; - if (valueDefn != null && valueDefn.hasBinding() && !valueDefn.getBinding().isEmpty()) - binding = makeUnifiedBinding(valueDefn.getBinding(), valueDefn); - else if (definition.hasBinding()) - binding = makeUnifiedBinding(definition.getBinding(), definition); - if (binding!=null && !binding.isEmpty()) { - if (!c.getPieces().isEmpty()) - c.addPiece(gen.new Piece("br")); - BindingResolution br = context.getPkp() == null ? makeNullBr(binding) : context.getPkp().resolveBinding(profile, binding, definition.getPath()); - c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(binding.getValueSetElement(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); - if (binding.hasStrength()) { - c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, " (", null))); - c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition()))); - c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, ")", null))); - } - if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) { - c.getPieces().add(gen.new Piece(null, ": ", null)); - c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()).asStringValue(), checkForNoChange(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()))); - } - - AdditionalBindingsRenderer abr = new AdditionalBindingsRenderer(context.getPkp(), corePath, profile, definition.getPath(), rc, null, this); - abr.seeAdditionalBindings(definition, null, false); - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { - abr.seeMaxBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MAX_VALUESET)); - } - if (binding.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { - abr.seeMinBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MIN_VALUESET)); - } - if (binding.hasExtension(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { - abr.seeAdditionalBindings(binding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)); - } - abr.render(gen, c); - } - for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { -// if (!inv.hasSource() || profile == null || inv.getSource().equals(profile.getUrl()) || allInvariants) { - if (!inv.hasSource() || profile == null || allInvariants || (!isAbstractBaseProfile(inv.getSource()) && !"http://hl7.org/fhir/StructureDefinition/Extension".equals(inv.getSource()))) { - if (!c.getPieces().isEmpty()) - c.addPiece(gen.new Piece("br")); - c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, gt(inv.getHumanElement()), null))); - } - } - if ((definition.hasBase() && "*".equals(definition.getBase().getMax())) || (definition.hasMax() && "*".equals(definition.getMax()))) { - if (c.getPieces().size() > 0) - c.addPiece(gen.new Piece("br")); - if (definition.hasOrderMeaning()) { - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT_ELE, definition.getOrderMeaning()), null)); - } else { - // don't show this, this it's important: c.getPieces().add(gen.new Piece(null, "This repeating element has no defined order", null)); - } - } - if (definition.hasFixed()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_FIXED))+": ", null).addStyle("font-weight:bold"))); - if (!useTableForFixedValues || !allowSubRows || definition.getFixed().isPrimitive()) { - String s = buildJson(definition.getFixed()); - String link = null; - if (Utilities.isAbsoluteUrl(s) && context.getPkp() != null) - link = context.getPkp().getLinkForUrl(corePath, s); - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen"))); - } else { - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_AS_SHOWN), null).addStyle("color: darkgreen"))); - genFixedValue(gen, row, definition.getFixed(), snapshot, false, corePath, false); - } - if (isCoded(definition.getFixed()) && !hasDescription(definition.getFixed())) { - Piece p = describeCoded(gen, definition.getFixed()); - if (p != null) - c.getPieces().add(p); - } - } else if (definition.hasPattern()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_REQ_PATT))+": ", null).addStyle("font-weight:bold"))); - if (!useTableForFixedValues || !allowSubRows || definition.getPattern().isPrimitive()) - c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); - else { - c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_LEAST_FOLLOW), null).addStyle("color: darkgreen"))); - genFixedValue(gen, row, definition.getPattern(), snapshot, true, corePath, mustSupportOnly); - } - } else if (definition.hasExample()) { - for (ElementDefinitionExampleComponent ex : definition.getExample()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_EXAMPLE))+("".equals("General")? "" : " "+ex.getLabel())+": ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); - } - } - - ObligationsRenderer obr = new ObligationsRenderer(corePath, profile, definition.getPath(), rc, null, this); - if (definition.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { - obr.seeObligations(definition.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); - } - if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { - obr.seeObligations(profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); - } - obr.renderTable(gen, c); - - if (definition.hasMaxLength() && definition.getMaxLength()!=0) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); - } - if (profile != null) { - for (StructureDefinitionMappingComponent md : profile.getMapping()) { - if (md.hasExtension(ToolingExtensions.EXT_TABLE_NAME)) { - ElementDefinitionMappingComponent map = null; - for (ElementDefinitionMappingComponent m : definition.getMapping()) - if (m.getIdentity().equals(md.getIdentity())) - map = m; - if (map != null) { - for (int i = 0; i t : ed.getDefinition().getRepresentation()) { - if (t.getValue() == PropertyRepresentation.XMLATTR) { - return true; - } - } - return false; - } - - private void getAncestorElements(StructureDefinition profile, List ancestors) { - StructureDefinition base = context.getContext().fetchResource(StructureDefinition.class, profile.getBaseDefinition()); - if (base != null) { - getAncestorElements(base, ancestors); - for (ElementDefinition ed : base.getDifferential().getElement()) { - if (Utilities.charCount(ed.getPath(), '.') == 1) { - ancestors.add(new SourcedElementDefinition(base, ed)); - } - } - } - } - - private void addCanonicalListExt(HierarchicalTableGenerator gen, Cell c, List list, String start, boolean bold) { - List clist = new ArrayList<>(); - for (Extension ext : list) { - if (ext.hasValueCanonicalType()) { - clist.add(ext.getValueCanonicalType()); - } - } - addCanonicalList(gen, c, clist, start, bold); - } - - private void addCanonicalList(HierarchicalTableGenerator gen, Cell c, List list, String start, boolean bold) { - if (!list.isEmpty()) { - - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - Piece p = gen.new Piece(null, start+(list.size() != 1 ? "s" : "")+" ", null); - c.addPiece(p); - if (bold) p.addStyle("font-weight:bold"); - - for (int i = 0; i < list.size(); i++) { - CanonicalType ct = list.get(i); - if (i > 0) { - if (i < list.size() - 1) { - c.addPiece(gen.new Piece(null, ", ", null)); - } else { - c.addPiece(gen.new Piece(null, " and ", null)); - } - } - String iu = ct.primitiveValue(); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, iu); - if (sd == null) { - p = gen.new Piece(null, iu, null).addStyle("font-weight:bold"); - c.addPiece(p); - } else { - String v = ""; - if (iu.contains("|") || hasMultipleVersions(context.getContext().fetchResourcesByUrl(StructureDefinition.class, iu))) { - v = " ("+sd.getVersion()+")"; - } - if (sd.hasWebPath()) { - p = gen.new Piece(sd.getWebPath(), sd.present()+v, null).addStyle("font-weight:bold"); - c.addPiece(p); - } else { - p = gen.new Piece(iu, sd.present()+v, null).addStyle("font-weight:bold"); - c.addPiece(p); - } - } - if (bold) p.addStyle("font-weight:bold"); - } - } - } - - private Piece checkForNoChange(Element source, Piece piece) { - if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { - piece.addStyle("opacity: 0.5"); - } - return piece; - } - - private String checkForNoChange(Element source) { - if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { - return "opacity: 0.5"; + renderDetails(f); + } + } + + protected class StatusList extends ArrayList implements List { + + public boolean merge(T item) { + if (item == null) { + return false; + } + boolean found = false; + for (T t : this) { + if (t.matches(item)) { + found = true; + t.status = ListItemStatus.Unchanged; + } + } + if (!found) { + item.status = ListItemStatus.Removed; + return add(item); + } else { + return false; + } + } + + public boolean add(T item) { + if (item != null) { + return super.add(item); + } else { + return false; + } + } + } + + private class ResolvedCanonical extends ItemWithStatus { + String url; // what we used to resolve + CanonicalResource cr; // what we resolved + + public ResolvedCanonical(String url, CanonicalResource cr) { + this.url = url; + this.cr = cr; + } + public void renderDetails(XhtmlNode f) { + if (cr != null && cr.hasWebPath()) { + f.ah(cr.getWebPath()).tx(cr.present()); + } else { + f.code().tx(url); + } + } + protected boolean matches(ItemWithStatus other) { + return ((ResolvedCanonical) other).url.equals(url); + } + } + + private class InvariantWithStatus extends ItemWithStatus { + ElementDefinitionConstraintComponent value; + protected InvariantWithStatus(ElementDefinitionConstraintComponent value) { + this.value = value; + } + + protected boolean matches(ItemWithStatus other) { + return ((InvariantWithStatus) other).value.equalsDeep(value); + } + + public void renderDetails(XhtmlNode f) { + f = renderStatus(value, f); + f.b().attribute("title", context.formatPhrase(RenderingContext.STRUC_DEF_FII)).tx(value.getKey()); + f.tx(": "); + if (value.hasHuman()) { + renderStatus(value.getHumanElement(), f).tx(value.getHuman()); + } else if (VersionComparisonAnnotation.hasDeleted(value, "human")) { + Base b =VersionComparisonAnnotation.getDeletedItem(value, "human"); + renderStatus(b, f).tx(b.primitiveValue()); + } + f.tx(" ("); + if (status == ListItemStatus.New) { + if (value.hasExpression()) { + renderStatus(value.getExpressionElement(), f).code().tx(value.getExpression()); + } else if (VersionComparisonAnnotation.hasDeleted(value, "expression")) { + Base b = VersionComparisonAnnotation.getDeletedItem(value, "expression"); + renderStatus(b, f).code().tx(b.primitiveValue()); + } + } else { + renderStatus(value.getExpressionElement(), f).tx(value.getExpression()); + } + f.tx(")"); + } + } + + private class DiscriminatorWithStatus extends ItemWithStatus { + ElementDefinitionSlicingDiscriminatorComponent value; + protected DiscriminatorWithStatus(ElementDefinitionSlicingDiscriminatorComponent value) { + this.value = value; + } + + protected boolean matches(ItemWithStatus other) { + return ((DiscriminatorWithStatus) other).value.equalsDeep(value); + } + + public void renderDetails(XhtmlNode f) { + f.tx(value.getType().toCode()); + f.tx(" @ "); + f.tx(value.getPath()); + } + } + + private class ValueWithStatus extends ItemWithStatus { + PrimitiveType value; + protected ValueWithStatus(PrimitiveType value) { + this.value = value; + } + + protected boolean matches(ItemWithStatus other) { + return ((ValueWithStatus) other).value.equalsDeep(value); + } + + public void renderDetails(XhtmlNode f) { + if (value.hasUserData("render.link")) { + f = f.ah(value.getUserString("render.link")); + } + f.tx(value.asStringValue()); + } + + } + + private class DataValueWithStatus extends ItemWithStatus { + DataType value; + protected DataValueWithStatus(DataType value) { + this.value = value; + } + + protected boolean matches(ItemWithStatus other) { + return ((ValueWithStatus) other).value.equalsDeep(value); + } + + public void renderDetails(XhtmlNode f) throws IOException { + + if (value.hasUserData("render.link")) { + f = f.ah(value.getUserString("render.link")); + } + f.tx(summarize(value)); + } + + } + + + private List keyRows = new ArrayList<>(); + private Map> sdMapCache = new HashMap<>(); + private IMarkdownProcessor hostMd; + + public StructureDefinitionRenderer(RenderingContext context) { + super(context); + hostMd = new InternalMarkdownProcessor(); + corePath = context.getContext().getSpecUrl(); + } + + public StructureDefinitionRenderer(RenderingContext context, ResourceContext rcontext) { + super(context, rcontext); + } + + + public Map> getSdMapCache() { + return sdMapCache; + } + + public void setSdMapCache(Map> sdMapCache) { + this.sdMapCache = sdMapCache; + } + + public IMarkdownProcessor getHostMd() { + return hostMd; + } + + public void setHostMd(IMarkdownProcessor hostMd) { + this.hostMd = hostMd; + } + + public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException { + return render(x, (StructureDefinition) dr); + } + + public boolean render(XhtmlNode x, StructureDefinition sd) throws FHIRFormatError, DefinitionException, IOException { + if (context.getStructureMode() == StructureDefinitionRendererMode.DATA_DICT) { + renderDict(sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, ""); } else { - return null; - } - } - - private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) { - Cell c = gen.new Cell(); - r.getCells().add(c); - if (e.hasContentReference()) { - ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), e.getContentReference(), profile); - if (ed == null) - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_REF, e.getContentReference())+" ", null)); - else { - if (ed.getSource() == profile) { - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SEE)+" ", null)); - c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath())); - } else { - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SEE)+" ", null)); - c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getWebPath())+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getTypeName()+")", ed.getElement().getPath())); - } - } - return c; - } - List types = e.getType(); - if (!e.hasType()) { - if (root) { // we'll use base instead of types then - StructureDefinition bsd = profile == null ? null : context.getWorker().fetchResource(StructureDefinition.class, profile.getBaseDefinition(), profile); - if (bsd != null) { - String v = ""; - if (profile != null && (profile.getBaseDefinition().contains("|") || hasMultipleVersions(context.getWorker().fetchResourcesByUrl(StructureDefinition.class, profile.getBaseDefinition())))) { - v = v +"("+bsd.getVersion()+")"; - } - if (bsd.hasWebPath()) { - c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getWebPath()) ? bsd.getWebPath() : imagePath +bsd.getWebPath(), bsd.getName()+v, null)); - } else { - c.getPieces().add(gen.new Piece(null, bsd.getName()+v, null)); - } - } - return c; - } else if (e.hasContentReference()) { - return c; - } else { - ElementDefinition d = (ElementDefinition) e.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); - if (d != null && d.hasType()) { - types = new ArrayList(); - for (TypeRefComponent tr : d.getType()) { - TypeRefComponent tt = tr.copy(); - tt.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); - types.add(tt); - } - } else { - return c; - } - } - } - - boolean first = true; - - TypeRefComponent tl = null; - for (TypeRefComponent t : types) { - if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) { - if (first) { - first = false; - } else { - c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); - } - tl = t; - if (t.hasTarget()) { - if (t.hasProfile()) { - String ref = t.getProfile().get(0).asStringValue(); - StructureDefinition tsd = context.getContext().fetchResource(StructureDefinition.class, ref); - if (tsd != null) { - // if there's multiple possible matches in scope, we will be explicit about the version - if (ref.contains("|") || hasMultipleVersions(context.getContext().fetchResourcesByUrl(StructureDefinition.class, ref))) { - c.getPieces().add(gen.new Piece(tsd.getWebPath(), tsd.getName()+"("+tsd.getVersion()+")", tsd.present())); - } else { - c.getPieces().add(gen.new Piece(tsd.getWebPath(), tsd.getName(), tsd.present())); - } - } else { - c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); - } - } else { - c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); - } - if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); - } - c.getPieces().add(gen.new Piece(null, "(", null)); - boolean tfirst = true; - for (CanonicalType u : t.getTargetProfile()) { - if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) { - if (tfirst) - tfirst = false; - else - c.addPiece(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue(), null); - if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); - } - } - } - c.getPieces().add(gen.new Piece(null, ")", null)); - if (t.getAggregation().size() > 0) { - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null)); - boolean firstA = true; - for (Enumeration a : t.getAggregation()) { - if (firstA == true) - firstA = false; - else - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", ", ", null)); - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", codeForAggregation(a.getValue()), hintForAggregation(a.getValue()))); - } - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null)); - } - } else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type - String ref; - boolean pfirst = true; - for (CanonicalType p : t.getProfile()) { - if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) { - if (pfirst) { - pfirst = false; - } else { - c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); - } - - ref = context.getPkp() == null ? null : context.getPkp().getLinkForProfile(profile, p.getValue()); - if (ref != null) { - String[] parts = ref.split("\\|"); - if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) { - if (p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) { - String pp = p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT); - pp = pp.substring(pp.indexOf(".")); - c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1]+pp, t.getWorkingCode()))); - } else { - c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode()))); - } - } else { - c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode()))); - } - } else { - c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); - } - if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_PROF_SUPP)), "S", "white", "red", null, false); - } - } - } - } else { - String tc = t.getWorkingCode(); - if (Utilities.isAbsoluteUrl(tc)) { - StructureDefinition sd = context.getWorker().fetchTypeDefinition(tc); - if (sd == null) { - c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), tc, null))); - } else { - c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), sd.getTypeName(), null))); - } - } else if (context.getPkp() != null && context.getPkp().hasLinkFor(tc)) { - c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), tc, null))); - } else { - c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); - } - if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); - } - } - } - } - return c; - } - - - private boolean hasMultipleVersions(List list) { - Set vl = new HashSet<>(); - for (CanonicalResource cr : list) { - vl.add(cr.getVersion()); - } - return vl.size() > 1; - } - - private String pfx(String prefix, String url) { - return Utilities.isAbsoluteUrl(url) ? url : prefix + url; - } - - private void genTargetLink(HierarchicalTableGenerator gen, String profileBaseFileName, String corePath, Cell c, TypeRefComponent t, String u, Resource src) { - if (u.startsWith("http://hl7.org/fhir/StructureDefinition/")) { - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, u, src); - if (sd != null) { - String disp = sd.hasTitle() ? sd.getTitle() : sd.getName(); - c.addPiece(checkForNoChange(t, gen.new Piece(checkPrepend(corePath, sd.getWebPath()), disp, null))); - } else { - String rn = u.substring(40); - c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, rn), rn, null))); - } - } else if (Utilities.isAbsoluteUrl(u)) { - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, u, src); - if (sd != null && context.getPkp() != null) { - String v = ""; - if (u.contains("|") || hasMultipleVersions(context.getWorker().fetchResourcesByUrl(StructureDefinition.class, u))) { - v = "("+sd.getVersion()+")"; - } - String disp = sd.present()+v; - String ref = context.getPkp().getLinkForProfile(null, sd.getUrl()); - if (ref != null && ref.contains("|")) - ref = ref.substring(0, ref.indexOf("|")); - c.addPiece(checkForNoChange(t, gen.new Piece(ref, disp, null))); - } else - c.addPiece(checkForNoChange(t, gen.new Piece(null, u, null))); - } else if (t.hasTargetProfile() && u.startsWith("#")) - c.addPiece(checkForNoChange(t, gen.new Piece(corePath+profileBaseFileName+"."+u.substring(1).toLowerCase()+".html", u, null))); - } - - private boolean isProfiledType(List theProfile) { - for (CanonicalType next : theProfile){ - if (StringUtils.defaultString(next.getValueAsString()).contains(":")) { - return true; - } - } - return false; - } - - - public String codeForAggregation(AggregationMode a) { - switch (a) { - case BUNDLED : return "b"; - case CONTAINED : return "c"; - case REFERENCED: return "r"; - default: return "?"; - } - } - - public String hintForAggregation(AggregationMode a) { - if (a != null) - return a.getDefinition(); - else - return null; - } - - - private String checkPrepend(String corePath, String path) { - if (context.getPkp() != null && context.getPkp().prependLinks() && !(path.startsWith("http:") || path.startsWith("https:"))) - return corePath+path; - else - return path; - } - - - private ElementDefinition findParent(List list, int i, String path) { - while (i > 0 && !path.startsWith(list.get(i).getPath()+".")) { - i--; - } - return list.get(i); - } - - private boolean isSibling(String[] pathCurrent, String[] pathLast, int firstDiff) { - return pathCurrent.length == pathLast.length && firstDiff == pathCurrent.length-1; - } - - - private boolean isChild(String[] pathCurrent, String[] pathLast, int firstDiff) { - return pathCurrent.length == pathLast.length+1 && firstDiff == pathLast.length; - } - - private String makeTail(String[] pathCurrent, int start, int index) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("."); - for (int i = start; i <= index; i++) { - b.append(pathCurrent[i]); - } - return b.toString(); - } - - private void genGridElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, String corePath, String imagePath, boolean root, boolean isConstraintMode) throws IOException, FHIRException { - StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); - String s = tail(element.getPath()); - List children = getChildren(all, element); - boolean isExtension = (s.equals("extension") || s.equals("modifierExtension")); - - if (!onlyInformationIsMapping(all, element)) { - Row row = gen.new Row(); - row.setId(s); - row.setAnchor(element.getPath()); - row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); - if (element.hasSlicing()) - row.setLineColor(1); - else if (element.hasSliceName()) - row.setLineColor(2); - else - row.setLineColor(0); - boolean hasDef = element != null; - String ref = defPath == null ? null : defPath + element.getId(); - UnusedTracker used = new UnusedTracker(); - used.used = true; - Cell left = gen.new Cell(); - if (element.getType().size() == 1 && element.getType().get(0).isPrimitive()) - left.getPieces().add(gen.new Piece(ref, "\u00A0\u00A0" + s, !hasDef ? null : gt(element.getDefinitionElement())).addStyle("font-weight:bold")); - else - left.getPieces().add(gen.new Piece(ref, "\u00A0\u00A0" + s, !hasDef ? null : gt(element.getDefinitionElement()))); - if (element.hasSliceName()) { - left.getPieces().add(gen.new Piece("br")); - String indent = StringUtils.repeat('\u00A0', 1+2*(element.getPath().split("\\.").length)); - left.getPieces().add(gen.new Piece(null, indent + "("+element.getSliceName() + ")", null)); - } - row.getCells().add(left); - - genCardinality(gen, element, row, hasDef, used, null); - if (hasDef && !"0".equals(element.getMax())) - genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, false); - else - row.getCells().add(gen.new Cell()); - generateGridDescription(gen, row, element, null, used.used, null, null, profile, corePath, imagePath, root, null); - /* if (element.hasSlicing()) { - if (standardExtensionSlicing(element)) { - used.used = element.hasType() && element.getType().get(0).hasProfile(); - showMissing = false; - } else { - row.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE); - row.getCells().get(2).getPieces().clear(); - for (Cell cell : row.getCells()) - for (Piece p : cell.getPieces()) { - p.addStyle("font-style: italic"); - } - } - }*/ - rows.add(row); - for (ElementDefinition child : children) - if (child.getMustSupport()) - genGridElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, corePath, imagePath, false, isConstraintMode); - } - } - - - private ExtensionContext locateExtension(Class class1, String value) { - if (value.contains("#")) { - StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value.substring(0, value.indexOf("#"))); - if (ext == null) - return null; - String tail = value.substring(value.indexOf("#")+1); - ElementDefinition ed = null; - for (ElementDefinition ted : ext.getSnapshot().getElement()) { - if (tail.equals(ted.getSliceName())) { - ed = ted; - return new ExtensionContext(ext, ed); - } - } - return null; - } else { - StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value); - if (ext == null) - return null; + x.getChildNodes().add(generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, + context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context, "")); + } + return true; + } + + public void describe(XhtmlNode x, StructureDefinition sd) { + x.tx(display(sd)); + } + + public String display(StructureDefinition sd) { + return sd.present(); + } + + @Override + public String display(Resource r) throws UnsupportedEncodingException, IOException { + return ((StructureDefinition) r).present(); + } + + public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { + if (r.has("title")) { + return r.children("title").get(0).getBase().primitiveValue(); + } + if (r.has("name")) { + return r.children("name").get(0).getBase().primitiveValue(); + } + return "??"; + } + + + // private static final int AGG_NONE = 0; + // private static final int AGG_IND = 1; + // private static final int AGG_GR = 2; + // private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false; + public static final String CONSTRAINT_CHAR = "C"; + public static final String CONSTRAINT_STYLE = "padding-left: 3px; padding-right: 3px; border: 1px maroon solid; font-weight: bold; color: #301212; background-color: #fdf4f4;"; + public static final int GEN_MODE_SNAP = 1; + public static final int GEN_MODE_DIFF = 2; + public static final int GEN_MODE_MS = 3; + public static final int GEN_MODE_KEY = 4; + public static final String RIM_MAPPING = "http://hl7.org/v3"; + public static final String v2_MAPPING = "http://hl7.org/v2"; + public static final String LOINC_MAPPING = "http://loinc.org"; + public static final String SNOMED_MAPPING = "http://snomed.info"; + + private final boolean ADD_REFERENCE_TO_TABLE = true; + + private boolean useTableForFixedValues = true; + private String corePath; + + public static class UnusedTracker { + private boolean used; + } + + private class SpanEntry { + private List children = new ArrayList(); + private boolean profile; + private String id; + private String name; + private String resType; + private String cardinality; + private String description; + private String profileLink; + private String resLink; + private String type; + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getResType() { + return resType; + } + public void setResType(String resType) { + this.resType = resType; + } + public String getCardinality() { + return cardinality; + } + public void setCardinality(String cardinality) { + this.cardinality = cardinality; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getProfileLink() { + return profileLink; + } + public void setProfileLink(String profileLink) { + this.profileLink = profileLink; + } + public String getResLink() { + return resLink; + } + public void setResLink(String resLink) { + this.resLink = resLink; + } + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public boolean isProfile() { + return profile; + } + public void setProfile(boolean profile) { + this.profile = profile; + } + public List getChildren() { + return children; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + } + + private class ElementInStructure { + + private StructureDefinition source; + private ElementDefinition element; + + public ElementInStructure(StructureDefinition source, ElementDefinition ed) { + this.source = source; + this.element = ed; + } + + public StructureDefinition getSource() { + return source; + } + + public ElementDefinition getElement() { + return element; + } + + } + private ElementInStructure getElementByName(List elements, String contentReference, StructureDefinition source) { + if (contentReference.contains("#")) { + String url = contentReference.substring(0, contentReference.indexOf("#")); + contentReference = contentReference.substring(contentReference.indexOf("#")); + if (Utilities.noString(url)) { + url = source.getUrl(); + } + if (!url.equals(source.getUrl())) { + source = context.getWorker().fetchResource(StructureDefinition.class, url, source); + if (source == null) { + throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_REND_UNABLE_RES, url, contentReference)); + } + elements = source.getSnapshot().getElement(); + } + } + for (ElementDefinition ed : elements) { + if (("#"+ed.getPath()).equals(contentReference)) { + return new ElementInStructure(source, ed); + } + if (("#"+ed.getId()).equals(contentReference)) { + return new ElementInStructure(source, ed); + } + } + throw new Error(context.formatPhrase(RenderingContext.STRUC_DEF_CANT_FIND, contentReference, elements.toString(), source.getUrl())); + // return null; + } + + public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set outputTracker) throws IOException, FHIRException { + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); + TableModel model = gen.initGridTable(corePath, profile.getId()); + List list = profile.getSnapshot().getElement(); + List profiles = new ArrayList(); + profiles.add(profile); + genGridElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, true, profileBaseFileName, null, corePath, imagePath, true, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list)); + try { + return gen.generate(model, imagePath, 1, outputTracker); + } catch (org.hl7.fhir.exceptions.FHIRException e) { + throw new FHIRException(e.getMessage(), e); + } + } + + + private static class Column { + String id; + String title; + String hint; + private String link; + + protected Column(String id, String title, String hint) { + super(); + this.id = id; + this.title = title; + this.hint = hint; + } + protected Column(String id, String title, String hint, String link) { + super(); + this.id = id; + this.title = title; + this.hint = hint; + this.link = link; + } + + } + + public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, + boolean logicalModel, boolean allInvariants, Set outputTracker, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { + assert(diff != snapshot);// check it's ok to get rid of one of these + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); + + List list; + if (diff) + list = supplementMissingDiffElements(profile); + else { + list = new ArrayList<>(); + list.addAll(profile.getSnapshot().getElement()); + } + + List columns = new ArrayList<>(); + TableModel model; + switch (context.getStructureMode()) { + case BINDINGS: + scanBindings(columns, list); + model = initCustomTable(gen, corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, columns); + break; + case OBLIGATIONS: + scanObligations(columns, list); + model = initCustomTable(gen, corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, columns); + break; + case SUMMARY: + model = gen.initNormalTable(corePath, false, true, profile.getId()+(diff ? "d" : "s"), rc.getRules() == GenerationRules.IG_PUBLISHER, rc.getRules() == GenerationRules.IG_PUBLISHER ? TableGenerationMode.XHTML : TableGenerationMode.XML); + break; + default: + throw new Error(context.formatPhrase(RenderingContext.STRUC_DEF_ERROR)); + } + + List profiles = new ArrayList(); + 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, profile, columns); + try { + return gen.generate(model, imagePath, 0, outputTracker); + } catch (org.hl7.fhir.exceptions.FHIRException e) { + throw new FHIRException(context.getWorker().formatMessage(I18nConstants.ERROR_GENERATING_TABLE_FOR_PROFILE__, profile.getUrl(), e.getMessage()), e); + } + } + + private void scanBindings(List columns, List list) { + Set cols = new HashSet<>(); + scanBindings(cols, list, list.get(0)); + if (cols.contains("required")) { + columns.add(new Column("required", context.formatPhrase(RenderingContext.STRUC_DEF_REQ), context.formatPhrase(RenderingContext.STRUC_DEF_CONC_SET))); + } + if (cols.contains("extensible")) { + columns.add(new Column("extensible", context.formatPhrase(RenderingContext.STRUC_DEF_EXT), context.formatPhrase(RenderingContext.STRUC_DEF_APPROP_CON))); + } + if (cols.contains("maximum")) { + columns.add(new Column("maximum", context.formatPhrase(RenderingContext.STRUC_DEF_MAX), context.formatPhrase(RenderingContext.STRUC_DEF_REQ_BIND))); + } + if (cols.contains("minimum")) { + columns.add(new Column("minimum", context.formatPhrase(RenderingContext.STRUC_DEF_MIN), context.formatPhrase(RenderingContext.STRUC_DEF_MIN_ALLOW))); + } + if (cols.contains("candidate")) { + columns.add(new Column("candidate", context.formatPhrase(RenderingContext.STRUC_DEF_CAND), context.formatPhrase(RenderingContext.STRUC_DEF_CAND_SUB))); + } + if (cols.contains("current")) { + columns.add(new Column("current", context.formatPhrase(RenderingContext.STRUC_DEF_CURR), context.formatPhrase(RenderingContext.STRUC_DEF_CURR_RULE))); + } + if (cols.contains("preferred")) { + columns.add(new Column("preferred", context.formatPhrase(RenderingContext.STRUC_DEF_PREF), context.formatPhrase(RenderingContext.STRUC_DEF_PREF_CONT))); + } + if (cols.contains("ui")) { + columns.add(new Column("ui", context.formatPhrase(RenderingContext.STRUC_DEF_UI), context.formatPhrase(RenderingContext.STRUC_DEF_UI_CONT))); + } + if (cols.contains("starter")) { + columns.add(new Column("starter", context.formatPhrase(RenderingContext.STRUC_DEF_START), context.formatPhrase(RenderingContext.STRUC_DEF_START_DEF))); + } + if (cols.contains("component")) { + columns.add(new Column("component", context.formatPhrase(RenderingContext.STRUC_DEF_COMP), context.formatPhrase(RenderingContext.STRUC_DEF_COMP_DOC))); + } + if (cols.contains("example")) { + columns.add(new Column("example", context.formatPhrase(RenderingContext.STRUC_DEF_EX), context.formatPhrase(RenderingContext.STRUC_DEF_EX_DESC))); + } + } + + public void scanBindings(Set cols, List list, ElementDefinition ed) { + if (ed.hasBinding()) { + if (ed.getBinding().hasValueSet() && ed.getBinding().hasStrength()) { + switch (ed.getBinding().getStrength()) { + case EXAMPLE: + cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_EXAM)); + break; + case EXTENSIBLE: + cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_EXTENSIBLE)); + break; + case PREFERRED: + cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_PREFERRED)); + break; + case REQUIRED: + cols.add(context.formatPhrase(RenderingContext.STRUC_DEF_REQUIRED)); + break; + default: + break; + } + } + for (ElementDefinitionBindingAdditionalComponent ab : ed.getBinding().getAdditional()) { + cols.add(ab.getPurpose().toCode()); + } + for (Extension ext : ed.getBinding().getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { + cols.add(ext.getExtensionString("purpose")); + } + } + + List children = getChildren(list, ed); + for (ElementDefinition element : children) { + scanBindings(cols, list, element); + } + } + + private void scanObligations(List columns, List list) { + Set cols = new HashSet<>(); + scanObligations(cols, list, list.get(0)); + + if (cols.contains("$all")) { + columns.add(new Column("$all", context.formatPhrase(RenderingContext.STRUC_DEF_ALL_ACTORS), context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ALL))); + } + for (String col : cols) { + if (!"$all".equals(col)) { + ActorDefinition actor = context.getWorker().fetchResource(ActorDefinition.class, col); + if (actor == null) { + columns.add(new Column(col, tail(col), context.formatPhrase(RenderingContext.STRUC_DEF_UNDEF_ACT, col, col)+" ")); + } else { + columns.add(new Column(col, actor.getName(), context.formatPhrase(RenderingContext.STRUC_DEF_ACT, actor.present(), actor.getWebPath())+" ")); + } + } + } + } + + private void scanObligations(Set cols, List list, ElementDefinition ed) { + + for (Extension ob : ed.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { + if (ob.hasExtension("actor", "actorId")) { + for (Extension a : ob.getExtensionsByUrl("actor", "actorId")) { + cols.add(a.getValueCanonicalType().primitiveValue()); + } + } else + cols.add("$all"); + } + + List children = getChildren(list, ed); + for (ElementDefinition element : children) { + scanObligations(cols, list, element); + } + } + + public TableModel initCustomTable(HierarchicalTableGenerator gen, String prefix, boolean isLogical, boolean alternating, String id, boolean isActive, List columns) throws IOException { + TableModel model = gen.new TableModel(id, isActive); + + model.setAlternating(alternating); + if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { + model.setDocoImg(HierarchicalTableGenerator.help16AsData()); + } else { + model.setDocoImg(Utilities.pathURL(prefix, "help16.png")); + } + model.setDocoRef(Utilities.pathURL("https://build.fhir.org/ig/FHIR/ig-guidance", "readingIgs.html#table-views")); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatPhrase(RenderingContext.STRUC_DEF_NAME)), (context.formatPhrase(RenderingContext.STRUC_DEF_LOGIC_NAME)), null, 0)); + for (Column col : columns) { + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (col.title), (col.hint), null, 0)); + } + return model; + } + + private Row genElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, + boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc, String anchorPrefix, Resource srcSD, List columns) throws IOException, FHIRException { + Row originalRow = slicingRow; + StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); + Row typesRow = null; + + List children = getChildren(all, element); + // if (!snapshot && isExtension && extensions != null && extensions != isExtension) + // return; + + if (!onlyInformationIsMapping(all, element)) { + Row row = gen.new Row(); + row.setId(element.getPath()); + row.setAnchor(element.getPath()); + row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); + if (element.hasSlicing()) + row.setLineColor(1); + else if (element.hasSliceName()) + row.setLineColor(2); else - return new ExtensionContext(ext, ext.getSnapshot().getElement().get(0)); - } - } - - - private boolean extensionIsComplex(String value) { - if (value.contains("#")) { - StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value.substring(0, value.indexOf("#"))); - if (ext == null) - return false; - String tail = value.substring(value.indexOf("#")+1); - ElementDefinition ed = null; - for (ElementDefinition ted : ext.getSnapshot().getElement()) { - if (tail.equals(ted.getSliceName())) { - ed = ted; - break; - } - } - if (ed == null) - return false; - int i = ext.getSnapshot().getElement().indexOf(ed); - int j = i+1; - while (j < ext.getSnapshot().getElement().size() && !ext.getSnapshot().getElement().get(j).getPath().equals(ed.getPath())) - j++; - return j - i > 5; - } else { - StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value); - return ext != null && ext.getSnapshot().getElement().size() > 5; - } - } - - - - - private BindingResolution makeNullBr(ElementDefinitionBindingComponent binding) { - BindingResolution br = new BindingResolution(); - br.url = "http://none.none/none"; - br.display = context.formatPhrase(RenderingContext.STRUC_DEF_TODO); - return br; - } - - private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) { - if (!element.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { - return binding; - } - ElementDefinition base = (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); - if (!base.hasBinding()) { - return binding; - } - ElementDefinitionBindingComponent o = base.getBinding(); - ElementDefinitionBindingComponent b = new ElementDefinitionBindingComponent(); - b.setUserData(ProfileUtilities.UD_DERIVATION_POINTER, o); - if (binding.hasValueSet()) { - b.setValueSet(binding.getValueSet()); - } else if (o.hasValueSet()) { - b.setValueSet(o.getValueSet()); - b.getValueSetElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getValueSetElement()); - } - if (binding.hasStrength()) { - b.setStrength(binding.getStrength()); - } else if (o.hasStrength()) { - b.setStrength(o.getStrength()); - b.getStrengthElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getStrengthElement()); - } - if (binding.hasDescription()) { - b.setDescription(binding.getDescription()); - } else if (o.hasDescription()) { - b.setDescription(o.getDescription()); - b.getDescriptionElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getDescriptionElement()); - } - // todo: derivation? - b.getExtension().addAll(binding.getExtension()); - return b; - } - - private void genFixedValue(HierarchicalTableGenerator gen, Row erow, DataType value, boolean snapshot, boolean pattern, String corePath, boolean skipnoValue) { - String ref = context.getPkp().getLinkFor(corePath, value.fhirType()); - if (ref != null && ref.contains(".html")) { - ref = ref.substring(0, ref.indexOf(".html"))+"-definitions.html#"; - } else { - ref = "?gen-fv?"; - } - StructureDefinition sd = context.getWorker().fetchTypeDefinition(value.fhirType()); - - for (org.hl7.fhir.r5.model.Property t : value.children()) { - ElementDefinition ed = findElementDefinitionOrNull(sd, t.getName()); - if (ed != null) { // might be null because of added properties across versions - if (t.getValues().size() > 0 || snapshot) { - if (t.getValues().size() == 0 || (t.getValues().size() == 1 && t.getValues().get(0).isEmpty())) { - if (!skipnoValue) { - Row row = gen.new Row(); - row.setId(ed.getPath()); - erow.getSubRows().add(row); - Cell c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : corePath+(VersionUtilities.isR5Plus(context.getWorker().getVersion()) ? "types-definitions.html#"+ed.getBase().getPath() : "element-definitions.html#"+ed.getBase().getPath())), t.getName(), null)); - c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece(null, null, null)); - c = gen.new Cell(); - row.getCells().add(c); - if (!pattern) { - c.addPiece(gen.new Piece(null, "0..0", null)); - row.setIcon("icon_fixed.gif", context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE) /*context.formatPhrase(RenderingContext.TEXT_ICON_FIXED*/); - } else if (context.getContext().isPrimitiveType(t.getTypeCode())) { - row.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); - c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); - } else if (isReference(t.getTypeCode())) { - row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); - c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); + row.setLineColor(0); + boolean hasDef = element != null; + boolean ext = false; + if (tail(element.getPath()).equals("extension") && isExtension(element)) { + if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) + row.setIcon("icon_extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); + else + row.setIcon("icon_extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); + ext = true; + } else if (tail(element.getPath()).equals("modifierExtension")) { + if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) + row.setIcon("icon_modifier_extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); + else + row.setIcon("icon_modifier_extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); + } else if (!hasDef || element.getType().size() == 0) { + if (root && profile != null && context.getWorker().getResourceNames().contains(profile.getType())) { + row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); + } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { + row.setIcon("icon-object-box.png", context.formatPhrase(RenderingContext.TEXT_ICON_OBJECT_BOX)); + keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); + } else { + row.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); + } + } else if (hasDef && element.getType().size() > 1) { + if (allAreReference(element.getType())) { + row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); + } else if (element.hasExtension(ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { + row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); + } else { + row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); + typesRow = row; + } + } else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) { + row.setIcon("icon_reuse.png", context.formatPhrase(RenderingContext.TEXT_ICON_REUSE)); + } else if (hasDef && context.getContext().isPrimitiveType(element.getType().get(0).getWorkingCode())) { + if (keyRows.contains(element.getId())) { + row.setIcon("icon-key.png", context.formatPhrase(RenderingContext.TEXT_ICON_KEY)); + } else { + row.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); + } + } else if (hasDef && element.getType().get(0).hasTarget()) { + row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); + } else if (hasDef && context.getContext().isDataType(element.getType().get(0).getWorkingCode())) { + row.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); + } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { + row.setIcon("icon-object-box.png", context.formatPhrase(RenderingContext.TEXT_ICON_OBJECT_BOX)); + keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); + } else if (hasDef && Utilities.existsInList(element.getType().get(0).getWorkingCode(), "Base", "Element", "BackboneElement")) { + row.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); + } else { + row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); + } + if (element.hasUserData("render.opaque")) { + row.setOpacity("0.5"); + } + UnusedTracker used = new UnusedTracker(); + String ref = defPath == null ? null : defPath + anchorPrefix + element.getId(); + String sName = tail(element.getPath()); + if (element.hasSliceName()) { + sName = sName +":"+element.getSliceName(); + } + used.used = true; + if (logicalModel) { + if (element.hasRepresentation(PropertyRepresentation.XMLATTR)) { + sName = "@"+sName; + } else if (element.hasUserData("derived.pointer")) { + ElementDefinition drv = (ElementDefinition) element.getUserData("derived.pointer"); + if (drv.hasRepresentation(PropertyRepresentation.XMLATTR)) { + sName = "@"+sName; + } + } + } + Cell nc = genElementNameCell(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, all); + switch (context.getStructureMode()) { + case BINDINGS: + genElementBindings(gen, element, columns, row, profile, corePath); + break; + case OBLIGATIONS: + genElementObligations(gen, element, columns, row, corePath, profile); + break; + case SUMMARY: + genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport, true, rc, children.size() > 0); + break; + } + if (element.hasSlicing()) { + if (standardExtensionSlicing(element)) { + used.used = true; // doesn't matter whether we have a type, we're used if we're setting up slicing ... element.hasType() && element.getType().get(0).hasProfile(); + showMissing = false; //? + slicingRow = row; + } else { + row.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); + slicingRow = row; + for (Cell cell : row.getCells()) + for (Piece p : cell.getPieces()) { + p.addStyle("font-style: italic"); + } + } + } else if (element.hasSliceName()) { + row.setIcon("icon_slice_item.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE_ITEM)); + } + if (used.used || showMissing) + rows.add(row); + if (!used.used && !element.hasSlicing()) { + for (Cell cell : row.getCells()) + for (Piece p : cell.getPieces()) { + p.setStyle("text-decoration:line-through"); + p.setReference(null); + } + } else { + if (slicingRow != originalRow && !children.isEmpty()) { + // we've entered a slice; we're going to create a holder row for the slice children + Row hrow = gen.new Row(); + hrow.setId(element.getPath()); + hrow.setAnchor(element.getPath()); + hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); + hrow.setLineColor(1); + hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); + hrow.getCells().add(gen.new Cell(null, null, sName+ (context.formatPhrase(RenderingContext.STRUC_DEF_ALL_SLICES)), "", null)); + switch (context.getStructureMode()) { + case BINDINGS: + case OBLIGATIONS: + for (Column col : columns) { + hrow.getCells().add(gen.new Cell()); + } + break; + case SUMMARY: + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_RULE), "", null)); + break; + } + row.getSubRows().add(hrow); + row = hrow; + } + if (typesRow != null && !children.isEmpty()) { + // we've entered a typing slice; we're going to create a holder row for the all types children + Row hrow = gen.new Row(); + hrow.setId(element.getPath()); + hrow.setAnchor(element.getPath()); + hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); + hrow.setLineColor(1); + hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); + hrow.getCells().add(gen.new Cell(null, null, sName+ context.formatPhrase(RenderingContext.STRUC_DEF_ALL_TYPES), "", null)); + switch (context.getStructureMode()) { + case BINDINGS: + case OBLIGATIONS: + for (Column col : columns) { + hrow.getCells().add(gen.new Cell()); + } + break; + case SUMMARY: + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell()); + hrow.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_TYPE), "", null)); + } + row.getSubRows().add(hrow); + row = hrow; + } + + Row slicer = null; + List groups = readChoices(element, children); + boolean isExtension = Utilities.existsInList(tail(element.getPath()), "extension", "modifierExtension"); + if (!element.prohibited()) { + for (ElementDefinition child : children) { + Row parent = null; + if (child.hasSliceName()) { + // ok, we're a slice + if (slicer == null || !slicer.getId().equals(child.getPath())) { + parent = gen.new Row(); + parent.setId(child.getPath()); + parent.setAnchor(child.getPath()); + parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); + parent.setLineColor(1); + parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); + parent.getCells().add(gen.new Cell(null, null, "Slices for "+ child.getName(), "", null)); + switch (context.getStructureMode()) { + case BINDINGS: + case OBLIGATIONS: + for (Column col : columns) { + parent.getCells().add(gen.new Cell()); + } + break; + case SUMMARY: + parent.getCells().add(gen.new Cell()); + parent.getCells().add(gen.new Cell()); + parent.getCells().add(gen.new Cell()); + parent.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CONT_RULE), "", null)); + break; + } + row.getSubRows().add(parent); + slicer = parent; } else { - row.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); - c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); - } - c = gen.new Cell(); - row.getCells().add(c); - if (t.getTypeCode().contains("(")) { - String tc = t.getTypeCode(); - String tn = tc.substring(0, tc.indexOf("(")); - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, tn), tn, null)); - c.addPiece(gen.new Piece(null, "(", null)); - String[] p = tc.substring(tc.indexOf("(")+1, tc.indexOf(")")).split("\\|"); - for (String s : p) { - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, s), s, null)); - } - c.addPiece(gen.new Piece(null, ")", null)); - } else { - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, t.getTypeCode()), t.getTypeCode(), null)); - } - c = gen.new Cell(); - c.addPiece(gen.new Piece(null, ed.getShort(), null)); - row.getCells().add(c); - } - } else { - for (Base b : t.getValues()) { - Row row = gen.new Row(); - row.setId(ed.getPath()); - erow.getSubRows().add(row); - row.setIcon("icon_fixed.gif", context.formatPhrase(RenderingContext.STRUC_DEF_FIXED) /*context.formatPhrase(RenderingContext.TEXT_ICON_FIXED*/); - - Cell c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : (VersionUtilities.isR5Ver(context.getWorker().getVersion()) ? corePath+"types-definitions.html#"+ed.getBase().getPath() : corePath+"element-definitions.html#"+ed.getBase().getPath())), t.getName(), null)); - - c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece(null, null, null)); - - c = gen.new Cell(); - row.getCells().add(c); - if (pattern) - c.addPiece(gen.new Piece(null, "1.."+(t.getMaxCardinality() == 2147483647 ? "*" : Integer.toString(t.getMaxCardinality())), null)); - else - c.addPiece(gen.new Piece(null, "1..1", null)); - - c = gen.new Cell(); - row.getCells().add(c); - if (b.fhirType().contains("(")) { - String tc = b.fhirType(); - String tn = tc.substring(0, tc.indexOf("(")); - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, tn), tn, null)); - c.addPiece(gen.new Piece(null, "(", null)); - String[] p = tc.substring(tc.indexOf("(")+1, tc.indexOf(")")).split("\\|"); - for (String s : p) { - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, s), s, null)); - } - c.addPiece(gen.new Piece(null, ")", null)); - } else { - c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, b.fhirType()), b.fhirType(), null)); - } - - if (b.isPrimitive()) { - c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece(null, ed.getShort(), null)); - c.addPiece(gen.new Piece("br")); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE)+" ", null).addStyle("font-weight: bold")); - String s = b.primitiveValue(); - // ok. let's see if we can find a relevant link for this - String link = null; - if (Utilities.isAbsoluteUrl(s)) { - link = context.getPkp().getLinkForUrl(corePath, s); - } - c.getPieces().add(gen.new Piece(link, s, null).addStyle("color: darkgreen")); - } else { - c = gen.new Cell(); - row.getCells().add(c); - c.addPiece(gen.new Piece(null, ed.getShort(), null)); - c.addPiece(gen.new Piece("br")); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE)+" ", null).addStyle("font-weight: bold")); - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEXBRACK), null).addStyle("color: darkgreen")); - genFixedValue(gen, row, (DataType) b, snapshot, pattern, corePath, skipnoValue); - } - } - } - } - } - } - } - - - private ElementDefinition findElementDefinition(StructureDefinition sd, String name) { - String path = sd.getTypeName()+"."+name; - for (ElementDefinition ed : sd.getSnapshot().getElement()) { - if (ed.getPath().equals(path)) - return ed; - } - throw new FHIRException(context.getWorker().formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT_, path)); - } - - - private ElementDefinition findElementDefinitionOrNull(StructureDefinition sd, String name) { - String path = sd.getTypeName()+"."+name; - for (ElementDefinition ed : sd.getSnapshot().getElement()) { - if (ed.getPath().equals(path)) - return ed; - } - return null; - } - - - private String getFixedUrl(StructureDefinition sd) { - for (ElementDefinition ed : sd.getSnapshot().getElement()) { - if (ed.getPath().equals("Extension.url")) { - if (ed.hasFixed() && ed.getFixed() instanceof UriType) - return ed.getFixed().primitiveValue(); - } - } - return null; - } - - - private Piece describeCoded(HierarchicalTableGenerator gen, DataType fixed) { - if (fixed instanceof Coding) { - Coding c = (Coding) fixed; - ValidationResult vr = context.getWorker().validateCode(context.getTerminologyServiceOptions(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay()); - if (vr.getDisplay() != null) - return gen.new Piece(null, " ("+vr.getDisplay()+")", null).addStyle("color: darkgreen"); - } else if (fixed instanceof CodeableConcept) { - CodeableConcept cc = (CodeableConcept) fixed; - for (Coding c : cc.getCoding()) { - ValidationResult vr = context.getWorker().validateCode(context.getTerminologyServiceOptions(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay()); - if (vr.getDisplay() != null) - return gen.new Piece(null, " ("+vr.getDisplay()+")", null).addStyle("color: darkgreen"); - } - } - return null; - } - - - private boolean hasDescription(DataType fixed) { - if (fixed instanceof Coding) { - return ((Coding) fixed).hasDisplay(); - } else if (fixed instanceof CodeableConcept) { - CodeableConcept cc = (CodeableConcept) fixed; - if (cc.hasText()) - return true; - for (Coding c : cc.getCoding()) - if (c.hasDisplay()) - return true; - } // (fixed instanceof CodeType) || (fixed instanceof Quantity); - return false; - } - - - private boolean isCoded(DataType fixed) { - return (fixed instanceof Coding) || (fixed instanceof CodeableConcept) || (fixed instanceof CodeType) || (fixed instanceof Quantity); - } - - - private Cell generateGridDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, ElementDefinition valueDefn) throws IOException, FHIRException { - Cell c = gen.new Cell(); - row.getCells().add(c); - - if (used) { - if (definition.hasContentReference()) { - ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), definition.getContentReference(), profile); - if (ed == null) - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_REF, definition.getContentReference()), null)); - else { - if (ed.getSource() == profile) { - c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SEE, ed.getElement().getPath()), null)); - } else { - c.getPieces().add(gen.new Piece(ed.getSource().getWebPath()+"#"+ed.getElement().getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SEE, ed.getSource().getTypeName()) +"."+ed.getElement().getPath(), null)); - } - } - } - if (definition.getPath().endsWith("url") && definition.hasFixed()) { - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen"))); - } else { - if (url != null) { - if (!c.getPieces().isEmpty()) - c.addPiece(gen.new Piece("br")); - String fullUrl = url.startsWith("#") ? baseURL+url : url; - StructureDefinition ed = context.getWorker().fetchResource(StructureDefinition.class, url, profile); - String ref = null; - if (ed != null) { - String p = ed.getWebPath(); - if (p != null) { - ref = p.startsWith("http:") || context.getRules() == GenerationRules.IG_PUBLISHER ? p : Utilities.pathURL(corePath, p); - } - } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_URLS), null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(ref, fullUrl, null)); - } - - if (definition.hasSlicing()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SLICES), null).addStyle("font-weight:bold")); - c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); - } - if (definition != null) { - ElementDefinitionBindingComponent binding = null; - if (valueDefn != null && valueDefn.hasBinding() && !valueDefn.getBinding().isEmpty()) - binding = valueDefn.getBinding(); - else if (definition.hasBinding()) - binding = definition.getBinding(); - if (binding!=null && !binding.isEmpty()) { - if (!c.getPieces().isEmpty()) - c.addPiece(gen.new Piece("br")); - BindingResolution br = context.getPkp().resolveBinding(profile, binding, definition.getPath()); - c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_BINDINGS), null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(binding, checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); - if (binding.hasStrength()) { - c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, " (", null))); - c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), binding.getStrength().toCode(), binding.getStrength().getDefinition()))); - c.getPieces().add(gen.new Piece(null, ")", null)); - } - if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) { - c.getPieces().add(gen.new Piece(null, ": ", null)); - c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()).asStringValue()); - } - } - for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold"))); - if (inv.getHumanElement().hasExtension(ToolingExtensions.EXT_REND_MD)) { - c.addMarkdown(inv.getHumanElement().getExtensionString(ToolingExtensions.EXT_REND_MD)); - } else { - c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getHuman(), null))); - } - } - if (definition.hasFixed()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE), null).addStyle("font-weight:bold"))); - String s = buildJson(definition.getFixed()); - String link = null; - if (Utilities.isAbsoluteUrl(s)) - link = context.getPkp().getLinkForUrl(corePath, s); - c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen"))); - } else if (definition.hasPattern()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REQUIRED_PATT), null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); - } else if (definition.hasExample()) { - for (ElementDefinitionExampleComponent ex : definition.getExample()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_EXAMPLE) +"'"+("".equals("General")? "": " "+ex.getLabel()+"'")+": ", "").addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); - } - } - if (definition.hasMaxLength() && definition.getMaxLength()!=0) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_LENGTH), null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); - } - if (profile != null) { - for (StructureDefinitionMappingComponent md : profile.getMapping()) { - if (md.hasExtension(ToolingExtensions.EXT_TABLE_NAME)) { - ElementDefinitionMappingComponent map = null; - for (ElementDefinitionMappingComponent m : definition.getMapping()) - if (m.getIdentity().equals(md.getIdentity())) - map = m; - if (map != null) { - for (int i = 0; i list, ElementDefinition e) { - return (!e.hasSliceName() && !e.hasSlicing() && (onlyInformationIsMapping(e))) && - getChildren(list, e).isEmpty(); - } - - private boolean onlyInformationIsMapping(ElementDefinition d) { - return !d.hasShort() && !d.hasDefinition() && - !d.hasRequirements() && !d.getAlias().isEmpty() && !d.hasMinElement() && - !d.hasMax() && !d.getType().isEmpty() && !d.hasContentReference() && - !d.hasExample() && !d.hasFixed() && !d.hasMaxLengthElement() && - !d.getCondition().isEmpty() && !d.getConstraint().isEmpty() && !d.hasMustSupportElement() && - !d.hasBinding(); - } - - private boolean allAreReference(List types) { - for (TypeRefComponent t : types) { - if (!t.hasTarget()) - return false; - } - return true; - } - - private List getChildren(List all, ElementDefinition element) { - List result = new ArrayList(); - int i = all.indexOf(element)+1; - while (i < all.size() && all.get(i).getPath().length() > element.getPath().length()) { - if ((all.get(i).getPath().substring(0, element.getPath().length()+1).equals(element.getPath()+".")) && !all.get(i).getPath().substring(element.getPath().length()+1).contains(".")) - result.add(all.get(i)); - i++; - } - return result; - } - - - protected String tail(String path) { - if (path == null) { - return ""; - } else if (path.contains(".")) - return path.substring(path.lastIndexOf('.')+1); - else - return path; - } - - private boolean slicesExist(List elements, ElementDefinition element) { - if (elements == null) { - return true; - } - boolean found = false; - int start = elements.indexOf(element); - if (start < 0) { - return false; - } - for (int i = start; i < elements.size(); i++) { - ElementDefinition ed = elements.get(i); - if (ed.getPath().equals(element.getPath())) { - if (ed.hasSliceName()) { - found = true; - } - } - if (ed.getPath().length() < element.getPath().length()) { - break; - } - } - return found; - } - - - private Cell addCell(Row row, Cell cell) { - row.getCells().add(cell); - return (cell); - } - - private String checkAdd(String src, String app) { - return app == null ? src : src + app; - } - - public boolean hasNonBaseConditions(List conditions) { - for (IdType c : conditions) { - if (!isBaseCondition(c)) { - return true; - } - } - return false; - } - - - public boolean hasNonBaseConstraints(List constraints) { - for (ElementDefinitionConstraintComponent c : constraints) { - if (!isBaseConstraint(c)) { - return true; - } - } - return false; - } - - public String listConstraintsAndConditions(ElementDefinition element) { - Set ids = new HashSet<>(); - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (ElementDefinitionConstraintComponent con : element.getConstraint()) { - if (!isBaseConstraint(con)) { - if (!ids.contains(con.getKey())) { - ids.add(con.getKey()); - b.append(con.getKey()); - } - } - } - for (IdType id : element.getCondition()) { - if (!isBaseCondition(id)) { - if (!ids.contains(id.asStringValue())) { - ids.add(id.asStringValue()); - b.append(id.asStringValue()); - } - } - } - return b.toString(); - } - - private boolean isBaseCondition(IdType c) { - String key = c.asStringValue(); - return key != null && (key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-")); - } - - private boolean isBaseConstraint(ElementDefinitionConstraintComponent con) { - String key = con.getKey(); - return key != null && (key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-")); - } - - private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode, Resource src) { - // create a child for each choice - for (TypeRefComponent tr : element.getType()) { - if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) { - boolean used = false; - Row choicerow = gen.new Row(); - choicerow.setId(element.getPath()); - String t = tr.getWorkingCode(); - if (isReference(t)) { - used = true; - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null)); - choicerow.getCells().add(gen.new Cell()); - choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); - Cell c = gen.new Cell(); - choicerow.getCells().add(c); - if (ADD_REFERENCE_TO_TABLE) { - if (tr.getWorkingCode().equals("canonical")) - c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); - else - c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); - if (!mustSupportMode && isMustSupportDirect(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); - } - c.getPieces().add(gen.new Piece(null, "(", null)); - } - boolean first = true; - for (CanonicalType rt : tr.getTargetProfile()) { - if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) { - if (!first) - c.getPieces().add(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue(), src); - if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TARG_SUPP)), "S", "white", "red", null, false); - } - first = false; - } - } - if (first) { - c.getPieces().add(gen.new Piece(null, "Any", null)); - } - - if (ADD_REFERENCE_TO_TABLE) { - c.getPieces().add(gen.new Piece(null, ")", null)); - } - - } else { - StructureDefinition sd = context.getWorker().fetchTypeDefinition(t); - if (sd == null) { - System.out.println("Unable to find "+t); - sd = context.getWorker().fetchTypeDefinition(t); - } else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { - used = true; - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); - choicerow.getCells().add(gen.new Cell()); - choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); - Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getTypeName(), null, null); - choicerow.getCells().add(c); - if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TARG_SUPP)), "S", "white", "red", null, false); - } - } else { - used = true; - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); - choicerow.getCells().add(gen.new Cell()); - choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); - Cell c = gen.new Cell(null, context.getPkp().getLinkFor(corePath, t), sd.getTypeName(), null, null); - choicerow.getCells().add(c); - if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); - } - } - if (tr.hasProfile() && used) { - Cell typeCell = choicerow.getCells().get(3); - typeCell.addPiece(gen.new Piece(null, "(", null)); - boolean first = true; - for (CanonicalType pt : tr.getProfile()) { - if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) { - if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); - StructureDefinition psd = context.getWorker().fetchResource(StructureDefinition.class, pt.getValue(), src); - if (psd == null) - typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); - else - typeCell.addPiece(gen.new Piece(psd.getWebPath(), psd.getName(), psd.present())); - if (!mustSupportMode && isMustSupport(pt) && element.getMustSupport()) { - typeCell.addPiece(gen.new Piece(null, " ", null)); - typeCell.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_PROF_SUPP)), "S", "white", "red", null, false); - } - } - } - typeCell.addPiece(gen.new Piece(null, ")", null)); - } - } - if (used) { - choicerow.getCells().add(gen.new Cell()); - subRows.add(choicerow); - } - } - } - } - - private boolean isReference(String t) { - return t.equals("Reference") || t.equals("canonical"); - } - - - - private List readChoices(ElementDefinition ed, List children) { - List result = new ArrayList<>(); - for (ElementDefinitionConstraintComponent c : ed.getConstraint()) { - ElementChoiceGroup grp = context.getProfileUtilities().processConstraint(children, c); - if (grp != null) { - result.add(grp); - } - } - return result; - } - - private Piece checkForNoChange(Element src1, Element src2, Piece piece) { - if (src1.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS) && src2.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { - piece.addStyle("opacity: 0.5"); - } - return piece; - } - - - private String buildJson(DataType value) throws IOException { - if (value instanceof PrimitiveType) - return ((PrimitiveType) value).asStringValue(); - - IParser json = new JsonParser(); - return json.composeString(value, null); - } - - private String describeSlice(ElementDefinitionSlicingComponent slicing) { - return formatPhrase(RenderingContext.SD_SLICING_INFO, slicing.getOrdered() ? (context.formatPhrase(RenderingContext.STRUC_DEF_ORDERED)) : (context.formatPhrase(RenderingContext.STRUC_DEF_UNORDERED)), describe(slicing.getRules()), commas(slicing.getDiscriminator())); - } - - - - private String commas(List list) { - CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder(); - for (ElementDefinitionSlicingDiscriminatorComponent id : list) - c.append((id.hasType() ? id.getType().toCode() : "??")+":"+id.getPath()); - return c.toString(); - } - - - private String describe(SlicingRules rules) { - if (rules == null) - return (context.formatPhrase(RenderingContext.STRUC_DEF_UNSPECIFIED)); - switch (rules) { - case CLOSED : return (context.formatPhrase(RenderingContext.STRUC_DEF_CLOSED)); - case OPEN : return (context.formatPhrase(RenderingContext.STRUC_DEF_OPEN)); - case OPENATEND : return (context.formatPhrase(RenderingContext.STRUC_DEF_OPEN_END)); - default: - return "?gen-sr?"; - } - } - - private boolean allTypesMustSupport(ElementDefinition e) { - boolean all = true; - boolean any = false; - for (TypeRefComponent tr : e.getType()) { - all = all && isMustSupport(tr); - any = any || isMustSupport(tr); - } - return !all && !any; - } - - private boolean allProfilesMustSupport(List profiles) { - boolean all = true; - boolean any = false; - for (CanonicalType u : profiles) { - all = all && isMustSupport(u); - any = any || isMustSupport(u); - } - return !all && !any; - } - public boolean isMustSupportDirect(TypeRefComponent tr) { - return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); - } - - public boolean isMustSupport(TypeRefComponent tr) { - if ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))) { - return true; - } - if (isMustSupport(tr.getProfile())) { - return true; - } - return isMustSupport(tr.getTargetProfile()); - } - - public boolean isMustSupport(List profiles) { - for (CanonicalType ct : profiles) { - if (isMustSupport(ct)) { - return true; - } - } - return false; - } - - - public boolean isMustSupport(CanonicalType profile) { - return "true".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_MUST_SUPPORT)); - } - - - - private SpanEntry buildSpanEntryFromProfile(String name, String cardinality, StructureDefinition profile) throws IOException { - SpanEntry res = new SpanEntry(); - res.setName(name); - res.setCardinality(cardinality); - res.setProfileLink(profile.getWebPath()); - res.setResType(profile.getTypeName()); - StructureDefinition base = context.getWorker().fetchResource(StructureDefinition.class, res.getResType()); - if (base != null) - res.setResLink(base.getWebPath()); - res.setId(profile.getId()); - res.setProfile(profile.getDerivation() == TypeDerivationRule.CONSTRAINT); - StringBuilder b = new StringBuilder(); - b.append(res.getResType()); - boolean first = true; - boolean open = false; - if (profile.getDerivation() == TypeDerivationRule.CONSTRAINT) { - res.setDescription(profile.getName()); - for (ElementDefinition ed : profile.getSnapshot().getElement()) { - if (isKeyProperty(ed.getBase().getPath()) && ed.hasFixed()) { - if (first) { - open = true; - first = false; - b.append("["); - } else { - b.append(", "); - } - b.append(tail(ed.getBase().getPath())); - b.append("="); - b.append(summarize(ed.getFixed())); - } - } - if (open) - b.append("]"); - } else - res.setDescription(context.formatPhrase(RenderingContext.STRUC_DEF_FHIR, profile.getName())+" "); - res.setType(b.toString()); - return res ; - } - - - private String summarize(DataType value) throws IOException { - if (value instanceof Coding) - return summarizeCoding((Coding) value); - else if (value instanceof CodeableConcept) - return summarizeCodeableConcept((CodeableConcept) value); - else - return buildJson(value); - } - - - private String summarizeCoding(Coding value) { - String uri = value.getSystem(); - String system = displaySystem(uri); - if (Utilities.isURL(system)) { - if (system.equals("http://cap.org/protocols")) - system = context.formatPhrase(RenderingContext.STRUC_DEF_CAP); - } - return system+" "+value.getCode(); - } - - - private String summarizeCodeableConcept(CodeableConcept value) { - if (value.hasCoding()) - return summarizeCoding(value.getCodingFirstRep()); - else - return value.getText(); - } - - - private boolean isKeyProperty(String path) { - return Utilities.existsInList(path, "Observation.code"); - } - - - private TableModel initSpanningTable(HierarchicalTableGenerator gen, String prefix, boolean isLogical, String id) throws IOException { - TableModel model = gen.new TableModel(id, true); - - if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { - model.setDocoImg(HierarchicalTableGenerator.help16AsData()); - } else { - model.setDocoImg(Utilities.pathURL(prefix, "help16.png")); - } - model.setDocoRef(Utilities.pathURL(prefix, "formats.html#table")); // todo: change to graph definition - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_PROPERTY), context.formatPhrase(RenderingContext.STRUC_DEF_PROF_RES), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_CARD), context.formatPhrase(RenderingContext.STRUC_DEF_MAX_MIN), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_CONTENT), context.formatPhrase(RenderingContext.STRUC_DEF_WHAT), null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_DESC), context.formatPhrase(RenderingContext.STRUC_DEF_DESC_PROF), null, 0)); - return model; - } - - private void genSpanEntry(HierarchicalTableGenerator gen, List rows, SpanEntry span) throws IOException { - Row row = gen.new Row(); - row.setId("??"); - rows.add(row); - row.setAnchor(span.getId()); - //row.setColor(..?); - if (span.isProfile()) { - row.setIcon("icon_profile.png", context.formatPhrase(RenderingContext.TEXT_ICON_PROFILE)); - } else { - row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); - } - - row.getCells().add(gen.new Cell(null, null, span.getName(), null, null)); - row.getCells().add(gen.new Cell(null, null, span.getCardinality(), null, null)); - row.getCells().add(gen.new Cell(null, span.getProfileLink(), span.getType(), null, null)); - row.getCells().add(gen.new Cell(null, null, span.getDescription(), null, null)); - - for (SpanEntry child : span.getChildren()) { - genSpanEntry(gen, row.getSubRows(), child); - } - } - - - public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set outputTracker) throws IOException, FHIRException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true); - TableModel model = initSpanningTable(gen, "", false, profile.getId()); - Set processed = new HashSet(); - SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); - - genSpanEntry(gen, model.getRows(), span); - return gen.generate(model, "", 0, outputTracker); - } - - private SpanEntry buildSpanningTable(String name, String cardinality, StructureDefinition profile, Set processed, boolean onlyConstraints, String constraintPrefix) throws IOException { - SpanEntry res = buildSpanEntryFromProfile(name, cardinality, profile); - boolean wantProcess = !processed.contains(profile.getUrl()); - processed.add(profile.getUrl()); - if (wantProcess && profile.getDerivation() == TypeDerivationRule.CONSTRAINT) { - for (ElementDefinition ed : profile.getSnapshot().getElement()) { - if (!"0".equals(ed.getMax()) && ed.getType().size() > 0) { - String card = getCardinality(ed, profile.getSnapshot().getElement()); - if (!card.endsWith(".0")) { - List refProfiles = listReferenceProfiles(ed); - if (refProfiles.size() > 0) { - String uri = refProfiles.get(0); - if (uri != null) { - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, uri); - if (sd != null && (!onlyConstraints || (sd.getDerivation() == TypeDerivationRule.CONSTRAINT && (constraintPrefix == null || sd.getUrl().startsWith(constraintPrefix))))) { - res.getChildren().add(buildSpanningTable(nameForElement(ed), card, sd, processed, onlyConstraints, constraintPrefix)); - } - } - } - } + parent = slicer; + } + } else { + parent = chooseChildRowByGroup(gen, row, groups, child, element, isConstraintMode); + } + + if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) { + slicer = genElement(defPath, gen, parent.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, slicer, mustSupport, rc, anchorPrefix, srcSD, columns); + } + } } - } - } - return res; - } - - - private String getCardinality(ElementDefinition ed, List list) { - int min = ed.getMin(); - int max = !ed.hasMax() || ed.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(ed.getMax()); - ElementDefinition ned = ed; - while (ned != null && ned.getPath().contains(".")) { - ned = findParent(ned, list); - if (ned != null) { // todo: this can happen if we've walked into a resoruce. Not sure what to about that? - if ("0".equals(ned.getMax())) - max = 0; - else if (!ned.getMax().equals("1") && !ned.hasSlicing()) - max = Integer.MAX_VALUE; - if (ned.getMin() == 0) { - min = 0; - } - } - } - return Integer.toString(min)+".."+(max == Integer.MAX_VALUE ? "*" : Integer.toString(max)); - } - - - private ElementDefinition findParent(ElementDefinition ed, List list) { - int i = list.indexOf(ed)-1; - while (i >= 0 && !ed.getPath().startsWith(list.get(i).getPath()+".")) - i--; - if (i == -1) - return null; - else - return list.get(i); - } - - - private List listReferenceProfiles(ElementDefinition ed) { - List res = new ArrayList(); - for (TypeRefComponent tr : ed.getType()) { - // code is null if we're dealing with "value" and profile is null if we just have Reference() - if (tr.hasTarget() && tr.hasTargetProfile()) - for (UriType u : tr.getTargetProfile()) - res.add(u.getValue()); - } - return res; - } - - - private String nameForElement(ElementDefinition ed) { - return ed.getPath().substring(ed.getPath().indexOf(".")+1); - } - - public XhtmlNode formatTypeSpecifiers(ElementDefinition d) { - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - boolean first = true; - for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { - if (first) first = false; else x.br(); - String cond = ToolingExtensions.readStringExtension(e, "condition"); - String type = ToolingExtensions.readStringExtension(e, "type"); - x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_IF)+" "); - x.code().tx(cond); - x.tx(" "+(context.formatPhrase(RenderingContext.STRUC_DEF_THEN_TYPE)+" ")); - StructureDefinition sd = context.getContext().fetchTypeDefinition(type); - if (sd == null) { - x.code().tx(type); - } else { - x.ah(sd.getWebPath()).tx(sd.getTypeName()); - } - } - return first ? null : x; - } - - public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set outputTracker, RenderingContext rc) throws IOException, FHIRException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); - TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML); - - boolean deep = false; - String m = ""; - boolean vdeep = false; - if (ed.getSnapshot().getElementFirstRep().getIsModifier()) - m = "modifier_"; - for (ElementDefinition eld : ed.getSnapshot().getElement()) { - deep = deep || eld.getPath().contains("Extension.extension."); - vdeep = vdeep || eld.getPath().contains("Extension.extension.extension."); - } - Row r = gen.new Row(); - r.setId("Extension"); - model.getRows().add(r); - String en; - if (!full) - en = ed.getName(); - else if (ed.getSnapshot().getElement().get(0).getIsModifier()) - en = "modifierExtension"; - else - en = "extension"; - - r.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#extension."+ed.getName(), en, null, null)); - r.getCells().add(gen.new Cell()); - r.getCells().add(gen.new Cell(null, null, describeCardinality(ed.getSnapshot().getElement().get(0), null, new UnusedTracker()), null, null)); - - ElementDefinition ved = null; - if (full || vdeep) { - r.getCells().add(gen.new Cell("", "", "Extension", null, null)); - - r.setIcon(deep ? "icon_"+m+"extension_complex.png" : "icon_extension_simple.png", deep ? context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX) : context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); - List children = getChildren(ed.getSnapshot().getElement(), ed.getSnapshot().getElement().get(0)); - for (ElementDefinition child : children) - if (!child.getPath().endsWith(".id")) { - List sdl = new ArrayList<>(); - sdl.add(ed); - genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc, "", ed, null); - } - } else if (deep) { - List children = new ArrayList(); - for (ElementDefinition ted : ed.getSnapshot().getElement()) { - if (ted.getPath().equals("Extension.extension")) - children.add(ted); - } - - r.getCells().add(gen.new Cell("", "", "Extension", null, null)); - r.setIcon("icon_"+m+"extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); - - for (ElementDefinition c : children) { - ved = getValueFor(ed, c); - ElementDefinition ued = getUrlFor(ed, c); - if (ved != null && ued != null) { - Row r1 = gen.new Row(); - r1.setId(ued.getPath()); - r.getSubRows().add(r1); - r1.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#"+ed.getId()+"."+c.getId(), ((UriType) ued.getFixed()).getValue(), null, null)); - r1.getCells().add(gen.new Cell()); - r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); - genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false); - r1.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); - generateDescription(gen, r1, c, null, true, corePath, corePath, ed, corePath, imagePath, false, false, false, ved, false, false, false, rc); - } - } - } else { - for (ElementDefinition ted : ed.getSnapshot().getElement()) { - if (ted.getPath().startsWith("Extension.value")) - ved = ted; - } - - genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false, false); - - r.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); - } - Cell c = gen.new Cell("", "", "URL = "+ed.getUrl(), null, null); - Piece cc = gen.new Piece(null, ed.getName()+": ", null); - c.addPiece(gen.new Piece("br")).addPiece(cc); - c.addMarkdown(ed.getDescription()); - - if (!full && !(deep || vdeep) && ved != null && ved.hasBinding()) { - c.addPiece(gen.new Piece("br")); - BindingResolution br = context.getPkp().resolveBinding(ed, ved.getBinding(), ved.getPath()); - c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(ved.getBinding(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); - if (ved.getBinding().hasStrength()) { - c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, " (", null))); - c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(corePath+"terminologies.html#"+ved.getBinding().getStrength().toCode(), egt(ved.getBinding().getStrengthElement()), ved.getBinding().getStrength().getDefinition()))); - c.getPieces().add(gen.new Piece(null, ")", null)); - } - if (ved.getBinding().hasDescription() && MarkDownProcessor.isSimpleMarkdown(ved.getBinding().getDescription())) { - c.getPieces().add(gen.new Piece(null, ": ", null)); - c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), ved.getBinding().getDescriptionElement()).asStringValue()); - } - } - c.addPiece(gen.new Piece("br")).addPiece(gen.new Piece(null, ProfileUtilities.describeExtensionContext(ed), null)); - r.getCells().add(c); - - try { - return gen.generate(model, corePath, 0, outputTracker); - } catch (org.hl7.fhir.exceptions.FHIRException e) { - throw new FHIRException(e.getMessage(), e); - } - } - - private String describeCardinality(ElementDefinition definition, ElementDefinition fallback, UnusedTracker tracker) { - IntegerType min = definition.hasMinElement() ? definition.getMinElement() : new IntegerType(); - StringType max = definition.hasMaxElement() ? definition.getMaxElement() : new StringType(); - if (min.isEmpty() && fallback != null) - min = fallback.getMinElement(); - if (max.isEmpty() && fallback != null) - max = fallback.getMaxElement(); - - tracker.used = !max.isEmpty() && !max.getValue().equals("0"); - - if (min.isEmpty() && max.isEmpty()) - return null; - else - return (!min.hasValue() ? "" : Integer.toString(min.getValue())) + ".." + (!max.hasValue() ? "" : max.getValue()); - } - - - private ElementDefinition getValueFor(StructureDefinition ed, ElementDefinition c) { - int i = ed.getSnapshot().getElement().indexOf(c) + 1; - while (i < ed.getSnapshot().getElement().size() && ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".")) { - if (ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".value")) - return ed.getSnapshot().getElement().get(i); - i++; - } - return null; - } - - private ElementDefinition getUrlFor(StructureDefinition ed, ElementDefinition c) { - int i = ed.getSnapshot().getElement().indexOf(c) + 1; - while (i < ed.getSnapshot().getElement().size() && ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".")) { - if (ed.getSnapshot().getElement().get(i).getPath().equals(c.getPath()+".url")) - return ed.getSnapshot().getElement().get(i); - i++; - } - return null; - } - - public void renderDict(StructureDefinition sd, List elements, XhtmlNode t, boolean incProfiledOut, int mode, String anchorPrefix) throws FHIRException, IOException { - int i = 0; - Map allAnchors = new HashMap<>(); - List excluded = new ArrayList<>(); - List stack = new ArrayList<>(); // keeps track of parents, for anchor generation - - for (ElementDefinition ec : elements) { - addToStack(stack, ec); - generateAnchors(stack, allAnchors); - checkInScope(stack, excluded); - } - Stack dstack = new Stack<>(); - for (ElementDefinition ec : elements) { - if ((incProfiledOut || !"0".equals(ec.getMax())) && !excluded.contains(ec)) { - ElementDefinition compareElement = null; - if (mode==GEN_MODE_DIFF) - compareElement = getBaseElement(ec, sd.getBaseDefinition()); - else if (mode==GEN_MODE_KEY) - compareElement = getRootElement(ec); - - List anchors = makeAnchors(ec, anchorPrefix); - String title = ec.getId(); - XhtmlNode tr = t.tr(); - XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent")); - for (String s : anchors) { - sp.an(s).tx(" "); - } - sp.span("color: grey", null).tx(Integer.toString(i++)); - sp.b().tx(". "+title); - link(sp, ec.getId(), anchorPrefix); - if (isProfiledExtension(ec)) { - StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue()); - if (extDefn == null) { - generateElementInner(t, sd, ec, 1, null, compareElement, null, false); - } else { - ElementDefinition valueDefn = getExtensionValueDefinition(extDefn); - ElementDefinition compareValueDefn = null; - try { - StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue()); - compareValueDefn = getExtensionValueDefinition(extDefn); - } catch (Exception except) {} - generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn, false); - // generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn); - } - } else { - while (!dstack.isEmpty() && !isParent(dstack.peek(), ec)) { - finish(t, sd, dstack.pop(), mode); - } - dstack.push(ec); - generateElementInner(t, sd, ec, mode, null, compareElement, null, false); - if (ec.hasSlicing()) { - generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false); - } - } - } - t.tx("\r\n"); - i++; - } - while (!dstack.isEmpty()) { - finish(t, sd, dstack.pop(), mode); - } - finish(t, sd, null, mode); - } - - private void finish(XhtmlNode t, StructureDefinition sd, ElementDefinition ed, int mode) throws FHIRException, IOException { - - for (Base b : VersionComparisonAnnotation.getDeleted(ed == null ? sd : ed, "element")) { - ElementDefinition ec = (ElementDefinition) b; - String title = ec.getId(); - XhtmlNode tr = t.tr(); - XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent")); - sp.span("color: grey", null).tx("--"); - sp.b().tx(". "+title); - - generateElementInner(t, sd, ec, mode, null, null, null, true); - if (ec.hasSlicing()) { - generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true); - } - } - } - - public ElementDefinition getElementById(String url, String id) { - Map sdCache = sdMapCache.get(url); - - if (sdCache == null) { - StructureDefinition sd = (StructureDefinition) context.getContext().fetchResource(StructureDefinition.class, url); - if (sd == null) { - if (url.equals("http://hl7.org/fhir/StructureDefinition/Base")) { - sd = (StructureDefinition) context.getContext().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Element"); - } - if (sd == null) { - throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_FHIR_EXCEP, url)+" "); - } - } - sdCache = new HashMap(); - sdMapCache.put(url, sdCache); - String webroot = sd.getUserString("webroot"); - for (ElementDefinition e : sd.getSnapshot().getElement()) { - context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e); - sdCache.put(e.getId(), e); - } - } - return sdCache.get(id); - } - - - // Returns the ElementDefinition for the 'parent' of the current element - private ElementDefinition getBaseElement(ElementDefinition e, String url) { - if (e.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { - return getElementById(url, e.getUserString(ProfileUtilities.UD_DERIVATION_POINTER)); - } - return null; - } - - // Returns the ElementDefinition for the 'root' ancestor of the current element - private ElementDefinition getRootElement(ElementDefinition e) { - if (!e.hasBase()) - return null; - String basePath = e.getBase().getPath(); - String url = "http://hl7.org/fhir/StructureDefinition/" + (basePath.contains(".") ? basePath.substring(0, basePath.indexOf(".")) : basePath); - try { - return getElementById(url, basePath); - } catch (FHIRException except) { - // Likely a logical model, so this is ok - return null; - } - } - private void checkInScope(List stack, List excluded) { - if (stack.size() > 2) { - ElementDefinition parent = stack.get(stack.size()-2); - ElementDefinition focus = stack.get(stack.size()-1); - - if (excluded.contains(parent) || "0".equals(parent.getMax())) { - excluded.add(focus); - } - } - } - - private void generateAnchors(List stack, Map allAnchors) { - List list = new ArrayList<>(); - list.add(stack.get(0).getId()); // initialise - for (int i = 1; i < stack.size(); i++) { - ElementDefinition ed = stack.get(i); - List aliases = new ArrayList<>(); - String name = tail(ed.getPath()); - if (name.endsWith("[x]")) { - aliases.add(name); - Set tl = new HashSet(); // guard against duplicate type names - can happn in some versions - for (TypeRefComponent tr : ed.getType()) { - String tc = tr.getWorkingCode(); - if (!tl.contains(tc)) { - aliases.add(name.replace("[x]", Utilities.capitalize(tc))); - aliases.add(name+":"+name.replace("[x]", Utilities.capitalize(tc))); - aliases.add(name.replace("[x]", Utilities.capitalize(tc))+":"+name.replace("[x]", Utilities.capitalize(tc))); - tl.add(tc); - } - } - } else if (ed.hasSliceName()) { - aliases.add(name+":"+ed.getSliceName()); - // names.add(name); no good generating this? - } else { - aliases.add(name); - } - List generated = new ArrayList<>(); - for (String l : list) { - for (String a : aliases) { - generated.add(l+"."+a); - } - } - list.clear(); - list.addAll(generated); - } - ElementDefinition ed = stack.get(stack.size()-1); - // now we have all the possible names, but some of them might be inappropriate if we've - // already generated a type slicer. On the other hand, if we've already done that, we're - // going to steal any type specific ones off it. - List removed = new ArrayList<>(); - for (String s : list) { - if (!allAnchors.containsKey(s)) { - allAnchors.put(s, ed); - } else if (s.endsWith("[x]")) { - // that belongs on the earlier element - removed.add(s); - } else { - // we delete it from the other - @SuppressWarnings("unchecked") - List other = (List) allAnchors.get(s).getUserData("dict.generator.anchors"); - other.remove(s); - allAnchors.put(s, ed); - } - } - list.removeAll(removed); - ed.setUserData("dict.generator.anchors", list); - } - - private void addToStack(List stack, ElementDefinition ec) { - while (!stack.isEmpty() && !isParent(stack.get(stack.size()-1), ec)) { - stack.remove(stack.size()-1); - } - stack.add(ec); - } - - private boolean isParent(ElementDefinition ed, ElementDefinition ec) { - return ec.getPath().startsWith(ed.getPath()+"."); - } - - private List makeAnchors(ElementDefinition ed, String anchorPrefix) { - List list = (List) ed.getUserData("dict.generator.anchors"); - List res = new ArrayList<>(); - res.add(anchorPrefix + ed.getId()); - for (String s : list) { - if (!s.equals(ed.getId())) { - res.add(anchorPrefix + s); - } - } - return res; - } - - - - private void link(XhtmlNode x, String id, String anchorPrefix) { - var ah = x.ah("#" + anchorPrefix + id); - ah.attribute("title", "link to here"); - ah.attribute("class", "self-link"); - var svg = ah.svg(); - svg.attribute("viewBox", "0 0 1792 1792"); - svg.attribute("width", "16"); - svg.attribute("height", "16"); - svg.attribute("class", "self-link"); - svg.path("M1520 1216q0-40-28-68l-208-208q-28-28-68-28-42 0-72 32 3 3 19 18.5t21.5 21.5 15 19 13 25.5 3.5 27.5q0 40-28 68t-68 28q-15 0-27.5-3.5t-25.5-13-19-15-21.5-21.5-18.5-19q-33 31-33 73 0 40 28 68l206 207q27 27 68 27 40 0 68-26l147-146q28-28 28-67zm-703-705q0-40-28-68l-206-207q-28-28-68-28-39 0-68 27l-147 146q-28 28-28 67 0 40 28 68l208 208q27 27 68 27 42 0 72-31-3-3-19-18.5t-21.5-21.5-15-19-13-25.5-3.5-27.5q0-40 28-68t68-28q15 0 27.5 3.5t25.5 13 19 15 21.5 21.5 18.5 19q33-31 33-73zm895 705q0 120-85 203l-147 146q-83 83-203 83-121 0-204-85l-206-207q-83-83-83-203 0-123 88-209l-88-88q-86 88-208 88-120 0-204-84l-208-208q-84-84-84-204t85-203l147-146q83-83 203-83 121 0 204 85l206 207q83 83 83 203 0 123-88 209l88 88q86-88 208-88 120 0 204 84l208 208q84 84 84 204z"); - } - - private boolean isProfiledExtension(ElementDefinition ec) { - return ec.getType().size() == 1 && "Extension".equals(ec.getType().get(0).getWorkingCode()) && ec.getType().get(0).hasProfile(); - } - - private ElementDefinition getExtensionValueDefinition(StructureDefinition extDefn) { - for (ElementDefinition ed : extDefn.getSnapshot().getElement()) { - if (ed.getPath().startsWith("Extension.value")) - return ed; - } - return null; - } - - public XhtmlNode compareMarkdown(String location, PrimitiveType md, PrimitiveType compare, int mode) throws FHIRException, IOException { - XhtmlNode ndiv = new XhtmlNode(NodeType.Element, "div"); - if (compare == null || mode == GEN_MODE_DIFF) { - if (md.hasValue()) { - String xhtml = hostMd.processMarkdown(location, md); - if (Utilities.noString(xhtml)) { - return null; - } - try { - renderStatusDiv(md, ndiv).addChildren(fixFontSizes(new XhtmlParser().parseMDFragment(xhtml), 11)); - } catch (Exception e) { - ndiv.span("color: maroon").tx(e.getLocalizedMessage()); - e.printStackTrace(); - } - return ndiv; - } else { - return null; - } - } else if (areEqual(compare, md)) { - if (md.hasValue()) { - String xhtml = hostMd.processMarkdown(location, md); - List nodes = new XhtmlParser().parseMDFragment(xhtml); - for (XhtmlNode n : nodes) { - if (n.getNodeType() == NodeType.Element) { - n.style(unchangedStyle()); - } - } - ndiv.addChildren(nodes); - return ndiv; - } else { - return null; - } - } else { - if (md.hasValue()) { - String xhtml = hostMd.processMarkdown(location, md); - List div = new XhtmlParser().parseMDFragment(xhtml); - ndiv.addChildren(div); - } - if (compare.hasValue()) { - String xhtml = "
"+hostMd.processMarkdown(location, compare)+"
"; - List div = new XhtmlParser().parseMDFragment(xhtml); - for (XhtmlNode n : div) { - if (n.getNodeType() == NodeType.Element) { - n.style(removedStyle()); - } - } - ndiv.br(); - ndiv.addChildren(div); - } - return ndiv; - } - } - - private List fixFontSizes(List nodes, int size) { - for (XhtmlNode x : nodes) { - if (Utilities.existsInList(x.getName(), "p", "li") && !x.hasAttribute("style")) { - x.style("font-size: "+size+"px"); - } - if (x.hasChildren()) { - fixFontSizes(x.getChildNodes(), size); - } - } - return nodes; - } - - private boolean areEqual(PrimitiveType compare, PrimitiveType md) { - if (compare == null && md == null) { - return true; - } else if (compare != null && md != null) { - String one = compare.getValueAsString(); - String two = md.getValueAsString(); - if (one == null && two == null) { - return true; - } else if (one != null && one.equals(two)) { - return true; - } - } - return false; - } - - public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) { - return compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode, externalN, externalO, false); - } - - public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO, boolean code) { - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - if (mode != GEN_MODE_KEY) { - if (newStr != null) { - renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); - } else if (VersionComparisonAnnotation.hasDeleted(parent, name)) { - PrimitiveType p = (PrimitiveType) VersionComparisonAnnotation.getDeletedItem(parent, name); - renderStatus(p, x).txOrCode(code, p.primitiveValue()); - } else { - return null; - } - } else if (oldStr==null || oldStr.isEmpty()) { - if (newStr==null || newStr.isEmpty()) { - return null; - } else { - renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); - } - } else if (oldStr!=null && !oldStr.isEmpty() && (newStr==null || newStr.isEmpty())) { - if (mode == GEN_MODE_DIFF) { - return null; - } else { - removed(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); - } - } else if (oldStr.equals(newStr)) { - if (mode==GEN_MODE_DIFF) { - return null; - } else { - unchanged(x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); - } - } else if (newStr.startsWith(oldStr)) { - unchanged(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); - renderStatus(source, x).ah(nLink).txN(newStr.substring(oldStr.length())).iff(externalN).txN(" ").img("external.png", null); - } else { - // TODO: improve comparision in this fall-through case, by looking for matches in sub-paragraphs? - renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); - removed(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); - } - return x; - } - - public boolean compareString(XhtmlNode x, String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) { - XhtmlNode x1 = compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode, externalN, externalO); - if (x1 == null) { - return false; - } else { - x.getChildNodes().addAll(x1.getChildNodes()); - return true; - } - } - - public XhtmlNode unchanged(XhtmlNode x) { - return x.span(unchangedStyle()); - } - - private String unchangedStyle() { - return "color:DarkGray"; - } - - public XhtmlNode removed(XhtmlNode x) { - return x.span(removedStyle()); - } - - private String removedStyle() { - return "color:DarkGray;text-decoration:line-through"; - } - - private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough) throws FHIRException, IOException { - boolean root = !d.getPath().contains("."); - boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension")); -// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970 - if (d.hasSliceName()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_NAME), "profiling.html#slicing", strikethrough, compareString(d.getSliceName(), d.getSliceNameElement(), null, (compare != null ? compare.getSliceName() : null), d, null, "sliceName", mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CONSTRAINING), "profiling.html#slicing", strikethrough, compareString(encodeValue(d.getSliceIsConstrainingElement(), null), d.getSliceIsConstrainingElement(), null, (compare != null ? encodeValue(compare.getSliceIsConstrainingElement(), null) : null), d, null, "sliceName", mode, false, false)); - } - - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFINITION), null, strikethrough, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SHORT), null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMMENTS), null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_NOTE_C), null, strikethrough, businessIdWarning(sd.getName(), tail(d.getPath()))); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CONTROL), "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_BINDING), "terminologies.html", strikethrough, describeBinding(sd, d, d.getPath(), compare, mode)); - if (d.hasContentReference()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_TYPE), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_SEE) + d.getContentReference().substring(1)); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_TYPE), "datatypes.html", strikethrough, describeTypes(d.getType(), false, d, compare, mode, value, compareValue, sd)); - } - if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFAULT_TYPE), "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE)); - } - if (d.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { - tableRow(tbl, Utilities.pluralize(context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SPEC), d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", strikethrough, formatTypeSpecifiers(d)); - } - if (d.getPath().endsWith("[x]") && !d.prohibited()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_NOTE_X), null, strikethrough).ahWithText(context.formatPhrase(RenderingContext.STRUC_DEF_SEE) - , spec("formats.html#choice"), null, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_DATA_TYPE), context.formatPhrase(RenderingContext.STRUC_DEF_FURTHER_INFO)); - } - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MODIFIER), "conformance-rules.html#ismodifier", strikethrough, presentModifier(d, mode, compare)); - if (d.getMustHaveValue()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_TYPE_VALUE)); - } else if (d.hasValueAlternatives()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, renderCanonicalList(context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_TYPE_PRESENT), d.getValueAlternatives())); - } else if (hasPrimitiveTypes(d)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_ELE)); - } - if (ToolingExtensions.hasAllowedUnits(d)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ALLOWED), "http://hl7.org/fhir/extensions/StructureDefinition-elementdefinition-allowedUnits.html", strikethrough, describeAllowedUnits(d)); - } - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT), "conformance-rules.html#mustSupport", strikethrough, displayBoolean(d.getMustSupport(), d.getMustSupportElement(), "mustSupport", d, compare==null ? null : compare.getMustSupportElement(), mode)); - if (d.getMustSupport()) { - if (hasMustSupportTypes(d.getType())) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT_TYPES), "datatypes.html", strikethrough, describeTypes(d.getType(), true, d, compare, mode, null, null, sd)); - } else if (hasChoices(d.getType())) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT_TYPES), "datatypes.html", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NO_MUST_SUPPORT)); - } - } - if (root && sd.getKind() == StructureDefinitionKind.LOGICAL) { - Extension lt = ToolingExtensions.getExtension(sd, ToolingExtensions.EXT_LOGICAL_TARGET); - if (lt == null || !lt.hasValue()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARKED)); - } else if (lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { - } else if (lt.getValueBooleanType().hasValue()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARKED)); - } else if (lt.getValueBooleanType().booleanValue()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET)); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_CANNOT_TARGET)); - } - - Extension lc = ToolingExtensions.getExtension(sd, ToolingExtensions.EXT_LOGICAL_CONTAINER); - if (lc != null && lc.hasValueUriType()) { - String uri = lc.getValue().primitiveValue(); - StructureDefinition lct = context.getContext().fetchTypeDefinition(uri); - if (lct != null) { - tableRowLink(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL_CONT), null, strikethrough, lct.present(), lct.getWebPath()); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL_CONT), null, strikethrough, uri); - } - } - - String ps = ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_PROFILE_STYLE); - if (ps != null) { - if ("cda".equals(ps)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALID), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_TEMPLATEID)); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALID), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_APPROACH, ps)+" "); - } - } - } - - if (root && sd.hasExtension(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_IMPOSE_PROFILE), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-imposeProfile.html", strikethrough, - renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_REQ)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE))); - } - if (root && sd.hasExtension(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMP_PROF), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", strikethrough, - renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_COMP)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE))); - } - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_OBLIGATIONS), null, strikethrough, describeObligations(d, root, sd)); - - if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { - String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); - if ("named-elements".equals(es)) { - if (context.hasLink(KnownLinkType.JSON_NAMES)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_STYLE), context.getLink(KnownLinkType.JSON_NAMES), strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ELE)); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_STYLE), ToolingExtensions.WEB_EXTENSION_STYLE, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ELE)); - } - } - } - - if (!d.getPath().contains(".") && ToolingExtensions.hasExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_BINDING_STYLE), ToolingExtensions.WEB_BINDING_STYLE, strikethrough, - context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_BOUND, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)+" binding style")+" "); - } - - if (d.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DATE_FORM), null, strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DATE_FORMAT)); - } - String ide = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_ID_EXPECTATION); - if (ide != null) { - if (ide.equals("optional")) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_IS)); - } else if (ide.equals("required")) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_REQ)); - } else if (ide.equals("required")) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_NOT_ALLOW)); - } - } - - if (d.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_GRP), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT)); - } - - // tooling extensions for formats - if (ToolingExtensions.hasAnyOfExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, - ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_FORM), null, strikethrough, describeJson(d)); - } - if (d.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) || sd.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) || - d.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED) || sd.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED) || - d.hasRepresentation()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_XML_FORM), null, strikethrough, describeXml(sd, d, root)); - } - - if (d.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STRING_FORM), null, strikethrough).codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_ELE_READ)+" ", ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_IMPLIED_PREFIX), context.formatPhrase(RenderingContext.STRUC_DEF_PREFIX_VALID)); - } - - if (d.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { - StandardsStatus ss = StandardsStatus.fromCode(d.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); - // gc.addStyledText("Standards Status = "+ss.toDisplay(), ss.getAbbrev(), "black", ss.getColor(), baseSpecUrl()+, true); - StructureDefinition sdb = context.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); - if (sdb != null) { - StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData("derived.pointer")); - if (base != null) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()+" (from "+base.toDisplay()+")"); - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()); - } - } else { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()); - } - } - if (mode != GEN_MODE_DIFF && d.hasIsSummary()) { - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SUMMARY), "search.html#summary", strikethrough, Boolean.toString(d.getIsSummary())); - } - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_REQUIREMENTS), null, strikethrough, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LABEL), null, strikethrough, compareString(d.getLabel(), d.getLabelElement(), null, "label", d, (compare != null ? compare.getLabel() : null), null, mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ALT_NAME), null, strikethrough, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEF_CODES), null, strikethrough, compareDataTypeLists(d.getCode(), ((compare==null) || slicedExtension ? null : compare.getCode()), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MIN_VALUE), null, strikethrough, compareString(d.hasMinValue() ? encodeValue(d.getMinValue(), null) : null, d.getMinValue(), null, "minValue", d, compare!= null && compare.hasMinValue() ? encodeValue(compare.getMinValue(), null) : null, null, mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_VALUE), null, strikethrough, compareString(d.hasMaxValue() ? encodeValue(d.getMaxValue(), null) : null, d.getMaxValue(), null, "maxValue", d, compare!= null && compare.hasMaxValue() ? encodeValue(compare.getMaxValue(), null) : null, null, mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_LENGTH), null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALUE_REQ), null, strikethrough, compareString(encodeValue(d.getMustHaveValueElement(), null), d.getMustHaveValueElement(), null, (compare != null ? encodeValue(compare.getMustHaveValueElement(), null) : null), d, null, "mustHaveValueElement", mode, false, false)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALUE_ALT), null, strikethrough, compareSimpleTypeLists(d.getValueAlternatives(), ((compare==null) || slicedExtension ? null : compare.getValueAlternatives()), mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFAULT_VALUE), null, strikethrough, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode, d.getName())); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MEAN_MISS), null, strikethrough, d.getMeaningWhenMissing()); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED), null, strikethrough, encodeValue(d.getFixed(), "fixed", d, compare==null ? null : compare.getFixed(), mode, d.getName())); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PATT_VALUE), null, strikethrough, encodeValue(d.getPattern(), "pattern", d, compare==null ? null : compare.getPattern(), mode, d.getName())); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EX), null, strikethrough, encodeValues(d.getExample())); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_INVAR), null, strikethrough, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), d, mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOINC), null, strikethrough, getMapping(sd, d, LOINC_MAPPING, compare, mode)); - tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SNOMED), null, strikethrough, getMapping(sd, d, SNOMED_MAPPING, compare, mode)); - tbl.tx("\r\n"); - } - - private XhtmlNode presentModifier(ElementDefinition d, int mode, ElementDefinition compare) throws FHIRException, IOException { - XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement(), null), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement(), null), null, mode, false, false); - if (x1 != null) { - XhtmlNode x2 = compareString(encodeValue(d.getIsModifierReasonElement(), null), d.getIsModifierReasonElement(), null, "isModifierReason", d, compare == null ? null : encodeValue(compare.getIsModifierReasonElement(), null), null, mode, false, false); - if (x2 != null) { - x1.tx(" "+(context.formatPhrase(RenderingContext.STRUC_DEF_BECAUSE)+" ")); - x1.copyAllContent(x2); - } - } - return x1; - } - - private String spec(String name) { - return Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()) , name); - } - - private XhtmlNode describeXml(StructureDefinition profile, ElementDefinition d, boolean root) { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - for (PropertyRepresentation pr : PropertyRepresentation.values()) { - if (d.hasRepresentation(pr)) { - switch (pr) { - case CDATEXT: - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_CDA)); - break; - case TYPEATTR: - ret.codeWithText((context.formatPhrase(RenderingContext.STRUC_DEF_XSI)+" "), "xsi:type", "attribute."); - break; - case XHTML: - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_XHTML)); - break; - case XMLATTR: - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_XML_ATTRIBUTE)); - break; - case XMLTEXT: - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_UNADORNED)); - break; - default: - } - } - } - String name = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED); - if (name == null && root) { - name = ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED); - } - if (name != null) { - ret.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_NAMESPACE)+" ", name, "."); - } - name = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED); - if (name != null) { - ret.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_XML_ACTUAL), name, "."); - } - return ret; - } - - private XhtmlNode describeJson(ElementDefinition d) { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - var ul = ret.ul(); - boolean list = ToolingExtensions.countExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) > 1; - - String code = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_EMPTY); - if (code != null) { - switch (code) { - case "present": - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_PRESENT)); - break; - case "absent": - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NOT_PRESENT)); - break; - case "either": - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_MAY_PRESENT)); - break; - } - } - String jn = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED); - if (jn != null) { - if (d.getPath().contains(".")) { - ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_PROPERTY_NAME), jn, null); - } else { - ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_CAN_NAME), jn, " " + context.formatPhrase(RenderingContext.STRUC_DEF_JSON_EXT)); - } - } - code = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_PROP_KEY); - if (code != null) { - ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_SINGLE), code, " "+ context.formatPhrase(RenderingContext.STRUC_DEF_JSON_CHILD)); - } - if (ToolingExtensions.readBoolExtension(d, ToolingExtensions.EXT_JSON_NULLABLE)) { - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_NULL_JSON)); - } - if (ToolingExtensions.readBoolExtension(d, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_INFERRED_JSON)); - } - - switch (ul.getChildNodes().size()) { - case 0: return null; - case 1: return ul.getChildNodes().get(0); - default: return ret; - } - } - - private XhtmlNode describeObligations(ElementDefinition d, boolean root, StructureDefinition sdx) throws IOException { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - ObligationsRenderer obr = new ObligationsRenderer(corePath, sdx, d.getPath(), context, hostMd, this); - obr.seeObligations(d.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); - obr.seeRootObligations(d.getId(), sdx.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); - if (obr.hasObligations() || (root && (sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG) || sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_INHERITS)))) { - XhtmlNode ul = ret.ul(); - if (root) { - if (sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { - ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ADD)); + // if (!snapshot && (extensions == null || !extensions)) + // for (ElementDefinition child : children) + // if (child.getPath().endsWith(".extension") || child.getPath().endsWith(".modifierExtension")) + // genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants); + } + if (typesRow != null && !element.prohibited() && context.getStructureMode() == StructureDefinitionRendererMode.SUMMARY) { + makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport, srcSD); + } + } + return slicingRow; + } + + private boolean isTypeSlice(ElementDefinition child) { + ElementDefinition derived = (ElementDefinition) child.getUserData("derived.pointer"); + return derived != null && derived.getBase().getPath().endsWith("[x]"); + } + + private boolean isExtension(ElementDefinition element) { + if (element.getType().isEmpty()) { + return true; + } + String type = element.getTypeFirstRep().getWorkingCode(); + return "Extension".equals(type); + } + + private void genElementObligations(HierarchicalTableGenerator gen, ElementDefinition element, List columns, Row row, String corePath, StructureDefinition profile) throws IOException { + for (Column col : columns) { + Cell gc = gen.new Cell(); + row.getCells().add(gc); + ObligationsRenderer obr = new ObligationsRenderer(corePath, profile, element.getPath(), context, null, this); + obr.seeObligations(element, col.id); + obr.renderList(gen, gc); + } + } + + private String displayForUsage(Coding c) { + if (c.hasDisplay()) { + return c.getDisplay(); + } + if ("http://terminology.hl7.org/CodeSystem/usage-context-type".equals(c.getSystem())) { + return c.getCode(); + } + return c.getCode(); + } + + private void genElementBindings(HierarchicalTableGenerator gen, ElementDefinition element, List columns, Row row, StructureDefinition profile, String corepath) { + for (Column col : columns) { + Cell gc = gen.new Cell(); + row.getCells().add(gc); + List bindings = collectBindings(element, col.id); + if (bindings.size() > 0) { + Piece p = gen.new Piece(null); + gc.addPiece(p); + new AdditionalBindingsRenderer(context.getPkp(), corepath, profile, element.getPath(), context, null, this).render(p.getChildren(), bindings); + } + } + } + + private List collectBindings(ElementDefinition element, String type) { + List res = new ArrayList<>(); + if (element.hasBinding()) { + ElementDefinitionBindingComponent b = element.getBinding(); + if (b.hasStrength() && type.equals(b.getStrength().toCode())) { + ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); + res.add(ab.setAny(false).setDocumentation(b.getDescription()).setValueSet(b.getValueSet())); + } + if ("maximum".equals(type) && b.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { + ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); + res.add(ab.setAny(false).setValueSet(ToolingExtensions.readStringExtension(b, ToolingExtensions.EXT_MAX_VALUESET))); + } + if ("minimum".equals(type) && b.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { + ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); + res.add(ab.setAny(false).setValueSet(ToolingExtensions.readStringExtension(b, ToolingExtensions.EXT_MIN_VALUESET))); + } + for (ElementDefinitionBindingAdditionalComponent t : b.getAdditional()) { + if (type.equals(t.getPurpose().toCode())) { + res.add(t); } - for (Extension ext : sdx.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_INHERITS)) { - String iu = ext.getValue().primitiveValue(); - XhtmlNode bb = ul.li(); - bb.tx(context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_FROM)+" "); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, iu); - if (sd == null) { - bb.code().tx(iu); - } else if (sd.hasWebPath()) { - bb.ah(sd.getWebPath()).tx(sd.present()); + } + for (Extension ext : b.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { + if (type.equals(ext.getExtensionString("purpose"))) { + ElementDefinitionBindingAdditionalComponent ab = new ElementDefinitionBindingAdditionalComponent(); + if (ext.hasExtension("any")) { + ab.setAny(ToolingExtensions.readBooleanExtension(ext, "any")); + } + if (ext.hasExtension("purpose")) { + ab.setPurpose(AdditionalBindingPurposeVS.fromCode(ToolingExtensions.readStringExtension(ext, "purpose"))); + } + if (ext.hasExtension("documentation")) { + ab.setDocumentation(ToolingExtensions.readStringExtension(ext, "documentation")); + } + if (ext.hasExtension("shortDoco")) { + ab.setShortDoco(ToolingExtensions.readStringExtension(ext, "shortDoco")); + } + if (ToolingExtensions.hasExtension(ext, "usage")) { + ab.addUsage(ext.getExtensionByUrl("usage").getValueUsageContext()); + } + if (ext.hasExtension("valueSet")) { + ab.setValueSet(ToolingExtensions.readStringExtension(ext, "valueSet")); + } + res.add(ab); + } + } + } + return res; + } + + public Cell genElementNameCell(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, + String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, + boolean ext, UnusedTracker used, String ref, String sName, List elements) throws IOException { + String hint = ""; + hint = checkAdd(hint, element.hasSliceName() ? context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_PAR, element.getSliceName()) : ""); + if (hasDef && element.hasDefinition()) { + hint = checkAdd(hint, (hasDef && element.hasSliceName() ? ": " : "")); + hint = checkAdd(hint, !hasDef ? null : gt(element.getDefinitionElement())); + } + if (element.hasSlicing() && slicesExist(elements, element)) { // some elements set up slicing but don't actually slice, so we don't augment the name + sName = context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_FOR, sName); + } + Cell left = gen.new Cell(null, ref, sName, hint, null); + row.getCells().add(left); + return left; + } + + public List genElementCells(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, + String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, + boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport, boolean allowSubRows, RenderingContext rc, boolean walksIntoThis) throws IOException { + List res = new ArrayList<>(); + Cell gc = gen.new Cell(); + row.getCells().add(gc); + res.add(gc); + if (element != null && element.getIsModifier()) { + checkForNoChange(element.getIsModifierElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_MOD)), "?!", null, null, null, false)); + } + if (element != null) { + if (element.getMustSupport() && element.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { + checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_SUPP)), "SO", "white", "red", null, false)); + } else if (element.getMustSupport()) { + checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_SUPP)), "S", "white", "red", null, false)); + } else if (element != null && element.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { + checkForNoChange(element.getMustSupportElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG)), "O", "white", "red", null, false)); + } + } + if (element != null && element.getIsSummary()) { + checkForNoChange(element.getIsSummaryElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_SUMM)), "\u03A3", null, null, null, false)); + } + if (element != null && element.getMustHaveValue()) { + checkForNoChange(element.getMustHaveValueElement(), gc.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_ELE)), "V", "maroon", null, null, true)); + } + if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) { + Piece p = gc.addText(CONSTRAINT_CHAR); + p.setHint((context.formatPhrase(RenderingContext.STRUC_DEF_ELE_AFFECTED, listConstraintsAndConditions(element), ")"))); + p.addStyle(CONSTRAINT_STYLE); + p.setReference(Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()), "conformance-rules.html#constraints")); + } + if (element != null && element.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + StandardsStatus ss = StandardsStatus.fromCode(element.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); + gc.addStyledText(context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STATUS) +ss.toDisplay(), ss.getAbbrev(), context.formatPhrase(RenderingContext.STRUC_DEF_BLACK), ss.getColor(), context.getWorker().getSpecUrl()+"versions.html#std-process", true); + } + + ExtensionContext extDefn = null; + if (ext) { + if (element != null) { + if (element.getType().size() == 1 && element.getType().get(0).hasProfile()) { + String eurl = element.getType().get(0).getProfile().get(0).getValue(); + extDefn = locateExtension(StructureDefinition.class, eurl); + if (extDefn == null) { + res.add(genCardinality(gen, element, row, hasDef, used, null)); + res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null))); + res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); } else { - bb.ah(iu).tx(sd.present()); + String name = element.hasSliceName() ? element.getSliceName() : urltail(eurl); + nameCell.getPieces().get(0).setText(name); + // left.getPieces().get(0).setReference((String) extDefn.getExtensionStructure().getTag("filename")); + nameCell.getPieces().get(0).setHint((context.formatPhrase(RenderingContext.STRUC_DEF_EX_URL, extDefn.getUrl()))); + res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement())); + ElementDefinition valueDefn = walksIntoThis ? null : extDefn.getExtensionValueDefinition(); + if (valueDefn != null && !"0".equals(valueDefn.getMax())) + res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); + else // if it's complex, we just call it nothing + // genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile); + res.add(addCell(row, gen.new Cell(null, null, "("+(context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEX))+")", null, null))); + res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport, allowSubRows, rc)); + } + } else { + res.add(genCardinality(gen, element, row, hasDef, used, null)); + if ("0".equals(element.getMax())) + res.add(addCell(row, gen.new Cell())); + else + res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); + res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); + } + } + } else if (element != null) { + res.add(genCardinality(gen, element, row, hasDef, used, null)); + if (hasDef && !"0".equals(element.getMax()) && typesRow == null) + res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); + else + res.add(addCell(row, gen.new Cell())); + res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); + } + return res; + } + + private Cell genCardinality(HierarchicalTableGenerator gen, ElementDefinition definition, Row row, boolean hasDef, UnusedTracker tracker, ElementDefinition fallback) { + IntegerType min = !hasDef ? new IntegerType() : definition.hasMinElement() ? definition.getMinElement() : new IntegerType(); + StringType max = !hasDef ? new StringType() : definition.hasMaxElement() ? definition.getMaxElement() : new StringType(); + if (min.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { + ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (base.hasMinElement()) { + min = base.getMinElement().copy(); + min.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + } + } + if (max.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { + ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (base.hasMaxElement()) { + max = base.getMaxElement().copy(); + max.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + } + } + if (min.isEmpty() && fallback != null) + min = fallback.getMinElement(); + if (max.isEmpty() && fallback != null) + max = fallback.getMaxElement(); + + if (!max.isEmpty()) + tracker.used = !max.getValue().equals("0"); + + String hint = null; + if (max.hasValue() && min.hasValue() && "*".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 = context.formatPhrase(RenderingContext.STRUC_DEF_JSON_IS); + } else { + hint = context.formatPhrase(RenderingContext.STRUC_DEF_JSON_MAY); + } + } + } + Cell cell = gen.new Cell(null, null, null, null, null); + row.getCells().add(cell); + if (!min.isEmpty() || !max.isEmpty()) { + cell.addPiece(checkForNoChange(min, gen.new Piece(null, !min.hasValue() ? "" : Integer.toString(min.getValue()), hint))); + cell.addPiece(checkForNoChange(min, max, gen.new Piece(null, "..", hint))); + cell.addPiece(checkForNoChange(max, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), hint))); + } + return cell; + } + + public List supplementMissingDiffElements(StructureDefinition profile) { + List list = new ArrayList<>(); + list.addAll(profile.getDifferential().getElement()); + if (list.isEmpty()) { + ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); + root.setId(profile.getTypeName()); + list.add(root); + } else { + if (list.get(0).getPath().contains(".")) { + ElementDefinition root = new ElementDefinition().setPath(profile.getTypeName()); + root.setId(profile.getTypeName()); + list.add(0, root); + } + } + insertMissingSparseElements(list); + return list; + } + + private boolean usesMustSupport(List list) { + for (ElementDefinition ed : list) + if (ed.hasMustSupport() && ed.getMustSupport()) + return true; + return false; + } + + + + private Row chooseChildRowByGroup(HierarchicalTableGenerator gen, Row row, List groups, ElementDefinition element, ElementDefinition parent, boolean isConstraintMode) { + String name = tail(element.getPath()); + for (ElementChoiceGroup grp : groups) { + if (grp.getElements().contains(name)) { + if (grp.getRow() == null) { + grp.setRow(makeChoiceElementRow(gen, row, grp, parent, isConstraintMode)); + } + return grp.getRow(); + } + } + return row; + } + + private Row makeChoiceElementRow(HierarchicalTableGenerator gen, Row prow, ElementChoiceGroup grp, ElementDefinition parent, boolean isConstraintMode) { + if (context.getStructureMode() != StructureDefinitionRendererMode.SUMMARY) { + return prow; + } + Row row = gen.new Row(); + row.setId(parent.getPath()+"-"+grp.getName()); + row.setAnchor(parent.getPath()+"-"+grp.getName()); + row.setColor(context.getProfileUtilities().getRowColor(parent, isConstraintMode)); + row.setLineColor(1); + row.setIcon("icon_choice.gif", context.formatPhrase(RenderingContext.TEXT_ICON_CHOICE)); + row.getCells().add(gen.new Cell(null, null, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE), "", null)); + row.getCells().add(gen.new Cell()); + row.getCells().add(gen.new Cell(null, null, (grp.isMandatory() ? "1" : "0")+"..1", "", null)); + row.getCells().add(gen.new Cell()); + row.getCells().add(gen.new Cell()); + prow.getSubRows().add(row); + return row; + } + + + private void insertMissingSparseElements(List list) { + int i = 1; + while (i < list.size()) { + String[] pathCurrent = list.get(i).getPath().split("\\."); + String[] pathLast = list.get(i-1).getPath().split("\\."); + int firstDiff = 0; // the first entry must be a match + while (firstDiff < pathCurrent.length && firstDiff < pathLast.length && pathCurrent[firstDiff].equals(pathLast[firstDiff])) { + firstDiff++; + } + if (!(isSibling(pathCurrent, pathLast, firstDiff) || isChild(pathCurrent, pathLast, firstDiff))) { + // now work backwards down to lastMatch inserting missing path nodes + ElementDefinition parent = findParent(list, i, list.get(i).getPath()); + int parentDepth = Utilities.charCount(parent.getPath(), '.')+1; + int childDepth = Utilities.charCount(list.get(i).getPath(), '.')+1; + if (childDepth > parentDepth + 1) { + String basePath = parent.getPath(); + String baseId = parent.getId(); + for (int index = parentDepth; index >= firstDiff; index--) { + String mtail = makeTail(pathCurrent, parentDepth, index); + ElementDefinition root = new ElementDefinition().setPath(basePath+"."+mtail); + root.setId(baseId+"."+mtail); + list.add(i, root); + } + } + } + i++; + } + } + + + private String urltail(String path) { + if (path.contains("#")) + return path.substring(path.lastIndexOf('#')+1); + if (path.contains("/")) + return path.substring(path.lastIndexOf('/')+1); + else + return path; + + } + + private boolean standardExtensionSlicing(ElementDefinition element) { + String t = tail(element.getPath()); + return (t.equals("extension") || t.equals("modifierExtension")) + && element.getSlicing().getRules() != SlicingRules.CLOSED && element.getSlicing().getDiscriminator().size() == 1 && element.getSlicing().getDiscriminator().get(0).getPath().equals("url") && element.getSlicing().getDiscriminator().get(0).getType().equals(DiscriminatorType.VALUE); + } + + public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { + return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows, rc); + } + + public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { + Cell c = gen.new Cell(); + row.getCells().add(c); + + if (used) { + if (logicalModel && ToolingExtensions.hasAnyOfExtensions(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { + if (root) { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); + } else if (!root && ToolingExtensions.hasAnyOfExtensions(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) && + !ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED).equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED))) { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); + } + } + if (root) { + if (profile != null && profile.getAbstract()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ABSTRACT) +(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profile" : "type")+". ", null)); + + List children = new ArrayList<>(); + for (StructureDefinition sd : context.getWorker().fetchResourcesByType(StructureDefinition.class)) { + if (sd.hasBaseDefinition() && sd.getBaseDefinition().equals(profile.getUrl())) { + children.add(sd); + } + } + if (!children.isEmpty()) { + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_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.getWebPath(), sd.getName(), null)); + } + } + } + if (logicalModel) { + List ancestors = new ArrayList<>(); + getAncestorElements(profile, ancestors); + if (ancestors.size() > 0) { + c.addPiece(gen.new Piece("br")); + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ELEMENTS), null)); + boolean first = true; + for (SourcedElementDefinition ed : ancestors) { + if (first) + first = false; + else + c.addPiece(gen.new Piece(null, ", ", null)); + c.addPiece(gen.new Piece(ed.getProfile().getWebPath(), (isAttr(ed) ? "@" : "")+ed.getDefinition().getName(), ed.getDefinition().getDefinition())); + } + } + } + } + if (definition.getPath().endsWith("url") && definition.hasFixed()) { + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen"))); + } else { + if (definition != null && definition.hasShort()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(checkForNoChange(definition.getShortElement(), gen.new Piece(null, gt(definition.getShortElement()), null))); + } else if (fallback != null && fallback.hasShort()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, gt(fallback.getShortElement()), null).addStyle("opacity: 0.5")); + } + if (url != null) { + if (!c.getPieces().isEmpty()) + c.addPiece(gen.new Piece("br")); + String fullUrl = url.startsWith("#") ? baseURL+url : url; + StructureDefinition ed = context.getWorker().fetchResource(StructureDefinition.class, url, profile); + String ref = null; + String ref2 = null; + String fixedUrl = null; + if (ed != null) { + ref = ed.getWebPath(); + fixedUrl = getFixedUrl(ed); + if (fixedUrl != null) {// if its null, we guess that it's not a profiled extension? + if (fixedUrl.equals(url)) + fixedUrl = null; + else { + StructureDefinition ed2 = context.getWorker().fetchResource(StructureDefinition.class, fixedUrl); + if (ed2 != null) { + String p2 = ed2.getWebPath(); + if (p2 != null) { + ref2 = p2.startsWith("http:") || context.getRules() == GenerationRules.IG_PUBLISHER ? p2 : Utilities.pathURL(corePath, p2); + } + } + } + } + } + if (fixedUrl == null) { + if (!Utilities.noString(fullUrl)) { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_URL))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(ref, fullUrl, null)); + } + } else { + // reference to a profile take on the extension show the base URL + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_URL))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(ref2, fixedUrl, null)); + c.getPieces().add(gen.new Piece(null, (" "+context.formatPhrase(RenderingContext.STRUC_DEF_PROFILED)+" ")+" ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(ref, fullUrl, null)); + + } + } + + if (definition.hasSlicing()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_SLICE))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); + } + if (!definition.getPath().contains(".") && ToolingExtensions.hasExtension(profile, ToolingExtensions.EXT_BINDING_STYLE)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SET)+" "), null)); + c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_BINDING_STYLE), null)); + c.getPieces().add(gen.new Piece(null, " "+context.formatPhrase(RenderingContext.STRUC_DEF_BINDING_STYLE), null)); + } + if (definition.hasValueAlternatives()) { + addCanonicalList(gen, c, definition.getValueAlternatives(), "The primitive value may be replaced by the extension", true); + } + if (definition.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_ELE_READ)+" "), null)); + Piece piece = gen.new Piece("code"); + piece.addHtml(new XhtmlNode(NodeType.Text).setContent(ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_IMPLIED_PREFIX))); + c.getPieces().add(piece); + c.getPieces().add(gen.new Piece(null, " "+ (context.formatPhrase(RenderingContext.STRUC_DEF_PREFIXED)), null)); + } + + if (definition.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + String es = definition.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); + if ("named-elements".equals(es)) { + if (rc.hasLink(KnownLinkType.JSON_NAMES)) { + c.getPieces().add(gen.new Piece(rc.getLink(KnownLinkType.JSON_NAMES), context.formatPhrase(RenderingContext.STRUC_DEF_EXT_JSON), null)); + } else { + c.getPieces().add(gen.new Piece(ToolingExtensions.WEB_EXTENSION_STYLE, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_JSON), null)); + } + } + } + if (definition.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) { + String df = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_DATE_FORMAT); + if (df != null) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_DATE, df)+" "), null)); + } + } + if (definition.hasExtension(ToolingExtensions.EXT_ID_EXPECTATION)) { + String ide = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_ID_EXPECTATION); + if (ide.equals("optional")) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_IS), null)); + } else if (ide.equals("required")) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_MAY), null)); + } else if (ide.equals("required")) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_ID_NOT_ALLOW), null)); + } + } + if (definition.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_GRP))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT), null)); + } + if (definition.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED), null)); + c.getPieces().add(gen.new Piece(null, " (", null)); + c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); + c.getPieces().add(gen.new Piece(null, ")", null)); + } else { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_ELE))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED), null)); + } + } else if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_XML_NAME))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, definition.getExtensionString(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED), null)); + } + if (definition.hasExtension(ToolingExtensions.EXT_JSON_EMPTY)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_EMPTY); + if ("present".equals(code)) { + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_INFERRED), null)); + } else { + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ARRAY), null)); + } + } + String jn = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED); + if (!Utilities.noString(jn)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + if (definition.getPath().contains(".")) { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NAME))+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, jn, null)); + } else { + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_JSON_TYPE))+": ", null).addStyle("font-weight:bold")); + Piece piece = gen.new Piece("code"); + piece.addHtml(new XhtmlNode(NodeType.Text).setContent(jn)); + c.getPieces().add(piece); + } + } + + if (ToolingExtensions.readBoolExtension(definition, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_INFERRED), null)); + } + if (ToolingExtensions.readBoolExtension(definition, ToolingExtensions.EXT_JSON_NULLABLE)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NULL), null)); + } + if (definition.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_PROP_KEY); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SINGLE_JSON_OBJECTS, code), null)); + } + if (definition.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { + for (Extension e : definition.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + String cond = ToolingExtensions.readStringExtension(e, "condition"); + String type = ToolingExtensions.readStringExtension(e, "type"); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_IF), null)); + Piece piece = gen.new Piece("code"); + piece.addHtml(new XhtmlNode(NodeType.Text).setContent(cond)); + c.getPieces().add(piece); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_THEN_TYPE), null)); + StructureDefinition sd = context.getWorker().fetchTypeDefinition(type); + if (sd == null) { + c.getPieces().add(gen.new Piece("")); + c.getPieces().add(gen.new Piece(null, type, null)); + c.getPieces().add(gen.new Piece("")); + } else { + c.getPieces().add(gen.new Piece(sd.getWebPath(), sd.getTypeName(), null)); + } + } + } + if (root) { + if (ToolingExtensions.readBoolExtension(profile, ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ADD), null).addStyle("font-weight:bold")); + } + addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_INHERITS), "This profile picks up obligations and additional bindings from the profile", true); + addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE), "This profile also imposes the profile", true); + addCanonicalListExt(gen, c, profile.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE), "This profile also complies with the profile", true); + + if (profile.getKind() == StructureDefinitionKind.LOGICAL) { + Extension lt = ToolingExtensions.getExtension(profile, ToolingExtensions.EXT_LOGICAL_TARGET); + if (lt == null || !lt.hasValueBooleanType()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARK), null).addStyle("font-weight:bold")); ; + } else if (lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { + } else if (!lt.getValueBooleanType().hasValue()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); ; + } else if (lt.getValueBooleanType().booleanValue()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); + } else { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REF), null).addStyle("font-weight:bold")); + } + String ps = ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE); + if (ps != null) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + if ("cda".equals(ps)) { + c.addPiece(gen.new Piece(null,context.formatPhrase(RenderingContext.STRUC_DEF_TEMPLATEID), null).addStyle("font-weight:bold")); + } else { + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_VALID_UNKNOWN, ps)+" ", null).addStyle("font-weight:bold")); + } + } + Extension lc = ToolingExtensions.getExtension(profile, ToolingExtensions.EXT_LOGICAL_CONTAINER); + if (lc != null && lc.hasValueUriType()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_LOGIC))+": ", context.formatPhrase(RenderingContext.STRUC_DEF_ROOT)).addStyle("font-weight:bold")); + + String uri = lc.getValue().primitiveValue(); + StructureDefinition lct = context.getContext().fetchTypeDefinition(uri); + if (lct != null) { + c.addPiece(gen.new Piece(lct.getWebPath(), lct.present(), null)); + } else { + c.addPiece(gen.new Piece(null, uri, null)); + } + } + } + } + if (definition != null) { + ElementDefinitionBindingComponent binding = null; + if (valueDefn != null && valueDefn.hasBinding() && !valueDefn.getBinding().isEmpty()) + binding = makeUnifiedBinding(valueDefn.getBinding(), valueDefn); + else if (definition.hasBinding()) + binding = makeUnifiedBinding(definition.getBinding(), definition); + if (binding!=null && !binding.isEmpty()) { + if (!c.getPieces().isEmpty()) + c.addPiece(gen.new Piece("br")); + BindingResolution br = context.getPkp() == null ? makeNullBr(binding) : context.getPkp().resolveBinding(profile, binding, definition.getPath()); + c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(binding.getValueSetElement(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); + if (binding.hasStrength()) { + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, " (", null))); + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition()))); + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, ")", null))); + } + if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) { + c.getPieces().add(gen.new Piece(null, ": ", null)); + c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()).asStringValue(), checkForNoChange(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()))); + } + + AdditionalBindingsRenderer abr = new AdditionalBindingsRenderer(context.getPkp(), corePath, profile, definition.getPath(), rc, null, this); + abr.seeAdditionalBindings(definition, null, false); + if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { + abr.seeMaxBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MAX_VALUESET)); + } + if (binding.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { + abr.seeMinBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MIN_VALUESET)); + } + if (binding.hasExtension(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { + abr.seeAdditionalBindings(binding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL)); + } + abr.render(gen, c); + } + for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { +// if (!inv.hasSource() || profile == null || inv.getSource().equals(profile.getUrl()) || allInvariants) { + if (!inv.hasSource() || profile == null || allInvariants || (!isAbstractBaseProfile(inv.getSource()) && !"http://hl7.org/fhir/StructureDefinition/Extension".equals(inv.getSource()))) { + if (!c.getPieces().isEmpty()) + c.addPiece(gen.new Piece("br")); + c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, gt(inv.getHumanElement()), null))); + } + } + if ((definition.hasBase() && "*".equals(definition.getBase().getMax())) || (definition.hasMax() && "*".equals(definition.getMax()))) { + if (c.getPieces().size() > 0) + c.addPiece(gen.new Piece("br")); + if (definition.hasOrderMeaning()) { + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT_ELE, definition.getOrderMeaning()), null)); + } else { + // don't show this, this it's important: c.getPieces().add(gen.new Piece(null, "This repeating element has no defined order", null)); + } + } + if (definition.hasFixed()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_FIXED))+": ", null).addStyle("font-weight:bold"))); + if (!useTableForFixedValues || !allowSubRows || definition.getFixed().isPrimitive()) { + String s = buildJson(definition.getFixed()); + String link = null; + if (Utilities.isAbsoluteUrl(s) && context.getPkp() != null) + link = context.getPkp().getLinkForUrl(corePath, s); + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen"))); + } else { + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_AS_SHOWN), null).addStyle("color: darkgreen"))); + genFixedValue(gen, row, definition.getFixed(), snapshot, false, corePath, false); + } + if (isCoded(definition.getFixed()) && !hasDescription(definition.getFixed())) { + Piece p = describeCoded(gen, definition.getFixed()); + if (p != null) + c.getPieces().add(p); + } + } else if (definition.hasPattern()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_REQ_PATT))+": ", null).addStyle("font-weight:bold"))); + if (!useTableForFixedValues || !allowSubRows || definition.getPattern().isPrimitive()) + c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); + else { + c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_LEAST_FOLLOW), null).addStyle("color: darkgreen"))); + genFixedValue(gen, row, definition.getPattern(), snapshot, true, corePath, mustSupportOnly); + } + } else if (definition.hasExample()) { + for (ElementDefinitionExampleComponent ex : definition.getExample()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_EXAMPLE))+("".equals("General")? "" : " "+ex.getLabel())+": ", null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); + } + } + + ObligationsRenderer obr = new ObligationsRenderer(corePath, profile, definition.getPath(), rc, null, this); + if (definition.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { + obr.seeObligations(definition.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); + } + if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { + obr.seeObligations(profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); + } + obr.renderTable(gen, c); + + if (definition.hasMaxLength() && definition.getMaxLength()!=0) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); + } + if (profile != null) { + for (StructureDefinitionMappingComponent md : profile.getMapping()) { + if (md.hasExtension(ToolingExtensions.EXT_TABLE_NAME)) { + ElementDefinitionMappingComponent map = null; + for (ElementDefinitionMappingComponent m : definition.getMapping()) + if (m.getIdentity().equals(md.getIdentity())) + map = m; + if (map != null) { + for (int i = 0; i t : ed.getDefinition().getRepresentation()) { + if (t.getValue() == PropertyRepresentation.XMLATTR) { + return true; + } + } + return false; + } + + private void getAncestorElements(StructureDefinition profile, List ancestors) { + StructureDefinition base = context.getContext().fetchResource(StructureDefinition.class, profile.getBaseDefinition()); + if (base != null) { + getAncestorElements(base, ancestors); + for (ElementDefinition ed : base.getDifferential().getElement()) { + if (Utilities.charCount(ed.getPath(), '.') == 1) { + ancestors.add(new SourcedElementDefinition(base, ed)); + } + } + } + } + + private void addCanonicalListExt(HierarchicalTableGenerator gen, Cell c, List list, String start, boolean bold) { + List clist = new ArrayList<>(); + for (Extension ext : list) { + if (ext.hasValueCanonicalType()) { + clist.add(ext.getValueCanonicalType()); + } + } + addCanonicalList(gen, c, clist, start, bold); + } + + private void addCanonicalList(HierarchicalTableGenerator gen, Cell c, List list, String start, boolean bold) { + if (!list.isEmpty()) { + + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + Piece p = gen.new Piece(null, start+(list.size() != 1 ? "s" : "")+" ", null); + c.addPiece(p); + if (bold) p.addStyle("font-weight:bold"); + + for (int i = 0; i < list.size(); i++) { + CanonicalType ct = list.get(i); + if (i > 0) { + if (i < list.size() - 1) { + c.addPiece(gen.new Piece(null, ", ", null)); + } else { + c.addPiece(gen.new Piece(null, " and ", null)); + } + } + String iu = ct.primitiveValue(); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, iu); + if (sd == null) { + p = gen.new Piece(null, iu, null).addStyle("font-weight:bold"); + c.addPiece(p); + } else { + String v = ""; + if (iu.contains("|") || hasMultipleVersions(context.getContext().fetchResourcesByUrl(StructureDefinition.class, iu))) { + v = " ("+sd.getVersion()+")"; + } + if (sd.hasWebPath()) { + p = gen.new Piece(sd.getWebPath(), sd.present()+v, null).addStyle("font-weight:bold"); + c.addPiece(p); + } else { + p = gen.new Piece(iu, sd.present()+v, null).addStyle("font-weight:bold"); + c.addPiece(p); + } + } + if (bold) p.addStyle("font-weight:bold"); + } + } + } + + private Piece checkForNoChange(Element source, Piece piece) { + if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + piece.addStyle("opacity: 0.5"); + } + return piece; + } + + private String checkForNoChange(Element source) { + if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + return "opacity: 0.5"; + } else { + return null; + } + } + + private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) { + Cell c = gen.new Cell(); + r.getCells().add(c); + if (e.hasContentReference()) { + ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), e.getContentReference(), profile); + if (ed == null) + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_REF, e.getContentReference())+" ", null)); + else { + if (ed.getSource() == profile) { + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SEE)+" ", null)); + c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath())); + } else { + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SEE)+" ", null)); + c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getWebPath())+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getTypeName()+")", ed.getElement().getPath())); + } + } + return c; + } + List types = e.getType(); + if (!e.hasType()) { + if (root) { // we'll use base instead of types then + StructureDefinition bsd = profile == null ? null : context.getWorker().fetchResource(StructureDefinition.class, profile.getBaseDefinition(), profile); + if (bsd != null) { + String v = ""; + if (profile != null && (profile.getBaseDefinition().contains("|") || hasMultipleVersions(context.getWorker().fetchResourcesByUrl(StructureDefinition.class, profile.getBaseDefinition())))) { + v = v +"("+bsd.getVersion()+")"; + } + if (bsd.hasWebPath()) { + c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getWebPath()) ? bsd.getWebPath() : imagePath +bsd.getWebPath(), bsd.getName()+v, null)); + } else { + c.getPieces().add(gen.new Piece(null, bsd.getName()+v, null)); + } + } + return c; + } else if (e.hasContentReference()) { + return c; + } else { + ElementDefinition d = (ElementDefinition) e.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (d != null && d.hasType()) { + types = new ArrayList(); + for (TypeRefComponent tr : d.getType()) { + TypeRefComponent tt = tr.copy(); + tt.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + types.add(tt); + } + } else { + return c; + } + } + } + + boolean first = true; + + TypeRefComponent tl = null; + for (TypeRefComponent t : types) { + if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) { + if (first) { + first = false; + } else { + c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); + } + tl = t; + if (t.hasTarget()) { + if (t.hasProfile()) { + String ref = t.getProfile().get(0).asStringValue(); + StructureDefinition tsd = context.getContext().fetchResource(StructureDefinition.class, ref); + if (tsd != null) { + // if there's multiple possible matches in scope, we will be explicit about the version + if (ref.contains("|") || hasMultipleVersions(context.getContext().fetchResourcesByUrl(StructureDefinition.class, ref))) { + c.getPieces().add(gen.new Piece(tsd.getWebPath(), tsd.getName()+"("+tsd.getVersion()+")", tsd.present())); + } else { + c.getPieces().add(gen.new Piece(tsd.getWebPath(), tsd.getName(), tsd.present())); + } + } else { + c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); + } + } else { + c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); + } + if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); + } + c.getPieces().add(gen.new Piece(null, "(", null)); + boolean tfirst = true; + for (CanonicalType u : t.getTargetProfile()) { + if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) { + if (tfirst) + tfirst = false; + else + c.addPiece(gen.new Piece(null, " | ", null)); + genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue(), null); + if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); + } + } + } + c.getPieces().add(gen.new Piece(null, ")", null)); + if (t.getAggregation().size() > 0) { + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null)); + boolean firstA = true; + for (Enumeration a : t.getAggregation()) { + if (firstA == true) + firstA = false; + else + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", ", ", null)); + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", codeForAggregation(a.getValue()), hintForAggregation(a.getValue()))); + } + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null)); + } + } else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type + String ref; + boolean pfirst = true; + for (CanonicalType p : t.getProfile()) { + if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) { + if (pfirst) { + pfirst = false; + } else { + c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); + } + + ref = context.getPkp() == null ? null : context.getPkp().getLinkForProfile(profile, p.getValue()); + if (ref != null) { + String[] parts = ref.split("\\|"); + if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) { + if (p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) { + String pp = p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT); + pp = pp.substring(pp.indexOf(".")); + c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1]+pp, t.getWorkingCode()))); + } else { + c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode()))); + } + } else { + c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode()))); + } + } else { + c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); + } + if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_PROF_SUPP)), "S", "white", "red", null, false); + } + } + } + } else { + String tc = t.getWorkingCode(); + if (Utilities.isAbsoluteUrl(tc)) { + StructureDefinition sd = context.getWorker().fetchTypeDefinition(tc); + if (sd == null) { + c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), tc, null))); + } else { + c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), sd.getTypeName(), null))); + } + } else if (context.getPkp() != null && context.getPkp().hasLinkFor(tc)) { + c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, tc), tc, null))); + } else { + c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); + } + if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); + } + } + } + } + return c; + } + + + private boolean hasMultipleVersions(List list) { + Set vl = new HashSet<>(); + for (CanonicalResource cr : list) { + vl.add(cr.getVersion()); + } + return vl.size() > 1; + } + + private String pfx(String prefix, String url) { + return Utilities.isAbsoluteUrl(url) ? url : prefix + url; + } + + private void genTargetLink(HierarchicalTableGenerator gen, String profileBaseFileName, String corePath, Cell c, TypeRefComponent t, String u, Resource src) { + if (u.startsWith("http://hl7.org/fhir/StructureDefinition/")) { + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, u, src); + if (sd != null) { + String disp = sd.hasTitle() ? sd.getTitle() : sd.getName(); + c.addPiece(checkForNoChange(t, gen.new Piece(checkPrepend(corePath, sd.getWebPath()), disp, null))); + } else { + String rn = u.substring(40); + c.addPiece(checkForNoChange(t, gen.new Piece(context.getPkp().getLinkFor(corePath, rn), rn, null))); + } + } else if (Utilities.isAbsoluteUrl(u)) { + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, u, src); + if (sd != null && context.getPkp() != null) { + String v = ""; + if (u.contains("|") || hasMultipleVersions(context.getWorker().fetchResourcesByUrl(StructureDefinition.class, u))) { + v = "("+sd.getVersion()+")"; + } + String disp = sd.present()+v; + String ref = context.getPkp().getLinkForProfile(null, sd.getUrl()); + if (ref != null && ref.contains("|")) + ref = ref.substring(0, ref.indexOf("|")); + c.addPiece(checkForNoChange(t, gen.new Piece(ref, disp, null))); + } else + c.addPiece(checkForNoChange(t, gen.new Piece(null, u, null))); + } else if (t.hasTargetProfile() && u.startsWith("#")) + c.addPiece(checkForNoChange(t, gen.new Piece(corePath+profileBaseFileName+"."+u.substring(1).toLowerCase()+".html", u, null))); + } + + private boolean isProfiledType(List theProfile) { + for (CanonicalType next : theProfile){ + if (StringUtils.defaultString(next.getValueAsString()).contains(":")) { + return true; + } + } + return false; + } + + + public String codeForAggregation(AggregationMode a) { + switch (a) { + case BUNDLED : return "b"; + case CONTAINED : return "c"; + case REFERENCED: return "r"; + default: return "?"; + } + } + + public String hintForAggregation(AggregationMode a) { + if (a != null) + return a.getDefinition(); + else + return null; + } + + + private String checkPrepend(String corePath, String path) { + if (context.getPkp() != null && context.getPkp().prependLinks() && !(path.startsWith("http:") || path.startsWith("https:"))) + return corePath+path; + else + return path; + } + + + private ElementDefinition findParent(List list, int i, String path) { + while (i > 0 && !path.startsWith(list.get(i).getPath()+".")) { + i--; + } + return list.get(i); + } + + private boolean isSibling(String[] pathCurrent, String[] pathLast, int firstDiff) { + return pathCurrent.length == pathLast.length && firstDiff == pathCurrent.length-1; + } + + + private boolean isChild(String[] pathCurrent, String[] pathLast, int firstDiff) { + return pathCurrent.length == pathLast.length+1 && firstDiff == pathLast.length; + } + + private String makeTail(String[] pathCurrent, int start, int index) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("."); + for (int i = start; i <= index; i++) { + b.append(pathCurrent[i]); + } + return b.toString(); + } + + private void genGridElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, String corePath, String imagePath, boolean root, boolean isConstraintMode) throws IOException, FHIRException { + StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); + String s = tail(element.getPath()); + List children = getChildren(all, element); + boolean isExtension = (s.equals("extension") || s.equals("modifierExtension")); + + if (!onlyInformationIsMapping(all, element)) { + Row row = gen.new Row(); + row.setId(s); + row.setAnchor(element.getPath()); + row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); + if (element.hasSlicing()) + row.setLineColor(1); + else if (element.hasSliceName()) + row.setLineColor(2); + else + row.setLineColor(0); + boolean hasDef = element != null; + String ref = defPath == null ? null : defPath + element.getId(); + UnusedTracker used = new UnusedTracker(); + used.used = true; + Cell left = gen.new Cell(); + if (element.getType().size() == 1 && element.getType().get(0).isPrimitive()) + left.getPieces().add(gen.new Piece(ref, "\u00A0\u00A0" + s, !hasDef ? null : gt(element.getDefinitionElement())).addStyle("font-weight:bold")); + else + left.getPieces().add(gen.new Piece(ref, "\u00A0\u00A0" + s, !hasDef ? null : gt(element.getDefinitionElement()))); + if (element.hasSliceName()) { + left.getPieces().add(gen.new Piece("br")); + String indent = StringUtils.repeat('\u00A0', 1+2*(element.getPath().split("\\.").length)); + left.getPieces().add(gen.new Piece(null, indent + "("+element.getSliceName() + ")", null)); + } + row.getCells().add(left); + + genCardinality(gen, element, row, hasDef, used, null); + if (hasDef && !"0".equals(element.getMax())) + genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, false); + else + row.getCells().add(gen.new Cell()); + generateGridDescription(gen, row, element, null, used.used, null, null, profile, corePath, imagePath, root, null); + /* if (element.hasSlicing()) { + if (standardExtensionSlicing(element)) { + used.used = element.hasType() && element.getType().get(0).hasProfile(); + showMissing = false; + } else { + row.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE); + row.getCells().get(2).getPieces().clear(); + for (Cell cell : row.getCells()) + for (Piece p : cell.getPieces()) { + p.addStyle("font-style: italic"); + } + } + }*/ + rows.add(row); + for (ElementDefinition child : children) + if (child.getMustSupport()) + genGridElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, corePath, imagePath, false, isConstraintMode); + } + } + + + private ExtensionContext locateExtension(Class class1, String value) { + if (value.contains("#")) { + StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value.substring(0, value.indexOf("#"))); + if (ext == null) + return null; + String tail = value.substring(value.indexOf("#")+1); + ElementDefinition ed = null; + for (ElementDefinition ted : ext.getSnapshot().getElement()) { + if (tail.equals(ted.getSliceName())) { + ed = ted; + return new ExtensionContext(ext, ed); + } + } + return null; + } else { + StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value); + if (ext == null) + return null; + else + return new ExtensionContext(ext, ext.getSnapshot().getElement().get(0)); + } + } + + + private boolean extensionIsComplex(String value) { + if (value.contains("#")) { + StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value.substring(0, value.indexOf("#"))); + if (ext == null) + return false; + String tail = value.substring(value.indexOf("#")+1); + ElementDefinition ed = null; + for (ElementDefinition ted : ext.getSnapshot().getElement()) { + if (tail.equals(ted.getSliceName())) { + ed = ted; + break; + } + } + if (ed == null) + return false; + int i = ext.getSnapshot().getElement().indexOf(ed); + int j = i+1; + while (j < ext.getSnapshot().getElement().size() && !ext.getSnapshot().getElement().get(j).getPath().equals(ed.getPath())) + j++; + return j - i > 5; + } else { + StructureDefinition ext = context.getWorker().fetchResource(StructureDefinition.class, value); + return ext != null && ext.getSnapshot().getElement().size() > 5; + } + } + + + + + private BindingResolution makeNullBr(ElementDefinitionBindingComponent binding) { + BindingResolution br = new BindingResolution(); + br.url = "http://none.none/none"; + br.display = context.formatPhrase(RenderingContext.STRUC_DEF_TODO); + return br; + } + + private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) { + if (!element.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { + return binding; + } + ElementDefinition base = (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (!base.hasBinding()) { + return binding; + } + ElementDefinitionBindingComponent o = base.getBinding(); + ElementDefinitionBindingComponent b = new ElementDefinitionBindingComponent(); + b.setUserData(ProfileUtilities.UD_DERIVATION_POINTER, o); + if (binding.hasValueSet()) { + b.setValueSet(binding.getValueSet()); + } else if (o.hasValueSet()) { + b.setValueSet(o.getValueSet()); + b.getValueSetElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getValueSetElement()); + } + if (binding.hasStrength()) { + b.setStrength(binding.getStrength()); + } else if (o.hasStrength()) { + b.setStrength(o.getStrength()); + b.getStrengthElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getStrengthElement()); + } + if (binding.hasDescription()) { + b.setDescription(binding.getDescription()); + } else if (o.hasDescription()) { + b.setDescription(o.getDescription()); + b.getDescriptionElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getDescriptionElement()); + } + // todo: derivation? + b.getExtension().addAll(binding.getExtension()); + return b; + } + + private void genFixedValue(HierarchicalTableGenerator gen, Row erow, DataType value, boolean snapshot, boolean pattern, String corePath, boolean skipnoValue) { + String ref = context.getPkp().getLinkFor(corePath, value.fhirType()); + if (ref != null && ref.contains(".html")) { + ref = ref.substring(0, ref.indexOf(".html"))+"-definitions.html#"; + } else { + ref = "?gen-fv?"; + } + StructureDefinition sd = context.getWorker().fetchTypeDefinition(value.fhirType()); + + for (org.hl7.fhir.r5.model.Property t : value.children()) { + ElementDefinition ed = findElementDefinitionOrNull(sd, t.getName()); + if (ed != null) { // might be null because of added properties across versions + if (t.getValues().size() > 0 || snapshot) { + if (t.getValues().size() == 0 || (t.getValues().size() == 1 && t.getValues().get(0).isEmpty())) { + if (!skipnoValue) { + Row row = gen.new Row(); + row.setId(ed.getPath()); + erow.getSubRows().add(row); + Cell c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : corePath+(VersionUtilities.isR5Plus(context.getWorker().getVersion()) ? "types-definitions.html#"+ed.getBase().getPath() : "element-definitions.html#"+ed.getBase().getPath())), t.getName(), null)); + c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece(null, null, null)); + c = gen.new Cell(); + row.getCells().add(c); + if (!pattern) { + c.addPiece(gen.new Piece(null, "0..0", null)); + row.setIcon("icon_fixed.gif", context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE) /*context.formatPhrase(RenderingContext.TEXT_ICON_FIXED*/); + } else if (context.getContext().isPrimitiveType(t.getTypeCode())) { + row.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); + c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); + } else if (isReference(t.getTypeCode())) { + row.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); + c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); + } else { + row.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); + c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); + } + c = gen.new Cell(); + row.getCells().add(c); + if (t.getTypeCode().contains("(")) { + String tc = t.getTypeCode(); + String tn = tc.substring(0, tc.indexOf("(")); + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, tn), tn, null)); + c.addPiece(gen.new Piece(null, "(", null)); + String[] p = tc.substring(tc.indexOf("(")+1, tc.indexOf(")")).split("\\|"); + for (String s : p) { + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, s), s, null)); + } + c.addPiece(gen.new Piece(null, ")", null)); + } else { + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, t.getTypeCode()), t.getTypeCode(), null)); + } + c = gen.new Cell(); + c.addPiece(gen.new Piece(null, ed.getShort(), null)); + row.getCells().add(c); + } + } else { + for (Base b : t.getValues()) { + Row row = gen.new Row(); + row.setId(ed.getPath()); + erow.getSubRows().add(row); + row.setIcon("icon_fixed.gif", context.formatPhrase(RenderingContext.STRUC_DEF_FIXED) /*context.formatPhrase(RenderingContext.TEXT_ICON_FIXED*/); + + Cell c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece((ed.getBase().getPath().equals(ed.getPath()) ? ref+ed.getPath() : (VersionUtilities.isR5Ver(context.getWorker().getVersion()) ? corePath+"types-definitions.html#"+ed.getBase().getPath() : corePath+"element-definitions.html#"+ed.getBase().getPath())), t.getName(), null)); + + c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece(null, null, null)); + + c = gen.new Cell(); + row.getCells().add(c); + if (pattern) + c.addPiece(gen.new Piece(null, "1.."+(t.getMaxCardinality() == 2147483647 ? "*" : Integer.toString(t.getMaxCardinality())), null)); + else + c.addPiece(gen.new Piece(null, "1..1", null)); + + c = gen.new Cell(); + row.getCells().add(c); + if (b.fhirType().contains("(")) { + String tc = b.fhirType(); + String tn = tc.substring(0, tc.indexOf("(")); + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, tn), tn, null)); + c.addPiece(gen.new Piece(null, "(", null)); + String[] p = tc.substring(tc.indexOf("(")+1, tc.indexOf(")")).split("\\|"); + for (String s : p) { + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, s), s, null)); + } + c.addPiece(gen.new Piece(null, ")", null)); + } else { + c.addPiece(gen.new Piece(context.getPkp().getLinkFor(corePath, b.fhirType()), b.fhirType(), null)); + } + + if (b.isPrimitive()) { + c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece(null, ed.getShort(), null)); + c.addPiece(gen.new Piece("br")); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE)+" ", null).addStyle("font-weight: bold")); + String s = b.primitiveValue(); + // ok. let's see if we can find a relevant link for this + String link = null; + if (Utilities.isAbsoluteUrl(s)) { + link = context.getPkp().getLinkForUrl(corePath, s); + } + c.getPieces().add(gen.new Piece(link, s, null).addStyle("color: darkgreen")); + } else { + c = gen.new Cell(); + row.getCells().add(c); + c.addPiece(gen.new Piece(null, ed.getShort(), null)); + c.addPiece(gen.new Piece("br")); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE)+" ", null).addStyle("font-weight: bold")); + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEXBRACK), null).addStyle("color: darkgreen")); + genFixedValue(gen, row, (DataType) b, snapshot, pattern, corePath, skipnoValue); + } + } + } + } + } + } + } + + + private ElementDefinition findElementDefinition(StructureDefinition sd, String name) { + String path = sd.getTypeName()+"."+name; + for (ElementDefinition ed : sd.getSnapshot().getElement()) { + if (ed.getPath().equals(path)) + return ed; + } + throw new FHIRException(context.getWorker().formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT_, path)); + } + + + private ElementDefinition findElementDefinitionOrNull(StructureDefinition sd, String name) { + String path = sd.getTypeName()+"."+name; + for (ElementDefinition ed : sd.getSnapshot().getElement()) { + if (ed.getPath().equals(path)) + return ed; + } + return null; + } + + + private String getFixedUrl(StructureDefinition sd) { + for (ElementDefinition ed : sd.getSnapshot().getElement()) { + if (ed.getPath().equals("Extension.url")) { + if (ed.hasFixed() && ed.getFixed() instanceof UriType) + return ed.getFixed().primitiveValue(); + } + } + return null; + } + + + private Piece describeCoded(HierarchicalTableGenerator gen, DataType fixed) { + if (fixed instanceof Coding) { + Coding c = (Coding) fixed; + ValidationResult vr = context.getWorker().validateCode(context.getTerminologyServiceOptions(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay()); + if (vr.getDisplay() != null) + return gen.new Piece(null, " ("+vr.getDisplay()+")", null).addStyle("color: darkgreen"); + } else if (fixed instanceof CodeableConcept) { + CodeableConcept cc = (CodeableConcept) fixed; + for (Coding c : cc.getCoding()) { + ValidationResult vr = context.getWorker().validateCode(context.getTerminologyServiceOptions(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay()); + if (vr.getDisplay() != null) + return gen.new Piece(null, " ("+vr.getDisplay()+")", null).addStyle("color: darkgreen"); + } + } + return null; + } + + + private boolean hasDescription(DataType fixed) { + if (fixed instanceof Coding) { + return ((Coding) fixed).hasDisplay(); + } else if (fixed instanceof CodeableConcept) { + CodeableConcept cc = (CodeableConcept) fixed; + if (cc.hasText()) + return true; + for (Coding c : cc.getCoding()) + if (c.hasDisplay()) + return true; + } // (fixed instanceof CodeType) || (fixed instanceof Quantity); + return false; + } + + + private boolean isCoded(DataType fixed) { + return (fixed instanceof Coding) || (fixed instanceof CodeableConcept) || (fixed instanceof CodeType) || (fixed instanceof Quantity); + } + + + private Cell generateGridDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, ElementDefinition valueDefn) throws IOException, FHIRException { + Cell c = gen.new Cell(); + row.getCells().add(c); + + if (used) { + if (definition.hasContentReference()) { + ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), definition.getContentReference(), profile); + if (ed == null) + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_REF, definition.getContentReference()), null)); + else { + if (ed.getSource() == profile) { + c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SEE, ed.getElement().getPath()), null)); + } else { + c.getPieces().add(gen.new Piece(ed.getSource().getWebPath()+"#"+ed.getElement().getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SEE, ed.getSource().getTypeName()) +"."+ed.getElement().getPath(), null)); + } + } + } + if (definition.getPath().endsWith("url") && definition.hasFixed()) { + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen"))); + } else { + if (url != null) { + if (!c.getPieces().isEmpty()) + c.addPiece(gen.new Piece("br")); + String fullUrl = url.startsWith("#") ? baseURL+url : url; + StructureDefinition ed = context.getWorker().fetchResource(StructureDefinition.class, url, profile); + String ref = null; + if (ed != null) { + String p = ed.getWebPath(); + if (p != null) { + ref = p.startsWith("http:") || context.getRules() == GenerationRules.IG_PUBLISHER ? p : Utilities.pathURL(corePath, p); + } + } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_URLS), null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(ref, fullUrl, null)); + } + + if (definition.hasSlicing()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SLICES), null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); + } + if (definition != null) { + ElementDefinitionBindingComponent binding = null; + if (valueDefn != null && valueDefn.hasBinding() && !valueDefn.getBinding().isEmpty()) + binding = valueDefn.getBinding(); + else if (definition.hasBinding()) + binding = definition.getBinding(); + if (binding!=null && !binding.isEmpty()) { + if (!c.getPieces().isEmpty()) + c.addPiece(gen.new Piece("br")); + BindingResolution br = context.getPkp().resolveBinding(profile, binding, definition.getPath()); + c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_BINDINGS), null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(binding, checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); + if (binding.hasStrength()) { + c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, " (", null))); + c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), binding.getStrength().toCode(), binding.getStrength().getDefinition()))); + c.getPieces().add(gen.new Piece(null, ")", null)); + } + if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) { + c.getPieces().add(gen.new Piece(null, ": ", null)); + c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), binding.getDescriptionElement()).asStringValue()); + } + } + for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold"))); + if (inv.getHumanElement().hasExtension(ToolingExtensions.EXT_REND_MD)) { + c.addMarkdown(inv.getHumanElement().getExtensionString(ToolingExtensions.EXT_REND_MD)); + } else { + c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getHuman(), null))); + } + } + if (definition.hasFixed()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED_VALUE), null).addStyle("font-weight:bold"))); + String s = buildJson(definition.getFixed()); + String link = null; + if (Utilities.isAbsoluteUrl(s)) + link = context.getPkp().getLinkForUrl(corePath, s); + c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen"))); + } else if (definition.hasPattern()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_REQUIRED_PATT), null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); + } else if (definition.hasExample()) { + for (ElementDefinitionExampleComponent ex : definition.getExample()) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_EXAMPLE) +"'"+("".equals("General")? "": " "+ex.getLabel()+"'")+": ", "").addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); + } + } + if (definition.hasMaxLength() && definition.getMaxLength()!=0) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_LENGTH), null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); + } + if (profile != null) { + for (StructureDefinitionMappingComponent md : profile.getMapping()) { + if (md.hasExtension(ToolingExtensions.EXT_TABLE_NAME)) { + ElementDefinitionMappingComponent map = null; + for (ElementDefinitionMappingComponent m : definition.getMapping()) + if (m.getIdentity().equals(md.getIdentity())) + map = m; + if (map != null) { + for (int i = 0; i list, ElementDefinition e) { + return (!e.hasSliceName() && !e.hasSlicing() && (onlyInformationIsMapping(e))) && + getChildren(list, e).isEmpty(); + } + + private boolean onlyInformationIsMapping(ElementDefinition d) { + return !d.hasShort() && !d.hasDefinition() && + !d.hasRequirements() && !d.getAlias().isEmpty() && !d.hasMinElement() && + !d.hasMax() && !d.getType().isEmpty() && !d.hasContentReference() && + !d.hasExample() && !d.hasFixed() && !d.hasMaxLengthElement() && + !d.getCondition().isEmpty() && !d.getConstraint().isEmpty() && !d.hasMustSupportElement() && + !d.hasBinding(); + } + + private boolean allAreReference(List types) { + for (TypeRefComponent t : types) { + if (!t.hasTarget()) + return false; + } + return true; + } + + private List getChildren(List all, ElementDefinition element) { + List result = new ArrayList(); + int i = all.indexOf(element)+1; + while (i < all.size() && all.get(i).getPath().length() > element.getPath().length()) { + if ((all.get(i).getPath().substring(0, element.getPath().length()+1).equals(element.getPath()+".")) && !all.get(i).getPath().substring(element.getPath().length()+1).contains(".")) + result.add(all.get(i)); + i++; + } + return result; + } + + + protected String tail(String path) { + if (path == null) { + return ""; + } else if (path.contains(".")) + return path.substring(path.lastIndexOf('.')+1); + else + return path; + } + + private boolean slicesExist(List elements, ElementDefinition element) { + if (elements == null) { + return true; + } + boolean found = false; + int start = elements.indexOf(element); + if (start < 0) { + return false; + } + for (int i = start; i < elements.size(); i++) { + ElementDefinition ed = elements.get(i); + if (ed.getPath().equals(element.getPath())) { + if (ed.hasSliceName()) { + found = true; + } + } + if (ed.getPath().length() < element.getPath().length()) { + break; + } + } + return found; + } + + + private Cell addCell(Row row, Cell cell) { + row.getCells().add(cell); + return (cell); + } + + private String checkAdd(String src, String app) { + return app == null ? src : src + app; + } + + public boolean hasNonBaseConditions(List conditions) { + for (IdType c : conditions) { + if (!isBaseCondition(c)) { + return true; + } + } + return false; + } + + + public boolean hasNonBaseConstraints(List constraints) { + for (ElementDefinitionConstraintComponent c : constraints) { + if (!isBaseConstraint(c)) { + return true; + } + } + return false; + } + + public String listConstraintsAndConditions(ElementDefinition element) { + Set ids = new HashSet<>(); + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (ElementDefinitionConstraintComponent con : element.getConstraint()) { + if (!isBaseConstraint(con)) { + if (!ids.contains(con.getKey())) { + ids.add(con.getKey()); + b.append(con.getKey()); + } + } + } + for (IdType id : element.getCondition()) { + if (!isBaseCondition(id)) { + if (!ids.contains(id.asStringValue())) { + ids.add(id.asStringValue()); + b.append(id.asStringValue()); + } + } + } + return b.toString(); + } + + private boolean isBaseCondition(IdType c) { + String key = c.asStringValue(); + return key != null && (key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-")); + } + + private boolean isBaseConstraint(ElementDefinitionConstraintComponent con) { + String key = con.getKey(); + return key != null && (key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-")); + } + + private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode, Resource src) { + // create a child for each choice + for (TypeRefComponent tr : element.getType()) { + if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) { + boolean used = false; + Row choicerow = gen.new Row(); + choicerow.setId(element.getPath()); + String t = tr.getWorkingCode(); + if (isReference(t)) { + used = true; + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null)); + choicerow.getCells().add(gen.new Cell()); + choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); + choicerow.setIcon("icon_reference.png", context.formatPhrase(RenderingContext.TEXT_ICON_REFERENCE)); + Cell c = gen.new Cell(); + choicerow.getCells().add(c); + if (ADD_REFERENCE_TO_TABLE) { + if (tr.getWorkingCode().equals("canonical")) + c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); + else + c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); + if (!mustSupportMode && isMustSupportDirect(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); + } + c.getPieces().add(gen.new Piece(null, "(", null)); + } + boolean first = true; + for (CanonicalType rt : tr.getTargetProfile()) { + if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) { + if (!first) + c.getPieces().add(gen.new Piece(null, " | ", null)); + genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue(), src); + if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TARG_SUPP)), "S", "white", "red", null, false); + } + first = false; + } + } + if (first) { + c.getPieces().add(gen.new Piece(null, "Any", null)); + } + + if (ADD_REFERENCE_TO_TABLE) { + c.getPieces().add(gen.new Piece(null, ")", null)); + } + + } else { + StructureDefinition sd = context.getWorker().fetchTypeDefinition(t); + if (sd == null) { + System.out.println("Unable to find "+t); + sd = context.getWorker().fetchTypeDefinition(t); + } else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { + used = true; + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); + choicerow.getCells().add(gen.new Cell()); + choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); + choicerow.setIcon("icon_primitive.png", context.formatPhrase(RenderingContext.TEXT_ICON_PRIMITIVE)); + Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getTypeName(), null, null); + choicerow.getCells().add(c); + if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TARG_SUPP)), "S", "white", "red", null, false); + } + } else { + used = true; + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); + choicerow.getCells().add(gen.new Cell()); + choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); + choicerow.setIcon("icon_datatype.gif", context.formatPhrase(RenderingContext.TEXT_ICON_DATATYPE)); + Cell c = gen.new Cell(null, context.getPkp().getLinkFor(corePath, t), sd.getTypeName(), null, null); + choicerow.getCells().add(c); + if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false); + } + } + if (tr.hasProfile() && used) { + Cell typeCell = choicerow.getCells().get(3); + typeCell.addPiece(gen.new Piece(null, "(", null)); + boolean first = true; + for (CanonicalType pt : tr.getProfile()) { + if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) { + if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); + StructureDefinition psd = context.getWorker().fetchResource(StructureDefinition.class, pt.getValue(), src); + if (psd == null) + typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); + else + typeCell.addPiece(gen.new Piece(psd.getWebPath(), psd.getName(), psd.present())); + if (!mustSupportMode && isMustSupport(pt) && element.getMustSupport()) { + typeCell.addPiece(gen.new Piece(null, " ", null)); + typeCell.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_PROF_SUPP)), "S", "white", "red", null, false); + } + } + } + typeCell.addPiece(gen.new Piece(null, ")", null)); + } + } + if (used) { + choicerow.getCells().add(gen.new Cell()); + subRows.add(choicerow); + } + } + } + } + + private boolean isReference(String t) { + return t.equals("Reference") || t.equals("canonical"); + } + + + + private List readChoices(ElementDefinition ed, List children) { + List result = new ArrayList<>(); + for (ElementDefinitionConstraintComponent c : ed.getConstraint()) { + ElementChoiceGroup grp = context.getProfileUtilities().processConstraint(children, c); + if (grp != null) { + result.add(grp); + } + } + return result; + } + + private Piece checkForNoChange(Element src1, Element src2, Piece piece) { + if (src1.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS) && src2.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + piece.addStyle("opacity: 0.5"); + } + return piece; + } + + + private String buildJson(DataType value) throws IOException { + if (value instanceof PrimitiveType) + return ((PrimitiveType) value).asStringValue(); + + IParser json = new JsonParser(); + return json.composeString(value, null); + } + + private String describeSlice(ElementDefinitionSlicingComponent slicing) { + return formatPhrase(RenderingContext.SD_SLICING_INFO, slicing.getOrdered() ? (context.formatPhrase(RenderingContext.STRUC_DEF_ORDERED)) : (context.formatPhrase(RenderingContext.STRUC_DEF_UNORDERED)), describe(slicing.getRules()), commas(slicing.getDiscriminator())); + } + + + + private String commas(List list) { + CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder(); + for (ElementDefinitionSlicingDiscriminatorComponent id : list) + c.append((id.hasType() ? id.getType().toCode() : "??")+":"+id.getPath()); + return c.toString(); + } + + + private String describe(SlicingRules rules) { + if (rules == null) + return (context.formatPhrase(RenderingContext.STRUC_DEF_UNSPECIFIED)); + switch (rules) { + case CLOSED : return (context.formatPhrase(RenderingContext.STRUC_DEF_CLOSED)); + case OPEN : return (context.formatPhrase(RenderingContext.STRUC_DEF_OPEN)); + case OPENATEND : return (context.formatPhrase(RenderingContext.STRUC_DEF_OPEN_END)); + default: + return "?gen-sr?"; + } + } + + private boolean allTypesMustSupport(ElementDefinition e) { + boolean all = true; + boolean any = false; + for (TypeRefComponent tr : e.getType()) { + all = all && isMustSupport(tr); + any = any || isMustSupport(tr); + } + return !all && !any; + } + + private boolean allProfilesMustSupport(List profiles) { + boolean all = true; + boolean any = false; + for (CanonicalType u : profiles) { + all = all && isMustSupport(u); + any = any || isMustSupport(u); + } + return !all && !any; + } + public boolean isMustSupportDirect(TypeRefComponent tr) { + return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); + } + + public boolean isMustSupport(TypeRefComponent tr) { + if ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + if (isMustSupport(tr.getProfile())) { + return true; + } + return isMustSupport(tr.getTargetProfile()); + } + + public boolean isMustSupport(List profiles) { + for (CanonicalType ct : profiles) { + if (isMustSupport(ct)) { + return true; + } + } + return false; + } + + + public boolean isMustSupport(CanonicalType profile) { + return "true".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_MUST_SUPPORT)); + } + + + + private SpanEntry buildSpanEntryFromProfile(String name, String cardinality, StructureDefinition profile) throws IOException { + SpanEntry res = new SpanEntry(); + res.setName(name); + res.setCardinality(cardinality); + res.setProfileLink(profile.getWebPath()); + res.setResType(profile.getTypeName()); + StructureDefinition base = context.getWorker().fetchResource(StructureDefinition.class, res.getResType()); + if (base != null) + res.setResLink(base.getWebPath()); + res.setId(profile.getId()); + res.setProfile(profile.getDerivation() == TypeDerivationRule.CONSTRAINT); + StringBuilder b = new StringBuilder(); + b.append(res.getResType()); + boolean first = true; + boolean open = false; + if (profile.getDerivation() == TypeDerivationRule.CONSTRAINT) { + res.setDescription(profile.getName()); + for (ElementDefinition ed : profile.getSnapshot().getElement()) { + if (isKeyProperty(ed.getBase().getPath()) && ed.hasFixed()) { + if (first) { + open = true; + first = false; + b.append("["); + } else { + b.append(", "); + } + b.append(tail(ed.getBase().getPath())); + b.append("="); + b.append(summarize(ed.getFixed())); + } + } + if (open) + b.append("]"); + } else + res.setDescription(context.formatPhrase(RenderingContext.STRUC_DEF_FHIR, profile.getName())+" "); + res.setType(b.toString()); + return res ; + } + + + private String summarize(DataType value) throws IOException { + if (value instanceof Coding) + return summarizeCoding((Coding) value); + else if (value instanceof CodeableConcept) + return summarizeCodeableConcept((CodeableConcept) value); + else + return buildJson(value); + } + + + private String summarizeCoding(Coding value) { + String uri = value.getSystem(); + String system = displaySystem(uri); + if (Utilities.isURL(system)) { + if (system.equals("http://cap.org/protocols")) + system = context.formatPhrase(RenderingContext.STRUC_DEF_CAP); + } + return system+" "+value.getCode(); + } + + + private String summarizeCodeableConcept(CodeableConcept value) { + if (value.hasCoding()) + return summarizeCoding(value.getCodingFirstRep()); + else + return value.getText(); + } + + + private boolean isKeyProperty(String path) { + return Utilities.existsInList(path, "Observation.code"); + } + + + private TableModel initSpanningTable(HierarchicalTableGenerator gen, String prefix, boolean isLogical, String id) throws IOException { + TableModel model = gen.new TableModel(id, true); + + if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { + model.setDocoImg(HierarchicalTableGenerator.help16AsData()); + } else { + model.setDocoImg(Utilities.pathURL(prefix, "help16.png")); + } + model.setDocoRef(Utilities.pathURL(prefix, "formats.html#table")); // todo: change to graph definition + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_PROPERTY), context.formatPhrase(RenderingContext.STRUC_DEF_PROF_RES), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_CARD), context.formatPhrase(RenderingContext.STRUC_DEF_MAX_MIN), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_CONTENT), context.formatPhrase(RenderingContext.STRUC_DEF_WHAT), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.STRUC_DEF_DESC), context.formatPhrase(RenderingContext.STRUC_DEF_DESC_PROF), null, 0)); + return model; + } + + private void genSpanEntry(HierarchicalTableGenerator gen, List rows, SpanEntry span) throws IOException { + Row row = gen.new Row(); + row.setId("??"); + rows.add(row); + row.setAnchor(span.getId()); + //row.setColor(..?); + if (span.isProfile()) { + row.setIcon("icon_profile.png", context.formatPhrase(RenderingContext.TEXT_ICON_PROFILE)); + } else { + row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.TEXT_ICON_RESOURCE)); + } + + row.getCells().add(gen.new Cell(null, null, span.getName(), null, null)); + row.getCells().add(gen.new Cell(null, null, span.getCardinality(), null, null)); + row.getCells().add(gen.new Cell(null, span.getProfileLink(), span.getType(), null, null)); + row.getCells().add(gen.new Cell(null, null, span.getDescription(), null, null)); + + for (SpanEntry child : span.getChildren()) { + genSpanEntry(gen, row.getSubRows(), child); + } + } + + + public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set outputTracker) throws IOException, FHIRException { + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true); + TableModel model = initSpanningTable(gen, "", false, profile.getId()); + Set processed = new HashSet(); + SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); + + genSpanEntry(gen, model.getRows(), span); + return gen.generate(model, "", 0, outputTracker); + } + + private SpanEntry buildSpanningTable(String name, String cardinality, StructureDefinition profile, Set processed, boolean onlyConstraints, String constraintPrefix) throws IOException { + SpanEntry res = buildSpanEntryFromProfile(name, cardinality, profile); + boolean wantProcess = !processed.contains(profile.getUrl()); + processed.add(profile.getUrl()); + if (wantProcess && profile.getDerivation() == TypeDerivationRule.CONSTRAINT) { + for (ElementDefinition ed : profile.getSnapshot().getElement()) { + if (!"0".equals(ed.getMax()) && ed.getType().size() > 0) { + String card = getCardinality(ed, profile.getSnapshot().getElement()); + if (!card.endsWith(".0")) { + List refProfiles = listReferenceProfiles(ed); + if (refProfiles.size() > 0) { + String uri = refProfiles.get(0); + if (uri != null) { + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, uri); + if (sd != null && (!onlyConstraints || (sd.getDerivation() == TypeDerivationRule.CONSTRAINT && (constraintPrefix == null || sd.getUrl().startsWith(constraintPrefix))))) { + res.getChildren().add(buildSpanningTable(nameForElement(ed), card, sd, processed, onlyConstraints, constraintPrefix)); + } + } + } } } - if (ul.isEmpty()) { - ret.remove(ul); - } - } - if (obr.hasObligations()) { - XhtmlNode tbl = ret.table("grid"); - obr.renderTable(tbl.getChildNodes(), true); - if (tbl.isEmpty()) { - ret.remove(tbl); - } - } - return ret.hasChildren() ? ret : null; - } else { - return null; - } - } - - private XhtmlNode describeAllowedUnits(ElementDefinition d) { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - DataType au = ToolingExtensions.getAllowedUnits(d); - if (au instanceof CanonicalType) { - String url = ((CanonicalType) au).asStringValue(); - ValueSet vs = context.getContext().findTxResource(ValueSet.class, url); - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_VALUE)+" "); - genCT(ret, url, vs); - return ret; - } else if (au instanceof CodeableConcept) { - CodeableConcept cc = (CodeableConcept) au; - if (cc.getCoding().size() != 1) { - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_ONE_OF)); - } - ret.tx(summarise(cc)); - return ret; - } - return null; - } - - private void genCT(XhtmlNode x, String url, CanonicalResource cr) { - if (cr == null) { - x.code().tx(url); - } else if (!cr.hasWebPath()) { - x.ah(url).tx(cr.present()); - } else { - x.ah(cr.getWebPath()).tx(cr.present()); - } - } - - private boolean hasPrimitiveTypes(ElementDefinition d) { - for (TypeRefComponent tr : d.getType()) { - if (context.getContext().isPrimitiveType(tr.getCode())) { - return true; - } - } - return false; - } - - - private XhtmlNode renderCanonicalListExt(String text, List list) { - List clist = new ArrayList<>(); - for (Extension ext : list) { - if (ext.hasValueCanonicalType()) { - clist.add(ext.getValueCanonicalType()); - } - } - return renderCanonicalList(text, clist); - } - - private XhtmlNode renderCanonicalList(String text, List list) { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - ret.tx(text); - var ul = ret.ul(); - for (CanonicalType ct : list) { - CanonicalResource cr = (CanonicalResource) context.getContext().fetchResource(Resource.class, ct.getValue()); - genCT(ul.li(), ct.getValue(), cr); - } - return ret; - } - - private StandardsStatus determineStandardsStatus(StructureDefinition sd, ElementDefinition ed) { - if (ed != null && ed.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { - return StandardsStatus.fromCode(ed.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); - } - while (sd != null) { - if (sd.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { - return ToolingExtensions.getStandardsStatus(sd); - } - sd = context.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); - } - return null; - } - - private boolean hasChoices(List types) { - for (TypeRefComponent type : types) { - if (type.getProfile().size() > 1 || type.getTargetProfile().size() > 1) { - return true; - } - } - return types.size() > 1; - } - - private String sliceOrderString(ElementDefinitionSlicingComponent slicing) { - if (slicing.getOrdered()) - return context.formatPhrase(RenderingContext.STRUC_DEF_ORDERED); - else - return context.formatPhrase(RenderingContext.STRUC_DEF_UNORDERED); - } - - private void generateSlicing(XhtmlNode tbl, StructureDefinition profile, ElementDefinition ed, ElementDefinitionSlicingComponent slicing, ElementDefinition compare, int mode, boolean strikethrough) throws IOException { - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - - x.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_SET_SLICES)+" ", ed.getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SET_ARE)); - String newOrdered = sliceOrderString(slicing); - String oldOrdered = (compare==null || !compare.hasSlicing()) ? null : sliceOrderString(compare.getSlicing()); - compareString(x, newOrdered, slicing.getOrderedElement(), null, null, null, oldOrdered, null, mode, false, false); - x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_AND) + " "); - compareString(x, slicing.hasRules() ? slicing.getRules().getDisplay() : null, slicing.getRulesElement(), null, "rules", slicing, compare!=null && compare.hasSlicing() && compare.getSlicing().hasRules() ? compare.getSlicing().getRules().getDisplay() : null, null, mode, false, false); - - if (slicing.hasDiscriminator()) { - x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_DESCRIM)); - StatusList list = new StatusList<>(); - for (ElementDefinitionSlicingDiscriminatorComponent d : slicing.getDiscriminator()) { - list.add(new DiscriminatorWithStatus(d)); - } - if (compare != null) { - for (ElementDefinitionSlicingDiscriminatorComponent d : slicing.getDiscriminator()) { - list.merge(new DiscriminatorWithStatus(d)); - } - } - var ul = x.ul(); - for (DiscriminatorWithStatus rc : list) { - rc.render(x.li()); - } - } else { - x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_NO_DESCRIM)); - } - tableRow(tbl, "Slicing", "profiling.html#slicing", strikethrough, x); - tbl.tx("\r\n"); - } - - private XhtmlNode tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough) throws IOException { - var tr = x.tr(); - if (strikethrough) { - tr.style("text-decoration: line-through"); - } - addFirstCell(name, defRef, tr); - return tr.td(); - } - - - private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, XhtmlNode possibleTd) throws IOException { - if (possibleTd != null && !possibleTd.isEmpty()) { - var tr = x.tr(); - if (strikethrough) { - tr.style("text-decoration: line-through"); - } - addFirstCell(name, defRef, tr); - tr.td().copyAllContent(possibleTd); - } - } - - private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, String text) throws IOException { - if (!Utilities.noString(text)) { - var tr = x.tr(); - if (strikethrough) { - tr.style("text-decoration: line-through"); - } - addFirstCell(name, defRef, tr); - tr.td().tx(text); - } - } - - private void tableRowLink(XhtmlNode x, String name, String defRef, boolean strikethrough, String text, String link) throws IOException { - if (!Utilities.noString(text)) { - var tr = x.tr(); - if (strikethrough) { - tr.style("text-decoration: line-through"); - } - addFirstCell(name, defRef, tr); - tr.td().ah(link).tx(text); - } - } - - private void addFirstCell(String name, String defRef, XhtmlNode tr) { - var td = tr.td(); - if (name.length() <= 16) { - td.style("white-space: nowrap"); - } - if (defRef == null) { - td.tx(name); - } else if (Utilities.isAbsoluteUrl(defRef)) { - td.ah(defRef).tx(name); - } else { - td.ah(corePath+defRef).tx(name); - } - } - - private String head(String path) { - if (path.contains(".")) - return path.substring(0, path.indexOf(".")); - else - return path; - } - private String nottail(String path) { - if (path.contains(".")) - return path.substring(0, path.lastIndexOf(".")); - else - return path; - } - - private XhtmlNode businessIdWarning(String resource, String name) { - if (name.equals("identifier")) { - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_BUSINESS_ID)+" "); - ret.ah(corePath + "resource.html#identifiers").tx(context.formatPhrase(RenderingContext.STRUC_DEF_DISCUSSION)); - ret.tx(")"); - return ret; + } } - if (name.equals("version")) {// && !resource.equals("Device")) - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_BUSINESS_VERID)+" "); - ret.ah(corePath + "resource.html#versions").tx(context.formatPhrase(RenderingContext.STRUC_DEF_DISCUSSION)); - ret.tx(")"); - return ret; - } - return null; - } - - private XhtmlNode describeCardinality(ElementDefinition d, ElementDefinition compare, int mode) throws IOException { - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - if (compare==null || mode==GEN_MODE_DIFF) { - if (!d.hasMax() && !d.hasMin()) - return null; - else if (d.getMax() == null) { - renderStatus(d.getMinElement(), x).tx(toStr(d.getMin())); - x.tx("..?"); - } else { - renderStatus(d.getMinElement(), x).tx(toStr(d.getMin())); - x.tx( ".."); - renderStatus(d.getMaxElement(), x).tx( d.getMax()); - } - } else { - if (!(mode==GEN_MODE_DIFF && (d.getMin()==compare.getMin() || d.getMin()==0))) { - compareString(x, toStr(d.getMin()), d.getMinElement(), null, "min", d, toStr(compare.getMin()), null, mode, false, false); - } - x.tx(".."); - if (!(mode==GEN_MODE_DIFF && (d.getMax().equals(compare.getMax()) || "1".equals(d.getMax())))) { - compareString(x, d.getMax(), d.getMaxElement(), null, "max", d, compare.getMax(), null, mode, false, false); - } - } - XhtmlNode t = compareSimpleTypeLists(d.getCondition(), compare == null ? null : compare.getCondition(), mode); - if (t != null) { - x.br(); - x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_INVARIANT)+" "); - x.copyAllContent(t); - } - return x; - } - - private boolean hasMustSupportTypes(List types) { - for (TypeRefComponent tr : types) { - if (isMustSupport(tr)) { - return true; - } - } - return false; - } - - private XhtmlNode describeTypes(List types, boolean mustSupportOnly, ElementDefinition ed, ElementDefinition compare, int mode, ElementDefinition value, ElementDefinition compareValue, StructureDefinition sd) throws FHIRException, IOException { - if (types.isEmpty()) - return null; - - List compareTypes = compare==null ? new ArrayList<>() : compare.getType(); - XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); - if ((!mustSupportOnly && types.size() == 1 && compareTypes.size() <=1 && (mode != GEN_MODE_DIFF || !VersionComparisonAnnotation.hasDeleted(ed, "type"))) || (mustSupportOnly && mustSupportCount(types) == 1)) { - if (!mustSupportOnly || isMustSupport(types.get(0))) { - describeType(ret, types.get(0), mustSupportOnly, compareTypes.size()==0 ? null : compareTypes.get(0), mode, sd); - } - } else { - boolean first = true; - if (types.size() > 1) { - ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_OF)+" "); - } - Map map = new HashMap(); - for (TypeRefComponent t : compareTypes) { - map.put(t.getCode(), t); - } - for (TypeRefComponent t : types) { - TypeRefComponent compareType = map.get(t.getCode()); - if (compareType!=null) - map.remove(t.getCode()); - if (!mustSupportOnly || isMustSupport(t)) { - if (first) { - first = false; - } else { - ret.tx(", "); - } - describeType(ret, t, mustSupportOnly, compareType, mode, sd); - } - } - for (TypeRefComponent t : map.values()) { - ret.tx(", "); - describeType(removed(ret), t, mustSupportOnly, null, mode, sd); - } - if (mode == GEN_MODE_DIFF) { - for (Base b : VersionComparisonAnnotation.getDeleted(ed, "type")) { - TypeRefComponent t = (TypeRefComponent) b; - ret.tx(", "); - describeType(ret, t, false, null, mode, sd); - } - } - } - if (value != null) { - XhtmlNode xt = processSecondary(mode, value, compareValue, mode, sd); - if (xt != null) { - ret.copyAllContent(xt); - } - } - return ret; - } - - private XhtmlNode processSecondary(int mode, ElementDefinition value, ElementDefinition compareValue, int compMode, StructureDefinition sd) throws FHIRException, IOException { - switch (mode) { - case 1: - return null; - case 2: - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_COMP_EX)); - return x; - case 3: - x = new XhtmlNode(NodeType.Element, "div"); - x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_EX_TYPE)+" "); - x.copyAllContent(describeTypes(value.getType(), false, value, compareValue, compMode, null, null, sd)); - x.tx(")"); - return x; - default: - return null; - } - } - - - private int mustSupportCount(List types) { - int c = 0; - for (TypeRefComponent tr : types) { - if (isMustSupport(tr)) { - c++; - } - } - return c; - } - - - private void describeType(XhtmlNode x, TypeRefComponent t, boolean mustSupportOnly, TypeRefComponent compare, int mode, StructureDefinition sd) throws FHIRException, IOException { - if (t.getWorkingCode() == null) { - return; - } - if (t.getWorkingCode().startsWith("=")) { - return; - } - - boolean ts = false; - if (t.getWorkingCode().startsWith("xs:")) { - ts = compareString(x, t.getWorkingCode(), t, null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode, false, false); - } else { - ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode, false, false); - } - - if ((!mustSupportOnly && (t.hasProfile() || (compare!=null && compare.hasProfile()))) || isMustSupport(t.getProfile())) { - StatusList profiles = analyseProfiles(t.getProfile(), compare == null ? null : compare.getProfile(), mustSupportOnly, mode); - if (profiles.size() > 0) { - if (!ts) { - getTypeLink(unchanged(x), t, sd); - ts = true; - } - x.tx("("); - boolean first = true; - for (ResolvedCanonical rc : profiles) { - if (first) first = false; else x.tx(", "); - rc.render(x); - } - x.tx(")"); - } - } - - if ((!mustSupportOnly && (t.hasTargetProfile() || (compare!=null && compare.hasTargetProfile()))) || isMustSupport(t.getTargetProfile())) { - List profiles = analyseProfiles(t.getTargetProfile(), compare == null ? null : compare.getTargetProfile(), mustSupportOnly, mode); - if (profiles.size() > 0) { - if (!ts) { - getTypeLink(unchanged(x), t, sd); - } - x.tx("("); // todo: double use of "(" is problematic - boolean first = true; - for (ResolvedCanonical rc : profiles) { - if (first) first = false; else x.tx(", "); - rc.render(x); - } - x.tx(")"); - } - - if (!t.getAggregation().isEmpty() || (compare!=null && !compare.getAggregation().isEmpty())) { - - for (Enumeration a :t.getAggregation()) { - a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); - } - if (compare!=null) { - for (Enumeration a : compare.getAggregation()) { - a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); - } - } - var xt = compareSimpleTypeLists(t.getAggregation(), compare == null ? null : compare.getAggregation(), mode); - if (xt != null) { - x.copyAllContent(xt); - } - } - } - } - - private StatusList analyseProfiles(List newProfiles, List oldProfiles, boolean mustSupportOnly, int mode) { - StatusList profiles = new StatusList(); - for (CanonicalType pt : newProfiles) { - ResolvedCanonical rc = fetchProfile(pt, mustSupportOnly); - profiles.add(rc); - } - if (oldProfiles!=null && mode != GEN_MODE_DIFF) { - for (CanonicalType pt : oldProfiles) { - profiles.merge(fetchProfile(pt, mustSupportOnly)); - } - } - return profiles; - } - - private ResolvedCanonical fetchProfile(CanonicalType pt, boolean mustSupportOnly) { - if (!pt.hasValue()) { - return null; - } - if (!mustSupportOnly || isMustSupport(pt)) { - StructureDefinition p = context.getContext().fetchResource(StructureDefinition.class, pt.getValue()); - return new ResolvedCanonical(pt.getValue(), p); - } else { - return null; - } - } -// -// private String getTypeProfile(CanonicalType pt, boolean mustSupportOnly) { -// StringBuilder b = new StringBuilder(); -// if (!mustSupportOnly || isMustSupport(pt)) { -// StructureDefinition p = context.getContext().fetchResource(StructureDefinition.class, pt.getValue()); -// if (p == null) -// b.append(pt.getValue()); -// else { -// String pth = p.getWebPath(); -// b.append(""); -// b.append(p.getName()); -// b.append(""); -// } -// } -// return b.toString(); -// } - - private void getTypeLink(XhtmlNode x, TypeRefComponent t, StructureDefinition sd) { - String s = context.getPkp().getLinkFor(sd.getWebPath(), t.getWorkingCode()); - if (s != null) { - x.ah(s).tx(t.getWorkingCode()); - } else { - x.code().tx(t.getWorkingCode()); - } - } - - - private String getTypeLink(TypeRefComponent t, StructureDefinition sd) { - String s = context.getPkp().getLinkFor(sd.getWebPath(), t.getWorkingCode()); - return s; - } - - private XhtmlNode displayBoolean(boolean value, BooleanType source, String name, Base parent, BooleanType compare, int mode) { - String newValue = value ? "true" : source.hasValue() ? "false" : null; - String oldValue = compare==null || compare.getValue()==null ? null : (compare.getValue()!=true ? null : "true"); - return compareString(newValue, source, null, name, parent, oldValue, null, mode, false, false); - } - - - private XhtmlNode invariants(List originalList, List compareList, ElementDefinition parent, int mode) throws IOException { - StatusList list = new StatusList<>(); - for (ElementDefinitionConstraintComponent v : originalList) { - if (!v.isEmpty()) { - list.add(new InvariantWithStatus(v)); - } - } - if (compareList != null && mode != GEN_MODE_DIFF) { - for (ElementDefinitionConstraintComponent v : compareList) { - list.merge(new InvariantWithStatus(v)); - } - } - if (list.size() == 0) { - return null; - } - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - boolean first = true; - for (InvariantWithStatus t : list) { - if (first) first = false; else x.br(); - t.render(x); - } - for (Base b : VersionComparisonAnnotation.getDeleted(parent, "invariant")) { - if (first) first = false; else x.br(); - InvariantWithStatus ts = new InvariantWithStatus((ElementDefinitionConstraintComponent) b); - ts.render(x); - } - return x; - } - - private XhtmlNode describeBinding(StructureDefinition sd, ElementDefinition d, String path, ElementDefinition compare, int mode) throws FHIRException, IOException { - if (!d.hasBinding()) - return null; - else { - ElementDefinitionBindingComponent binding = d.getBinding(); - ElementDefinitionBindingComponent compBinding = compare == null ? null : compare.getBinding(); - XhtmlNode bindingDesc = null; - if (binding.hasDescription()) { - MarkdownType newBinding = PublicationHacker.fixBindingDescriptions(context.getContext(), binding.getDescriptionElement()); - if (mode == GEN_MODE_SNAP || mode == GEN_MODE_MS) { - bindingDesc = new XhtmlNode(NodeType.Element, "div"); - bindingDesc.addChildren(new XhtmlParser().parseMDFragment(hostMd.processMarkdown("Binding.description", newBinding))); - } else { - - StringType oldBinding = compBinding != null && compBinding.hasDescription() ? PublicationHacker.fixBindingDescriptions(context.getContext(), compBinding.getDescriptionElement()) : null; - bindingDesc = compareMarkdown("Binding.description", newBinding, oldBinding, mode); - } - } - if (!binding.hasValueSet()) { - return bindingDesc; - } - - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - var nsp = x.span(); - renderBinding(nsp, binding, compBinding, path, sd, mode); - if (bindingDesc != null) { - if (isSimpleContent(bindingDesc)) { - x.tx(": "); - x.copyAllContent(bindingDesc.getChildNodes().get(0)); - } else { - x.br(); - x.copyAllContent(bindingDesc); - } - } - - AdditionalBindingsRenderer abr = new AdditionalBindingsRenderer(context.getPkp(), corePath, sd, d.getPath(), context, hostMd, this); - - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { - abr.seeMaxBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), compBinding==null ? null : ToolingExtensions.getExtension(compBinding, ToolingExtensions.EXT_MAX_VALUESET), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); - } - if (binding.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { - abr.seeMinBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MIN_VALUESET), compBinding==null ? null : ToolingExtensions.getExtension(compBinding, ToolingExtensions.EXT_MIN_VALUESET), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); - } - if (binding.hasExtension(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { - abr.seeAdditionalBindings(binding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL), compBinding==null ? null : compBinding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); - } - - if (abr.hasBindings()) { - var tbl = x.table("grid"); - abr.render(tbl.getChildNodes(), true); - } - return x; - } - } - - private boolean isSimpleContent(XhtmlNode bindingDesc) { - return bindingDesc.getChildNodes().size() == 1 && bindingDesc.getChildNodes().get(0).isPara(); - } - - private void renderBinding(XhtmlNode span, ElementDefinitionBindingComponent binding, ElementDefinitionBindingComponent compare, String path, StructureDefinition sd, int mode) { - compareString(span, conf(binding), binding.getStrengthElement(), null, "strength", binding, compare == null ? null : conf(compare), null, mode, false, false); - span.tx(" "); - BindingResolution br = context.getPkp().resolveBinding(sd, binding, path); - compareString(span, br.display, binding.getValueSetElement(), br.url, "valueSet", binding, compare == null ? null : compare.getValueSet(), null, mode, br.external, false); - if (binding.hasStrength() || binding.hasValueSet()) { - span.br(); - span.tx("("); - if (binding.hasStrength()) { - span.ah(Utilities.pathURL(corePath, "terminologies.html#"+binding.getStrength().toCode())).tx(binding.getStrength().toCode()); - } - if (binding.hasStrength() && binding.hasValueSet()) { - span.tx(" "); - } - if (binding.hasValueSet()) { - span.tx("to "); - XhtmlNode ispan = span.spanClss("copy-text-inline"); - ispan.code().tx(binding.getValueSet()); - ispan.button("btn-copy", context.formatPhrase(RenderingContext.STRUC_DEF_COPY_URL)).attribute("data-clipboard-text", binding.getValueSet()); - } - span.tx(")"); - } - } - - private String stripPara(String s) { - if (s.startsWith("

")) { - s = s.substring(3); - } - if (s.trim().endsWith("

")) { - s = s.substring(0, s.lastIndexOf("

")-1) + s.substring(s.lastIndexOf("

") +4); - } - return s; - } - - private String conf(ElementDefinitionBindingComponent def) { - if (def.getStrength() == null) { - return context.formatPhrase(RenderingContext.STRUC_DEF_FOR_CODE)+" "; - } - switch (def.getStrength()) { - case EXAMPLE: - return context.formatPhrase(RenderingContext.STRUC_DEF_EX_CODE)+" "; - case PREFERRED: - return context.formatPhrase(RenderingContext.STRUC_DEF_SHOULD_CODE)+" "; - case EXTENSIBLE: - return context.formatPhrase(RenderingContext.STRUC_DEF_SUIT_SHALL_CODE)+" "; - case REQUIRED: - return context.formatPhrase(RenderingContext.STRUC_DEF_SHALL_CODE)+" "; - default: - return "?sd-conf?"; - } - } - - private String encodeValues(List examples) throws FHIRException, IOException { - StringBuilder b = new StringBuilder(); - boolean first = false; - for (ElementDefinitionExampleComponent ex : examples) { - if (first) - first = false; - else - b.append("
"); - b.append("" + Utilities.escapeXml(ex.getLabel()) + ":" + encodeValue(ex.getValue(), null) + "\r\n"); - } - return b.toString(); - - } - - private XhtmlNode encodeValue(DataType value, String name, Base parent, DataType compare, int mode, String elementName) throws FHIRException, IOException { - String oldValue = encodeValue(compare, elementName); - String newValue = encodeValue(value, elementName); - return compareString(newValue, value, null, name, parent, oldValue, null, mode, false, false, true); - } - - private String encodeValue(DataType value, String elementName) throws FHIRException, IOException { - if (value == null || value.isEmpty()) { - return null; - } - if (value instanceof PrimitiveType && (context.getFixedFormat().notPrimitives() || elementName == null)) { - return ((PrimitiveType) value).asStringValue(); - } - - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - if (context.getFixedFormat().isXml()) { - XmlParser parser = new XmlParser(); - parser.setOutputStyle(OutputStyle.PRETTY); - parser.compose(bs, value, null); - } else if (value instanceof PrimitiveType) { - if (value instanceof BooleanType || value instanceof IntegerType || value instanceof DecimalType) { - TextFile.stringToStream(((PrimitiveType) value).asStringValue(), bs); - } else { - TextFile.stringToStream("\""+Utilities.escapeJson(((PrimitiveType) value).asStringValue())+"\"", bs); - } - } else { - JsonParser parser = new JsonParser(); - parser.setOutputStyle(OutputStyle.PRETTY); - parser.compose(bs, value, null); - } - String[] lines = bs.toString().split("\\r?\\n"); - StringBuilder b = new StringBuilder(); - for (String s : lines) { - if (!Utilities.noString(s) && !s.startsWith(" original, List compare, int mode) throws IOException { - return compareSimpleTypeLists(original, compare, mode, ", "); - } - + return res; + } - private XhtmlNode compareSimpleTypeLists(List originalList, List compareList, int mode, String separator) throws IOException { - StatusList list = new StatusList<>(); - for (PrimitiveType v : originalList) { - if (!v.isEmpty()) { - list.add(new ValueWithStatus(v)); - } - } - if (compareList != null && mode != GEN_MODE_DIFF) { - for (PrimitiveType v : compareList) { - list.merge(new ValueWithStatus(v)); - } - } - if (list.size() == 0) { - return null; - } - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - boolean first = true; - for (ValueWithStatus t : list) { - if (first) first = false; else x.tx(separator); - t.render(x); - } - return x; - } - - - private XhtmlNode compareDataTypeLists(List original, List compare, int mode) throws IOException { - return compareDataTypeLists(original, compare, mode, ", "); - } - - private XhtmlNode compareDataTypeLists(List originalList, List compareList, int mode, String separator) throws IOException { - StatusList list = new StatusList<>(); - for (DataType v : originalList) { - if (!v.isEmpty()) { - list.add(new DataValueWithStatus(v)); - } - } - if (compareList != null && mode != GEN_MODE_DIFF) { - for (DataType v : compareList) { - list.merge(new DataValueWithStatus(v)); - } - } - if (list.size() == 0) { - return null; - } - XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); - boolean first = true; - for (DataValueWithStatus t : list) { - if (first) first = false; else x.tx(separator); - t.render(x); - } - return x; - } + private String getCardinality(ElementDefinition ed, List list) { + int min = ed.getMin(); + int max = !ed.hasMax() || ed.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(ed.getMax()); + ElementDefinition ned = ed; + while (ned != null && ned.getPath().contains(".")) { + ned = findParent(ned, list); + if (ned != null) { // todo: this can happen if we've walked into a resoruce. Not sure what to about that? + if ("0".equals(ned.getMax())) + max = 0; + else if (!ned.getMax().equals("1") && !ned.hasSlicing()) + max = Integer.MAX_VALUE; + if (ned.getMin() == 0) { + min = 0; + } + } + } + return Integer.toString(min)+".."+(max == Integer.MAX_VALUE ? "*" : Integer.toString(max)); + } + + + private ElementDefinition findParent(ElementDefinition ed, List list) { + int i = list.indexOf(ed)-1; + while (i >= 0 && !ed.getPath().startsWith(list.get(i).getPath()+".")) + i--; + if (i == -1) + return null; + else + return list.get(i); + } + + + private List listReferenceProfiles(ElementDefinition ed) { + List res = new ArrayList(); + for (TypeRefComponent tr : ed.getType()) { + // code is null if we're dealing with "value" and profile is null if we just have Reference() + if (tr.hasTarget() && tr.hasTargetProfile()) + for (UriType u : tr.getTargetProfile()) + res.add(u.getValue()); + } + return res; + } + + + private String nameForElement(ElementDefinition ed) { + return ed.getPath().substring(ed.getPath().indexOf(".")+1); + } + + public XhtmlNode formatTypeSpecifiers(ElementDefinition d) { + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + boolean first = true; + for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { + if (first) first = false; else x.br(); + String cond = ToolingExtensions.readStringExtension(e, "condition"); + String type = ToolingExtensions.readStringExtension(e, "type"); + x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_IF)+" "); + x.code().tx(cond); + x.tx(" "+(context.formatPhrase(RenderingContext.STRUC_DEF_THEN_TYPE)+" ")); + StructureDefinition sd = context.getContext().fetchTypeDefinition(type); + if (sd == null) { + x.code().tx(type); + } else { + x.ah(sd.getWebPath()).tx(sd.getTypeName()); + } + } + return first ? null : x; + } + + public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set outputTracker, RenderingContext rc) throws IOException, FHIRException { + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); + TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML); + + boolean deep = false; + String m = ""; + boolean vdeep = false; + if (ed.getSnapshot().getElementFirstRep().getIsModifier()) + m = "modifier_"; + for (ElementDefinition eld : ed.getSnapshot().getElement()) { + deep = deep || eld.getPath().contains("Extension.extension."); + vdeep = vdeep || eld.getPath().contains("Extension.extension.extension."); + } + Row r = gen.new Row(); + r.setId("Extension"); + model.getRows().add(r); + String en; + if (!full) + en = ed.getName(); + else if (ed.getSnapshot().getElement().get(0).getIsModifier()) + en = "modifierExtension"; + else + en = "extension"; + + r.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#extension."+ed.getName(), en, null, null)); + r.getCells().add(gen.new Cell()); + r.getCells().add(gen.new Cell(null, null, describeCardinality(ed.getSnapshot().getElement().get(0), null, new UnusedTracker()), null, null)); + + ElementDefinition ved = null; + if (full || vdeep) { + r.getCells().add(gen.new Cell("", "", "Extension", null, null)); + + r.setIcon(deep ? "icon_"+m+"extension_complex.png" : "icon_extension_simple.png", deep ? context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX) : context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); + List children = getChildren(ed.getSnapshot().getElement(), ed.getSnapshot().getElement().get(0)); + for (ElementDefinition child : children) + if (!child.getPath().endsWith(".id")) { + List sdl = new ArrayList<>(); + sdl.add(ed); + genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc, "", ed, null); + } + } else if (deep) { + List children = new ArrayList(); + for (ElementDefinition ted : ed.getSnapshot().getElement()) { + if (ted.getPath().equals("Extension.extension")) + children.add(ted); + } + + r.getCells().add(gen.new Cell("", "", "Extension", null, null)); + r.setIcon("icon_"+m+"extension_complex.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_COMPLEX)); + + for (ElementDefinition c : children) { + ved = getValueFor(ed, c); + ElementDefinition ued = getUrlFor(ed, c); + if (ved != null && ued != null) { + Row r1 = gen.new Row(); + r1.setId(ued.getPath()); + r.getSubRows().add(r1); + r1.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#"+ed.getId()+"."+c.getId(), ((UriType) ued.getFixed()).getValue(), null, null)); + r1.getCells().add(gen.new Cell()); + r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); + genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false); + r1.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); + generateDescription(gen, r1, c, null, true, corePath, corePath, ed, corePath, imagePath, false, false, false, ved, false, false, false, rc); + } + } + } else { + for (ElementDefinition ted : ed.getSnapshot().getElement()) { + if (ted.getPath().startsWith("Extension.value")) + ved = ted; + } + + genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false, false); + + r.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); + } + Cell c = gen.new Cell("", "", "URL = "+ed.getUrl(), null, null); + Piece cc = gen.new Piece(null, ed.getName()+": ", null); + c.addPiece(gen.new Piece("br")).addPiece(cc); + c.addMarkdown(ed.getDescription()); + + if (!full && !(deep || vdeep) && ved != null && ved.hasBinding()) { + c.addPiece(gen.new Piece("br")); + BindingResolution br = context.getPkp().resolveBinding(ed, ved.getBinding(), ved.getPath()); + c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, (context.formatPhrase(RenderingContext.STRUC_DEF_BINDING))+": ", null).addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(ved.getBinding(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri)))); + if (ved.getBinding().hasStrength()) { + c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, " (", null))); + c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(corePath+"terminologies.html#"+ved.getBinding().getStrength().toCode(), egt(ved.getBinding().getStrengthElement()), ved.getBinding().getStrength().getDefinition()))); + c.getPieces().add(gen.new Piece(null, ")", null)); + } + if (ved.getBinding().hasDescription() && MarkDownProcessor.isSimpleMarkdown(ved.getBinding().getDescription())) { + c.getPieces().add(gen.new Piece(null, ": ", null)); + c.addMarkdownNoPara(PublicationHacker.fixBindingDescriptions(context.getWorker(), ved.getBinding().getDescriptionElement()).asStringValue()); + } + } + c.addPiece(gen.new Piece("br")).addPiece(gen.new Piece(null, ProfileUtilities.describeExtensionContext(ed), null)); + r.getCells().add(c); + + try { + return gen.generate(model, corePath, 0, outputTracker); + } catch (org.hl7.fhir.exceptions.FHIRException e) { + throw new FHIRException(e.getMessage(), e); + } + } + + private String describeCardinality(ElementDefinition definition, ElementDefinition fallback, UnusedTracker tracker) { + IntegerType min = definition.hasMinElement() ? definition.getMinElement() : new IntegerType(); + StringType max = definition.hasMaxElement() ? definition.getMaxElement() : new StringType(); + if (min.isEmpty() && fallback != null) + min = fallback.getMinElement(); + if (max.isEmpty() && fallback != null) + max = fallback.getMaxElement(); + + tracker.used = !max.isEmpty() && !max.getValue().equals("0"); + + if (min.isEmpty() && max.isEmpty()) + return null; + else + return (!min.hasValue() ? "" : Integer.toString(min.getValue())) + ".." + (!max.hasValue() ? "" : max.getValue()); + } + + + private ElementDefinition getValueFor(StructureDefinition ed, ElementDefinition c) { + int i = ed.getSnapshot().getElement().indexOf(c) + 1; + while (i < ed.getSnapshot().getElement().size() && ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".")) { + if (ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".value")) + return ed.getSnapshot().getElement().get(i); + i++; + } + return null; + } + + private ElementDefinition getUrlFor(StructureDefinition ed, ElementDefinition c) { + int i = ed.getSnapshot().getElement().indexOf(c) + 1; + while (i < ed.getSnapshot().getElement().size() && ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".")) { + if (ed.getSnapshot().getElement().get(i).getPath().equals(c.getPath()+".url")) + return ed.getSnapshot().getElement().get(i); + i++; + } + return null; + } + + public void renderDict(StructureDefinition sd, List elements, XhtmlNode t, boolean incProfiledOut, int mode, String anchorPrefix) throws FHIRException, IOException { + int i = 0; + Map allAnchors = new HashMap<>(); + List excluded = new ArrayList<>(); + List stack = new ArrayList<>(); // keeps track of parents, for anchor generation + + for (ElementDefinition ec : elements) { + addToStack(stack, ec); + generateAnchors(stack, allAnchors); + checkInScope(stack, excluded); + } + Stack dstack = new Stack<>(); + for (ElementDefinition ec : elements) { + if ((incProfiledOut || !"0".equals(ec.getMax())) && !excluded.contains(ec)) { + ElementDefinition compareElement = null; + if (mode==GEN_MODE_DIFF) + compareElement = getBaseElement(ec, sd.getBaseDefinition()); + else if (mode==GEN_MODE_KEY) + compareElement = getRootElement(ec); + + List anchors = makeAnchors(ec, anchorPrefix); + String title = ec.getId(); + XhtmlNode tr = t.tr(); + XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent")); + for (String s : anchors) { + sp.an(s).tx(" "); + } + sp.span("color: grey", null).tx(Integer.toString(i++)); + sp.b().tx(". "+title); + link(sp, ec.getId(), anchorPrefix); + if (isProfiledExtension(ec)) { + StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue()); + if (extDefn == null) { + generateElementInner(t, sd, ec, 1, null, compareElement, null, false); + } else { + ElementDefinition valueDefn = getExtensionValueDefinition(extDefn); + ElementDefinition compareValueDefn = null; + try { + StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue()); + compareValueDefn = getExtensionValueDefinition(extDefn); + } catch (Exception except) {} + generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn, false); + // generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn); + } + } else { + while (!dstack.isEmpty() && !isParent(dstack.peek(), ec)) { + finish(t, sd, dstack.pop(), mode); + } + dstack.push(ec); + generateElementInner(t, sd, ec, mode, null, compareElement, null, false); + if (ec.hasSlicing()) { + generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false); + } + } + } + t.tx("\r\n"); + i++; + } + while (!dstack.isEmpty()) { + finish(t, sd, dstack.pop(), mode); + } + finish(t, sd, null, mode); + } + + private void finish(XhtmlNode t, StructureDefinition sd, ElementDefinition ed, int mode) throws FHIRException, IOException { + + for (Base b : VersionComparisonAnnotation.getDeleted(ed == null ? sd : ed, "element")) { + ElementDefinition ec = (ElementDefinition) b; + String title = ec.getId(); + XhtmlNode tr = t.tr(); + XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent")); + sp.span("color: grey", null).tx("--"); + sp.b().tx(". "+title); + + generateElementInner(t, sd, ec, mode, null, null, null, true); + if (ec.hasSlicing()) { + generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true); + } + } + } + + public ElementDefinition getElementById(String url, String id) { + Map sdCache = sdMapCache.get(url); + + if (sdCache == null) { + StructureDefinition sd = (StructureDefinition) context.getContext().fetchResource(StructureDefinition.class, url); + if (sd == null) { + if (url.equals("http://hl7.org/fhir/StructureDefinition/Base")) { + sd = (StructureDefinition) context.getContext().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Element"); + } + if (sd == null) { + throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_FHIR_EXCEP, url)+" "); + } + } + sdCache = new HashMap(); + sdMapCache.put(url, sdCache); + String webroot = sd.getUserString("webroot"); + for (ElementDefinition e : sd.getSnapshot().getElement()) { + context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e); + sdCache.put(e.getId(), e); + } + } + return sdCache.get(id); + } + + + // Returns the ElementDefinition for the 'parent' of the current element + private ElementDefinition getBaseElement(ElementDefinition e, String url) { + if (e.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { + return getElementById(url, e.getUserString(ProfileUtilities.UD_DERIVATION_POINTER)); + } + return null; + } + + // Returns the ElementDefinition for the 'root' ancestor of the current element + private ElementDefinition getRootElement(ElementDefinition e) { + if (!e.hasBase()) + return null; + String basePath = e.getBase().getPath(); + String url = "http://hl7.org/fhir/StructureDefinition/" + (basePath.contains(".") ? basePath.substring(0, basePath.indexOf(".")) : basePath); + try { + return getElementById(url, basePath); + } catch (FHIRException except) { + // Likely a logical model, so this is ok + return null; + } + } + private void checkInScope(List stack, List excluded) { + if (stack.size() > 2) { + ElementDefinition parent = stack.get(stack.size()-2); + ElementDefinition focus = stack.get(stack.size()-1); + + if (excluded.contains(parent) || "0".equals(parent.getMax())) { + excluded.add(focus); + } + } + } + + private void generateAnchors(List stack, Map allAnchors) { + List list = new ArrayList<>(); + list.add(stack.get(0).getId()); // initialise + for (int i = 1; i < stack.size(); i++) { + ElementDefinition ed = stack.get(i); + List aliases = new ArrayList<>(); + String name = tail(ed.getPath()); + if (name.endsWith("[x]")) { + aliases.add(name); + Set tl = new HashSet(); // guard against duplicate type names - can happn in some versions + for (TypeRefComponent tr : ed.getType()) { + String tc = tr.getWorkingCode(); + if (!tl.contains(tc)) { + aliases.add(name.replace("[x]", Utilities.capitalize(tc))); + aliases.add(name+":"+name.replace("[x]", Utilities.capitalize(tc))); + aliases.add(name.replace("[x]", Utilities.capitalize(tc))+":"+name.replace("[x]", Utilities.capitalize(tc))); + tl.add(tc); + } + } + } else if (ed.hasSliceName()) { + aliases.add(name+":"+ed.getSliceName()); + // names.add(name); no good generating this? + } else { + aliases.add(name); + } + List generated = new ArrayList<>(); + for (String l : list) { + for (String a : aliases) { + generated.add(l+"."+a); + } + } + list.clear(); + list.addAll(generated); + } + ElementDefinition ed = stack.get(stack.size()-1); + // now we have all the possible names, but some of them might be inappropriate if we've + // already generated a type slicer. On the other hand, if we've already done that, we're + // going to steal any type specific ones off it. + List removed = new ArrayList<>(); + for (String s : list) { + if (!allAnchors.containsKey(s)) { + allAnchors.put(s, ed); + } else if (s.endsWith("[x]")) { + // that belongs on the earlier element + removed.add(s); + } else { + // we delete it from the other + @SuppressWarnings("unchecked") + List other = (List) allAnchors.get(s).getUserData("dict.generator.anchors"); + other.remove(s); + allAnchors.put(s, ed); + } + } + list.removeAll(removed); + ed.setUserData("dict.generator.anchors", list); + } + + private void addToStack(List stack, ElementDefinition ec) { + while (!stack.isEmpty() && !isParent(stack.get(stack.size()-1), ec)) { + stack.remove(stack.size()-1); + } + stack.add(ec); + } + + private boolean isParent(ElementDefinition ed, ElementDefinition ec) { + return ec.getPath().startsWith(ed.getPath()+"."); + } + + private List makeAnchors(ElementDefinition ed, String anchorPrefix) { + List list = (List) ed.getUserData("dict.generator.anchors"); + List res = new ArrayList<>(); + res.add(anchorPrefix + ed.getId()); + for (String s : list) { + if (!s.equals(ed.getId())) { + res.add(anchorPrefix + s); + } + } + return res; + } + + + + private void link(XhtmlNode x, String id, String anchorPrefix) { + var ah = x.ah("#" + anchorPrefix + id); + ah.attribute("title", "link to here"); + ah.attribute("class", "self-link"); + var svg = ah.svg(); + svg.attribute("viewBox", "0 0 1792 1792"); + svg.attribute("width", "16"); + svg.attribute("height", "16"); + svg.attribute("class", "self-link"); + svg.path("M1520 1216q0-40-28-68l-208-208q-28-28-68-28-42 0-72 32 3 3 19 18.5t21.5 21.5 15 19 13 25.5 3.5 27.5q0 40-28 68t-68 28q-15 0-27.5-3.5t-25.5-13-19-15-21.5-21.5-18.5-19q-33 31-33 73 0 40 28 68l206 207q27 27 68 27 40 0 68-26l147-146q28-28 28-67zm-703-705q0-40-28-68l-206-207q-28-28-68-28-39 0-68 27l-147 146q-28 28-28 67 0 40 28 68l208 208q27 27 68 27 42 0 72-31-3-3-19-18.5t-21.5-21.5-15-19-13-25.5-3.5-27.5q0-40 28-68t68-28q15 0 27.5 3.5t25.5 13 19 15 21.5 21.5 18.5 19q33-31 33-73zm895 705q0 120-85 203l-147 146q-83 83-203 83-121 0-204-85l-206-207q-83-83-83-203 0-123 88-209l-88-88q-86 88-208 88-120 0-204-84l-208-208q-84-84-84-204t85-203l147-146q83-83 203-83 121 0 204 85l206 207q83 83 83 203 0 123-88 209l88 88q86-88 208-88 120 0 204 84l208 208q84 84 84 204z"); + } + + private boolean isProfiledExtension(ElementDefinition ec) { + return ec.getType().size() == 1 && "Extension".equals(ec.getType().get(0).getWorkingCode()) && ec.getType().get(0).hasProfile(); + } + + private ElementDefinition getExtensionValueDefinition(StructureDefinition extDefn) { + for (ElementDefinition ed : extDefn.getSnapshot().getElement()) { + if (ed.getPath().startsWith("Extension.value")) + return ed; + } + return null; + } + + public XhtmlNode compareMarkdown(String location, PrimitiveType md, PrimitiveType compare, int mode) throws FHIRException, IOException { + XhtmlNode ndiv = new XhtmlNode(NodeType.Element, "div"); + if (compare == null || mode == GEN_MODE_DIFF) { + if (md.hasValue()) { + String xhtml = hostMd.processMarkdown(location, md); + if (Utilities.noString(xhtml)) { + return null; + } + try { + renderStatusDiv(md, ndiv).addChildren(fixFontSizes(new XhtmlParser().parseMDFragment(xhtml), 11)); + } catch (Exception e) { + ndiv.span("color: maroon").tx(e.getLocalizedMessage()); + e.printStackTrace(); + } + return ndiv; + } else { + return null; + } + } else if (areEqual(compare, md)) { + if (md.hasValue()) { + String xhtml = hostMd.processMarkdown(location, md); + List nodes = new XhtmlParser().parseMDFragment(xhtml); + for (XhtmlNode n : nodes) { + if (n.getNodeType() == NodeType.Element) { + n.style(unchangedStyle()); + } + } + ndiv.addChildren(nodes); + return ndiv; + } else { + return null; + } + } else { + if (md.hasValue()) { + String xhtml = hostMd.processMarkdown(location, md); + List div = new XhtmlParser().parseMDFragment(xhtml); + ndiv.addChildren(div); + } + if (compare.hasValue()) { + String xhtml = "
"+hostMd.processMarkdown(location, compare)+"
"; + List div = new XhtmlParser().parseMDFragment(xhtml); + for (XhtmlNode n : div) { + if (n.getNodeType() == NodeType.Element) { + n.style(removedStyle()); + } + } + ndiv.br(); + ndiv.addChildren(div); + } + return ndiv; + } + } + + private List fixFontSizes(List nodes, int size) { + for (XhtmlNode x : nodes) { + if (Utilities.existsInList(x.getName(), "p", "li") && !x.hasAttribute("style")) { + x.style("font-size: "+size+"px"); + } + if (x.hasChildren()) { + fixFontSizes(x.getChildNodes(), size); + } + } + return nodes; + } + + private boolean areEqual(PrimitiveType compare, PrimitiveType md) { + if (compare == null && md == null) { + return true; + } else if (compare != null && md != null) { + String one = compare.getValueAsString(); + String two = md.getValueAsString(); + if (one == null && two == null) { + return true; + } else if (one != null && one.equals(two)) { + return true; + } + } + return false; + } + + public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) { + return compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode, externalN, externalO, false); + } + + public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO, boolean code) { + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + if (mode != GEN_MODE_KEY) { + if (newStr != null) { + renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); + } else if (VersionComparisonAnnotation.hasDeleted(parent, name)) { + PrimitiveType p = (PrimitiveType) VersionComparisonAnnotation.getDeletedItem(parent, name); + renderStatus(p, x).txOrCode(code, p.primitiveValue()); + } else { + return null; + } + } else if (oldStr==null || oldStr.isEmpty()) { + if (newStr==null || newStr.isEmpty()) { + return null; + } else { + renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); + } + } else if (oldStr!=null && !oldStr.isEmpty() && (newStr==null || newStr.isEmpty())) { + if (mode == GEN_MODE_DIFF) { + return null; + } else { + removed(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); + } + } else if (oldStr.equals(newStr)) { + if (mode==GEN_MODE_DIFF) { + return null; + } else { + unchanged(x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); + } + } else if (newStr.startsWith(oldStr)) { + unchanged(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); + renderStatus(source, x).ah(nLink).txN(newStr.substring(oldStr.length())).iff(externalN).txN(" ").img("external.png", null); + } else { + // TODO: improve comparision in this fall-through case, by looking for matches in sub-paragraphs? + renderStatus(source, x).ah(nLink).txOrCode(code, newStr).iff(externalN).txN(" ").img("external.png", null); + removed(x).ah(oLink).txOrCode(code, oldStr).iff(externalO).txN(" ").img("external.png", null); + } + return x; + } + + public boolean compareString(XhtmlNode x, String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) { + XhtmlNode x1 = compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode, externalN, externalO); + if (x1 == null) { + return false; + } else { + x.getChildNodes().addAll(x1.getChildNodes()); + return true; + } + } + + public XhtmlNode unchanged(XhtmlNode x) { + return x.span(unchangedStyle()); + } + + private String unchangedStyle() { + return "color:DarkGray"; + } + + public XhtmlNode removed(XhtmlNode x) { + return x.span(removedStyle()); + } + + private String removedStyle() { + return "color:DarkGray;text-decoration:line-through"; + } + + private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough) throws FHIRException, IOException { + boolean root = !d.getPath().contains("."); + boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension")); +// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970 + if (d.hasSliceName()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SLICE_NAME), "profiling.html#slicing", strikethrough, compareString(d.getSliceName(), d.getSliceNameElement(), null, (compare != null ? compare.getSliceName() : null), d, null, "sliceName", mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CONSTRAINING), "profiling.html#slicing", strikethrough, compareString(encodeValue(d.getSliceIsConstrainingElement(), null), d.getSliceIsConstrainingElement(), null, (compare != null ? encodeValue(compare.getSliceIsConstrainingElement(), null) : null), d, null, "sliceName", mode, false, false)); + } + + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFINITION), null, strikethrough, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SHORT), null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMMENTS), null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_NOTE_C), null, strikethrough, businessIdWarning(sd.getName(), tail(d.getPath()))); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CONTROL), "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_BINDING), "terminologies.html", strikethrough, describeBinding(sd, d, d.getPath(), compare, mode)); + if (d.hasContentReference()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_TYPE), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_SEE) + d.getContentReference().substring(1)); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_TYPE), "datatypes.html", strikethrough, describeTypes(d.getType(), false, d, compare, mode, value, compareValue, sd)); + } + if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFAULT_TYPE), "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE)); + } + if (d.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { + tableRow(tbl, Utilities.pluralize(context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SPEC), d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", strikethrough, formatTypeSpecifiers(d)); + } + if (d.getPath().endsWith("[x]") && !d.prohibited()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_NOTE_X), null, strikethrough).ahWithText(context.formatPhrase(RenderingContext.STRUC_DEF_SEE) + , spec("formats.html#choice"), null, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_DATA_TYPE), context.formatPhrase(RenderingContext.STRUC_DEF_FURTHER_INFO)); + } + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MODIFIER), "conformance-rules.html#ismodifier", strikethrough, presentModifier(d, mode, compare)); + if (d.getMustHaveValue()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_TYPE_VALUE)); + } else if (d.hasValueAlternatives()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, renderCanonicalList(context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_TYPE_PRESENT), d.getValueAlternatives())); + } else if (hasPrimitiveTypes(d)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_PRIM_ELE)); + } + if (ToolingExtensions.hasAllowedUnits(d)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ALLOWED), "http://hl7.org/fhir/extensions/StructureDefinition-elementdefinition-allowedUnits.html", strikethrough, describeAllowedUnits(d)); + } + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT), "conformance-rules.html#mustSupport", strikethrough, displayBoolean(d.getMustSupport(), d.getMustSupportElement(), "mustSupport", d, compare==null ? null : compare.getMustSupportElement(), mode)); + if (d.getMustSupport()) { + if (hasMustSupportTypes(d.getType())) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT_TYPES), "datatypes.html", strikethrough, describeTypes(d.getType(), true, d, compare, mode, null, null, sd)); + } else if (hasChoices(d.getType())) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MUST_SUPPORT_TYPES), "datatypes.html", strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NO_MUST_SUPPORT)); + } + } + if (root && sd.getKind() == StructureDefinitionKind.LOGICAL) { + Extension lt = ToolingExtensions.getExtension(sd, ToolingExtensions.EXT_LOGICAL_TARGET); + if (lt == null || !lt.hasValue()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARKED)); + } else if (lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { + } else if (lt.getValueBooleanType().hasValue()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARKED)); + } else if (lt.getValueBooleanType().booleanValue()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET)); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_CANNOT_TARGET)); + } + + Extension lc = ToolingExtensions.getExtension(sd, ToolingExtensions.EXT_LOGICAL_CONTAINER); + if (lc != null && lc.hasValueUriType()) { + String uri = lc.getValue().primitiveValue(); + StructureDefinition lct = context.getContext().fetchTypeDefinition(uri); + if (lct != null) { + tableRowLink(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL_CONT), null, strikethrough, lct.present(), lct.getWebPath()); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOGICAL_CONT), null, strikethrough, uri); + } + } + + String ps = ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_PROFILE_STYLE); + if (ps != null) { + if ("cda".equals(ps)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALID), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_TEMPLATEID)); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALID), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_UNKNOWN_APPROACH, ps)+" "); + } + } + } + + if (root && sd.hasExtension(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_IMPOSE_PROFILE), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-imposeProfile.html", strikethrough, + renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_REQ)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE))); + } + if (root && sd.hasExtension(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMP_PROF), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", strikethrough, + renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_COMP)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE))); + } + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_OBLIGATIONS), null, strikethrough, describeObligations(d, root, sd)); + + if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { + String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); + if ("named-elements".equals(es)) { + if (context.hasLink(KnownLinkType.JSON_NAMES)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_STYLE), context.getLink(KnownLinkType.JSON_NAMES), strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ELE)); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EXT_STYLE), ToolingExtensions.WEB_EXTENSION_STYLE, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_ELE)); + } + } + } + + if (!d.getPath().contains(".") && ToolingExtensions.hasExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_BINDING_STYLE), ToolingExtensions.WEB_BINDING_STYLE, strikethrough, + context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_BOUND, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)+" binding style")+" "); + } + + if (d.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DATE_FORM), null, strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DATE_FORMAT)); + } + String ide = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_ID_EXPECTATION); + if (ide != null) { + if (ide.equals("optional")) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_IS)); + } else if (ide.equals("required")) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_REQ)); + } else if (ide.equals("required")) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ID_EXPECT), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_ID_NOT_ALLOW)); + } + } + + if (d.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_GRP), null, strikethrough, context.formatPhrase(RenderingContext.STRUC_DEF_REPEAT)); + } + + // tooling extensions for formats + if (ToolingExtensions.hasAnyOfExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, + ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_JSON_FORM), null, strikethrough, describeJson(d)); + } + if (d.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) || sd.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED) || + d.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED) || sd.hasExtension(ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED) || + d.hasRepresentation()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_XML_FORM), null, strikethrough, describeXml(sd, d, root)); + } + + if (d.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STRING_FORM), null, strikethrough).codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_ELE_READ)+" ", ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_IMPLIED_PREFIX), context.formatPhrase(RenderingContext.STRUC_DEF_PREFIX_VALID)); + } + + if (d.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + StandardsStatus ss = StandardsStatus.fromCode(d.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); + // gc.addStyledText("Standards Status = "+ss.toDisplay(), ss.getAbbrev(), "black", ss.getColor(), baseSpecUrl()+, true); + StructureDefinition sdb = context.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + if (sdb != null) { + StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData("derived.pointer")); + if (base != null) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()+" (from "+base.toDisplay()+")"); + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()); + } + } else { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()); + } + } + if (mode != GEN_MODE_DIFF && d.hasIsSummary()) { + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SUMMARY), "search.html#summary", strikethrough, Boolean.toString(d.getIsSummary())); + } + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_REQUIREMENTS), null, strikethrough, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LABEL), null, strikethrough, compareString(d.getLabel(), d.getLabelElement(), null, "label", d, (compare != null ? compare.getLabel() : null), null, mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_ALT_NAME), null, strikethrough, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEF_CODES), null, strikethrough, compareDataTypeLists(d.getCode(), ((compare==null) || slicedExtension ? null : compare.getCode()), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MIN_VALUE), null, strikethrough, compareString(d.hasMinValue() ? encodeValue(d.getMinValue(), null) : null, d.getMinValue(), null, "minValue", d, compare!= null && compare.hasMinValue() ? encodeValue(compare.getMinValue(), null) : null, null, mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_VALUE), null, strikethrough, compareString(d.hasMaxValue() ? encodeValue(d.getMaxValue(), null) : null, d.getMaxValue(), null, "maxValue", d, compare!= null && compare.hasMaxValue() ? encodeValue(compare.getMaxValue(), null) : null, null, mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MAX_LENGTH), null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALUE_REQ), null, strikethrough, compareString(encodeValue(d.getMustHaveValueElement(), null), d.getMustHaveValueElement(), null, (compare != null ? encodeValue(compare.getMustHaveValueElement(), null) : null), d, null, "mustHaveValueElement", mode, false, false)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_VALUE_ALT), null, strikethrough, compareSimpleTypeLists(d.getValueAlternatives(), ((compare==null) || slicedExtension ? null : compare.getValueAlternatives()), mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFAULT_VALUE), null, strikethrough, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode, d.getName())); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_MEAN_MISS), null, strikethrough, d.getMeaningWhenMissing()); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_FIXED), null, strikethrough, encodeValue(d.getFixed(), "fixed", d, compare==null ? null : compare.getFixed(), mode, d.getName())); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_PATT_VALUE), null, strikethrough, encodeValue(d.getPattern(), "pattern", d, compare==null ? null : compare.getPattern(), mode, d.getName())); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_EX), null, strikethrough, encodeValues(d.getExample())); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_INVAR), null, strikethrough, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), d, mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_LOINC), null, strikethrough, getMapping(sd, d, LOINC_MAPPING, compare, mode)); + tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_SNOMED), null, strikethrough, getMapping(sd, d, SNOMED_MAPPING, compare, mode)); + tbl.tx("\r\n"); + } + + private XhtmlNode presentModifier(ElementDefinition d, int mode, ElementDefinition compare) throws FHIRException, IOException { + XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement(), null), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement(), null), null, mode, false, false); + if (x1 != null) { + XhtmlNode x2 = compareString(encodeValue(d.getIsModifierReasonElement(), null), d.getIsModifierReasonElement(), null, "isModifierReason", d, compare == null ? null : encodeValue(compare.getIsModifierReasonElement(), null), null, mode, false, false); + if (x2 != null) { + x1.tx(" "+(context.formatPhrase(RenderingContext.STRUC_DEF_BECAUSE)+" ")); + x1.copyAllContent(x2); + } + } + return x1; + } + + private String spec(String name) { + return Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()) , name); + } + + private XhtmlNode describeXml(StructureDefinition profile, ElementDefinition d, boolean root) { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + for (PropertyRepresentation pr : PropertyRepresentation.values()) { + if (d.hasRepresentation(pr)) { + switch (pr) { + case CDATEXT: + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_CDA)); + break; + case TYPEATTR: + ret.codeWithText((context.formatPhrase(RenderingContext.STRUC_DEF_XSI)+" "), "xsi:type", "attribute."); + break; + case XHTML: + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_XHTML)); + break; + case XMLATTR: + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_XML_ATTRIBUTE)); + break; + case XMLTEXT: + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_UNADORNED)); + break; + default: + } + } + } + String name = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED); + if (name == null && root) { + name = ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_XML_NAMESPACE, ToolingExtensions.EXT_XML_NAMESPACE_DEPRECATED); + } + if (name != null) { + ret.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_NAMESPACE)+" ", name, "."); + } + name = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_XML_NAME, ToolingExtensions.EXT_XML_NAME_DEPRECATED); + if (name != null) { + ret.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_XML_ACTUAL), name, "."); + } + return ret; + } + + private XhtmlNode describeJson(ElementDefinition d) { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + var ul = ret.ul(); + boolean list = ToolingExtensions.countExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED) > 1; + + String code = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_EMPTY); + if (code != null) { + switch (code) { + case "present": + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_PRESENT)); + break; + case "absent": + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_NOT_PRESENT)); + break; + case "either": + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_MAY_PRESENT)); + break; + } + } + String jn = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_NAME_DEPRECATED); + if (jn != null) { + if (d.getPath().contains(".")) { + ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_PROPERTY_NAME), jn, null); + } else { + ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_CAN_NAME), jn, " " + context.formatPhrase(RenderingContext.STRUC_DEF_JSON_EXT)); + } + } + code = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_JSON_PROP_KEY); + if (code != null) { + ul.li().codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_JSON_SINGLE), code, " "+ context.formatPhrase(RenderingContext.STRUC_DEF_JSON_CHILD)); + } + if (ToolingExtensions.readBoolExtension(d, ToolingExtensions.EXT_JSON_NULLABLE)) { + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_NULL_JSON)); + } + if (ToolingExtensions.readBoolExtension(d, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_INFERRED_JSON)); + } + + switch (ul.getChildNodes().size()) { + case 0: return null; + case 1: return ul.getChildNodes().get(0); + default: return ret; + } + } + + private XhtmlNode describeObligations(ElementDefinition d, boolean root, StructureDefinition sdx) throws IOException { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + ObligationsRenderer obr = new ObligationsRenderer(corePath, sdx, d.getPath(), context, hostMd, this); + obr.seeObligations(d.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); + obr.seeRootObligations(d.getId(), sdx.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); + if (obr.hasObligations() || (root && (sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG) || sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_INHERITS)))) { + XhtmlNode ul = ret.ul(); + if (root) { + if (sdx.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { + ul.li().tx(context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_ADD)); + } + for (Extension ext : sdx.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_INHERITS)) { + String iu = ext.getValue().primitiveValue(); + XhtmlNode bb = ul.li(); + bb.tx(context.formatPhrase(RenderingContext.STRUC_DEF_OBLIG_FROM)+" "); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, iu); + if (sd == null) { + bb.code().tx(iu); + } else if (sd.hasWebPath()) { + bb.ah(sd.getWebPath()).tx(sd.present()); + } else { + bb.ah(iu).tx(sd.present()); + } + } + if (ul.isEmpty()) { + ret.remove(ul); + } + } + if (obr.hasObligations()) { + XhtmlNode tbl = ret.table("grid"); + obr.renderTable(tbl.getChildNodes(), true); + if (tbl.isEmpty()) { + ret.remove(tbl); + } + } + return ret.hasChildren() ? ret : null; + } else { + return null; + } + } + + private XhtmlNode describeAllowedUnits(ElementDefinition d) { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + DataType au = ToolingExtensions.getAllowedUnits(d); + if (au instanceof CanonicalType) { + String url = ((CanonicalType) au).asStringValue(); + ValueSet vs = context.getContext().findTxResource(ValueSet.class, url); + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_VALUE)+" "); + genCT(ret, url, vs); + return ret; + } else if (au instanceof CodeableConcept) { + CodeableConcept cc = (CodeableConcept) au; + if (cc.getCoding().size() != 1) { + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_ONE_OF)); + } + ret.tx(summarise(cc)); + return ret; + } + return null; + } + + private void genCT(XhtmlNode x, String url, CanonicalResource cr) { + if (cr == null) { + x.code().tx(url); + } else if (!cr.hasWebPath()) { + x.ah(url).tx(cr.present()); + } else { + x.ah(cr.getWebPath()).tx(cr.present()); + } + } + + private boolean hasPrimitiveTypes(ElementDefinition d) { + for (TypeRefComponent tr : d.getType()) { + if (context.getContext().isPrimitiveType(tr.getCode())) { + return true; + } + } + return false; + } + + + private XhtmlNode renderCanonicalListExt(String text, List list) { + List clist = new ArrayList<>(); + for (Extension ext : list) { + if (ext.hasValueCanonicalType()) { + clist.add(ext.getValueCanonicalType()); + } + } + return renderCanonicalList(text, clist); + } + + private XhtmlNode renderCanonicalList(String text, List list) { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + ret.tx(text); + var ul = ret.ul(); + for (CanonicalType ct : list) { + CanonicalResource cr = (CanonicalResource) context.getContext().fetchResource(Resource.class, ct.getValue()); + genCT(ul.li(), ct.getValue(), cr); + } + return ret; + } + + private StandardsStatus determineStandardsStatus(StructureDefinition sd, ElementDefinition ed) { + if (ed != null && ed.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + return StandardsStatus.fromCode(ed.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); + } + while (sd != null) { + if (sd.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + return ToolingExtensions.getStandardsStatus(sd); + } + sd = context.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + } + return null; + } + + private boolean hasChoices(List types) { + for (TypeRefComponent type : types) { + if (type.getProfile().size() > 1 || type.getTargetProfile().size() > 1) { + return true; + } + } + return types.size() > 1; + } + + private String sliceOrderString(ElementDefinitionSlicingComponent slicing) { + if (slicing.getOrdered()) + return context.formatPhrase(RenderingContext.STRUC_DEF_ORDERED); + else + return context.formatPhrase(RenderingContext.STRUC_DEF_UNORDERED); + } + + private void generateSlicing(XhtmlNode tbl, StructureDefinition profile, ElementDefinition ed, ElementDefinitionSlicingComponent slicing, ElementDefinition compare, int mode, boolean strikethrough) throws IOException { + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + + x.codeWithText(context.formatPhrase(RenderingContext.STRUC_DEF_SET_SLICES)+" ", ed.getPath(), context.formatPhrase(RenderingContext.STRUC_DEF_SET_ARE)); + String newOrdered = sliceOrderString(slicing); + String oldOrdered = (compare==null || !compare.hasSlicing()) ? null : sliceOrderString(compare.getSlicing()); + compareString(x, newOrdered, slicing.getOrderedElement(), null, null, null, oldOrdered, null, mode, false, false); + x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_AND) + " "); + compareString(x, slicing.hasRules() ? slicing.getRules().getDisplay() : null, slicing.getRulesElement(), null, "rules", slicing, compare!=null && compare.hasSlicing() && compare.getSlicing().hasRules() ? compare.getSlicing().getRules().getDisplay() : null, null, mode, false, false); + + if (slicing.hasDiscriminator()) { + x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_DESCRIM)); + StatusList list = new StatusList<>(); + for (ElementDefinitionSlicingDiscriminatorComponent d : slicing.getDiscriminator()) { + list.add(new DiscriminatorWithStatus(d)); + } + if (compare != null) { + for (ElementDefinitionSlicingDiscriminatorComponent d : slicing.getDiscriminator()) { + list.merge(new DiscriminatorWithStatus(d)); + } + } + var ul = x.ul(); + for (DiscriminatorWithStatus rc : list) { + rc.render(x.li()); + } + } else { + x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_NO_DESCRIM)); + } + tableRow(tbl, "Slicing", "profiling.html#slicing", strikethrough, x); + tbl.tx("\r\n"); + } + + private XhtmlNode tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough) throws IOException { + var tr = x.tr(); + if (strikethrough) { + tr.style("text-decoration: line-through"); + } + addFirstCell(name, defRef, tr); + return tr.td(); + } + + + private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, XhtmlNode possibleTd) throws IOException { + if (possibleTd != null && !possibleTd.isEmpty()) { + var tr = x.tr(); + if (strikethrough) { + tr.style("text-decoration: line-through"); + } + addFirstCell(name, defRef, tr); + tr.td().copyAllContent(possibleTd); + } + } + + private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, String text) throws IOException { + if (!Utilities.noString(text)) { + var tr = x.tr(); + if (strikethrough) { + tr.style("text-decoration: line-through"); + } + addFirstCell(name, defRef, tr); + tr.td().tx(text); + } + } + + private void tableRowLink(XhtmlNode x, String name, String defRef, boolean strikethrough, String text, String link) throws IOException { + if (!Utilities.noString(text)) { + var tr = x.tr(); + if (strikethrough) { + tr.style("text-decoration: line-through"); + } + addFirstCell(name, defRef, tr); + tr.td().ah(link).tx(text); + } + } + + private void addFirstCell(String name, String defRef, XhtmlNode tr) { + var td = tr.td(); + if (name.length() <= 16) { + td.style("white-space: nowrap"); + } + if (defRef == null) { + td.tx(name); + } else if (Utilities.isAbsoluteUrl(defRef)) { + td.ah(defRef).tx(name); + } else { + td.ah(corePath+defRef).tx(name); + } + } + + private String head(String path) { + if (path.contains(".")) + return path.substring(0, path.indexOf(".")); + else + return path; + } + private String nottail(String path) { + if (path.contains(".")) + return path.substring(0, path.lastIndexOf(".")); + else + return path; + } + + private XhtmlNode businessIdWarning(String resource, String name) { + if (name.equals("identifier")) { + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_BUSINESS_ID)+" "); + ret.ah(corePath + "resource.html#identifiers").tx(context.formatPhrase(RenderingContext.STRUC_DEF_DISCUSSION)); + ret.tx(")"); + return ret; + } + if (name.equals("version")) {// && !resource.equals("Device")) + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_BUSINESS_VERID)+" "); + ret.ah(corePath + "resource.html#versions").tx(context.formatPhrase(RenderingContext.STRUC_DEF_DISCUSSION)); + ret.tx(")"); + return ret; + } + return null; + } + + private XhtmlNode describeCardinality(ElementDefinition d, ElementDefinition compare, int mode) throws IOException { + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + if (compare==null || mode==GEN_MODE_DIFF) { + if (!d.hasMax() && !d.hasMin()) + return null; + else if (d.getMax() == null) { + renderStatus(d.getMinElement(), x).tx(toStr(d.getMin())); + x.tx("..?"); + } else { + renderStatus(d.getMinElement(), x).tx(toStr(d.getMin())); + x.tx( ".."); + renderStatus(d.getMaxElement(), x).tx( d.getMax()); + } + } else { + if (!(mode==GEN_MODE_DIFF && (d.getMin()==compare.getMin() || d.getMin()==0))) { + compareString(x, toStr(d.getMin()), d.getMinElement(), null, "min", d, toStr(compare.getMin()), null, mode, false, false); + } + x.tx(".."); + if (!(mode==GEN_MODE_DIFF && (d.getMax().equals(compare.getMax()) || "1".equals(d.getMax())))) { + compareString(x, d.getMax(), d.getMaxElement(), null, "max", d, compare.getMax(), null, mode, false, false); + } + } + XhtmlNode t = compareSimpleTypeLists(d.getCondition(), compare == null ? null : compare.getCondition(), mode); + if (t != null) { + x.br(); + x.tx(context.formatPhrase(RenderingContext.STRUC_DEF_INVARIANT)+" "); + x.copyAllContent(t); + } + return x; + } + + private boolean hasMustSupportTypes(List types) { + for (TypeRefComponent tr : types) { + if (isMustSupport(tr)) { + return true; + } + } + return false; + } + + private XhtmlNode describeTypes(List types, boolean mustSupportOnly, ElementDefinition ed, ElementDefinition compare, int mode, ElementDefinition value, ElementDefinition compareValue, StructureDefinition sd) throws FHIRException, IOException { + if (types.isEmpty()) + return null; + + List compareTypes = compare==null ? new ArrayList<>() : compare.getType(); + XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); + if ((!mustSupportOnly && types.size() == 1 && compareTypes.size() <=1 && (mode != GEN_MODE_DIFF || !VersionComparisonAnnotation.hasDeleted(ed, "type"))) || (mustSupportOnly && mustSupportCount(types) == 1)) { + if (!mustSupportOnly || isMustSupport(types.get(0))) { + describeType(ret, types.get(0), mustSupportOnly, compareTypes.size()==0 ? null : compareTypes.get(0), mode, sd); + } + } else { + boolean first = true; + if (types.size() > 1) { + ret.tx(context.formatPhrase(RenderingContext.STRUC_DEF_CHOICE_OF)+" "); + } + Map map = new HashMap(); + for (TypeRefComponent t : compareTypes) { + map.put(t.getCode(), t); + } + for (TypeRefComponent t : types) { + TypeRefComponent compareType = map.get(t.getCode()); + if (compareType!=null) + map.remove(t.getCode()); + if (!mustSupportOnly || isMustSupport(t)) { + if (first) { + first = false; + } else { + ret.tx(", "); + } + describeType(ret, t, mustSupportOnly, compareType, mode, sd); + } + } + for (TypeRefComponent t : map.values()) { + ret.tx(", "); + describeType(removed(ret), t, mustSupportOnly, null, mode, sd); + } + if (mode == GEN_MODE_DIFF) { + for (Base b : VersionComparisonAnnotation.getDeleted(ed, "type")) { + TypeRefComponent t = (TypeRefComponent) b; + ret.tx(", "); + describeType(ret, t, false, null, mode, sd); + } + } + } + if (value != null) { + XhtmlNode xt = processSecondary(mode, value, compareValue, mode, sd); + if (xt != null) { + ret.copyAllContent(xt); + } + } + return ret; + } + + private XhtmlNode processSecondary(int mode, ElementDefinition value, ElementDefinition compareValue, int compMode, StructureDefinition sd) throws FHIRException, IOException { + switch (mode) { + case 1: + return null; + case 2: + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_COMP_EX)); + return x; + case 3: + x = new XhtmlNode(NodeType.Element, "div"); + x.tx(" "+context.formatPhrase(RenderingContext.STRUC_DEF_EX_TYPE)+" "); + x.copyAllContent(describeTypes(value.getType(), false, value, compareValue, compMode, null, null, sd)); + x.tx(")"); + return x; + default: + return null; + } + } + + + private int mustSupportCount(List types) { + int c = 0; + for (TypeRefComponent tr : types) { + if (isMustSupport(tr)) { + c++; + } + } + return c; + } + + + private void describeType(XhtmlNode x, TypeRefComponent t, boolean mustSupportOnly, TypeRefComponent compare, int mode, StructureDefinition sd) throws FHIRException, IOException { + if (t.getWorkingCode() == null) { + return; + } + if (t.getWorkingCode().startsWith("=")) { + return; + } + + boolean ts = false; + if (t.getWorkingCode().startsWith("xs:")) { + ts = compareString(x, t.getWorkingCode(), t, null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode, false, false); + } else { + ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode, false, false); + } + + if ((!mustSupportOnly && (t.hasProfile() || (compare!=null && compare.hasProfile()))) || isMustSupport(t.getProfile())) { + StatusList profiles = analyseProfiles(t.getProfile(), compare == null ? null : compare.getProfile(), mustSupportOnly, mode); + if (profiles.size() > 0) { + if (!ts) { + getTypeLink(unchanged(x), t, sd); + ts = true; + } + x.tx("("); + boolean first = true; + for (ResolvedCanonical rc : profiles) { + if (first) first = false; else x.tx(", "); + rc.render(x); + } + x.tx(")"); + } + } + + if ((!mustSupportOnly && (t.hasTargetProfile() || (compare!=null && compare.hasTargetProfile()))) || isMustSupport(t.getTargetProfile())) { + List profiles = analyseProfiles(t.getTargetProfile(), compare == null ? null : compare.getTargetProfile(), mustSupportOnly, mode); + if (profiles.size() > 0) { + if (!ts) { + getTypeLink(unchanged(x), t, sd); + } + x.tx("("); // todo: double use of "(" is problematic + boolean first = true; + for (ResolvedCanonical rc : profiles) { + if (first) first = false; else x.tx(", "); + rc.render(x); + } + x.tx(")"); + } + + if (!t.getAggregation().isEmpty() || (compare!=null && !compare.getAggregation().isEmpty())) { + + for (Enumeration a :t.getAggregation()) { + a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); + } + if (compare!=null) { + for (Enumeration a : compare.getAggregation()) { + a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); + } + } + var xt = compareSimpleTypeLists(t.getAggregation(), compare == null ? null : compare.getAggregation(), mode); + if (xt != null) { + x.copyAllContent(xt); + } + } + } + } + + private StatusList analyseProfiles(List newProfiles, List oldProfiles, boolean mustSupportOnly, int mode) { + StatusList profiles = new StatusList(); + for (CanonicalType pt : newProfiles) { + ResolvedCanonical rc = fetchProfile(pt, mustSupportOnly); + profiles.add(rc); + } + if (oldProfiles!=null && mode != GEN_MODE_DIFF) { + for (CanonicalType pt : oldProfiles) { + profiles.merge(fetchProfile(pt, mustSupportOnly)); + } + } + return profiles; + } + + private ResolvedCanonical fetchProfile(CanonicalType pt, boolean mustSupportOnly) { + if (!pt.hasValue()) { + return null; + } + if (!mustSupportOnly || isMustSupport(pt)) { + StructureDefinition p = context.getContext().fetchResource(StructureDefinition.class, pt.getValue()); + return new ResolvedCanonical(pt.getValue(), p); + } else { + return null; + } + } +// +// private String getTypeProfile(CanonicalType pt, boolean mustSupportOnly) { +// StringBuilder b = new StringBuilder(); +// if (!mustSupportOnly || isMustSupport(pt)) { +// StructureDefinition p = context.getContext().fetchResource(StructureDefinition.class, pt.getValue()); +// if (p == null) +// b.append(pt.getValue()); +// else { +// String pth = p.getWebPath(); +// b.append(""); +// b.append(p.getName()); +// b.append(""); +// } +// } +// return b.toString(); +// } + + private void getTypeLink(XhtmlNode x, TypeRefComponent t, StructureDefinition sd) { + String s = context.getPkp().getLinkFor(sd.getWebPath(), t.getWorkingCode()); + if (s != null) { + x.ah(s).tx(t.getWorkingCode()); + } else { + x.code().tx(t.getWorkingCode()); + } + } + + + private String getTypeLink(TypeRefComponent t, StructureDefinition sd) { + String s = context.getPkp().getLinkFor(sd.getWebPath(), t.getWorkingCode()); + return s; + } + + private XhtmlNode displayBoolean(boolean value, BooleanType source, String name, Base parent, BooleanType compare, int mode) { + String newValue = value ? "true" : source.hasValue() ? "false" : null; + String oldValue = compare==null || compare.getValue()==null ? null : (compare.getValue()!=true ? null : "true"); + return compareString(newValue, source, null, name, parent, oldValue, null, mode, false, false); + } + + + private XhtmlNode invariants(List originalList, List compareList, ElementDefinition parent, int mode) throws IOException { + StatusList list = new StatusList<>(); + for (ElementDefinitionConstraintComponent v : originalList) { + if (!v.isEmpty()) { + list.add(new InvariantWithStatus(v)); + } + } + if (compareList != null && mode != GEN_MODE_DIFF) { + for (ElementDefinitionConstraintComponent v : compareList) { + list.merge(new InvariantWithStatus(v)); + } + } + if (list.size() == 0) { + return null; + } + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + boolean first = true; + for (InvariantWithStatus t : list) { + if (first) first = false; else x.br(); + t.render(x); + } + for (Base b : VersionComparisonAnnotation.getDeleted(parent, "invariant")) { + if (first) first = false; else x.br(); + InvariantWithStatus ts = new InvariantWithStatus((ElementDefinitionConstraintComponent) b); + ts.render(x); + } + return x; + } + + private XhtmlNode describeBinding(StructureDefinition sd, ElementDefinition d, String path, ElementDefinition compare, int mode) throws FHIRException, IOException { + if (!d.hasBinding()) + return null; + else { + ElementDefinitionBindingComponent binding = d.getBinding(); + ElementDefinitionBindingComponent compBinding = compare == null ? null : compare.getBinding(); + XhtmlNode bindingDesc = null; + if (binding.hasDescription()) { + MarkdownType newBinding = PublicationHacker.fixBindingDescriptions(context.getContext(), binding.getDescriptionElement()); + if (mode == GEN_MODE_SNAP || mode == GEN_MODE_MS) { + bindingDesc = new XhtmlNode(NodeType.Element, "div"); + bindingDesc.addChildren(new XhtmlParser().parseMDFragment(hostMd.processMarkdown("Binding.description", newBinding))); + } else { + + StringType oldBinding = compBinding != null && compBinding.hasDescription() ? PublicationHacker.fixBindingDescriptions(context.getContext(), compBinding.getDescriptionElement()) : null; + bindingDesc = compareMarkdown("Binding.description", newBinding, oldBinding, mode); + } + } + if (!binding.hasValueSet()) { + return bindingDesc; + } + + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + var nsp = x.span(); + renderBinding(nsp, binding, compBinding, path, sd, mode); + if (bindingDesc != null) { + if (isSimpleContent(bindingDesc)) { + x.tx(": "); + x.copyAllContent(bindingDesc.getChildNodes().get(0)); + } else { + x.br(); + x.copyAllContent(bindingDesc); + } + } + + AdditionalBindingsRenderer abr = new AdditionalBindingsRenderer(context.getPkp(), corePath, sd, d.getPath(), context, hostMd, this); + + if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { + abr.seeMaxBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), compBinding==null ? null : ToolingExtensions.getExtension(compBinding, ToolingExtensions.EXT_MAX_VALUESET), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); + } + if (binding.hasExtension(ToolingExtensions.EXT_MIN_VALUESET)) { + abr.seeMinBinding(ToolingExtensions.getExtension(binding, ToolingExtensions.EXT_MIN_VALUESET), compBinding==null ? null : ToolingExtensions.getExtension(compBinding, ToolingExtensions.EXT_MIN_VALUESET), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); + } + if (binding.hasExtension(ToolingExtensions.EXT_BINDING_ADDITIONAL)) { + abr.seeAdditionalBindings(binding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL), compBinding==null ? null : compBinding.getExtensionsByUrl(ToolingExtensions.EXT_BINDING_ADDITIONAL), mode!=GEN_MODE_SNAP && mode!=GEN_MODE_MS); + } + + if (abr.hasBindings()) { + var tbl = x.table("grid"); + abr.render(tbl.getChildNodes(), true); + } + return x; + } + } + + private boolean isSimpleContent(XhtmlNode bindingDesc) { + return bindingDesc.getChildNodes().size() == 1 && bindingDesc.getChildNodes().get(0).isPara(); + } + + private void renderBinding(XhtmlNode span, ElementDefinitionBindingComponent binding, ElementDefinitionBindingComponent compare, String path, StructureDefinition sd, int mode) { + compareString(span, conf(binding), binding.getStrengthElement(), null, "strength", binding, compare == null ? null : conf(compare), null, mode, false, false); + span.tx(" "); + BindingResolution br = context.getPkp().resolveBinding(sd, binding, path); + compareString(span, br.display, binding.getValueSetElement(), br.url, "valueSet", binding, compare == null ? null : compare.getValueSet(), null, mode, br.external, false); + if (binding.hasStrength() || binding.hasValueSet()) { + span.br(); + span.tx("("); + if (binding.hasStrength()) { + span.ah(Utilities.pathURL(corePath, "terminologies.html#"+binding.getStrength().toCode())).tx(binding.getStrength().toCode()); + } + if (binding.hasStrength() && binding.hasValueSet()) { + span.tx(" "); + } + if (binding.hasValueSet()) { + span.tx("to "); + XhtmlNode ispan = span.spanClss("copy-text-inline"); + ispan.code().tx(binding.getValueSet()); + ispan.button("btn-copy", context.formatPhrase(RenderingContext.STRUC_DEF_COPY_URL)).attribute("data-clipboard-text", binding.getValueSet()); + } + span.tx(")"); + } + } + + private String stripPara(String s) { + if (s.startsWith("

")) { + s = s.substring(3); + } + if (s.trim().endsWith("

")) { + s = s.substring(0, s.lastIndexOf("

")-1) + s.substring(s.lastIndexOf("

") +4); + } + return s; + } + + private String conf(ElementDefinitionBindingComponent def) { + if (def.getStrength() == null) { + return context.formatPhrase(RenderingContext.STRUC_DEF_FOR_CODE)+" "; + } + switch (def.getStrength()) { + case EXAMPLE: + return context.formatPhrase(RenderingContext.STRUC_DEF_EX_CODE)+" "; + case PREFERRED: + return context.formatPhrase(RenderingContext.STRUC_DEF_SHOULD_CODE)+" "; + case EXTENSIBLE: + return context.formatPhrase(RenderingContext.STRUC_DEF_SUIT_SHALL_CODE)+" "; + case REQUIRED: + return context.formatPhrase(RenderingContext.STRUC_DEF_SHALL_CODE)+" "; + default: + return "?sd-conf?"; + } + } + + private String encodeValues(List examples) throws FHIRException, IOException { + StringBuilder b = new StringBuilder(); + boolean first = false; + for (ElementDefinitionExampleComponent ex : examples) { + if (first) + first = false; + else + b.append("
"); + b.append("" + Utilities.escapeXml(ex.getLabel()) + ":" + encodeValue(ex.getValue(), null) + "\r\n"); + } + return b.toString(); + + } + + private XhtmlNode encodeValue(DataType value, String name, Base parent, DataType compare, int mode, String elementName) throws FHIRException, IOException { + String oldValue = encodeValue(compare, elementName); + String newValue = encodeValue(value, elementName); + return compareString(newValue, value, null, name, parent, oldValue, null, mode, false, false, true); + } + + private String encodeValue(DataType value, String elementName) throws FHIRException, IOException { + if (value == null || value.isEmpty()) { + return null; + } + if (value instanceof PrimitiveType && (context.getFixedFormat().notPrimitives() || elementName == null)) { + return ((PrimitiveType) value).asStringValue(); + } + + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + if (context.getFixedFormat().isXml()) { + XmlParser parser = new XmlParser(); + parser.setOutputStyle(OutputStyle.PRETTY); + parser.compose(bs, value, null); + } else if (value instanceof PrimitiveType) { + if (value instanceof BooleanType || value instanceof IntegerType || value instanceof DecimalType) { + TextFile.stringToStream(((PrimitiveType) value).asStringValue(), bs); + } else { + TextFile.stringToStream("\""+Utilities.escapeJson(((PrimitiveType) value).asStringValue())+"\"", bs); + } + } else { + JsonParser parser = new JsonParser(); + parser.setOutputStyle(OutputStyle.PRETTY); + parser.compose(bs, value, null); + } + String[] lines = bs.toString().split("\\r?\\n"); + StringBuilder b = new StringBuilder(); + for (String s : lines) { + if (!Utilities.noString(s) && !s.startsWith(" original, List compare, int mode) throws IOException { + return compareSimpleTypeLists(original, compare, mode, ", "); + } + - + private XhtmlNode compareSimpleTypeLists(List originalList, List compareList, int mode, String separator) throws IOException { + StatusList list = new StatusList<>(); + for (PrimitiveType v : originalList) { + if (!v.isEmpty()) { + list.add(new ValueWithStatus(v)); + } + } + if (compareList != null && mode != GEN_MODE_DIFF) { + for (PrimitiveType v : compareList) { + list.merge(new ValueWithStatus(v)); + } + } + if (list.size() == 0) { + return null; + } + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + boolean first = true; + for (ValueWithStatus t : list) { + if (first) first = false; else x.tx(separator); + t.render(x); + } + return x; + } + + + private XhtmlNode compareDataTypeLists(List original, List compare, int mode) throws IOException { + return compareDataTypeLists(original, compare, mode, ", "); + } + - private String summarise(CodeableConcept cc) throws FHIRException { - if (cc.getCoding().size() == 1 && cc.getText() == null) { - return summarise(cc.getCoding().get(0)); - } else if (cc.hasText()) { - return "\"" + cc.getText() + "\""; - } else if (cc.getCoding().size() > 0) { - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); - for (Coding c : cc.getCoding()) { - b.append(summarise(c)); - } - return b.toString(); - } else { - throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_ERR_DESC)); - } - } - - private String summarise(Coding coding) throws FHIRException { - if ("http://snomed.info/sct".equals(coding.getSystem())) - return "" + (context.formatPhrase(RenderingContext.STRUC_DEF_SNOMED)) + " " + coding.getCode() + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); - if ("http://loinc.org".equals(coding.getSystem())) - return "" + (context.formatPhrase(RenderingContext.STRUC_DEF_LOINC_CODE)) + " " + coding.getCode() + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); - if ("http://unitsofmeasure.org/".equals(coding.getSystem())) - return " (" + (context.formatPhrase(RenderingContext.STRUC_DEF_UCUM)) + ": " + coding.getCode() + ")"; - CodeSystem cs = context.getContext().fetchCodeSystem(coding.getSystem()); - if (cs == null) - return "" + coding.getCode() + "" + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); - else - return "" + coding.getCode() + "" + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); - } - -} + private XhtmlNode compareDataTypeLists(List originalList, List compareList, int mode, String separator) throws IOException { + StatusList list = new StatusList<>(); + for (DataType v : originalList) { + if (!v.isEmpty()) { + list.add(new DataValueWithStatus(v)); + } + } + if (compareList != null && mode != GEN_MODE_DIFF) { + for (DataType v : compareList) { + list.merge(new DataValueWithStatus(v)); + } + } + if (list.size() == 0) { + return null; + } + XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); + boolean first = true; + for (DataValueWithStatus t : list) { + if (first) first = false; else x.tx(separator); + t.render(x); + } + return x; + } + + + + private String summarise(CodeableConcept cc) throws FHIRException { + if (cc.getCoding().size() == 1 && cc.getText() == null) { + return summarise(cc.getCoding().get(0)); + } else if (cc.hasText()) { + return "\"" + cc.getText() + "\""; + } else if (cc.getCoding().size() > 0) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); + for (Coding c : cc.getCoding()) { + b.append(summarise(c)); + } + return b.toString(); + } else { + throw new FHIRException(context.formatPhrase(RenderingContext.STRUC_DEF_ERR_DESC)); + } + } + + private String summarise(Coding coding) throws FHIRException { + if ("http://snomed.info/sct".equals(coding.getSystem())) + return "" + (context.formatPhrase(RenderingContext.STRUC_DEF_SNOMED_CODE)) + " " + coding.getCode() + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); + if ("http://loinc.org".equals(coding.getSystem())) + return "" + (context.formatPhrase(RenderingContext.STRUC_DEF_LOINC_CODE)) + " " + coding.getCode() + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); + if ("http://unitsofmeasure.org/".equals(coding.getSystem())) + return " (" + (context.formatPhrase(RenderingContext.STRUC_DEF_UCUM)) + ": " + coding.getCode() + ")"; + CodeSystem cs = context.getContext().fetchCodeSystem(coding.getSystem()); + if (cs == null) + return "" + coding.getCode() + "" + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); + else + return "" + coding.getCode() + "" + (!coding.hasDisplay() ? "" : "(\"" + gt(coding.getDisplayElement()) + "\")"); + } + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java index 948d54227..5565b6ec9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java @@ -211,7 +211,7 @@ public abstract class TerminologyRenderer extends ResourceRenderer { if (hasHierarchy) { tr.td().b().tx(context.formatPhrase(RenderingContext.TERMINOLOGY_LVL)); } - tr.td().attribute("style", "white-space:nowrap").b().tx(formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().attribute("style", "white-space:nowrap").b().tx(formatPhrase(RenderingContext.TX_CODE)); if (hasDisplay) { tr.td().b().tx(formatPhrase(RenderingContext.TX_DISPLAY)); } @@ -229,7 +229,13 @@ public abstract class TerminologyRenderer extends ResourceRenderer { } if (properties != null) { for (PropertyComponent pc : properties) { - String display = getPropertyDisplay(pc); + String display = ToolingExtensions.getPresentation(pc, pc.getCodeElement()); + if (display == null || display.equals(pc.getCode()) && pc.hasUri()) { + display = getDisplayForProperty(pc.getUri()); + if (display == null) { + display = pc.getCode(); + } + } tr.td().b().tx(display); } } @@ -248,17 +254,6 @@ public abstract class TerminologyRenderer extends ResourceRenderer { return tr; } - protected String getPropertyDisplay(PropertyComponent pc) { - String display = ToolingExtensions.getPresentation(pc, pc.getCodeElement()); - if (display == null || display.equals(pc.getCode()) && pc.hasUri()) { - display = getDisplayForProperty(pc.getUri()); - if (display == null) { - display = pc.getCode(); - } - } - return display; - } - protected String getDisplayForProperty(String uri) { if (Utilities.noString(uri)){ diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java index 0588349d4..7f9071f02 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java @@ -208,7 +208,7 @@ public class ValueSetRenderer extends TerminologyRenderer { if (vs.getExpansion().getContains().isEmpty()) { msg = context.formatPhrase(RenderingContext.VALUE_SET_TOO_COSTLY); } else { - msg = context.formatPhrase(RenderingContext.GENERAL_CODE_SELEC, countMembership(vs)); + msg = context.formatPhrase(RenderingContext.VALUE_SET_CODE_SELEC, countMembership(vs)); } x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(msg); } else { @@ -216,9 +216,9 @@ public class ValueSetRenderer extends TerminologyRenderer { if (vs.getExpansion().hasTotal()) { if (count != vs.getExpansion().getTotal()) { x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px") - .addText(context.formatPhrase(hasFragment ? RenderingContext.VALUE_SET_HAS_AT_LEAST : RenderingContext.VALUE_SET_HAS, vs.getExpansion().getTotal(), count)); + .addText(context.formatPhrase(hasFragment ? RenderingContext.VALUE_SET_HAS_AT_LEAST : RenderingContext.VALUE_SET_HAS, vs.getExpansion().getTotal())); } else { - x.para().tx(context.formatPhrase(hasFragment ? RenderingContext.VALUE_SET_CONTAINS_AT_LEAST : RenderingContext.VALUE_SET_CONTAINS, vs.getExpansion().getTotal(), count)); + x.para().tx(context.formatPhrase(hasFragment ? RenderingContext.VALUE_SET_CONTAINS_AT_LEAST : RenderingContext.VALUE_SET_CONTAINS, vs.getExpansion().getTotal())); } } else if (count == 1000) { // it's possible that there's exactly 1000 codes, in which case wht we're about to do is wrong @@ -245,7 +245,7 @@ public class ValueSetRenderer extends TerminologyRenderer { XhtmlNode tr = t.tr(); if (doLevel) tr.td().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_LEVEL)); - tr.td().attribute("style", "white-space:nowrap").b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().attribute("style", "white-space:nowrap").b().tx(context.formatPhrase(RenderingContext.VALUE_SET_CODE)); tr.td().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_SYSTEM)); XhtmlNode tdDisp = tr.td(); tdDisp.b().tx(context.formatPhrase(RenderingContext.VALUE_SET_DISPLAY)); @@ -294,7 +294,7 @@ public class ValueSetRenderer extends TerminologyRenderer { if (!doDesignations && langs.size() + designations.size() > 0) { Collections.sort(langs); if (designations.size() == 0) { - x.para().b().tx(context.formatPhrase(RenderingContext.GENERAL_ADD_LANG)); + x.para().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_ADD_LANG)); } else if (langs.size() == 0) { x.para().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_DESIG)); } else { @@ -302,7 +302,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } t = x.table("codes"); tr = t.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_CODE)); for (String url : designations.keySet()) { tr.td().b().addText(designations.get(url)); } @@ -989,7 +989,7 @@ public class ValueSetRenderer extends TerminologyRenderer { if (!doDesignations && langs.size() + designations.size() > 0) { Collections.sort(langs); if (designations.size() == 0) { - x.para().b().tx(context.formatPhrase(RenderingContext.GENERAL_ADD_LANG)); + x.para().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_ADD_LANG)); } else if (langs.size() == 0) { x.para().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_DESIG)); } else { @@ -997,7 +997,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } XhtmlNode t = x.table("codes"); XhtmlNode tr = t.tr(); - tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE)); + tr.td().b().tx(context.formatPhrase(RenderingContext.VALUE_SET_CODE)); for (String url : designations.keySet()) { tr.td().b().addText(designations.get(url)); } @@ -1032,7 +1032,7 @@ public class ValueSetRenderer extends TerminologyRenderer { HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); TableModel model = gen.new TableModel("exp.h="+index, context.getRules() == GenerationRules.IG_PUBLISHER); model.setAlternating(true); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_CODE), context.formatPhrase(RenderingContext.GENERAL_CODE_ITEM), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.VALUE_SET_CODE), context.formatPhrase(RenderingContext.VALUE_SET_CODE_ITEM), null, 0)); model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.VALUE_SET_DISPLAY), context.formatPhrase(RenderingContext.VALUE_SET_DISPLAY_ITEM), null, 0)); for (Extension ext : inc.getExtensionsByUrl(ToolingExtensions.EXT_EXPAND_GROUP)) { @@ -1211,7 +1211,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } } if (inc.getFilter().size() > 0) { - li.addText(type+" "+ context.formatPhrase(RenderingContext.GENERAL_CODES_FROM)); + li.addText(type+" "+ context.formatPhrase(RenderingContext.VALUE_SET_CODES_FROM)); addCsRef(inc, li, e); li.tx(" "+ context.formatPhrase(RenderingContext.VALUE_SET_WHERE)+" "); for (int i = 0; i < inc.getFilter().size(); i++) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstantMaintainer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstantMaintainer.java index 5e8988d96..15eb01e88 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstantMaintainer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstantMaintainer.java @@ -17,7 +17,7 @@ public class I18nConstantMaintainer { rename("/Users/grahamegrieve/work/core", "OP_DEF_CARD", "GENERAL_CARDINALITY"); replace("/Users/grahamegrieve/work/core", "QUEST_CARD", "GENERAL_CARDINALITY"); -// rename("/Users/grahamegrieve/work/core", "CODEPROP_CODE", "GENERAL_CODE"); + rename("/Users/grahamegrieve/work/core", "CODEPROP_CODE", "GENERAL_CODE"); replace("/Users/grahamegrieve/work/core", "CODE_SYS_CODE", "GENERAL_CODE"); replace("/Users/grahamegrieve/work/core", "CONC_MAP_CODE", "GENERAL_CODE"); replace("/Users/grahamegrieve/work/core", "DATA_REND_CODE", "GENERAL_CODE"); @@ -28,12 +28,381 @@ public class I18nConstantMaintainer { replace("/Users/grahamegrieve/work/core", "VALUE_SET_CODE", "GENERAL_CODE"); replace("/Users/grahamegrieve/work/core", "DATA_REND_GETCODE", "GENERAL_CODE"); replace("/Users/grahamegrieve/work/core", "LIST_REND_CODE", "GENERAL_CODE"); + + // Comment + rename("/Users/grahamegrieve/work/core", "CONC_MAP_CMNT", "GENERAL_COMMENT"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_COM", "GENERAL_COMMENT"); + + // Comments + rename("/Users/grahamegrieve/work/core", "SD_COMP_HEAD_COMP", "GENERAL_COMMENTS"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_COMMENTS", "GENERAL_COMMENTS"); + replace("/Users/grahamegrieve/work/core", "TX_COMMENTS", "GENERAL_COMMENTS"); + + // Comparators + rename("/Users/grahamegrieve/work/core", "SEARCH_PAR_COMP", "GENERAL_COMPARATORS"); + replace("/Users/grahamegrieve/work/core", "SUB_TOPIC_COMP", "GENERAL_COMPARATORS"); + + // Component + rename("/Users/grahamegrieve/work/core", "ADD_BIND_COMPONENT", "GENERAL_COMPONENT"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_COMP", "GENERAL_COMPONENT"); + + // Conformance + rename("/Users/grahamegrieve/work/core", "CAPABILITY_CONF", "GENERAL_CONFORMANCE"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_CONFORMANCE", "GENERAL_CONFORMANCE"); + + // Contact: + rename("/Users/grahamegrieve/work/core", "PAT_NOK_CONTACT", "GENERAL_CONTACT"); + replace("/Users/grahamegrieve/work/core", "TEST_PLAN_CONT", "GENERAL_CONTACT"); + + // Content + rename("/Users/grahamegrieve/work/core", "CODE_SYS_CONTENT", "GENERAL_CONTENT"); + replace("/Users/grahamegrieve/work/core", "EX_SCEN_CONT", "GENERAL_CONTENT"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_CONTENT", "GENERAL_CONTENT"); + replace("/Users/grahamegrieve/work/core", "TEST_PLAN_CONTENT", "GENERAL_CONTENT"); + + // Copyright + rename("/Users/grahamegrieve/work/core", "CANON_REND_COPYRIGHT", "GENERAL_COPYRIGHT"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_COPY", "GENERAL_COPYRIGHT"); + replace("/Users/grahamegrieve/work/core", "QUEST_COPYRIGHT", "GENERAL_COPYRIGHT"); + + // Criteria + rename("/Users/grahamegrieve/work/core", "CAPABILITY_CRIT", "GENERAL_CRIT"); + replace("/Users/grahamegrieve/work/core", "SUB_TOPIC_CRITERIA", "GENERAL_CRIT"); + + // Defining URL + rename("/Users/grahamegrieve/work/core", "CANON_REND_URL", "GENERAL_DEFINING_URL"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_URL", "GENERAL_DEFINING_URL"); + + // Definition + rename("/Users/grahamegrieve/work/core", "CANON_REND_DEFINITION", "GENERAL_DEFINITION"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_DEF", "GENERAL_DEFINITION"); + replace("/Users/grahamegrieve/work/core", "QUEST_DEFINITION", "GENERAL_DEFINITION"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_DEFINITION", "GENERAL_DEFINITION"); + replace("/Users/grahamegrieve/work/core", "TX_DEFINITION", "GENERAL_DEFINITION"); + replace("/Users/grahamegrieve/work/core", "VALUE_SET_DEF", "GENERAL_DEFINITION"); + + // Definition: + rename("/Users/grahamegrieve/work/core", "QUEST_DEF", "GENERAL_DEFINITION_COLON"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_DEF", "GENERAL_DEFINITION_COLON"); + + // Deprecated + rename("/Users/grahamegrieve/work/core", "CODESYSTEM_DEPRECATED", "CODESYSTEM_DEPRECATED"); + replace("/Users/grahamegrieve/work/core", "TX_DEPRECATED", "CODESYSTEM_DEPRECATED"); + + // Description + rename("/Users/grahamegrieve/work/core", "CODESYSTEM_DESC", "GENERAL_DESC"); + replace("/Users/grahamegrieve/work/core", "CODESYSTEM_PROP_DESC", "GENERAL_DESC"); + replace("/Users/grahamegrieve/work/core", "EX_SCEN_DESC", "GENERAL_DESC"); + replace("/Users/grahamegrieve/work/core", "QUEST_DESCRIPTION", "GENERAL_DESC"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_DESC", "GENERAL_DESC"); + replace("/Users/grahamegrieve/work/core", "SUB_TOPIC_DESC", "GENERAL_DESC"); + + // Description & Constraints + rename("/Users/grahamegrieve/work/core", "QUEST_DESC", "GENERAL_DESC_CONST"); + replace("/Users/grahamegrieve/work/core", "SD_HEAD_DESC", "GENERAL_DESC_CONST"); + + // Details + rename("/Users/grahamegrieve/work/core", "OP_OUT_DET", "GENERAL_DETAILS"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_DETAILS", "GENERAL_DETAILS"); + + // Display + rename("/Users/grahamegrieve/work/core", "TX_DISPLAY", "TX_DISPLAY"); + replace("/Users/grahamegrieve/work/core", "VALUE_SET_DISPLAY", "TX_DISPLAY"); + + // Documentation + rename("/Users/grahamegrieve/work/core", "ADD_BIND_DOC", "GENERAL_DOCUMENTATION"); + replace("/Users/grahamegrieve/work/core", "CAPABILITY_DOC", "GENERAL_DOCUMENTATION"); + replace("/Users/grahamegrieve/work/core", "OBLIG_DOC", "GENERAL_DOCUMENTATION"); + replace("/Users/grahamegrieve/work/core", "OP_DEF_DOC", "GENERAL_DOCUMENTATION"); + + // Example + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_EX", "GENERAL_EXAMPLE"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_EXAMPLE", "GENERAL_EXAMPLE"); + + // Experimental + rename("/Users/grahamegrieve/work/core", "QUEST_EXPER", "GENERAL_EXPER"); + replace("/Users/grahamegrieve/work/core", "RES_REND_EXP", "GENERAL_EXPER"); + + // Filter + rename("/Users/grahamegrieve/work/core", "DATA_REND_FILT", "GENERAL_FILTER"); + replace("/Users/grahamegrieve/work/core", "OBLIG_FILT", "GENERAL_FILTER"); + + // Flags + rename("/Users/grahamegrieve/work/core", "DIAG_REP_REND_FLAG", "GENERAL_FLAGS"); + replace("/Users/grahamegrieve/work/core", "QUEST_FLAG", "GENERAL_FLAGS"); + replace("/Users/grahamegrieve/work/core", "SD_HEAD_FLAGS", "GENERAL_FLAGS"); + + // Id is required to be present (this is the default for resources but not elements) + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_ID_MAY", "STRUC_DEF_ID_MAY"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_ID_REQ", "STRUC_DEF_ID_MAY"); + + // Instances of this logical model are not marked to be the target of a Reference + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_NOT_MARK", "STRUC_DEF_NOT_MARK"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_NOT_MARKED", "STRUC_DEF_NOT_MARK"); + + // Instances of this logical model can be the target of a Reference + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_CAN_TARGET", "STRUC_DEF_CAN_TARGET"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_REF", "STRUC_DEF_CAN_TARGET"); + + // Instances of this type are validated using an unknown approach: {0} + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_UNKNOWN_APPROACH", "STRUC_DEF_UNKNOWN_APPROACH"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_VALID_UNKNOWN", "STRUC_DEF_UNKNOWN_APPROACH"); + + // Location + rename("/Users/grahamegrieve/work/core", "OP_OUT_LOC", "GENERAL_LOCATION"); + replace("/Users/grahamegrieve/work/core", "PROV_LOC", "GENERAL_LOCATION"); + + // Logical Container + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_LOGIC", "STRUC_DEF_LOGICAL_CONT"); + + // Maturity + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_MATURITY", "CANON_REND_MATURITY"); + + // Max Length: + rename("/Users/grahamegrieve/work/core", "QUEST_MAX", "GENERAL_MAX_LENGTH"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_MAX_LENGTH", "GENERAL_MAX_LENGTH"); + + // Modifiers + rename("/Users/grahamegrieve/work/core", "SEARCH_PAR_MOD", "GENERAL_MODIFIERS"); + replace("/Users/grahamegrieve/work/core", "SUB_TOPIC_MOD", "GENERAL_MODIFIERS"); + + // Name + rename("/Users/grahamegrieve/work/core", "CANON_REND_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "CODESYSTEM_PROP_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "DATA_REND_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "EX_SCEN_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "OP_DEF_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "QUEST_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "SD_COMP_HEAD_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "SD_GRID_HEAD_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "SD_HEAD_NAME", "GENERAL_NAME"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_NAME", "GENERAL_NAME"); + + // Not done yet + rename("/Users/grahamegrieve/work/core", "DIAG_REP_REND_NOTDONE", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "OP_OUT_NOT", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "PROV_NOT", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "QUEST_NOT_DONE", "GENERAL_TODO"); + + // Note + rename("/Users/grahamegrieve/work/core", "DIAG_REP_REND_NOTE", "GENERAL_NOTE"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_NOTE_C", "GENERAL_NOTE"); + + // OID + rename("/Users/grahamegrieve/work/core", "CODE_SYS_OID", "GENERAL_OID"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_OID", "GENERAL_OID"); + replace("/Users/grahamegrieve/work/core", "VALUE_SET_OID", "GENERAL_OID"); + + // Obligations + rename("/Users/grahamegrieve/work/core", "OBLIG_OBLIG", "GENERAL_OBLIG"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_OBLIGATIONS", "GENERAL_OBLIG"); + + // Parameter + rename("/Users/grahamegrieve/work/core", "CAPABILITY_PAR", "GENERAL_PAR"); + replace("/Users/grahamegrieve/work/core", "SEARCH_PAR_PAR", "GENERAL_PAR"); + + // Parameters + rename("/Users/grahamegrieve/work/core", "CAPABILITY_PARS", "GENERAL_PARS"); + replace("/Users/grahamegrieve/work/core", "LIB_REND_PARA", "GENERAL_PARS"); + replace("/Users/grahamegrieve/work/core", "OP_DEF_PAR", "GENERAL_PARS"); + replace("/Users/grahamegrieve/work/core", "PAR_REND_PAR", "GENERAL_PARS"); + + // Preferred + rename("/Users/grahamegrieve/work/core", "ADD_BIND_PREFERRED", "GENERAL_PREFERRED"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_PREF", "GENERAL_PREFERRED"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_PREF", "GENERAL_PREFERRED"); + + // Profile + rename("/Users/grahamegrieve/work/core", "CAPABILITY_PROF", "GENERAL_PROF"); + replace("/Users/grahamegrieve/work/core", "RES_REND_PROF", "GENERAL_PROF"); + replace("/Users/grahamegrieve/work/core", "RES_REND_PROFILE", "GENERAL_PROF"); + replace("/Users/grahamegrieve/work/core", "TEXT_ICON_PROFILE", "GENERAL_PROF"); + + // Properties + rename("/Users/grahamegrieve/work/core", "CODESYSTEM_PROPS", "GENERAL_PROPS"); + replace("/Users/grahamegrieve/work/core", "CONC_MAP_PROP", "GENERAL_PROPS"); + + // Publisher + rename("/Users/grahamegrieve/work/core", "CANON_REND_PUBLISHER", "CANON_REND_PUBLISHER"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_PUB", "CANON_REND_PUBLISHER"); + + // Purpose + rename("/Users/grahamegrieve/work/core", "ADD_BIND_PUR", "GENERAL_PURPOSE"); + replace("/Users/grahamegrieve/work/core", "QUEST_PURPOSE", "GENERAL_PURPOSE"); + + // Reference to the type of the element + replace("/Users/grahamegrieve/work/core", "SD_HEAD_TYPE_DESC", "SD_GRID_HEAD_TYPE_DESC"); + + // References: + rename("/Users/grahamegrieve/work/core", "ACTOR_DEF_REF", "GENERAL_REFS"); + replace("/Users/grahamegrieve/work/core", "REQ_REFERENCES", "GENERAL_REFS"); + + // Request + rename("/Users/grahamegrieve/work/core", "DIAG_REP_REND_REQUEST", "GENERAL_REQUEST"); + replace("/Users/grahamegrieve/work/core", "EX_SCEN_REQ", "GENERAL_REQUEST"); + + // Required + rename("/Users/grahamegrieve/work/core", "ADD_BIND_REQUIRED", "GENERAL_REQUIRED"); + replace("/Users/grahamegrieve/work/core", "QUEST_REQ", "GENERAL_REQUIRED"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_REQ", "GENERAL_REQUIRED"); + + // Resource + rename("/Users/grahamegrieve/work/core", "RES_REND_RESOURCE", "GENERAL_RESOURCE"); + replace("/Users/grahamegrieve/work/core", "SEARCH_PAR_REND_RES", "GENERAL_RESOURCE"); + replace("/Users/grahamegrieve/work/core", "SUB_TOPIC_RES", "GENERAL_RESOURCE"); + replace("/Users/grahamegrieve/work/core", "TEXT_ICON_RESOURCE", "GENERAL_RESOURCE"); + + // SNOMED-CT + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_SNOMED_CT", "GENERAL_SNOMED_CT"); + replace("/Users/grahamegrieve/work/core", "TERMINOLOGY_SNOMED", "GENERAL_SNOMED_CT"); + + // Security Label + rename("/Users/grahamegrieve/work/core", "RES_REND_SECURITY", "GENERAL_SECURITY_LABEL"); + replace("/Users/grahamegrieve/work/core", "RES_REND_SECURITY_LABEL", "GENERAL_SECURITY_LABEL"); + + // Source: + rename("/Users/grahamegrieve/work/core", "LIST_REND_SRC", "GENERAL_SRC"); + replace("/Users/grahamegrieve/work/core", "REQ_SOURCES", "GENERAL_SRC"); + + // Starter + rename("/Users/grahamegrieve/work/core", "ADD_BIND_STARTER", "GENERAL_STARTER"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_START", "GENERAL_STARTER"); + + // Status + rename("/Users/grahamegrieve/work/core", "CANON_REND_STATUS", "GENERAL_STATUS"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_STAT", "GENERAL_STATUS"); + replace("/Users/grahamegrieve/work/core", "QUEST_STATUS", "GENERAL_STATUS"); + + // Subject + rename("/Users/grahamegrieve/work/core", "DATA_REND_SUB", "GENERAL_SUBJ"); + replace("/Users/grahamegrieve/work/core", "DIAG_REP_REND_SUB", "GENERAL_SUBJ"); + replace("/Users/grahamegrieve/work/core", "QUEST_SUB", "GENERAL_SUBJ"); + + // Summary + rename("/Users/grahamegrieve/work/core", "CAPABILITY_SUMM", "GENERAL_SUMM"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_SUM", "GENERAL_SUMM"); + replace("/Users/grahamegrieve/work/core", "PROV_SUM", "GENERAL_SUMM"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_SUMMARY", "GENERAL_SUMM"); + + // The logical name of the element + rename("/Users/grahamegrieve/work/core", "SD_COMP_HEAD_NAME_DESC", "GENERAL_LOGICAL_NAME"); + replace("/Users/grahamegrieve/work/core", "SD_HEAD_NAME_DESC", "GENERAL_LOGICAL_NAME"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_LOGIC_NAME", "GENERAL_LOGICAL_NAME"); + + // The minimum allowable value set - any conformant system SHALL support all these codes + rename("/Users/grahamegrieve/work/core", "ADD_BIND_MIN_ALLOW", "GENERAL_BIND_MIN_ALLOW"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_MIN_ALLOW", "GENERAL_BIND_MIN_ALLOW"); + + // This content has been removed since {0} + rename("/Users/grahamegrieve/work/core", "REND_ROW_REMOVED_SINCE", "GENERAL_REMOVED_SINCE"); + replace("/Users/grahamegrieve/work/core", "REND_SINCE_DELETED", "GENERAL_REMOVED_SINCE"); + + // This element can be extended by named JSON elements + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_JSON_ELE", "STRUC_DEF_EXT_JSON"); + + // This element is a modifier element + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_MOD_ELEMENT", "STRUC_DEF_MOD"); + + // This element is included in summaries + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_SUMM", "STRUC_DEF_ELE_INCLUDED"); + + // This element must be supported + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_SUPP", "STRUC_DEF_ELE_MUST_SUPP"); + + // This is a repeating choice group that does not appear directly in the instance + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_REP_CHOICE", "STRUC_DEF_REPEAT"); + + // This value set is a good set of codes to start with when designing your system + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_START_DEF", "ADD_BIND_DESIG_SYS"); + + // Title + rename("/Users/grahamegrieve/work/core", "CANON_REND_TITLE", "GENERAL_TITLE"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_TITLE", "GENERAL_TITLE"); + replace("/Users/grahamegrieve/work/core", "QUEST_TITLE", "GENERAL_TITLE"); + + // Type + rename("/Users/grahamegrieve/work/core", "CAPABILITY_TYP", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "CODESYSTEM_PROP_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "DATA_REND_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "EX_SCEN_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "OP_DEF_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "PROV_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "QUEST_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "SD_GRID_HEAD_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "SD_HEAD_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_TYPE", "GENERAL_TYPE"); + replace("/Users/grahamegrieve/work/core", "TEST_PLAN_TYPE", "GENERAL_TYPE"); + + // UCUM + rename("/Users/grahamegrieve/work/core", "DATA_REND_UCUM", "GENERAL_UCUM"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_UCUM", "GENERAL_UCUM"); + + // URI + rename("/Users/grahamegrieve/work/core", "CODESYSTEM_PROP_URI", "GENERAL_URI"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_URI", "GENERAL_URI"); + + // URL + rename("/Users/grahamegrieve/work/core", "QUEST_URL", "GENERAL_URL"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_URL", "GENERAL_URL"); + + // Usage + rename("/Users/grahamegrieve/work/core", "ADD_BIND_USE", "GENERAL_USAGE"); + replace("/Users/grahamegrieve/work/core", "OBLIG_USE", "GENERAL_USAGE"); + + // Value + rename("/Users/grahamegrieve/work/core", "CODESYSTEM_FILTER_VALUE", "GENERAL_VALUE"); + replace("/Users/grahamegrieve/work/core", "DATA_REND_VALUE", "GENERAL_VALUE"); + replace("/Users/grahamegrieve/work/core", "DIAG_REP_REND_VALUE", "GENERAL_VALUE"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_VALUE", "GENERAL_VALUE"); + + // Value Set + rename("/Users/grahamegrieve/work/core", "CODE_SYS_VALUE_SET", "GENERAL_VALUESET"); + replace("/Users/grahamegrieve/work/core", "QUEST_VALUE_SET", "GENERAL_VALUESET"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_VALUE", "GENERAL_VALUESET"); + + // Version + rename("/Users/grahamegrieve/work/core", "CANON_REND_VER", "GENERAL_VER"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_VER", "GENERAL_VER"); + replace("/Users/grahamegrieve/work/core", "QUEST_VERSION", "GENERAL_VER"); + replace("/Users/grahamegrieve/work/core", "RES_REND_VERSION", "GENERAL_VER"); + replace("/Users/grahamegrieve/work/core", "TX_VERSION", "GENERAL_VER"); + + // XML + rename("/Users/grahamegrieve/work/core", "CANON_REND_XML", "GENERAL_XML"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_XML", "GENERAL_XML"); + + // for OID based terminology systems + rename("/Users/grahamegrieve/work/core", "CODE_SYS_FOR_OID", "CODE_SYS_FOR_OID"); + replace("/Users/grahamegrieve/work/core", "NAME_SYS_FOROID", "CODE_SYS_FOR_OID"); + replace("/Users/grahamegrieve/work/core", "VALUE_SET_OID_TERM_SYS", "CODE_SYS_FOR_OID"); + + // is prefixed to the value before validation + rename("/Users/grahamegrieve/work/core", "STRUC_DEF_PREFIXED", "STRUC_DEF_PREFIXED"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_PREFIX_VALID", "STRUC_DEF_PREFIXED"); + + // todo + replace("/Users/grahamegrieve/work/core", "OP_OUT_TODO", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "QUEST_TODO", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "RES_REND_TODO", "GENERAL_TODO"); + replace("/Users/grahamegrieve/work/core", "STRUC_DEF_TODO", "GENERAL_TODO"); + + // version + rename("/Users/grahamegrieve/work/core", "EX_SCEN_VER", "GENERAL_VER_LOW"); + replace("/Users/grahamegrieve/work/core", "VALUE_SET_VERSION", "GENERAL_VER_LOW"); + + // {0}, {1} by {2} + rename("/Users/grahamegrieve/work/core", "SD_SLICING_INFO", "SD_SLICING_INFO"); + replace("/Users/grahamegrieve/work/core", "SD_SUMMARY_INFO", "SD_SLICING_INFO"); } private static void replace(String dir, String src, String tgt) throws FileNotFoundException, IOException { - System.out.println("Replace "+src+" with "+tgt+" in "+dir); - int count = replace(new File(dir), src, tgt); - System.out.println("Done. "+count+" files changed"); + if (!src.equals(tgt)) { + System.out.println("Replace "+src+" with "+tgt+" in "+dir); + int count = replace(new File(dir), src, tgt); + System.out.println("Done. "+count+" files changed"); + } } private static int replace(File file, String src, String tgt) throws FileNotFoundException, IOException { @@ -47,18 +416,34 @@ public class I18nConstantMaintainer { if ("java".equals(ext)) { String source = TextFile.fileToString(file); boolean mod = false; - if (source.contains("I18nConstants."+src)) { - source = source.replace("I18nConstants."+src, "I18nConstants."+tgt); + if (source.contains("I18nConstants."+src+",")) { + source = source.replace("I18nConstants."+src+",", "I18nConstants."+tgt+","); mod = true; } - if (source.contains("RenderingI18nContext."+src)) { - source = source.replace("RenderingI18nContext."+src, "RenderingI18nContext."+tgt); + if (source.contains("I18nConstants."+src+")")) { + source = source.replace("I18nConstants."+src+")", "I18nConstants."+tgt+")"); mod = true; } - if (source.contains("RenderingContext."+src)) { - source = source.replace("RenderingContext."+src, "RenderingContext."+tgt); + + if (source.contains("RenderingI18nContext."+src+",")) { + source = source.replace("RenderingI18nContext."+src+",", "RenderingI18nContext."+tgt+","); mod = true; } + if (source.contains("RenderingI18nContext."+src+")")) { + source = source.replace("RenderingI18nContext."+src+")", "RenderingI18nContext."+tgt+")"); + mod = true; + } + + if (source.contains("RenderingContext."+src+",")) { + source = source.replace("RenderingContext."+src+",", "RenderingContext."+tgt+","); + mod = true; + } + + if (source.contains("RenderingContext."+src+")")) { + source = source.replace("RenderingContext."+src+")", "RenderingContext."+tgt+")"); + mod = true; + } + if (file.getName().equals("I18nConstants.java") && source.contains(src)) { source = removeLines(source, src); mod = true; @@ -71,7 +456,7 @@ public class I18nConstantMaintainer { TextFile.stringToFile(source, file); count++; } - + } else if (Utilities.existsInList(ext, "properties")) { String source = TextFile.fileToString(file); if (source.contains(src)) { @@ -83,12 +468,12 @@ public class I18nConstantMaintainer { } return count; } - + private static String removeLines(String source, String src) { String[] lines = Utilities.splitLines(source); StringBuilder b = new StringBuilder(); for (String s : lines) { - if (!s.contains(src)) { + if (!(s.contains(src+"\"") || s.contains(src+"=") || s.contains(src+" "))) { b.append(s); b.append("\r\n"); } @@ -97,9 +482,11 @@ public class I18nConstantMaintainer { } private static void rename(String dir, String src, String tgt) throws FileNotFoundException, IOException { - System.out.println("Rename "+src+" to "+tgt+" in "+dir); - int count = rename(new File(dir), src, tgt); - System.out.println("Done. "+count+" files changed"); + if (!src.equals(tgt)) { + System.out.println("Rename "+src+" to "+tgt+" in "+dir); + int count = rename(new File(dir), src, tgt); + System.out.println("Done. "+count+" files changed"); + } } private static int rename(File file, String src, String tgt) throws FileNotFoundException, IOException { @@ -113,31 +500,67 @@ public class I18nConstantMaintainer { if ("java".equals(ext)) { String source = TextFile.fileToString(file); boolean mod = false; - if (source.contains("I18nConstants."+src)) { - source = source.replace("I18nConstants."+src, "I18nConstants."+tgt); + + if (source.contains("I18nConstants."+src+",")) { + source = source.replace("I18nConstants."+src+",", "I18nConstants."+tgt+","); mod = true; } - if (source.contains("RenderingI18nContext."+src)) { - source = source.replace("RenderingI18nContext."+src, "RenderingI18nContext."+tgt); + if (source.contains("I18nConstants."+src+")")) { + source = source.replace("I18nConstants."+src+")", "I18nConstants."+tgt+")"); mod = true; } - if (source.contains("RenderingContext."+src)) { - source = source.replace("RenderingContext."+src, "RenderingContext."+tgt); + + if (source.contains("RenderingI18nContext."+src+",")) { + source = source.replace("RenderingI18nContext."+src+",", "RenderingI18nContext."+tgt+","); mod = true; } - if (file.getName().equals("I18nConstants.java") && source.contains(src)) { - source = source.replace(src, tgt); + if (source.contains("RenderingI18nContext."+src+")")) { + source = source.replace("RenderingI18nContext."+src+")", "RenderingI18nContext."+tgt+")"); mod = true; } - if (file.getName().equals("RenderingI18nContext.java") && source.contains(src)) { - source = source.replace(src, tgt); + + if (source.contains("RenderingContext."+src+",")) { + source = source.replace("RenderingContext."+src+",", "RenderingContext."+tgt+","); + mod = true; + } + + if (source.contains("RenderingContext."+src+")")) { + source = source.replace("RenderingContext."+src+")", "RenderingContext."+tgt+")"); + mod = true; + } + + + + if (file.getName().equals("I18nConstants.java") && source.contains(src+" =")) { + source = source.replace(src+" =", tgt+" ="); + mod = true; + } + if (file.getName().equals("I18nConstants.java") && source.contains(src+"=")) { + source = source.replace(src+"=", tgt+" ="); mod = true; } + if (file.getName().equals("I18nConstants.java") && source.contains(src+" =")) { + source = source.replace(src+" =", tgt+" ="); + mod = true; + } + if (file.getName().equals("I18nConstants.java") && source.contains(src+"=")) { + source = source.replace(src+"=", tgt+" ="); + mod = true; + } + if (file.getName().equals("RenderingI18nContext.java") && source.contains(src+" =")) { + source = source.replace(src+" =", tgt+" ="); + mod = true; + } + if (file.getName().equals("RenderingI18nContext.java") && source.contains(src+"=")) { + source = source.replace(src+"=", tgt+" ="); + mod = true; + } + if (mod) { TextFile.stringToFile(source, file); count++; } - + } else if (Utilities.existsInList(ext, "po", "properties")) { String source = TextFile.fileToString(file); if (source.contains(src)) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index ddb8a0b37..6a2d2fdae 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -1079,6 +1079,11 @@ public class I18nConstants { public static final String _HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_ = "_has_children__and_multiple_types__in_profile_"; public static final String _HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE = "_has_children__for_type__in_profile__but_cant_find_type"; public static final String _HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_ = "_has_no_children__and_no_types_in_profile_"; + public static final String TERMINOLOGY_TX_CODE_NOTVALID = "Terminology_TX_Code_NotValid"; + public static final String TERMINOLOGY_TX_CODE_UNKNOWN = "Terminology_TX_Code_Unknown"; + public static final String TERMINOLOGY_TX_CODE_VALUESET = "Terminology_TX_Code_ValueSet"; + public static final String TERMINOLOGY_TX_CODE_VALUESETMAX = "Terminology_TX_Code_ValueSetMax"; + public static final String TERMINOLOGY_TX_CODE_VALUESET_EXT = "Terminology_TX_Code_ValueSet_Ext"; //public static final String DUPLICATE_RESOURCE_VERSION = "DUPLICATE_RESOURCE_VERSION"; //public static final String FHIRPATH_BAD_DATE = "FHIRPATH_BAD_DATE"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/POGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/POGenerator.java index 08989e96e..4f9d2599d 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/POGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/POGenerator.java @@ -41,26 +41,29 @@ public class POGenerator { private String comment; private List msgstr = new ArrayList(); } - + public static void main(String[] args) throws IOException { - new POGenerator().execute(args[0], args[1]); + new POGenerator().execute(args[0]); } private List prefixes = new ArrayList<>(); - private void execute(String source, String dest) throws IOException { - generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(dest, "rendering-phrases-de.po")); - generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(dest, "rendering-phrases-es.po")); - generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(dest, "rendering-phrases-ja.po")); - generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(dest, "rendering-phrases-nl.po")); + private void execute(String source) throws IOException { + generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(source, "source", "rendering-phrases-de.po"), Utilities.path(source, "rendering-phrases_de.properties"), true); + generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(source, "source", "rendering-phrases-es.po"), Utilities.path(source, "rendering-phrases_es.properties"), false); + generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(source, "source", "rendering-phrases-ja.po"), Utilities.path(source, "rendering-phrases_ja.properties"), false); + generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(source, "source", "rendering-phrases-nl.po"), Utilities.path(source, "rendering-phrases_nl.properties"), false); + generate(Utilities.path(source, "rendering-phrases.properties"), Utilities.path(source, "source", "rendering-phrases-pt-BR.po"), Utilities.path(source, "rendering-phrases_pt-BR.properties"), false); - generate(Utilities.path(source, "Messages.properties"), Utilities.path(dest, "validator-messages-de.po")); - generate(Utilities.path(source, "Messages.properties"), Utilities.path(dest, "validator-messages-es.po")); - generate(Utilities.path(source, "Messages.properties"), Utilities.path(dest, "validator-messages-ja.po")); - generate(Utilities.path(source, "Messages.properties"), Utilities.path(dest, "validator-messages-nl.po")); + generate(Utilities.path(source, "Messages.properties"), Utilities.path(source, "source", "validator-messages-de.po"), Utilities.path(source, "Messages_de.properties"), true); + generate(Utilities.path(source, "Messages.properties"), Utilities.path(source, "source", "validator-messages-es.po"), Utilities.path(source, "Messages_es.properties"), false); + generate(Utilities.path(source, "Messages.properties"), Utilities.path(source, "source", "validator-messages-ja.po"), Utilities.path(source, "Messages_ja.properties"), false); + generate(Utilities.path(source, "Messages.properties"), Utilities.path(source, "source", "validator-messages-nl.po"), Utilities.path(source, "Messages_nl.properties"), false); + generate(Utilities.path(source, "Messages.properties"), Utilities.path(source, "source", "validator-messages-pt-BR.po"), Utilities.path(source, "Messages_pt-BR.properties"), false); + } - private void generate(String source, String dest) throws IOException { + private void generate(String source, String dest, String tgt, boolean firstRun) throws IOException { // load the destination file // load the source file // update the destination object set for changes from the source file @@ -95,10 +98,12 @@ public class POGenerator { objects.removeIf(o -> o.orphan); Collections.sort(objects, new POObjectSorter()); Map sources = new HashMap<>(); + Set dups = new HashSet<>(); for (POObject o : objects) { if (sources.containsKey(o.msgid)) { Integer c = sources.get(o.msgid)+1; sources.put(o.msgid, c); + dups.add(o.msgid); // System.out.println("Duplicate in "+dest.substring(dest.lastIndexOf("/")+1)+": "+o.msgid+" on ("+CommaSeparatedStringBuilder.join(",", listIds(objects, o.msgid))+")"); } else { sources.put(o.msgid, 1); @@ -110,7 +115,29 @@ public class POGenerator { o.duplicate = true; } } + if (firstRun) { + for (String s : Utilities.sorted(dups)) { + String mid = null; + boolean first = true; + for (POObject o : objects) { + if (o.msgid.equals(s) && o.msgidPlural == null) { + if (mid == null) { + mid = o.id; + } else { + if (first) { + System.out.println(""); + System.out.println("// "+s); + System.out.println("rename(\"/Users/grahamegrieve/work/core\", \""+mid+"\", \""+mid+"\");"); + first = false; + } + System.out.println("replace(\"/Users/grahamegrieve/work/core\", \""+o.id+"\", \""+mid+"\");"); + } + } + } + } + } savePOFile(dest, objects); + savePropFile(tgt, objects); } private Set listIds(List objects, String msgid) { @@ -198,12 +225,12 @@ public class POGenerator { // we don't care; nothing to do } } else if (mode == 2) { - if (!value.equals(o.msgid)) { + if (!value.equals(o.msgidPlural)) { // the english string has changed, and the other language string is now out of date // if (o.oldMsgId != null) { // o.oldMsgId = o.msgid; // } - o.msgid = value; + o.msgidPlural = value; if (o.msgstr.size() > 1 && !Utilities.noString(o.msgstr.get(1))) { o.msgstr.set(1, "!!"+o.msgstr.get(1)); } @@ -290,9 +317,32 @@ public class POGenerator { if (!(v.length() == 3 && v.startsWith("{") && v.endsWith("}"))) { res.add(new StringPair(n, v)); } - } + } } return res; } + private void savePropFile(String tgt, List objects) throws IOException { + String nameLine = TextFile.fileToLines(tgt)[0]; + String[] parts = nameLine.substring(1).trim().split("\\="); + String[] names = parts[1].split("\\,"); + + StringBuilder b = new StringBuilder(); + b.append(nameLine+"\r\n"); + for (POObject o : objects) { + if (o.msgidPlural == null) { + b.append(o.id+" = "+(o.msgstr.size() > 0 ? o.msgstr.get(0) : "")+"\r\n"); + } else { + for (int i = 0; i < names.length; i++) { + b.append(o.id+"_"+names[i].trim()+" = "+(o.msgstr.size() > i ? o.msgstr.get(i) : "")+"\r\n"); + } + } + } + + TextFile.stringToFile(b.toString(), tgt); + + + } + + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java index edf1a76c1..4df0289d9 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java @@ -153,17 +153,20 @@ public class RenderingI18nContext extends I18nBase { public static final String CODESYSTEM_CONTENT_SUPPLEMENT = "CODESYSTEM_CONTENT_SUPPLEMENT"; public static final String CODESYSTEM_DEPRECATED = "CODESYSTEM_DEPRECATED"; public static final String CODESYSTEM_FILTERS = "CODESYSTEM_FILTERS"; - public static final String GENERAL_CODE = "GENERAL_CODE"; + public static final String CODESYSTEM_FILTER_CODE = "CODESYSTEM_FILTER_CODE"; public static final String CODESYSTEM_FILTER_DESC = "CODESYSTEM_FILTER_DESC"; public static final String CODESYSTEM_FILTER_OP = "CODESYSTEM_FILTER_OP"; public static final String CODESYSTEM_FILTER_VALUE = "CODESYSTEM_FILTER_VALUE"; public static final String CODESYSTEM_PROPS = "CODESYSTEM_PROPS"; public static final String CODESYSTEM_PROPS_DESC = "CODESYSTEM_PROPS_DESC"; + public static final String CODESYSTEM_PROP_CODE = "CODESYSTEM_PROP_CODE"; public static final String CODESYSTEM_PROP_DESC = "CODESYSTEM_PROP_DESC"; public static final String CODESYSTEM_PROP_NAME = "CODESYSTEM_PROP_NAME"; public static final String CODESYSTEM_PROP_TYPE = "CODESYSTEM_PROP_TYPE"; public static final String CODESYSTEM_PROP_URI = "CODESYSTEM_PROP_URI"; - public static final String GENERAL_ADD_LANG = "GENERAL_ADD_LANG"; + public static final String CODE_SYS_ADD_LANG = "CODE_SYS_ADD_LANG"; + public static final String CODE_SYS_CODE = "CODE_SYS_CODE"; + public static final String CODE_SYS_CODE_NOT_HERE = "CODE_SYS_CODE_NOT_HERE"; public static final String CODE_SYS_COMPLETE = "CODE_SYS_COMPLETE"; public static final String CODE_SYS_CONTENT = "CODE_SYS_CONTENT"; public static final String CODE_SYS_COPY = "CODE_SYS_COPY"; @@ -184,6 +187,9 @@ public class RenderingI18nContext extends I18nBase { public static final String CODE_SYS_UNKN_MODE = "CODE_SYS_UNKN_MODE"; public static final String CODE_SYS_VALUE_SET = "CODE_SYS_VALUE_SET"; public static final String CONC_MAP_CMNT = "CONC_MAP_CMNT"; + public static final String CONC_MAP_CODE = "CONC_MAP_CODE"; + public static final String CONC_MAP_CODES = "CONC_MAP_CODES"; + public static final String CONC_MAP_CODE_SYS_UNSPEC = "CONC_MAP_CODE_SYS_UNSPEC"; public static final String CONC_MAP_FRM = "CONC_MAP_FRM"; public static final String CONC_MAP_FROM = "CONC_MAP_FROM"; public static final String CONC_MAP_GRP = "CONC_MAP_GRP"; @@ -212,6 +218,8 @@ public class RenderingI18nContext extends I18nBase { public static final String DATA_REND_BFMEALS = "DATA_REND_BFMEALS"; public static final String DATA_REND_BFSLEEP = "DATA_REND_BFSLEEP"; public static final String DATA_REND_BY = "DATA_REND_BY"; + public static final String DATA_REND_CODE = "DATA_REND_CODE"; + public static final String DATA_REND_CODES = "DATA_REND_CODES"; public static final String DATA_REND_COND = "DATA_REND_COND"; public static final String DATA_REND_COUNT = "DATA_REND_COUNT"; public static final String DATA_REND_DATA = "DATA_REND_DATA"; @@ -226,6 +234,7 @@ public class RenderingI18nContext extends I18nBase { public static final String DATA_REND_FACT = "DATA_REND_FACT"; public static final String DATA_REND_FAX = "DATA_REND_FAX"; public static final String DATA_REND_FILT = "DATA_REND_FILT"; + public static final String DATA_REND_GETCODE = "DATA_REND_GETCODE"; public static final String DATA_REND_GLN = "DATA_REND_GLN"; public static final String DATA_REND_ICD = "DATA_REND_ICD"; public static final String DATA_REND_INT = "DATA_REND_INT"; @@ -264,6 +273,8 @@ public class RenderingI18nContext extends I18nBase { public static final String DATA_REND_VALUESET = "DATA_REND_VALUESET"; public static final String DATA_REND_VERSION = "DATA_REND_VERSION"; public static final String DIAG_REP_REND_AGE = "DIAG_REP_REND_AGE"; + public static final String DIAG_REP_REND_CODE = "DIAG_REP_REND_CODE"; + public static final String DIAG_REP_REND_CODECON = "DIAG_REP_REND_CODECON"; public static final String DIAG_REP_REND_ERR = "DIAG_REP_REND_ERR"; public static final String DIAG_REP_REND_FLAG = "DIAG_REP_REND_FLAG"; public static final String DIAG_REP_REND_FOR = "DIAG_REP_REND_FOR"; @@ -322,6 +333,7 @@ public class RenderingI18nContext extends I18nBase { public static final String LIB_REND_REV = "LIB_REND_REV"; public static final String LIB_REND_SHOW = "LIB_REND_SHOW"; public static final String LIB_REND_SIZE = "LIB_REND_SIZE"; + public static final String LIST_REND_CODE = "LIST_REND_CODE"; public static final String LIST_REND_DAT = "LIST_REND_DAT"; public static final String LIST_REND_DATE = "LIST_REND_DATE"; public static final String LIST_REND_DEL = "LIST_REND_DEL"; @@ -357,8 +369,8 @@ public class RenderingI18nContext extends I18nBase { public static final String OBLIG_FILT = "OBLIG_FILT"; public static final String OBLIG_OBLIG = "OBLIG_OBLIG"; public static final String OBLIG_USE = "OBLIG_USE"; - public static final String GENERAL_BINDING = "GENERAL_BINDING"; - public static final String GENERAL_CARDINALITY = "GENERAL_CARDINALITY"; + public static final String OP_DEF_BIND = "OP_DEF_BIND"; + public static final String OP_DEF_CARD = "OP_DEF_CARD"; public static final String OP_DEF_DOC = "OP_DEF_DOC"; public static final String OP_DEF_INPAR = "OP_DEF_INPAR"; public static final String OP_DEF_NAME = "OP_DEF_NAME"; @@ -370,6 +382,7 @@ public class RenderingI18nContext extends I18nBase { public static final String OP_DEF_URL = "OP_DEF_URL"; public static final String OP_DEF_URLS = "OP_DEF_URLS"; public static final String OP_DEF_USE = "OP_DEF_USE"; + public static final String OP_OUT_CODE = "OP_OUT_CODE"; public static final String OP_OUT_DET = "OP_OUT_DET"; public static final String OP_OUT_DIAG = "OP_OUT_DIAG"; public static final String OP_OUT_LOC = "OP_OUT_LOC"; @@ -446,7 +459,9 @@ public class RenderingI18nContext extends I18nBase { public static final String QUEST_ATTRIBUTES = "QUEST_ATTRIBUTES"; public static final String QUEST_CALC = "QUEST_CALC"; public static final String QUEST_CAND = "QUEST_CAND"; + public static final String QUEST_CARD = "QUEST_CARD"; public static final String QUEST_CAT = "QUEST_CAT"; + public static final String QUEST_CODE = "QUEST_CODE"; public static final String QUEST_CONT = "QUEST_CONT"; public static final String QUEST_COPYRIGHT = "QUEST_COPYRIGHT"; public static final String QUEST_DEF = "QUEST_DEF"; @@ -586,14 +601,16 @@ public class RenderingI18nContext extends I18nBase { public static final String SD_COMP_HEAD_TYPE_R = "SD_COMP_HEAD_TYPE_R"; public static final String SD_COMP_HEAD_TYPE_R_DESC ="SD_COMP_HEAD_TYPE_R_DESC"; public static final String SD_DOCO = "SD_DOCO"; - public static final String GENERAL_CARD = "GENERAL_CARD"; - public static final String GENERAL_CARD_DESC = "GENERAL_CARD_DESC"; + public static final String SD_GRID_HEAD_CARD = "SD_GRID_HEAD_CARD"; + public static final String SD_GRID_HEAD_CARD_DESC = "SD_GRID_HEAD_CARD_DESC"; public static final String SD_GRID_HEAD_DESC = "SD_GRID_HEAD_DESC"; public static final String SD_GRID_HEAD_DESC_DESC = "SD_GRID_HEAD_DESC_DESC"; public static final String SD_GRID_HEAD_NAME = "SD_GRID_HEAD_NAME"; public static final String SD_GRID_HEAD_NAME_DESC = "SD_GRID_HEAD_NAME_DESC"; public static final String SD_GRID_HEAD_TYPE = "SD_GRID_HEAD_TYPE"; public static final String SD_GRID_HEAD_TYPE_DESC = "SD_GRID_HEAD_TYPE_DESC"; + public static final String SD_HEAD_CARD = "SD_HEAD_CARD"; + public static final String SD_HEAD_CARD_DESC = "SD_HEAD_CARD_DESC"; public static final String SD_HEAD_DESC = "SD_HEAD_DESC"; public static final String SD_HEAD_DESC_DESC = "SD_HEAD_DESC_DESC"; public static final String SD_HEAD_FLAGS = "SD_HEAD_FLAGS"; @@ -648,6 +665,9 @@ public class RenderingI18nContext extends I18nBase { public static final String STRUC_DEF_APPROP_CON = "STRUC_DEF_APPROP_CON"; public static final String STRUC_DEF_AS_SHOWN = "STRUC_DEF_AS_SHOWN"; public static final String STRUC_DEF_BECAUSE = "STRUC_DEF_BECAUSE"; + public static final String STRUC_DEF_BINDING = "STRUC_DEF_BINDING"; + public static final String STRUC_DEF_BINDINGS = "STRUC_DEF_BINDINGS"; + public static final String STRUC_DEF_BINDING_STYLE = "STRUC_DEF_BINDING_STYLE"; public static final String STRUC_DEF_BIND_STYLE = "STRUC_DEF_BIND_STYLE"; public static final String STRUC_DEF_BLACK = "STRUC_DEF_BLACK"; public static final String STRUC_DEF_BUSINESS_ID = "STRUC_DEF_BUSINESS_ID"; @@ -658,6 +678,7 @@ public class RenderingI18nContext extends I18nBase { public static final String STRUC_DEF_CANT_FIND = "STRUC_DEF_CANT_FIND"; public static final String STRUC_DEF_CAN_TARGET = "STRUC_DEF_CAN_TARGET"; public static final String STRUC_DEF_CAP = "STRUC_DEF_CAP"; + public static final String STRUC_DEF_CARD = "STRUC_DEF_CARD"; public static final String STRUC_DEF_CDA = "STRUC_DEF_CDA"; public static final String STRUC_DEF_CHILD = "STRUC_DEF_CHILD"; public static final String STRUC_DEF_CHOICE = "STRUC_DEF_CHOICE"; @@ -849,6 +870,7 @@ public class RenderingI18nContext extends I18nBase { public static final String STRUC_DEF_SLICE_NAME = "STRUC_DEF_SLICE_NAME"; public static final String STRUC_DEF_SLICE_PAR = "STRUC_DEF_SLICE_PAR"; public static final String STRUC_DEF_SNOMED = "STRUC_DEF_SNOMED"; + public static final String STRUC_DEF_SNOMED_CODE = "STRUC_DEF_SNOMED_CODE"; public static final String STRUC_DEF_SNOMED_CT = "STRUC_DEF_SNOMED_CT"; public static final String STRUC_DEF_STAND_STAT = "STRUC_DEF_STAND_STAT"; public static final String STRUC_DEF_STAND_STATUS = "STRUC_DEF_STAND_STATUS"; @@ -956,17 +978,23 @@ public class RenderingI18nContext extends I18nBase { public static final String TEXT_ICON_REUSE = "TEXT_ICON_REUSE"; public static final String TEXT_ICON_SLICE = "TEXT_ICON_SLICE"; public static final String TEXT_ICON_SLICE_ITEM = "TEXT_ICON_SLICE_ITEM"; + public static final String TX_CODE = "TX_CODE"; public static final String TX_COMMENTS = "TX_COMMENTS"; public static final String TX_DEFINITION = "TX_DEFINITION"; public static final String TX_DEPRECATED = "TX_DEPRECATED"; public static final String TX_DISPLAY = "TX_DISPLAY"; public static final String TX_VERSION = "TX_VERSION"; public static final String VALUE_SET_ADD_DESIG = "VALUE_SET_ADD_DESIG"; + public static final String VALUE_SET_ADD_LANG = "VALUE_SET_ADD_LANG"; public static final String VALUE_SET_ALL_CODE = "VALUE_SET_ALL_CODE"; public static final String VALUE_SET_ALL_CODES_DEF = "VALUE_SET_ALL_CODES_DEF"; public static final String VALUE_SET_AND = "VALUE_SET_AND"; public static final String VALUE_SET_HAS_AT_LEAST = "VALUE_SET_HAS_AT_LEAST"; public static final String VALUE_SET_AUS = "VALUE_SET_AUS"; + public static final String VALUE_SET_CODE = "VALUE_SET_CODE"; + public static final String VALUE_SET_CODES_FROM = "VALUE_SET_CODES_FROM"; + public static final String VALUE_SET_CODE_ITEM = "VALUE_SET_CODE_ITEM"; + public static final String VALUE_SET_CODE_SELEC = "VALUE_SET_CODE_SELEC"; public static final String VALUE_SET_COMMA = "VALUE_SET_COMMA"; public static final String VALUE_SET_CONT = "VALUE_SET_CONT"; public static final String VALUE_SET_CONTAINS = "VALUE_SET_CONTAINS"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java index c7132164b..5956321a3 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java @@ -673,7 +673,7 @@ public class HierarchicalTableGenerator { model.setDocoRef(Utilities.pathURL("https://build.fhir.org/ig/FHIR/ig-guidance", "readingIgs.html#table-views")); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_NAME), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_NAME_DESC), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_FLAGS), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_FLAGS_DESC), null, 0)); - model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.GENERAL_CARD), i18n.formatPhrase(RenderingI18nContext.GENERAL_CARD_DESC), null, 0)); + model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_CARD), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_CARD_DESC), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_TYPE), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_TYPE_DESC), null, 100)); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_DESC), i18n.formatPhrase(RenderingI18nContext.SD_HEAD_DESC_DESC), null, 0)); if (isLogical) { @@ -710,7 +710,7 @@ public class HierarchicalTableGenerator { public TableModel initGridTable(String prefix, String id) { TableModel model = new TableModel(id, false); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_NAME), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_NAME_DESC), null, 0)); - model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.GENERAL_CARD), i18n.formatPhrase(RenderingI18nContext.GENERAL_CARD_DESC), null, 0)); + model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_CARD), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_CARD_DESC), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_TYPE), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_TYPE_DESC), null, 100)); model.getTitles().add(new Title(null, model.getDocoRef(), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_DESC), i18n.formatPhrase(RenderingI18nContext.SD_GRID_HEAD_DESC_DESC), null, 0)); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index b3a11de0d..27b951a64 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -1171,7 +1171,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat CodeSystem cs = getCodeSystem(system); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, I18nConstants.TERMINOLOGY_TX_SYSTEM_UNKNOWN, system)) { ConceptDefinitionComponent def = getCodeDefinition(cs, code); - if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, def != null, I18nConstants.TERMINOLOGY_TX_CODE_UNKNOWN, system, code)) + if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, def != null, I18nConstants.UNKNOWN_CODESYSTEM, system, code)) return warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, display == null || display.equals(def.getDisplay()), I18nConstants.TERMINOLOGY_TX_DISPLAY_WRONG, def.getDisplay()) && ok; } return false;