start building the renderer package

This commit is contained in:
Grahame Grieve 2020-05-05 11:50:23 +10:00
parent ef2f9e01c7
commit 37d4994c8f
20 changed files with 3226 additions and 497 deletions

View File

@ -87,7 +87,7 @@ import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer;
import org.hl7.fhir.r5.renderers.TerminologyRenderer;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.NarrativeGenerator;
import org.hl7.fhir.r5.utils.ToolingExtensions;

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.terminologies;
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.util.ArrayList;
@ -10,12 +10,12 @@ import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
@ -25,34 +25,46 @@ import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent;
import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.CodeSystemNavigator;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class CodeSystemRenderer extends TerminologyRenderer {
private List<String> codeSystemPropList = new ArrayList<>();
public CodeSystemRenderer(RenderingContext context) {
super(context);
}
/**
*
* @param mode - whether we are rendering for a resource directly, or for an IG
* @param context - common services (terminology server, code system cache etc)
* @param markdown - markdown processing engine of the correct sort for the version applicable
* @param prefix - the path to the base FHIR specification
* @param lang - the language to use (null for the default)
*/
public CodeSystemRenderer(TerminologyRendererMode mode, IWorkerContext context, MarkDownProcessor markdown, String prefix, String lang) {
super(mode, context, markdown, prefix, lang);
public CodeSystemRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext);
}
private List<String> codeSystemPropList = new ArrayList<>();
public List<String> getCodeSystemPropList() {
return codeSystemPropList;
}
public void render(CodeSystem cs) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, cs);
inject(cs, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean generate(XhtmlNode x, CodeSystem cs, boolean header) throws FHIRFormatError, DefinitionException, IOException {
public boolean render(XhtmlNode x, CodeSystem cs) throws FHIRFormatError, DefinitionException, IOException {
return render(x, cs, false);
}
public boolean render(XhtmlNode x, CodeSystem cs, boolean header) throws FHIRFormatError, DefinitionException, IOException {
boolean hasExtensions = false;
if (header) {
@ -71,15 +83,23 @@ public class CodeSystemRenderer extends TerminologyRenderer {
return hasExtensions;
}
public void describe(XhtmlNode x, CodeSystem cs) {
x.tx(display(cs));
}
public String display(CodeSystem cs) {
return cs.present();
}
private void generateFilters(XhtmlNode x, CodeSystem cs) {
if (cs.hasFilter()) {
x.para().b().tx(context.translator().translate("xhtml-gen-cs", "Filters", lang));
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Filters", getContext().getLang()));
XhtmlNode tbl = x.table("grid");
XhtmlNode tr = tbl.tr();
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Code", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Description", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "operator", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Value", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "operator", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
for (CodeSystemFilterComponent f : cs.getFilter()) {
tr = tbl.tr();
tr.td().tx(f.getCode());
@ -99,16 +119,16 @@ public class CodeSystemRenderer extends TerminologyRenderer {
hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
}
x.para().b().tx(context.translator().translate("xhtml-gen-cs", "Properties", lang));
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
XhtmlNode tbl = x.table("grid");
XhtmlNode tr = tbl.tr();
if (hasRendered) {
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Name", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Name", getContext().getLang()));
}
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Code", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "URL", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Description", lang));
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Type", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "URL", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Type", getContext().getLang()));
for (PropertyComponent p : cs.getProperty()) {
tr = tbl.tr();
if (hasRendered) {
@ -125,13 +145,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode p = x.para();
if (cs.getContent() == CodeSystemContentMode.COMPLETE)
p.tx(context.translator().translateAndFormat("xhtml-gen-cs", lang, "This code system %s defines the following codes", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":");
else if (cs.getContent() == CodeSystemContentMode.EXAMPLE)
p.tx(context.translator().translateAndFormat("xhtml-gen-cs", lang, "This code system %s defines many codes, of which the following are some examples", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are some examples", cs.getUrl())+":");
else if (cs.getContent() == CodeSystemContentMode.FRAGMENT )
p.tx(context.translator().translateAndFormat("xhtml-gen-cs", lang, "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) {
p.tx(context.translator().translateAndFormat("xhtml-gen-cs", lang, "This code system %s defines many codes, but they are not represented here", cs.getUrl()));
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, but they are not represented here", cs.getUrl()));
return false;
}
XhtmlNode t = x.table( "codes");
@ -212,7 +232,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (Utilities.existsInList(uri, "http://hl7.org/fhir/concept-properties") || codeSystemPropList.contains(uri)) {
return true;
};
CodeSystem cs = context.fetchCodeSystem(uri);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(uri);
if (cs == null) {
return false;
}
@ -298,12 +318,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td = tr.td();
if (c != null &&
c.hasDefinitionElement()) {
if (lang == null) {
if (getContext().getLang() == null) {
if (hasMarkdownInDefinitions(cs))
addMarkdown(td, c.getDefinition());
else
td.addText(c.getDefinition());
} else if (lang.equals("*")) {
} else if (getContext().getLang().equals("*")) {
boolean sl = false;
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue()))
@ -315,11 +335,11 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td.addText(cd.getLanguage()+": "+cd.getValue());
}
}
} else if (lang.equals(cs.getLanguage()) || (lang.equals("en") && !cs.hasLanguage())) {
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
td.addText(c.getDefinition());
} else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(lang)) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
td.addText(cd.getValue());
}
}
@ -329,7 +349,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td = tr.td();
Boolean b = CodeSystemUtilities.isDeprecated(cs, c);
if (b != null && b) {
smartAddText(td, context.translator().translate("xhtml-gen-cs", "Deprecated", lang));
smartAddText(td, getContext().getWorker().translator().translate("xhtml-gen-cs", "Deprecated", getContext().getLang()));
hasExtensions = true;
if (ToolingExtensions.hasExtension(c, ToolingExtensions.EXT_REPLACED_BY)) {
Coding cc = (Coding) ToolingExtensions.getExtension(c, ToolingExtensions.EXT_REPLACED_BY).getValue();
@ -351,10 +371,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
String bc = ext.hasValue() ? ext.getValue().primitiveValue() : null;
Map<String, String> translations = ToolingExtensions.getLanguageTranslations(ext.getValue());
if (lang == null) {
if (getContext().getLang() == null) {
if (bc != null)
td.addText(bc);
} else if (lang.equals("*")) {
} else if (getContext().getLang().equals("*")) {
boolean sl = false;
for (String l : translations.keySet())
if (bc == null || !bc.equalsIgnoreCase(translations.get(l)))
@ -369,14 +389,14 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td.addText(l+": "+translations.get(l));
}
}
} else if (lang.equals(cs.getLanguage()) || (lang.equals("en") && !cs.hasLanguage())) {
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
if (bc != null)
td.addText(bc);
} else {
if (bc != null)
translations.put(cs.getLanguage("en"), bc);
for (String l : translations.keySet()) {
if (l.equals(lang)) {
if (l.equals(getContext().getLang())) {
td.addText(translations.get(l));
}
}
@ -416,7 +436,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
first = false;
XhtmlNode span = td.span(null, mapping.comp.hasRelationship() ? mapping.comp.getRelationship().toCode() : "");
span.addText(getCharForRelationship(mapping.comp));
a = td.ah(prefix+m.getLink()+"#"+makeAnchor(mapping.group.getTarget(), mapping.comp.getCode()));
a = td.ah(getContext().getPrefix()+m.getLink()+"#"+makeAnchor(mapping.group.getTarget(), mapping.comp.getCode()));
a.addText(mapping.comp.getCode());
if (!Utilities.noString(mapping.comp.getComment()))
td.i().tx("("+mapping.comp.getComment()+")");
@ -456,9 +476,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
if (c.hasDisplayElement()) {
if (lang == null) {
if (getContext().getLang() == null) {
td.addText(c.getDisplay());
} else if (lang.equals("*")) {
} else if (getContext().getLang().equals("*")) {
boolean sl = false;
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && !c.getDisplay().equalsIgnoreCase(cd.getValue()))
@ -470,11 +490,11 @@ public class CodeSystemRenderer extends TerminologyRenderer {
td.addText(cd.getLanguage()+": "+cd.getValue());
}
}
} else if (lang.equals(cs.getLanguage()) || (lang.equals("en") && !cs.hasLanguage())) {
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
td.addText(c.getDisplay());
} else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(lang)) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
td.addText(cd.getValue());
}
}

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.terminologies;
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.util.HashMap;
@ -8,50 +8,54 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.ContactDetail;
import org.hl7.fhir.r5.model.ContactPoint;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r5.model.ConceptMap.OtherElementComponent;
import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r5.model.Enumerations.ConceptMapRelationship;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
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.r5.utils.NarrativeGenerator.ResourceContext;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ConceptMapRenderer extends TerminologyRenderer {
/**
*
* @param mode - whether we are rendering for a resource directly, or for an IG
* @param context - common services (terminology server, code system cache etc)
* @param markdown - markdown processing engine of the correct sort for the version applicable
* @param prefix - the path to the base FHIR specification
* @param lang - the language to use (null for the default)
*/
public ConceptMapRenderer(TerminologyRendererMode mode, IWorkerContext context, MarkDownProcessor markdown, String prefix, String lang) {
super(mode, context, markdown, prefix, lang);
public ConceptMapRenderer(RenderingContext context) {
super(context);
}
public boolean generate(ResourceContext rcontext, ConceptMap cm, XhtmlNode x) throws FHIRFormatError, DefinitionException, IOException {
public ConceptMapRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext);
}
public void render(ConceptMap cm) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, cm);
inject(cm, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean render(XhtmlNode x, ConceptMap cm) throws FHIRFormatError, DefinitionException, IOException {
x.h2().addText(cm.getName()+" ("+cm.getUrl()+")");
XhtmlNode p = x.para();
p.tx("Mapping from ");
if (cm.hasSource())
AddVsRef(rcontext, cm.getSource().primitiveValue(), p);
AddVsRef(cm.getSource().primitiveValue(), p);
else
p.tx("(not specified)");
p.tx(" to ");
if (cm.hasTarget())
AddVsRef(rcontext, cm.getTarget().primitiveValue(), p);
AddVsRef(cm.getTarget().primitiveValue(), p);
else
p.tx("(not specified)");
@ -89,9 +93,9 @@ public class ConceptMapRenderer extends TerminologyRenderer {
x.br();
CodeSystem cs = context.fetchCodeSystem("http://hl7.org/fhir/concept-map-relationship");
CodeSystem cs = getContext().getWorker().fetchCodeSystem("http://hl7.org/fhir/concept-map-relationship");
if (cs == null)
cs = context.fetchCodeSystem("http://hl7.org/fhir/concept-map-equivalence");
cs = getContext().getWorker().fetchCodeSystem("http://hl7.org/fhir/concept-map-equivalence");
String eqpath = cs == null ? null : cs.getUserString("path");
for (ConceptMapGroupComponent grp : cm.getGroup()) {
@ -307,6 +311,14 @@ public class ConceptMapRenderer extends TerminologyRenderer {
return true;
}
public void describe(XhtmlNode x, ConceptMap cm) {
x.tx(display(cm));
}
public String display(ConceptMap cm) {
return cm.present();
}
private boolean isSameCodeAndDisplay(String code, String display) {
String c = code.replace(" ", "").replace("-", "").toLowerCase();
String d = display.replace(" ", "").replace("-", "").toLowerCase();
@ -359,7 +371,7 @@ public class ConceptMapRenderer extends TerminologyRenderer {
public void renderCSDetailsLink(XhtmlNode tr, String url, boolean span2) {
CodeSystem cs;
XhtmlNode td;
cs = context.fetchCodeSystem(url);
cs = getContext().getWorker().fetchCodeSystem(url);
td = tr.td();
if (span2) {
td.colspan("2");

View File

@ -0,0 +1,715 @@
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.Address;
import org.hl7.fhir.r5.model.Annotation;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ContactPoint;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.Timing;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem;
import org.hl7.fhir.r5.model.HumanName.NameUse;
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.DataType;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.HumanName;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.Period;
import org.hl7.fhir.r5.model.Quantity;
import org.hl7.fhir.r5.model.Range;
import org.hl7.fhir.r5.model.SampledData;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
public class DataRenderer {
// -- 1. context --------------------------------------------------------------
protected RenderingContext context;
public DataRenderer(RenderingContext context) {
super();
this.context = context;
}
// -- 2. Markdown support -------------------------------------------------------
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 url = link;
String[] parts = link.split("\\#");
StructureDefinition p = getContext().getWorker().fetchResource(StructureDefinition.class, parts[0]);
if (p == null)
p = getContext().getWorker().fetchTypeDefinition(parts[0]);
if (p == null)
p = getContext().getWorker().fetchResource(StructureDefinition.class, link);
if (p != null) {
url = p.getUserString("path");
if (url == null)
url = p.getUserString("filename");
} else
throw new DefinitionException("Unable to resolve markdown link "+link);
text = left+"["+link+"]("+url+")"+right;
}
// 2. markdown
String s = getContext().getMarkdown().process(Utilities.escapeXml(text), "narrative generator");
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+s+"</div>", "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]);
}
}
// -- 3. Gener Purpose Terminology Support -----------------------------------------
public static String describeSystem(String system) {
if (system == null)
return "[not stated]";
if (system.equals("http://loinc.org"))
return "LOINC";
if (system.startsWith("http://snomed.info"))
return "SNOMED CT";
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
return "RxNorm";
if (system.equals("http://hl7.org/fhir/sid/icd-9"))
return "ICD-9";
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
return "DICOM";
if (system.equals("http://unitsofmeasure.org"))
return "UCUM";
return system;
}
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 code) {
ValidationResult t = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), system, code, null);
if (t != null && t.getDisplay() != null)
return t.getDisplay();
else
return code;
}
protected String describeLang(String lang) {
ValueSet v = getContext().getWorker().fetchResource(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) || cc.getCode().startsWith(lang+"-"))
l = cc;
}
}
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;
StructureDefinition sd = getContext().getWorker().fetchTypeDefinition(path.substring(0, path.length()-4));
if (sd == null)
return false;
if (Utilities.existsInList(path.substring(0, path.length()-4), "CapabilityStatement", "StructureDefinition", "ImplementationGuide", "SearchParameter", "MessageDefinition", "OperationDefinition", "CompartmentDefinition", "StructureMap", "GraphDefinition",
"ExampleScenario", "CodeSystem", "ValueSet", "ConceptMap", "NamingSystem", "TerminologyCapabilities"))
return true;
return sd.getBaseDefinitionElement().hasExtension("http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super");
}
// -- 4. Data type Rendering ----------------------------------------------
public static String display(IWorkerContext context, DataType type) {
return new DataRenderer(new RenderingContext(context, null, null, "", null, ResourceRendererMode.RESOURCE)).display(type);
}
public String display(DataType type) {
return null;
}
public void render(XhtmlNode x, DataType type) {
}
public void renderDateTime(XhtmlNode x, Base e) {
if (e.hasPrimitiveValue())
x.addText(((DateTimeType) e).toHumanDisplay());
}
protected void renderUri(XhtmlNode x, UriType uri) {
if (uri.getValue().startsWith("mailto:"))
x.ah(uri.getValue()).addText(uri.getValue().substring(7));
else
x.ah(uri.getValue()).addText(uri.getValue());
}
protected void renderUri(XhtmlNode x, UriType uri, String path, String id) {
String url = uri.getValue();
if (isCanonical(path)) {
CanonicalResource mr = getContext().getWorker().fetchResource(null, url);
if (mr != null) {
if (path.startsWith(mr.fhirType()+".") && mr.getId().equals(id)) {
url = null; // don't link to self whatever
} else if (mr.hasUserData("path"))
url = mr.getUserString("path");
} else if (!getContext().isCanonicalUrlsAsLinks())
url = null;
}
if (url == null)
x.b().tx(uri.getValue());
else if (uri.getValue().startsWith("mailto:"))
x.ah(uri.getValue()).addText(uri.getValue().substring(7));
else
x.ah(uri.getValue()).addText(uri.getValue());
}
protected void renderAnnotation(XhtmlNode x, Annotation annot) {
renderAnnotation(x, annot, false);
}
protected void renderAnnotation(XhtmlNode x, Annotation a, boolean showCodeDetails) throws FHIRException {
StringBuilder s = new StringBuilder();
if (a.hasAuthor()) {
s.append("Author: ");
if (a.hasAuthorReference())
s.append(a.getAuthorReference().getReference());
else if (a.hasAuthorStringType())
s.append(a.getAuthorStringType().getValue());
}
if (a.hasTimeElement()) {
if (s.length() > 0)
s.append("; ");
s.append("Made: ").append(a.getTimeElement().toHumanDisplay());
}
if (a.hasText()) {
if (s.length() > 0)
s.append("; ");
s.append("Annotation: ").append(a.getText());
}
x.addText(s.toString());
}
protected void renderCoding(XhtmlNode x, Coding c) {
renderCoding(x, c, false);
}
protected void renderCoding(XhtmlNode x, Coding c, boolean showCodeDetails) {
String s = "";
if (c.hasDisplayElement())
s = c.getDisplay();
if (Utilities.noString(s))
s = lookupCode(c.getSystem(), c.getCode());
if (Utilities.noString(s))
s = c.getCode();
if (showCodeDetails) {
x.addText(s+" (Details: "+TerminologyRenderer.describeSystem(c.getSystem())+" code "+c.getCode()+" = '"+lookupCode(c.getSystem(), c.getCode())+"', stated as '"+c.getDisplay()+"')");
} else
x.span(null, "{"+c.getSystem()+" "+c.getCode()+"}").addText(s);
}
public String displayCodeableConcept(CodeableConcept cc) {
String s = cc.getText();
if (Utilities.noString(s)) {
for (Coding c : cc.getCoding()) {
if (c.hasDisplayElement()) {
s = c.getDisplay();
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.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) {
renderCodeableConcept(x, cc, false);
}
protected void renderCodeableConcept(XhtmlNode x, CodeableConcept cc, boolean showCodeDetails) {
if (cc.isEmpty()) {
return;
}
String s = cc.getText();
if (Utilities.noString(s)) {
for (Coding c : cc.getCoding()) {
if (c.hasDisplayElement()) {
s = c.getDisplay();
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.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", null);
sp.tx("(Details ");
boolean first = true;
for (Coding c : cc.getCoding()) {
if (first) {
sp.tx(": ");
first = false;
} else
sp.tx("; ");
sp.tx("{"+TerminologyRenderer.describeSystem(c.getSystem())+" code '"+c.getCode()+"' = '"+lookupCode(c.getSystem(), c.getCode())+(c.hasDisplay() ? "', given as '"+c.getDisplay()+"'}" : ""));
}
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, "Codes: "+b.toString()).addText(s);
}
}
private String displayIdentifier(Identifier ii) {
String s = Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue();
if (ii.hasType()) {
if (ii.getType().hasText())
s = ii.getType().getText()+" = "+s;
else if (ii.getType().hasCoding() && ii.getType().getCoding().get(0).hasDisplay())
s = ii.getType().getCoding().get(0).getDisplay()+" = "+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).getCode())+" = "+s;
}
if (ii.hasUse())
s = s + " ("+ii.getUse().toString()+")";
return s;
}
protected void renderIdentifier(XhtmlNode x, Identifier ii) {
x.addText(displayIdentifier(ii));
}
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) {
x.addText(displayHumanName(name));
}
private String displayAddress(Address address) {
StringBuilder s = new StringBuilder();
if (address.hasText())
s.append(address.getText());
else {
for (StringType p : address.getLine()) {
s.append(p.getValue());
s.append(" ");
}
if (address.hasCity()) {
s.append(address.getCity());
s.append(" ");
}
if (address.hasState()) {
s.append(address.getState());
s.append(" ");
}
if (address.hasPostalCode()) {
s.append(address.getPostalCode());
s.append(" ");
}
if (address.hasCountry()) {
s.append(address.getCountry());
s.append(" ");
}
}
if (address.hasUse())
s.append("("+address.getUse().toString()+")");
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();
}
protected void renderContactPoint(XhtmlNode x, ContactPoint contact) {
x.addText(displayContactPoint(contact));
}
protected void addTelecom(XhtmlNode p, ContactPoint c) {
if (c.getSystem() == ContactPointSystem.PHONE) {
p.tx("Phone: "+c.getValue());
} else if (c.getSystem() == ContactPointSystem.FAX) {
p.tx("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("(system = '").append(TerminologyRenderer.describeSystem(q.getSystem()))
.append("' code ").append(q.getCode())
.append(" = '").append(lookupCode(q.getSystem(), q.getCode())).append("')");
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());
x.addText(q.getValue().toString());
if (q.hasUnit())
x.tx(" "+q.getUnit());
else if (q.hasCode())
x.tx(" "+q.getCode());
if (showCodeDetails && q.hasCode()) {
x.span("background: LightGoldenRodYellow", null).tx(" (Details: "+TerminologyRenderer.describeSystem(q.getSystem())+" code "+q.getCode()+" = '"+lookupCode(q.getSystem(), q.getCode())+"')");
}
}
public String displayRange(Range q) {
StringBuilder b = new StringBuilder();
if (q.hasLow())
b.append(q.getLow().getValue().toString());
else
b.append("?");
b.append("-");
if (q.hasHigh())
b.append(q.getHigh().getValue().toString());
else
b.append("?");
if (q.getLow().hasUnit())
b.append(" "+q.getLow().getUnit());
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 static String displayPeriod(Period p) {
String s = !p.hasStart() ? "?ngen-5?" : p.getStartElement().toHumanDisplay();
s = s + " --> ";
return s + (!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
}
public void renderPeriod(XhtmlNode x, Period p) {
x.addText(!p.hasStart() ? "??" : p.getStartElement().toHumanDisplay());
x.tx(" --> ");
x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
}
private String displayTiming(Timing s) throws FHIRException {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
if (s.hasCode())
b.append("Code: "+displayCodeableConcept(s.getCode()));
if (s.getEvent().size() > 0) {
CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder();
for (DateTimeType p : s.getEvent()) {
c.append(p.toHumanDisplay());
}
b.append("Events: "+ c.toString());
}
if (s.hasRepeat()) {
TimingRepeatComponent rep = s.getRepeat();
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart())
b.append("Starting "+rep.getBoundsPeriod().getStartElement().toHumanDisplay());
if (rep.hasCount())
b.append("Count "+Integer.toString(rep.getCount())+" times");
if (rep.hasDuration())
b.append("Duration "+rep.getDuration().toPlainString()+displayTimeUnits(rep.getPeriodUnit()));
if (rep.hasWhen()) {
String st = "";
if (rep.hasOffset()) {
st = Integer.toString(rep.getOffset())+"min ";
}
b.append("Do "+st);
for (Enumeration<EventTiming> wh : rep.getWhen())
b.append(displayEventCode(wh.getValue()));
} else {
String st = "";
if (!rep.hasFrequency() || (!rep.hasFrequencyMax() && rep.getFrequency() == 1) )
st = "Once";
else {
st = Integer.toString(rep.getFrequency());
if (rep.hasFrequencyMax())
st = st + "-"+Integer.toString(rep.getFrequency());
}
if (rep.hasPeriod()) {
st = st + " per "+rep.getPeriod().toPlainString();
if (rep.hasPeriodMax())
st = st + "-"+rep.getPeriodMax().toPlainString();
st = st + " "+displayTimeUnits(rep.getPeriodUnit());
}
b.append("Do "+st);
}
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd())
b.append("Until "+rep.getBoundsPeriod().getEndElement().toHumanDisplay());
}
return b.toString();
}
private String displayEventCode(EventTiming when) {
switch (when) {
case C: return "at meals";
case CD: return "at lunch";
case CM: return "at breakfast";
case CV: return "at dinner";
case AC: return "before meals";
case ACD: return "before lunch";
case ACM: return "before breakfast";
case ACV: return "before dinner";
case HS: return "before sleeping";
case PC: return "after meals";
case PCD: return "after lunch";
case PCM: return "after breakfast";
case PCV: return "after dinner";
case WAKE: return "after waking";
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("Origin: "+displayQuantity(s.getOrigin()));
if (s.hasPeriod())
b.append("Period: "+s.getPeriod().toString());
if (s.hasFactor())
b.append("Factor: "+s.getFactor().toString());
if (s.hasLowerLimit())
b.append("Lower: "+s.getLowerLimit().toString());
if (s.hasUpperLimit())
b.append("Upper: "+s.getUpperLimit().toString());
if (s.hasDimensions())
b.append("Dimensions: "+s.getDimensions());
if (s.hasData())
b.append("Data: "+s.getData());
return b.toString();
}
protected void renderSampledData(XhtmlNode x, SampledData sampledData) {
x.addText(displaySampledData(sampledData));
}
public RenderingContext getContext() {
return context;
}
}

View File

@ -0,0 +1,39 @@
package org.hl7.fhir.r5.renderers;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Encounter;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class EncounterRenderer extends ResourceRenderer {
public EncounterRenderer(RenderingContext context) {
super(context);
}
public void render(Encounter enc) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, enc);
inject(enc, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean render(XhtmlNode x, Encounter enc) {
describe(x, enc);
return false;
}
public void describe(XhtmlNode x, Encounter enc) {
x.tx(display(enc));
}
public String display(Encounter enc) {
return "Not done yet";
}
}

View File

@ -0,0 +1,40 @@
package org.hl7.fhir.r5.renderers;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Patient;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class PatientRenderer extends ResourceRenderer {
public PatientRenderer(RenderingContext context) {
super(context);
}
public void render(Patient pat) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, pat);
inject(pat, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean render(XhtmlNode x, Patient pat) {
describe(x, pat);
return false;
}
public void describe(XhtmlNode x, Patient pat) {
x.tx(display(pat));
}
public String display(Patient pat) {
return "Not done yet";
}
}

View File

@ -0,0 +1,164 @@
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Provenance;
import org.hl7.fhir.r5.model.Provenance;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.Provenance.ProvenanceAgentComponent;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ProvenanceRenderer extends ResourceRenderer {
public ProvenanceRenderer(RenderingContext context) {
super(context);
}
public void render(Provenance prv) throws UnsupportedEncodingException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, prv);
inject(prv, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean render(XhtmlNode x, Provenance prv) throws UnsupportedEncodingException, IOException {
boolean hasExtensions = false;
if (!prv.getTarget().isEmpty()) {
if (prv.getTarget().size() == 1) {
XhtmlNode p = x.para();
p.tx("Provenance for ");
renderReference(prv, p, prv.getTargetFirstRep());
} else {
x.para().tx("Provenance for:");
XhtmlNode ul = x.ul();
for (Reference ref : prv.getTarget()) {
renderReference(prv, ul.li(), ref);
}
}
}
// summary table
x.para().tx("Summary");
XhtmlNode t = x.table("grid");
XhtmlNode tr;
if (prv.hasOccurred()) {
tr = t.tr();
tr.td().tx("Occurrence");
if (prv.hasOccurredPeriod()) {
renderPeriod(tr.td(), prv.getOccurredPeriod());
} else {
renderDateTime(tr.td(), prv.getOccurredDateTimeType());
}
}
if (prv.hasRecorded()) {
tr = t.tr();
tr.td().tx("Recorded");
tr.td().addText(prv.getRecordedElement().toHumanDisplay());
}
if (prv.hasPolicy()) {
tr = t.tr();
tr.td().tx("Policy");
if (prv.getPolicy().size() == 1) {
renderUri(tr.td(), prv.getPolicy().get(0));
} else {
XhtmlNode ul = tr.td().ul();
for (UriType u : prv.getPolicy()) {
renderUri(ul.li(), u);
}
}
}
if (prv.hasLocation()) {
tr = t.tr();
tr.td().tx("Location");
renderReference(prv, tr.td(), prv.getLocation());
}
if (prv.hasActivity()) {
tr = t.tr();
tr.td().tx("Activity");
renderCodeableConcept(tr.td(), prv.getActivity(), false);
}
boolean hasType = false;
boolean hasRole = false;
boolean hasOnBehalfOf = false;
for (ProvenanceAgentComponent a : prv.getAgent()) {
hasType = hasType || a.hasType();
hasRole = hasRole || a.hasRole();
hasOnBehalfOf = hasOnBehalfOf || a.hasOnBehalfOf();
}
x.para().tx("Agents");
t = x.table("grid");
tr = t.tr();
if (hasType) {
tr.td().b().tx("type");
}
if (hasRole) {
tr.td().b().tx("role");
}
tr.td().b().tx("who");
if (hasOnBehalfOf) {
tr.td().b().tx("onBehalfOf");
}
for (ProvenanceAgentComponent a : prv.getAgent()) {
tr = t.tr();
if (hasType) {
if (a.hasType()) {
renderCodeableConcept(tr.td(), a.getType(), false);
} else {
tr.td();
}
}
if (hasRole) {
if (a.hasRole()) {
if (a.getRole().size() == 1) {
renderCodeableConcept(tr.td(), a.getType(), false);
} else {
XhtmlNode ul = tr.td().ul();
for (CodeableConcept cc : a.getRole()) {
renderCodeableConcept(ul.li(), cc, false);
}
}
} else {
tr.td();
}
}
if (a.hasWho()) {
renderReference(prv, tr.td(), a.getWho());
} else {
tr.td();
}
if (hasOnBehalfOf) {
if (a.hasOnBehalfOf()) {
renderReference(prv, tr.td(), a.getOnBehalfOf());
} else {
tr.td();
}
}
}
// agent table
return hasExtensions;
}
public void describe(XhtmlNode x, Provenance prv) throws UnsupportedEncodingException, IOException {
x.tx(display(prv));
}
public String display(Provenance prv) throws UnsupportedEncodingException, IOException {
return "Provenance for "+displayReference(prv, prv.getTargetFirstRep());
}
// }
//
}

View File

@ -0,0 +1,969 @@
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.FormatUtilities;
import org.hl7.fhir.r5.model.CanonicalResource;
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.ConceptMap;
import org.hl7.fhir.r5.model.ContactDetail;
import org.hl7.fhir.r5.model.ContactPoint;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Dosage;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Encounter;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.HumanName;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.InstantType;
import org.hl7.fhir.r5.model.Meta;
import org.hl7.fhir.r5.model.Narrative;
import org.hl7.fhir.r5.model.Period;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Property;
import org.hl7.fhir.r5.model.Provenance;
import org.hl7.fhir.r5.model.Quantity;
import org.hl7.fhir.r5.model.Range;
import org.hl7.fhir.r5.model.Ratio;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.RelatedArtifact;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.SampledData;
import org.hl7.fhir.r5.model.Signature;
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.UriType;
import org.hl7.fhir.r5.model.UsageContext;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.TerminologyRenderer.UsedConceptMap;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers;
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.DOMWrappers.BaseWrapperElement;
import org.hl7.fhir.r5.renderers.utils.DOMWrappers.ResourceWrapperElement;
import org.hl7.fhir.r5.renderers.utils.DirectWrappers.ResourceWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.DirectWrappers.PropertyWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.DirectWrappers.BaseWrapperDirect;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers.ResourceWrapperMetaElement;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.IReferenceResolver;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
import org.hl7.fhir.r5.model.Address;
import org.hl7.fhir.r5.model.Annotation;
import org.hl7.fhir.r5.model.Attachment;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Base64BinaryType;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.Patient;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.w3c.dom.Element;
public class ResourceRenderer extends DataRenderer {
protected ResourceContext rcontext;
private XVerExtensionManager xverManager;
public ResourceRenderer(RenderingContext context) {
super(context);
}
public ResourceRenderer(RenderingContext context, ResourceContext rcontext) {
super(context);
this.rcontext = rcontext;
}
/**
* given a resource, update it's narrative with the best rendering available
*
* @param r - the domain resource in question
*
* @throws FHIRFormatError
* @throws DefinitionException
* @throws IOException
*/
public void render(DomainResource r) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, r);
inject(r, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public boolean render(XhtmlNode x, DomainResource r) throws FHIRFormatError, DefinitionException, IOException {
if (r instanceof CodeSystem) {
return new CodeSystemRenderer(context).render(x, (CodeSystem) r);
}
if (r instanceof ValueSet) {
return new ValueSetRenderer(context).render(x, (ValueSet) r);
}
if (r instanceof ConceptMap) {
return new ConceptMapRenderer(context).render(x, (ConceptMap) r);
}
if (r instanceof Patient) {
return new PatientRenderer(context).render(x, (Patient) r);
}
if (r instanceof Encounter) {
return new EncounterRenderer(context).render(x, (Encounter) r);
}
if (r instanceof Provenance) {
return new ProvenanceRenderer(context).render(x, (Provenance) r);
}
return false;
}
public void describe(XhtmlNode x, DomainResource r) throws UnsupportedEncodingException, IOException {
x.tx(display(r));
}
public String display(DomainResource r) throws UnsupportedEncodingException, IOException {
if (r instanceof CodeSystem) {
return new CodeSystemRenderer(context).display((CodeSystem) r);
}
if (r instanceof ValueSet) {
return new ValueSetRenderer(context).display((ValueSet) r);
}
if (r instanceof ConceptMap) {
return new ConceptMapRenderer(context).display((ConceptMap) r);
}
if (r instanceof Patient) {
return new PatientRenderer(context).display((Patient) r);
}
if (r instanceof Encounter) {
return new EncounterRenderer(context).display((Encounter) r);
}
if (r instanceof Provenance) {
return new ProvenanceRenderer(context).display((Provenance) r);
}
return "todo";
}
protected void inject(DomainResource r, XhtmlNode x, NarrativeStatus status) {
if (!x.hasAttribute("xmlns"))
x.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
if (r.hasLanguage()) {
// use both - see https://www.w3.org/TR/i18n-html-tech-lang/#langvalues
x.setAttribute("lang", r.getLanguage());
x.setAttribute("xml:lang", r.getLanguage());
}
if (!r.hasText() || !r.getText().hasDiv() || r.getText().getDiv().getChildNodes().isEmpty()) {
r.setText(new Narrative());
r.getText().setDiv(x);
r.getText().setStatus(status);
} else {
XhtmlNode n = r.getText().getDiv();
n.hr();
n.getChildNodes().addAll(x.getChildNodes());
}
}
public void inject(Element er, XhtmlNode x, NarrativeStatus status, boolean pretty) {
if (!x.hasAttribute("xmlns"))
x.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
Element le = XMLUtil.getNamedChild(er, "language");
String l = le == null ? null : le.getAttribute("value");
if (!Utilities.noString(l)) {
// use both - see https://www.w3.org/TR/i18n-html-tech-lang/#langvalues
x.setAttribute("lang", l);
x.setAttribute("xml:lang", l);
}
Element txt = XMLUtil.getNamedChild(er, "text");
if (txt == null) {
txt = er.getOwnerDocument().createElementNS(FormatUtilities.FHIR_NS, "text");
Element n = XMLUtil.getFirstChild(er);
while (n != null && (n.getNodeName().equals("id") || n.getNodeName().equals("meta") || n.getNodeName().equals("implicitRules") || n.getNodeName().equals("language")))
n = XMLUtil.getNextSibling(n);
if (n == null)
er.appendChild(txt);
else
er.insertBefore(txt, n);
}
Element st = XMLUtil.getNamedChild(txt, "status");
if (st == null) {
st = er.getOwnerDocument().createElementNS(FormatUtilities.FHIR_NS, "status");
Element n = XMLUtil.getFirstChild(txt);
if (n == null)
txt.appendChild(st);
else
txt.insertBefore(st, n);
}
st.setAttribute("value", status.toCode());
Element div = XMLUtil.getNamedChild(txt, "div");
if (div == null) {
div = er.getOwnerDocument().createElementNS(FormatUtilities.XHTML_NS, "div");
div.setAttribute("xmlns", FormatUtilities.XHTML_NS);
txt.appendChild(div);
}
if (div.hasChildNodes())
div.appendChild(er.getOwnerDocument().createElementNS(FormatUtilities.XHTML_NS, "hr"));
new XhtmlComposer(XhtmlComposer.XML, pretty).compose(div, x);
}
public void inject(org.hl7.fhir.r5.elementmodel.Element er, XhtmlNode x, NarrativeStatus status, boolean pretty) throws IOException, FHIRException {
if (!x.hasAttribute("xmlns"))
x.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
String l = er.getChildValue("language");
if (!Utilities.noString(l)) {
// use both - see https://www.w3.org/TR/i18n-html-tech-lang/#langvalues
x.setAttribute("lang", l);
x.setAttribute("xml:lang", l);
}
org.hl7.fhir.r5.elementmodel.Element txt = er.getNamedChild("text");
if (txt == null) {
txt = new org.hl7.fhir.r5.elementmodel.Element("text", er.getProperty().getChild(null, "text"));
int i = 0;
while (i < er.getChildren().size() && (er.getChildren().get(i).getName().equals("id") || er.getChildren().get(i).getName().equals("meta") || er.getChildren().get(i).getName().equals("implicitRules") || er.getChildren().get(i).getName().equals("language")))
i++;
if (i >= er.getChildren().size())
er.getChildren().add(txt);
else
er.getChildren().add(i, txt);
}
org.hl7.fhir.r5.elementmodel.Element st = txt.getNamedChild("status");
if (st == null) {
st = new org.hl7.fhir.r5.elementmodel.Element("status", txt.getProperty().getChild(null, "status"));
txt.getChildren().add(0, st);
}
st.setValue(status.toCode());
org.hl7.fhir.r5.elementmodel.Element div = txt.getNamedChild("div");
if (div == null) {
div = new org.hl7.fhir.r5.elementmodel.Element("div", txt.getProperty().getChild(null, "div"));
txt.getChildren().add(div);
div.setValue(new XhtmlComposer(XhtmlComposer.XML, pretty).compose(x));
}
div.setValue(x.toString());
div.setXhtml(x);
}
protected void generateCopyright(XhtmlNode x, CanonicalResource cs) {
XhtmlNode p = x.para();
p.b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Copyright Statement:", context.getLang()));
smartAddText(p, " " + cs.getCopyright());
}
public String displayReference(Resource res, Reference r) throws UnsupportedEncodingException, IOException {
return "todo";
}
public void renderReference(Resource res, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
ResourceWrapper rw = new ResourceWrapperDirect(this, res);
renderReference(rw, x, r);
}
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
XhtmlNode c = x;
ResourceWithReference tr = null;
if (r.hasReferenceElement()) {
tr = resolveReference(rw, r.getReference());
if (!r.getReference().startsWith("#")) {
if (tr != null && tr.getReference() != null)
c = x.ah(tr.getReference());
else
c = x.ah(r.getReference());
}
}
// what to display: if text is provided, then that. if the reference was resolved, then show the generated narrative
if (r.hasDisplayElement()) {
c.addText(r.getDisplay());
if (tr != null && tr.getResource() != null) {
c.tx(". Generated Summary: ");
generateResourceSummary(c, tr.getResource(), true, r.getReference().startsWith("#"));
}
} else if (tr != null && tr.getResource() != null) {
generateResourceSummary(c, tr.getResource(), r.getReference().startsWith("#"), r.getReference().startsWith("#"));
} else {
c.addText(r.getReference());
}
}
private ResourceWithReference resolveReference(ResourceWrapper res, String url) {
if (url == null)
return null;
if (url.startsWith("#")) {
for (ResourceWrapper r : res.getContained()) {
if (r.getId().equals(url.substring(1)))
return new ResourceWithReference(null, r);
}
return null;
}
if (rcontext != null) {
BundleEntryComponent bundleResource = rcontext.resolve(url);
if (bundleResource != null) {
String bundleUrl = "#" + bundleResource.getResource().getResourceType().name().toLowerCase() + "_" + bundleResource.getResource().getId();
return new ResourceWithReference(bundleUrl, new ResourceWrapperDirect(this, bundleResource.getResource()));
}
org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url);
if (bundleElement != null) {
String bundleUrl = null;
if (bundleElement.getNamedChild("resource").getChildValue("id") != null) {
bundleUrl = "#" + bundleElement.fhirType().toLowerCase() + "_" + bundleElement.getNamedChild("resource").getChildValue("id");
} else {
bundleUrl = "#" +fullUrlToAnchor(bundleElement.getChildValue("fullUrl"));
}
return new ResourceWithReference(bundleUrl, new ResourceWrapperMetaElement(this, bundleElement));
}
}
Resource ae = getContext().getWorker().fetchResource(null, url);
if (ae != null)
return new ResourceWithReference(url, new ResourceWrapperDirect(this, ae));
else if (context.getResolver() != null) {
return context.getResolver().resolve(url);
} else
return null;
}
private String fullUrlToAnchor(String url) {
return url.replace(":", "").replace("/", "_");
}
public Base parseType(String string, String type) {
return null;
}
private void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
if (!textAlready) {
XhtmlNode div = res.getNarrative();
if (div != null) {
if (div.allChildrenAreText())
x.getChildNodes().addAll(div.getChildNodes());
if (div.getChildNodes().size() == 1 && div.getChildNodes().get(0).allChildrenAreText())
x.getChildNodes().addAll(div.getChildNodes().get(0).getChildNodes());
}
x.tx("Generated Summary: ");
}
String path = res.getName();
StructureDefinition profile = getContext().getWorker().fetchResource(StructureDefinition.class, path);
if (profile == null)
x.tx("unknown resource " +path);
else {
boolean firstElement = true;
boolean last = false;
for (PropertyWrapper p : res.children()) {
ElementDefinition child = getElementDefinition(profile.getSnapshot().getElement(), path+"."+p.getName(), p);
if (p.getValues().size() > 0 && p.getValues().get(0) != null && child != null && isPrimitive(child) && includeInSummary(child)) {
if (firstElement)
firstElement = false;
else if (last)
x.tx("; ");
boolean first = true;
last = false;
for (BaseWrapper v : p.getValues()) {
if (first)
first = false;
else if (last)
x.tx(", ");
last = displayLeaf(res, v, child, x, p.getName(), showCodeDetails) || last;
}
}
}
}
}
private boolean includeInSummary(ElementDefinition child) {
if (child.getIsModifier())
return true;
if (child.getMustSupport())
return true;
if (child.getType().size() == 1) {
String t = child.getType().get(0).getWorkingCode();
if (t.equals("Address") || t.equals("Contact") || t.equals("Reference") || t.equals("Uri") || t.equals("Url") || t.equals("Canonical"))
return false;
}
return true;
}
private ElementDefinition getElementDefinition(List<ElementDefinition> elements, String path, PropertyWrapper p) {
for (ElementDefinition element : elements)
if (element.getPath().equals(path))
return element;
if (path.endsWith("\"]") && p.getStructure() != null)
return p.getStructure().getSnapshot().getElement().get(0);
return null;
}
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException {
if (ew == null)
return;
Base e = ew.getBase();
if (e instanceof StringType)
x.addText(((StringType) e).getValue());
else if (e instanceof CodeType)
x.addText(((CodeType) e).getValue());
else if (e instanceof IdType)
x.addText(((IdType) e).getValue());
else if (e instanceof Extension)
return;
else if (e instanceof InstantType)
x.addText(((InstantType) e).toHumanDisplay());
else if (e instanceof DateTimeType) {
renderDateTime(x, e);
} else if (e instanceof Base64BinaryType)
x.addText(new Base64().encodeAsString(((Base64BinaryType) e).getValue()));
else if (e instanceof org.hl7.fhir.r5.model.DateType)
x.addText(((org.hl7.fhir.r5.model.DateType) e).toHumanDisplay());
else if (e instanceof Enumeration) {
Object ev = ((Enumeration<?>) e).getValue();
x.addText(ev == null ? "" : ev.toString()); // todo: look up a display name if there is one
} else if (e instanceof BooleanType)
x.addText(((BooleanType) e).getValue().toString());
else if (e instanceof CodeableConcept) {
renderCodeableConcept(x, (CodeableConcept) e, showCodeDetails);
} else if (e instanceof Coding) {
renderCoding(x, (Coding) e, showCodeDetails);
} else if (e instanceof Annotation) {
renderAnnotation(x, (Annotation) e);
} else if (e instanceof Identifier) {
renderIdentifier(x, (Identifier) e);
} else if (e instanceof org.hl7.fhir.r5.model.IntegerType) {
x.addText(Integer.toString(((org.hl7.fhir.r5.model.IntegerType) e).getValue()));
} else if (e instanceof org.hl7.fhir.r5.model.DecimalType) {
x.addText(((org.hl7.fhir.r5.model.DecimalType) e).getValue().toString());
} else if (e instanceof HumanName) {
renderHumanName(x, (HumanName) e);
} else if (e instanceof SampledData) {
renderSampledData(x, (SampledData) e);
} else if (e instanceof Address) {
renderAddress(x, (Address) e);
} else if (e instanceof ContactPoint) {
renderContactPoint(x, (ContactPoint) e);
} else if (e instanceof ContactDetail) {
ContactDetail cd = (ContactDetail) e;
if (cd.hasName()) {
x.tx(cd.getName()+": ");
}
boolean first = true;
for (ContactPoint c : cd.getTelecom()) {
if (first) first = false; else x.tx(",");
renderContactPoint(x, c);
}
} else if (e instanceof UriType) {
renderUri(x, (UriType) e, defn.getPath(), rcontext != null && rcontext.getResourceResource() != null ? rcontext.getResourceResource().getId() : null);
} else if (e instanceof Timing) {
renderTiming(x, (Timing) e);
} else if (e instanceof Range) {
renderRange(x, (Range) e);
} else if (e instanceof Quantity) {
renderQuantity(x, (Quantity) e, showCodeDetails);
} else if (e instanceof Ratio) {
renderQuantity(x, ((Ratio) e).getNumerator(), showCodeDetails);
x.tx("/");
renderQuantity(x, ((Ratio) e).getDenominator(), showCodeDetails);
} else if (e instanceof Period) {
Period p = (Period) e;
renderPeriod(x, p);
} else if (e instanceof Reference) {
Reference r = (Reference) e;
renderReference(res, x, r);
} else if (e instanceof Resource) {
return;
} else if (e instanceof ElementDefinition) {
x.tx("todo-bundle");
} else if (e != null && !(e instanceof Attachment) && !(e instanceof Narrative) && !(e instanceof Meta)) {
StructureDefinition sd = getContext().getWorker().fetchTypeDefinition(e.fhirType());
if (sd == null)
throw new NotImplementedException("type "+e.getClass().getName()+" not handled yet, and no structure found");
else
generateByProfile(res, sd, ew, sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep(),
getChildrenForPath(sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep().getPath()), x, path, showCodeDetails, indent + 1);
}
}
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
if (ew == null)
return false;
Base e = ew.getBase();
if (e == null)
return false;
Map<String, String> displayHints = readDisplayHints(defn);
if (name.endsWith("[x]"))
name = name.substring(0, name.length() - 3);
if (!showCodeDetails && e instanceof PrimitiveType && isDefault(displayHints, ((PrimitiveType) e)))
return false;
if (e instanceof StringType) {
x.addText(name+": "+((StringType) e).getValue());
return true;
} else if (e instanceof CodeType) {
x.addText(name+": "+((CodeType) e).getValue());
return true;
} else if (e instanceof IdType) {
x.addText(name+": "+((IdType) e).getValue());
return true;
} else if (e instanceof UriType) {
x.addText(name+": "+((UriType) e).getValue());
return true;
} else if (e instanceof DateTimeType) {
x.addText(name+": "+((DateTimeType) e).toHumanDisplay());
return true;
} else if (e instanceof InstantType) {
x.addText(name+": "+((InstantType) e).toHumanDisplay());
return true;
} else if (e instanceof Extension) {
// x.tx("Extensions: todo");
return false;
} else if (e instanceof org.hl7.fhir.r5.model.DateType) {
x.addText(name+": "+((org.hl7.fhir.r5.model.DateType) e).toHumanDisplay());
return true;
} else if (e instanceof Enumeration) {
x.addText(((Enumeration<?>) e).getValue().toString()); // todo: look up a display name if there is one
return true;
} else if (e instanceof BooleanType) {
if (((BooleanType) e).getValue()) {
x.addText(name);
return true;
}
} else if (e instanceof CodeableConcept) {
renderCodeableConcept(x, (CodeableConcept) e, showCodeDetails);
return true;
} else if (e instanceof Coding) {
renderCoding(x, (Coding) e, showCodeDetails);
return true;
} else if (e instanceof Annotation) {
renderAnnotation(x, (Annotation) e, showCodeDetails);
return true;
} else if (e instanceof org.hl7.fhir.r5.model.IntegerType) {
x.addText(Integer.toString(((org.hl7.fhir.r5.model.IntegerType) e).getValue()));
return true;
} else if (e instanceof org.hl7.fhir.r5.model.DecimalType) {
x.addText(((org.hl7.fhir.r5.model.DecimalType) e).getValue().toString());
return true;
} else if (e instanceof Identifier) {
renderIdentifier(x, (Identifier) e);
return true;
} else if (e instanceof HumanName) {
renderHumanName(x, (HumanName) e);
return true;
} else if (e instanceof SampledData) {
renderSampledData(x, (SampledData) e);
return true;
} else if (e instanceof Address) {
renderAddress(x, (Address) e);
return true;
} else if (e instanceof ContactPoint) {
renderContactPoint(x, (ContactPoint) e);
return true;
} else if (e instanceof Timing) {
renderTiming(x, (Timing) e);
return true;
} else if (e instanceof Quantity) {
renderQuantity(x, (Quantity) e, showCodeDetails);
return true;
} else if (e instanceof Ratio) {
renderQuantity(x, ((Ratio) e).getNumerator(), showCodeDetails);
x.tx("/");
renderQuantity(x, ((Ratio) e).getDenominator(), showCodeDetails);
return true;
} else if (e instanceof Period) {
Period p = (Period) e;
x.addText(name+": ");
x.addText(!p.hasStart() ? "?ngen-2?" : p.getStartElement().toHumanDisplay());
x.tx(" --> ");
x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
return true;
} else if (e instanceof Reference) {
Reference r = (Reference) e;
if (r.hasDisplayElement())
x.addText(r.getDisplay());
else if (r.hasReferenceElement()) {
ResourceWithReference tr = resolveReference(res, r.getReference());
x.addText(tr == null ? r.getReference() : "?ngen-3"); // getDisplayForReference(tr.getReference()));
} else
x.tx("?ngen-4?");
return true;
} else if (e instanceof Narrative) {
return false;
} else if (e instanceof Resource) {
return false;
} else if (e instanceof ContactDetail) {
ContactDetail cd = (ContactDetail) e;
if (cd.hasName()) {
x.tx(cd.getName()+": ");
}
boolean first = true;
for (ContactPoint c : cd.getTelecom()) {
if (first) first = false; else x.tx(",");
renderContactPoint(x, c);
}
return true;
} else if (e instanceof Range) {
return false;
} else if (e instanceof Meta) {
return false;
} else if (e instanceof Dosage) {
return false;
} else if (e instanceof Signature) {
return false;
} else if (e instanceof UsageContext) {
return false;
} else if (e instanceof RelatedArtifact) {
return false;
} else if (e instanceof ElementDefinition) {
return false;
} else if (e instanceof Base64BinaryType) {
return false;
} else if (!(e instanceof Attachment))
throw new NotImplementedException("type "+e.getClass().getName()+" not handled yet");
return false;
}
private boolean isPrimitive(ElementDefinition e) {
//we can tell if e is a primitive because it has types
if (e.getType().isEmpty())
return false;
if (e.getType().size() == 1 && isBase(e.getType().get(0).getWorkingCode()))
return false;
return true;
// return !e.getType().isEmpty()
}
private boolean isBase(String code) {
return code.equals("Element") || code.equals("BackboneElement");
}
private List<ElementDefinition> getChildrenForPath(List<ElementDefinition> elements, String path) throws DefinitionException {
// do we need to do a name reference substitution?
for (ElementDefinition e : elements) {
if (e.getPath().equals(path) && e.hasContentReference()) {
String ref = e.getContentReference();
ElementDefinition t = null;
// now, resolve the name
for (ElementDefinition e1 : elements) {
if (ref.equals("#"+e1.getId()))
t = e1;
}
if (t == null)
throw new DefinitionException("Unable to resolve content reference "+ref+" trying to resolve "+path);
path = t.getPath();
break;
}
}
List<ElementDefinition> results = new ArrayList<ElementDefinition>();
for (ElementDefinition e : elements) {
if (e.getPath().startsWith(path+".") && !e.getPath().substring(path.length()+1).contains("."))
results.add(e);
}
return results;
}
private boolean generateByProfile(StructureDefinition profile, boolean showCodeDetails) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().b().tx("Generated Narrative"+(showCodeDetails ? " with Details" : ""));
try {
generateByProfile(rcontext.getResourceResource(), profile, rcontext.getResourceResource(), profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile.getSnapshot().getElement(), rcontext.getResourceResource().getResourceType().toString()), x, rcontext.getResourceResource().getResourceType().toString(), showCodeDetails);
} catch (Exception e) {
e.printStackTrace();
x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage());
}
inject(rcontext.getResourceResource(), x, NarrativeStatus.GENERATED);
return true;
}
private String generateByProfile(Element er, StructureDefinition profile, boolean showCodeDetails) throws IOException, org.hl7.fhir.exceptions.FHIRException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().b().tx("Generated Narrative"+(showCodeDetails ? " with Details" : ""));
try {
generateByProfile(er, profile, er, profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile.getSnapshot().getElement(), er.getLocalName()), x, er.getLocalName(), showCodeDetails);
} catch (Exception e) {
e.printStackTrace();
x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage());
}
inject(er, x, NarrativeStatus.GENERATED, false);
String b = new XhtmlComposer(XhtmlComposer.XML, false).compose(x);
return b;
}
private void generateByProfile(Element eres, StructureDefinition profile, Element ee, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
ResourceWrapperElement resw = new ResourceWrapperElement(this, eres, profile);
BaseWrapperElement base = new BaseWrapperElement(this, ee, null, profile, profile.getSnapshot().getElement().get(0));
generateByProfile(resw, profile, base, allElements, defn, children, x, path, showCodeDetails, 0);
}
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
generateByProfile(new ResourceWrapperDirect(this, res), profile, new BaseWrapperDirect(this, e), allElements, defn, children, x, path, showCodeDetails, 0);
}
private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent) throws FHIRException, UnsupportedEncodingException, IOException {
if (children.isEmpty()) {
renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent);
} else {
for (PropertyWrapper p : splitExtensions(profile, e.children())) {
if (p.hasValues()) {
ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p);
if (child != null) {
Map<String, String> displayHints = readDisplayHints(child);
if (!exemptFromRendering(child)) {
List<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName());
filterGrandChildren(grandChildren, path+"."+p.getName(), p);
if (p.getValues().size() > 0 && child != null) {
if (isPrimitive(child)) {
XhtmlNode para = x.para();
String name = p.getName();
if (name.endsWith("[x]"))
name = name.substring(0, name.length() - 3);
if (showCodeDetails || !isDefaultValue(displayHints, p.getValues())) {
para.b().addText(name);
para.tx(": ");
if (renderAsList(child) && p.getValues().size() > 1) {
XhtmlNode list = x.ul();
for (BaseWrapper v : p.getValues())
renderLeaf(res, v, child, list.li(), false, showCodeDetails, displayHints, path, indent);
} else {
boolean first = true;
for (BaseWrapper v : p.getValues()) {
if (first)
first = false;
else
para.tx(", ");
renderLeaf(res, v, child, para, false, showCodeDetails, displayHints, path, indent);
}
}
}
} else if (canDoTable(path, p, grandChildren)) {
x.addTag(getHeader()).addText(Utilities.capitalize(Utilities.camelCase(Utilities.pluralizeMe(p.getName()))));
XhtmlNode tbl = x.table( "grid");
XhtmlNode tr = tbl.tr();
tr.td().tx("-"); // work around problem with empty table rows
addColumnHeadings(tr, grandChildren);
for (BaseWrapper v : p.getValues()) {
if (v != null) {
tr = tbl.tr();
tr.td().tx("*"); // work around problem with empty table rows
addColumnValues(res, tr, grandChildren, v, showCodeDetails, displayHints, path, indent);
}
}
} else {
for (BaseWrapper v : p.getValues()) {
if (v != null) {
XhtmlNode bq = x.addTag("blockquote");
bq.para().b().addText(p.getName());
generateByProfile(res, profile, v, allElements, child, grandChildren, bq, path+"."+p.getName(), showCodeDetails, indent+1);
}
}
}
}
}
}
}
}
}
}
private String getHeader() {
int i = 3;
while (i <= context.getHeaderLevelContext())
i++;
if (i > 6)
i = 6;
return "h"+Integer.toString(i);
}
private List<PropertyWrapper> getValues(String path, PropertyWrapper p, ElementDefinition e) {
List<PropertyWrapper> res = new ArrayList<PropertyWrapper>();
for (BaseWrapper v : p.getValues()) {
for (PropertyWrapper g : v.children()) {
if ((path+"."+p.getName()+"."+g.getName()).equals(e.getPath()))
res.add(p);
}
}
return res;
}
private boolean canDoTable(String path, PropertyWrapper p, List<ElementDefinition> grandChildren) {
for (ElementDefinition e : grandChildren) {
List<PropertyWrapper> values = getValues(path, p, e);
if (values.size() > 1 || !isPrimitive(e) || !canCollapse(e))
return false;
}
return true;
}
private boolean canCollapse(ElementDefinition e) {
// we can collapse any data type
return !e.getType().isEmpty();
}
private boolean exemptFromRendering(ElementDefinition child) {
if (child == null)
return false;
if ("Composition.subject".equals(child.getPath()))
return true;
if ("Composition.section".equals(child.getPath()))
return true;
return false;
}
private boolean renderAsList(ElementDefinition child) {
if (child.getType().size() == 1) {
String t = child.getType().get(0).getWorkingCode();
if (t.equals("Address") || t.equals("Reference"))
return true;
}
return false;
}
private void addColumnHeadings(XhtmlNode tr, List<ElementDefinition> grandChildren) {
for (ElementDefinition e : grandChildren)
tr.td().b().addText(Utilities.capitalize(tail(e.getPath())));
}
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent) throws FHIRException, UnsupportedEncodingException, IOException {
for (ElementDefinition e : grandChildren) {
PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1));
if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null)
tr.td().tx(" ");
else
renderLeaf(res, p.getValues().get(0), e, tr.td(), false, showCodeDetails, displayHints, path, indent);
}
}
private void filterGrandChildren(List<ElementDefinition> grandChildren, String string, PropertyWrapper prop) {
List<ElementDefinition> toRemove = new ArrayList<ElementDefinition>();
toRemove.addAll(grandChildren);
for (BaseWrapper b : prop.getValues()) {
List<ElementDefinition> list = new ArrayList<ElementDefinition>();
for (ElementDefinition ed : toRemove) {
PropertyWrapper p = b.getChildByName(tail(ed.getPath()));
if (p != null && p.hasValues())
list.add(ed);
}
toRemove.removeAll(list);
}
grandChildren.removeAll(toRemove);
}
private List<PropertyWrapper> splitExtensions(StructureDefinition profile, List<PropertyWrapper> children) throws UnsupportedEncodingException, IOException, FHIRException {
List<PropertyWrapper> results = new ArrayList<PropertyWrapper>();
Map<String, PropertyWrapper> map = new HashMap<String, PropertyWrapper>();
for (PropertyWrapper p : children)
if (p.getName().equals("extension") || p.getName().equals("modifierExtension")) {
// we're going to split these up, and create a property for each url
if (p.hasValues()) {
for (BaseWrapper v : p.getValues()) {
Extension ex = (Extension) v.getBase();
String url = ex.getUrl();
StructureDefinition ed = getContext().getWorker().fetchResource(StructureDefinition.class, url);
if (ed == null) {
if (xverManager == null) {
xverManager = new XVerExtensionManager(context.getWorker());
}
if (xverManager.matchingUrl(url) && xverManager.status(url) == XVerExtensionStatus.Valid) {
ed = xverManager.makeDefinition(url);
getContext().getWorker().generateSnapshot(ed);
getContext().getWorker().cacheResource(ed);
}
}
if (p.getName().equals("modifierExtension") && ed == null)
throw new DefinitionException("Unknown modifier extension "+url);
PropertyWrapper pe = map.get(p.getName()+"["+url+"]");
if (pe == null) {
if (ed == null) {
if (url.startsWith("http://hl7.org/fhir") && !url.startsWith("http://hl7.org/fhir/us"))
throw new DefinitionException("unknown extension "+url);
// System.out.println("unknown extension "+url);
pe = new PropertyWrapperDirect(this, new Property(p.getName()+"["+url+"]", p.getTypeCode(), p.getDefinition(), p.getMinCardinality(), p.getMaxCardinality(), ex));
} else {
ElementDefinition def = ed.getSnapshot().getElement().get(0);
pe = new PropertyWrapperDirect(this, new Property(p.getName()+"["+url+"]", "Extension", def.getDefinition(), def.getMin(), def.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(def.getMax()), ex));
((PropertyWrapperDirect) pe).getWrapped().setStructure(ed);
}
results.add(pe);
} else
pe.getValues().add(v);
}
}
} else
results.add(p);
return results;
}
private Map<String, String> readDisplayHints(ElementDefinition defn) throws DefinitionException {
Map<String, String> hints = new HashMap<String, String>();
if (defn != null) {
String displayHint = ToolingExtensions.getDisplayHint(defn);
if (!Utilities.noString(displayHint)) {
String[] list = displayHint.split(";");
for (String item : list) {
String[] parts = item.split(":");
if (parts.length != 2)
throw new DefinitionException("error reading display hint: '"+displayHint+"'");
hints.put(parts[0].trim(), parts[1].trim());
}
}
}
return hints;
}
@SuppressWarnings("rawtypes")
private boolean isDefaultValue(Map<String, String> displayHints, List<BaseWrapper> list) throws UnsupportedEncodingException, IOException, FHIRException {
if (list.size() != 1)
return false;
if (list.get(0).getBase() instanceof PrimitiveType)
return isDefault(displayHints, (PrimitiveType) list.get(0).getBase());
else
return false;
}
private boolean isDefault(Map<String, String> displayHints, PrimitiveType primitiveType) {
String v = primitiveType.asStringValue();
if (!Utilities.noString(v) && displayHints.containsKey("default") && v.equals(displayHints.get("default")))
return true;
return false;
}
protected String tail(String path) {
return path.substring(path.lastIndexOf(".")+1);
}
}

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.terminologies;
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.util.ArrayList;
@ -7,8 +7,6 @@ import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ConceptMap;
@ -17,6 +15,7 @@ import org.hl7.fhir.r5.model.Questionnaire;
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.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent;
@ -29,20 +28,25 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.NarrativeGenerator.ResourceContext;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
public class TerminologyRenderer {
public class TerminologyRenderer extends ResourceRenderer {
public TerminologyRenderer(RenderingContext context) {
super(context);
}
public enum TerminologyRendererMode {
RESOURCE, IG
public TerminologyRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext);
}
protected class TargetElementComponentWrapper {
@ -100,52 +104,7 @@ public class TerminologyRenderer {
}
protected TerminologyRendererMode mode;
protected IWorkerContext context;
protected MarkDownProcessor markdown;
protected String lang;
protected String prefix;
protected int headerLevelContext;
protected ValidationOptions terminologyServiceOptions = new ValidationOptions();
protected boolean noSlowLookup;
/**
*
* @param mode - whether we are rendering for a resource directly, or for an IG
* @param context - common services (terminology server, code system cache etc)
* @param markdown - markdown processing engine of the correct sort for the version applicable
* @param prefix - the path to the base FHIR specification
* @param lang - the language to use (null for the default)
*/
public TerminologyRenderer(TerminologyRendererMode mode, IWorkerContext context, MarkDownProcessor markdown, String prefix, String lang) {
super();
this.mode = mode;
this.context = context;
this.markdown = markdown;
this.lang = lang;
this.prefix = prefix;
}
public TerminologyRendererMode getMode() {
return mode;
}
public int getHeaderLevelContext() {
return headerLevelContext;
}
public void setHeaderLevelContext(int headerLevelContext) {
this.headerLevelContext = headerLevelContext;
}
public ValidationOptions getTerminologyServiceOptions() {
return terminologyServiceOptions;
}
public void setTerminologyServiceOptions(ValidationOptions terminologyServiceOptions) {
this.terminologyServiceOptions = terminologyServiceOptions;
}
public boolean isNoSlowLookup() {
@ -156,66 +115,11 @@ public class TerminologyRenderer {
this.noSlowLookup = noSlowLookup;
}
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 url = link;
String[] parts = link.split("\\#");
StructureDefinition p = context.fetchResource(StructureDefinition.class, parts[0]);
if (p == null)
p = context.fetchTypeDefinition(parts[0]);
if (p == null)
p = context.fetchResource(StructureDefinition.class, link);
if (p != null) {
url = p.getUserString("path");
if (url == null)
url = p.getUserString("filename");
} else
throw new DefinitionException("Unable to resolve markdown link "+link);
text = left+"["+link+"]("+url+")"+right;
}
// 2. markdown
String s = markdown.process(Utilities.escapeXml(text), "narrative generator");
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+s+"</div>", "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
}
x.getChildNodes().addAll(m.getChildNodes());
}
}
protected void generateCopyright(XhtmlNode x, CanonicalResource cs) {
XhtmlNode p = x.para();
p.b().tx(context.translator().translate("xhtml-gen-cs", "Copyright Statement:", lang));
smartAddText(p, " " + cs.getCopyright());
}
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 addMapHeaders(XhtmlNode tr, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
for (UsedConceptMap m : maps) {
XhtmlNode td = tr.td();
XhtmlNode b = td.b();
XhtmlNode a = b.ah(prefix+m.getLink());
XhtmlNode a = b.ah(getContext().getPrefix()+m.getLink());
a.addText(m.getDetails().getName());
if (m.getDetails().isDoDescription() && m.getMap().hasDescription())
addMarkdown(td, m.getMap().getDescription());
@ -224,45 +128,13 @@ public class TerminologyRenderer {
protected String getHeader() {
int i = 3;
while (i <= headerLevelContext)
while (i <= getContext().getHeaderLevelContext())
i++;
if (i > 6)
i = 6;
return "h"+Integer.toString(i);
}
public static String describeSystem(String system) {
if (system == null)
return "[not stated]";
if (system.equals("http://loinc.org"))
return "LOINC";
if (system.startsWith("http://snomed.info"))
return "SNOMED CT";
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
return "RxNorm";
if (system.equals("http://hl7.org/fhir/sid/icd-9"))
return "ICD-9";
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
return "DICOM";
if (system.equals("http://unitsofmeasure.org"))
return "UCUM";
return system;
}
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();
}
protected List<TargetElementComponentWrapper> findMappingsForCode(String code, ConceptMap map) {
List<TargetElementComponentWrapper> mappings = new ArrayList<TargetElementComponentWrapper>();
@ -307,11 +179,11 @@ public class TerminologyRenderer {
XhtmlNode a = li.ah(spec);
a.code(inc.getSystem());
} else if (cs != null && ref != null) {
if (!Utilities.noString(prefix) && ref.startsWith("http://hl7.org/fhir/"))
if (!Utilities.noString(getContext().getPrefix()) && ref.startsWith("http://hl7.org/fhir/"))
ref = ref.substring(20)+"/index.html";
else if (addHtml && !ref.contains(".html"))
ref = ref + ".html";
XhtmlNode a = li.ah(prefix+ref.replace("\\", "/"));
XhtmlNode a = li.ah(getContext().getPrefix()+ref.replace("\\", "/"));
a.code(inc.getSystem());
} else {
li.code(inc.getSystem());
@ -335,17 +207,17 @@ public class TerminologyRenderer {
XhtmlNode tr = t.tr();
if (hasHierarchy)
tr.td().b().tx("Lvl");
tr.td().attribute("style", "white-space:nowrap").b().tx(context.translator().translate("xhtml-gen-cs", "Code", lang));
tr.td().attribute("style", "white-space:nowrap").b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Code", getContext().getLang()));
if (hasDisplay)
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Display", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Display", getContext().getLang()));
if (definitions)
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Definition", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Definition", getContext().getLang()));
if (deprecated)
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Deprecated", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Deprecated", getContext().getLang()));
if (comments)
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Comments", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Comments", getContext().getLang()));
if (version)
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", "Version", lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Version", getContext().getLang()));
if (properties != null) {
for (PropertyComponent pc : properties) {
String display = ToolingExtensions.getPresentation(pc, pc.getCodeElement());
@ -355,7 +227,7 @@ public class TerminologyRenderer {
display = pc.getCode();
}
}
tr.td().b().tx(context.translator().translate("xhtml-gen-cs", display, lang));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", display, getContext().getLang()));
}
}
return tr;
@ -371,7 +243,7 @@ public class TerminologyRenderer {
code = uri.substring(uri.indexOf("#")+1);
uri = uri.substring(0, uri.indexOf("#"));
}
CodeSystem cs = context.fetchCodeSystem(uri);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(uri);
if (cs == null) {
return null;
}
@ -380,7 +252,7 @@ public class TerminologyRenderer {
}
protected void AddVsRef(ResourceContext rcontext, String value, XhtmlNode li) {
protected void AddVsRef(String value, XhtmlNode li) {
Resource res = null;
if (rcontext != null) {
BundleEntryComponent be = rcontext.resolve(value);
@ -394,13 +266,13 @@ public class TerminologyRenderer {
}
CanonicalResource vs = (CanonicalResource) res;
if (vs == null)
vs = context.fetchResource(ValueSet.class, value);
vs = getContext().getWorker().fetchResource(ValueSet.class, value);
if (vs == null)
vs = context.fetchResource(StructureDefinition.class, value);
vs = getContext().getWorker().fetchResource(StructureDefinition.class, value);
// if (vs == null)
// vs = context.fetchResource(DataElement.class, value);
// vs = context.getWorker().fetchResource(DataElement.class, value);
if (vs == null)
vs = context.fetchResource(Questionnaire.class, value);
vs = getContext().getWorker().fetchResource(Questionnaire.class, value);
if (vs != null) {
String ref = (String) vs.getUserData("path");
@ -408,7 +280,7 @@ public class TerminologyRenderer {
XhtmlNode a = li.ah(ref == null ? "?ngen-11?" : ref.replace("\\", "/"));
a.addText(value);
} else {
CodeSystem cs = context.fetchCodeSystem(value);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(value);
if (cs != null) {
String ref = (String) cs.getUserData("path");
ref = adjustForPath(ref);
@ -427,69 +299,19 @@ public class TerminologyRenderer {
}
private String adjustForPath(String ref) {
if (prefix == null)
if (getContext().getPrefix() == null)
return ref;
else
return prefix+ref;
return getContext().getPrefix()+ref;
}
protected void addTelecom(XhtmlNode p, ContactPoint c) {
if (c.getSystem() == ContactPointSystem.PHONE) {
p.tx("Phone: "+c.getValue());
} else if (c.getSystem() == ContactPointSystem.FAX) {
p.tx("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());
}
}
protected String getDisplayForConcept(String system, String value) {
if (value == null || system == null)
return null;
ValidationResult cl = context.validateCode(terminologyServiceOptions, system, value, null);
ValidationResult cl = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), system, value, null);
return cl == null ? null : cl.getDisplay();
}
protected String describeLang(String lang) {
ValueSet v = context.fetchResource(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) || cc.getCode().startsWith(lang+"-"))
l = cc;
}
}
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;
}
}

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.terminologies;
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.text.ParseException;
@ -12,7 +12,6 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
@ -21,6 +20,7 @@ import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.ExtensionHelper;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.UriType;
@ -28,6 +28,7 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r5.model.Enumerations.FilterOperator;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
@ -35,12 +36,16 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer.ConceptMapRenderInstructions;
import org.hl7.fhir.r5.renderers.TerminologyRenderer.ConceptMapRenderInstructions;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.NarrativeGenerator.ResourceContext;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
@ -49,81 +54,59 @@ import com.google.common.collect.Multimap;
public class ValueSetRenderer extends TerminologyRenderer {
public ValueSetRenderer(RenderingContext context) {
super(context);
}
public ValueSetRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext);
}
private static final String ABSTRACT_CODE_HINT = "This code is not selectable ('Abstract')";
private String tooCostlyNoteEmpty;
private String tooCostlyNoteNotEmpty;
private String tooCostlyNoteEmptyDependent;
private String tooCostlyNoteNotEmptyDependent;
private List<ConceptMapRenderInstructions> renderingMaps = new ArrayList<ConceptMapRenderInstructions>();
/**
*
* @param mode - whether we are rendering for a resource directly, or for an IG
* @param context - common services (terminology server, code system cache etc)
* @param markdown - markdown processing engine of the correct sort for the version applicable
* @param prefix - the path to the base FHIR specification
* @param lang - the language to use (null for the default)
*/
public ValueSetRenderer(TerminologyRendererMode mode, IWorkerContext context, MarkDownProcessor markdown, String prefix, String lang) {
super(mode, context, markdown, prefix, lang);
renderingMaps.add(new ConceptMapRenderInstructions("Canonical Status", "http://hl7.org/fhir/ValueSet/resource-status", false));
public void render(ValueSet vs) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean hasExtensions = render(x, vs);
inject(vs, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}
public String getTooCostlyNoteEmpty() {
return tooCostlyNoteEmpty;
public boolean render(XhtmlNode x, ValueSet vs) throws FHIRFormatError, DefinitionException, IOException {
return render(x, vs, false);
}
public void setTooCostlyNoteEmpty(String tooCostlyNoteEmpty) {
this.tooCostlyNoteEmpty = tooCostlyNoteEmpty;
}
public String getTooCostlyNoteNotEmpty() {
return tooCostlyNoteNotEmpty;
}
public void setTooCostlyNoteNotEmpty(String tooCostlyNoteNotEmpty) {
this.tooCostlyNoteNotEmpty = tooCostlyNoteNotEmpty;
}
public String getTooCostlyNoteEmptyDependent() {
return tooCostlyNoteEmptyDependent;
}
public void setTooCostlyNoteEmptyDependent(String tooCostlyNoteEmptyDependent) {
this.tooCostlyNoteEmptyDependent = tooCostlyNoteEmptyDependent;
}
public String getTooCostlyNoteNotEmptyDependent() {
return tooCostlyNoteNotEmptyDependent;
}
public void setTooCostlyNoteNotEmptyDependent(String tooCostlyNoteNotEmptyDependent) {
this.tooCostlyNoteNotEmptyDependent = tooCostlyNoteNotEmptyDependent;
}
public boolean render(ResourceContext rcontext, XhtmlNode x, ValueSet vs, ValueSet src, boolean header) throws FHIRFormatError, DefinitionException, IOException {
public boolean render(XhtmlNode x, ValueSet vs, boolean header) throws FHIRFormatError, DefinitionException, IOException {
List<UsedConceptMap> maps = findReleventMaps(vs);
boolean hasExtensions;
if (vs.hasExpansion()) {
// for now, we just accept an expansion if there is one
hasExtensions = generateExpansion(x, vs, src, header, maps);
hasExtensions = generateExpansion(x, vs, header, maps);
} else {
hasExtensions = generateComposition(rcontext, x, vs, header, maps);
hasExtensions = generateComposition(x, vs, header, maps);
}
return hasExtensions;
}
public void describe(XhtmlNode x, ValueSet vs) {
x.tx(display(vs));
}
public String display(ValueSet vs) {
return vs.present();
}
private List<UsedConceptMap> findReleventMaps(ValueSet vs) throws FHIRException {
List<UsedConceptMap> res = new ArrayList<UsedConceptMap>();
for (CanonicalResource md : context.allConformanceResources()) {
for (CanonicalResource md : getContext().getWorker().allConformanceResources()) {
if (md instanceof ConceptMap) {
ConceptMap cm = (ConceptMap) md;
if (isSource(vs, cm.getSource())) {
ConceptMapRenderInstructions re = findByTarget(cm.getTarget());
if (re != null) {
ValueSet vst = cm.hasTarget() ? context.fetchResource(ValueSet.class, cm.hasTargetCanonicalType() ? cm.getTargetCanonicalType().getValue() : cm.getTargetUriType().asStringValue()) : null;
ValueSet vst = cm.hasTarget() ? getContext().getWorker().fetchResource(ValueSet.class, cm.hasTargetCanonicalType() ? cm.getTargetCanonicalType().getValue() : cm.getTargetUriType().asStringValue()) : null;
res.add(new UsedConceptMap(re, vst == null ? cm.getUserString("path") : vst.getUserString("path"), cm));
}
}
@ -131,17 +114,17 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
return res;
// Map<ConceptMap, String> mymaps = new HashMap<ConceptMap, String>();
// for (ConceptMap a : context.findMapsForSource(vs.getUrl())) {
// for (ConceptMap a : context.getWorker().findMapsForSource(vs.getUrl())) {
// String url = "";
// ValueSet vsr = context.fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
// ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
// if (vsr != null)
// url = (String) vsr.getUserData("filename");
// mymaps.put(a, url);
// }
// Map<ConceptMap, String> mymaps = new HashMap<ConceptMap, String>();
// for (ConceptMap a : context.findMapsForSource(cs.getValueSet())) {
// for (ConceptMap a : context.getWorker().findMapsForSource(cs.getValueSet())) {
// String url = "";
// ValueSet vsr = context.fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
// ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
// if (vsr != null)
// url = (String) vsr.getUserData("filename");
// mymaps.put(a, url);
@ -152,7 +135,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
// ConceptMap cm = (ConceptMap) r;
// if (((Reference) cm.getSource()).getReference().equals(cs.getValueSet())) {
// String url = "";
// ValueSet vsr = context.fetchResource(ValueSet.class, ((Reference) cm.getTarget()).getReference());
// ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) cm.getTarget()).getReference());
// if (vsr != null)
// url = (String) vsr.getUserData("filename");
// mymaps.put(cm, url);
@ -165,7 +148,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
return vs.hasUrl() && source != null && vs.getUrl().equals(source.primitiveValue());
}
private boolean generateExpansion(XhtmlNode x, ValueSet vs, ValueSet src, boolean header, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
private boolean generateExpansion(XhtmlNode x, ValueSet vs, boolean header, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
boolean hasExtensions = false;
List<String> langs = new ArrayList<String>();
@ -183,9 +166,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
boolean other = false;
for (Extension ex : exl) {
if (ex.getValue() instanceof BooleanType) {
x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(vs.getExpansion().getContains().isEmpty() ? tooCostlyNoteEmpty : tooCostlyNoteNotEmpty );
x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(vs.getExpansion().getContains().isEmpty() ? getContext().getTooCostlyNoteEmpty() : getContext().getTooCostlyNoteNotEmpty());
} else if (!other) {
x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(vs.getExpansion().getContains().isEmpty() ? tooCostlyNoteEmptyDependent : tooCostlyNoteNotEmptyDependent );
x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(vs.getExpansion().getContains().isEmpty() ? getContext().getTooCostlyNoteEmptyDependent() : getContext().getTooCostlyNoteNotEmptyDependent());
other = true;
}
}
@ -230,14 +213,14 @@ public class ValueSetRenderer extends TerminologyRenderer {
doSystem = false;
XhtmlNode p = x.para();
p.tx("All codes from system ");
allCS = context.fetchCodeSystem(vs.getExpansion().getContains().get(0).getSystem());
allCS = getContext().getWorker().fetchCodeSystem(vs.getExpansion().getContains().get(0).getSystem());
String ref = null;
if (allCS != null)
ref = getCsRef(allCS);
if (ref == null)
p.code(vs.getExpansion().getContains().get(0).getSystem());
else
p.ah(prefix+ref).code(vs.getExpansion().getContains().get(0).getSystem());
p.ah(getContext().getPrefix()+ref).code(vs.getExpansion().getContains().get(0).getSystem());
}
XhtmlNode t = x.table( "codes");
XhtmlNode tr = t.tr();
@ -319,7 +302,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
if (vs.hasCompose()) {
if (vs.getCompose().hasExclude()) {
try {
ValueSetExpansionOutcome vse = context.expandVS(vs, true, false);
ValueSetExpansionOutcome vse = getContext().getWorker().expandVS(vs, true, false);
count = 0;
count += conceptCount(vse.getValueset().getExpansion().getContains());
return count;
@ -350,7 +333,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
private void addCSRef(XhtmlNode x, String url) {
CodeSystem cs = context.fetchCodeSystem(url);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(url);
if (cs == null) {
x.code(url);
} else if (cs.hasUserData("path")) {
@ -419,7 +402,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
x.tx("Loinc v"+v);
}
} else {
CanonicalResource cr = (CanonicalResource) context.fetchResource(Resource.class, u+"|"+v);
CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v);
if (cr != null) {
if (cr.hasUserData("path")) {
x.ah(cr.getUserString("path")).tx(cr.present()+" v"+v+" ("+cr.fhirType()+")");
@ -548,7 +531,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
private boolean checkDoDefinition(List<ValueSetExpansionContainsComponent> contains) {
for (ValueSetExpansionContainsComponent c : contains) {
CodeSystem cs = context.fetchCodeSystem(c.getSystem());
CodeSystem cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
if (cs != null)
return true;
if (checkDoDefinition(c.getContains()))
@ -570,7 +553,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
private String getCsRef(String system) {
CodeSystem cs = context.fetchCodeSystem(system);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(system);
return getCsRef(cs);
}
@ -610,7 +593,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
if (doDefinition) {
CodeSystem cs = allCS;
if (cs == null)
cs = context.fetchCodeSystem(c.getSystem());
cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
td = tr.td();
if (cs != null)
td.addText(CodeSystemUtilities.getCodeDefinition(cs, c.getCode()));
@ -657,7 +640,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
private void addCodeToTable(boolean isAbstract, String system, String code, String display, XhtmlNode td) {
CodeSystem e = context.fetchCodeSystem(system);
CodeSystem e = getContext().getWorker().fetchCodeSystem(system);
if (e == null || e.getContent() != org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode.COMPLETE) {
if (isAbstract)
td.i().setAttribute("title", ABSTRACT_CODE_HINT).addText(code);
@ -668,7 +651,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
} else
td.addText(code);
} else {
String href = prefix+getCsRef(e);
String href = getContext().getPrefix()+getCsRef(e);
if (href.contains("#"))
href = href + "-"+Utilities.nmtokenize(code);
else
@ -688,17 +671,17 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
private void addRefToCode(XhtmlNode td, String target, String vslink, String code) {
CodeSystem cs = context.fetchCodeSystem(target);
CodeSystem cs = getContext().getWorker().fetchCodeSystem(target);
String cslink = getCsRef(cs);
XhtmlNode a = null;
if (cslink != null)
a = td.ah(prefix+cslink+"#"+cs.getId()+"-"+code);
a = td.ah(getContext().getPrefix()+cslink+"#"+cs.getId()+"-"+code);
else
a = td.ah(prefix+vslink+"#"+code);
a = td.ah(getContext().getPrefix()+vslink+"#"+code);
a.addText(code);
}
private boolean generateComposition(ResourceContext rcontext, XhtmlNode x, ValueSet vs, boolean header, List<UsedConceptMap> maps) throws FHIRException, IOException {
private boolean generateComposition(XhtmlNode x, ValueSet vs, boolean header, List<UsedConceptMap> maps) throws FHIRException, IOException {
boolean hasExtensions = false;
List<String> langs = new ArrayList<String>();
@ -711,17 +694,17 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
XhtmlNode ul = x.ul();
if (vs.getCompose().getInclude().size() == 1 && vs.getCompose().getExclude().size() == 0) {
hasExtensions = genInclude(rcontext, ul, vs.getCompose().getInclude().get(0), "Include", langs, maps) || hasExtensions;
hasExtensions = genInclude(ul, vs.getCompose().getInclude().get(0), "Include", langs, maps) || hasExtensions;
} else {
XhtmlNode p = x.para();
p.tx("This value set includes codes based on the following rules:");
XhtmlNode li;
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
hasExtensions = genInclude(rcontext, ul, inc, "Include", langs, maps) || hasExtensions;
hasExtensions = genInclude(ul, inc, "Include", langs, maps) || hasExtensions;
}
for (ConceptSetComponent exc : vs.getCompose().getExclude()) {
hasExtensions = genInclude(rcontext, ul, exc, "Exclude", langs, maps) || hasExtensions;
hasExtensions = genInclude(ul, exc, "Exclude", langs, maps) || hasExtensions;
}
}
@ -745,11 +728,11 @@ public class ValueSetRenderer extends TerminologyRenderer {
return hasExtensions;
}
private boolean genInclude(ResourceContext rcontext, XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, List<UsedConceptMap> maps) throws FHIRException, IOException {
private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, List<UsedConceptMap> maps) throws FHIRException, IOException {
boolean hasExtensions = false;
XhtmlNode li;
li = ul.li();
CodeSystem e = context.fetchCodeSystem(inc.getSystem());
CodeSystem e = getContext().getWorker().fetchCodeSystem(inc.getSystem());
if (inc.hasSystem()) {
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
@ -823,7 +806,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
} else {
li.tx(f.getProperty()+" "+describe(f.getOp())+" ");
if (e != null && codeExistsInValueSet(e, f.getValue())) {
String href = prefix+getCsRef(e);
String href = getContext().getPrefix()+getCsRef(e);
if (href.contains("#"))
href = href + "-"+Utilities.nmtokenize(f.getValue());
else
@ -831,7 +814,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
li.ah(href).addText(f.getValue());
} else if ("concept".equals(f.getProperty()) && inc.hasSystem()) {
li.addText(f.getValue());
ValidationResult vr = context.validateCode(terminologyServiceOptions, inc.getSystem(), f.getValue(), null);
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), f.getValue(), null);
if (vr.isOk()) {
li.tx(" ("+vr.getDisplay()+")");
}
@ -853,7 +836,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
else
li.tx(", ");
AddVsRef(rcontext, vs.asStringValue(), li);
AddVsRef(vs.asStringValue(), li);
}
}
} else {
@ -864,7 +847,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
else
li.tx(", ");
AddVsRef(rcontext, vs.asStringValue(), li);
AddVsRef(vs.asStringValue(), li);
}
}
return hasExtensions;
@ -877,7 +860,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
// first, look in the code systems
if (e == null)
e = context.fetchCodeSystem(inc.getSystem());
e = getContext().getWorker().fetchCodeSystem(inc.getSystem());
if (e != null) {
ConceptDefinitionComponent v = getConceptForCode(e.getConcept(), code);
if (v != null)
@ -887,10 +870,10 @@ public class ValueSetRenderer extends TerminologyRenderer {
if (noSlowLookup)
return null;
if (!context.hasCache()) {
if (!getContext().getWorker().hasCache()) {
ValueSetExpansionComponent vse;
try {
ValueSetExpansionOutcome vso = context.expandVS(inc, false);
ValueSetExpansionOutcome vso = getContext().getWorker().expandVS(inc, false);
ValueSet valueset = vso.getValueset();
if (valueset == null)
throw new TerminologyServiceException("Error Expanding ValueSet: "+vso.getError());
@ -906,7 +889,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
return context.validateCode(terminologyServiceOptions, inc.getSystem(), code, null).asConceptDefinition();
return getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), code, null).asConceptDefinition();
}
private ConceptDefinitionComponent getConceptForCode(List<ConceptDefinitionComponent> list, String code) {

View File

@ -0,0 +1,116 @@
package org.hl7.fhir.r5.renderers.utils;
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.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.renderers.ResourceRenderer;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.RendererWrapper;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class BaseWrappers {
public interface RendererWrapper {
public ResourceRenderer getRenderer();
}
public interface PropertyWrapper extends RendererWrapper {
public String getName();
public boolean hasValues();
public List<BaseWrapper> getValues();
public String getTypeCode();
public String getDefinition();
public int getMinCardinality();
public int getMaxCardinality();
public StructureDefinition getStructure();
public BaseWrapper value();
}
public interface WrapperBase extends RendererWrapper {
public boolean has(String name);
public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException;
public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException;
public List<PropertyWrapper> children();
}
public interface ResourceWrapper extends WrapperBase {
public List<ResourceWrapper> getContained();
public String getId();
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException;
public String getName();
public void describe(XhtmlNode x);
}
public interface BaseWrapper extends WrapperBase {
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException;
public PropertyWrapper getChildByName(String tail);
}
public static abstract class RendererWrapperImpl implements RendererWrapper {
protected ResourceRenderer renderer;
public RendererWrapperImpl(ResourceRenderer renderer) {
super();
this.renderer = renderer;
}
public ResourceRenderer getRenderer() {
return renderer;
}
protected String tail(String path) {
return path.substring(path.lastIndexOf(".")+1);
}
}
public static abstract class WrapperBaseImpl extends RendererWrapperImpl implements WrapperBase {
public WrapperBaseImpl(ResourceRenderer renderer) {
super(renderer);
}
@Override
public boolean has(String name) {
for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) {
return p.hasValues();
}
}
return false;
}
@Override
public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException {
for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) {
if (p.hasValues()) {
return p.getValues().get(0).getBase();
} else {
return null;
}
}
}
return null;
}
@Override
public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException {
for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) {
List<BaseWrapper> res = new ArrayList<>();
for (BaseWrapper b : p.getValues()) {
res.add(b);
}
return res;
}
}
return null;
}
}
}

View File

@ -0,0 +1,258 @@
package org.hl7.fhir.r5.renderers.utils;
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.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.renderers.ResourceRenderer;
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.RendererWrapperImpl;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.WrapperBaseImpl;
import org.hl7.fhir.r5.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.utilities.xml.XmlGenerator;
import org.w3c.dom.Element;
public class DOMWrappers {
public static class BaseWrapperElement extends WrapperBaseImpl implements BaseWrapper {
private Element element;
private String type;
private StructureDefinition structure;
private ElementDefinition definition;
private List<ElementDefinition> children;
private List<PropertyWrapper> list;
public BaseWrapperElement(ResourceRenderer renderer, Element element, String type, StructureDefinition structure, ElementDefinition definition) {
super(renderer);
this.element = element;
this.type = type;
this.structure = structure;
this.definition = definition;
}
@Override
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
return null;
String xml;
try {
xml = new XmlGenerator().generate(element);
} catch (org.hl7.fhir.exceptions.FHIRException e) {
throw new FHIRException(e.getMessage(), e);
}
return renderer.parseType(xml, type);
}
@Override
public List<PropertyWrapper> children() {
if (list == null) {
children = renderer.getContext().getProfileUtilities().getChildList(structure, definition);
list = new ArrayList<PropertyWrapper>();
for (ElementDefinition child : children) {
List<Element> elements = new ArrayList<Element>();
XMLUtil.getNamedChildrenWithWildcard(element, tail(child.getPath()), elements);
list.add(new PropertyWrapperElement(renderer, structure, child, elements));
}
}
return list;
}
@Override
public PropertyWrapper getChildByName(String name) {
for (PropertyWrapper p : children())
if (p.getName().equals(name))
return p;
return null;
}
}
public static class PropertyWrapperElement extends RendererWrapperImpl implements PropertyWrapper {
private StructureDefinition structure;
private ElementDefinition definition;
private List<Element> values;
private List<BaseWrapper> list;
public PropertyWrapperElement(ResourceRenderer renderer, StructureDefinition structure, ElementDefinition definition, List<Element> values) {
super(renderer);
this.structure = structure;
this.definition = definition;
this.values = values;
}
@Override
public String getName() {
return tail(definition.getPath());
}
@Override
public boolean hasValues() {
return values.size() > 0;
}
@Override
public List<BaseWrapper> getValues() {
if (list == null) {
list = new ArrayList<BaseWrapper>();
for (Element e : values)
list.add(new BaseWrapperElement(renderer, e, determineType(e), structure, definition));
}
return list;
}
private String determineType(Element e) {
if (definition.getType().isEmpty())
return null;
if (definition.getType().size() == 1) {
if (definition.getType().get(0).getWorkingCode().equals("Element") || definition.getType().get(0).getWorkingCode().equals("BackboneElement"))
return null;
return definition.getType().get(0).getWorkingCode();
}
String t = e.getNodeName().substring(tail(definition.getPath()).length()-3);
if (isPrimitive(Utilities.uncapitalize(t)))
return Utilities.uncapitalize(t);
else
return t;
}
private boolean isPrimitive(String code) {
StructureDefinition sd = renderer.getContext().getWorker().fetchTypeDefinition(code);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
@Override
public String getTypeCode() {
if (definition == null || definition.getType().size() != 1)
throw new Error("not handled");
return definition.getType().get(0).getWorkingCode();
}
@Override
public String getDefinition() {
if (definition == null)
throw new Error("not handled");
return definition.getDefinition();
}
@Override
public int getMinCardinality() {
if (definition == null)
throw new Error("not handled");
return definition.getMin();
}
@Override
public int getMaxCardinality() {
if (definition == null)
throw new Error("not handled");
return definition.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(definition.getMax());
}
@Override
public StructureDefinition getStructure() {
return structure;
}
@Override
public BaseWrapper value() {
if (getValues().size() != 1)
throw new Error("Access single value, but value count is "+getValues().size());
return getValues().get(0);
}
}
public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper {
private Element wrapped;
private StructureDefinition definition;
private List<ResourceWrapper> list;
private List<PropertyWrapper> list2;
public ResourceWrapperElement(ResourceRenderer renderer, Element wrapped, StructureDefinition definition) {
super(renderer);
this.wrapped = wrapped;
this.definition = definition;
}
@Override
public List<ResourceWrapper> getContained() {
if (list == null) {
List<Element> children = new ArrayList<Element>();
XMLUtil.getNamedChildren(wrapped, "contained", children);
list = new ArrayList<ResourceWrapper>();
for (Element e : children) {
Element c = XMLUtil.getFirstChild(e);
list.add(new ResourceWrapperElement(renderer, c, renderer.getContext().getWorker().fetchTypeDefinition(c.getNodeName())));
}
}
return list;
}
@Override
public String getId() {
return XMLUtil.getNamedChildValue(wrapped, "id");
}
@Override
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException {
Element txt = XMLUtil.getNamedChild(wrapped, "text");
if (txt == null)
return null;
Element div = XMLUtil.getNamedChild(txt, "div");
if (div == null)
return null;
try {
return new XhtmlParser().parse(new XmlGenerator().generate(div), "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
} catch (org.hl7.fhir.exceptions.FHIRException e) {
throw new FHIRException(e.getMessage(), e);
}
}
@Override
public String getName() {
return wrapped.getNodeName();
}
@Override
public List<PropertyWrapper> children() {
if (list2 == null) {
List<ElementDefinition> children = renderer.getContext().getProfileUtilities().getChildList(definition, definition.getSnapshot().getElement().get(0));
list2 = new ArrayList<PropertyWrapper>();
for (ElementDefinition child : children) {
List<Element> elements = new ArrayList<Element>();
XMLUtil.getNamedChildrenWithWildcard(wrapped, tail(child.getPath()), elements);
list2.add(new PropertyWrapperElement(renderer, definition, child, elements));
}
}
return list2;
}
@Override
public void describe(XhtmlNode x) {
throw new Error("Not done yet");
}
}
}

View File

@ -0,0 +1,201 @@
package org.hl7.fhir.r5.renderers.utils;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Encounter;
import org.hl7.fhir.r5.model.Patient;
import org.hl7.fhir.r5.model.Property;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.renderers.EncounterRenderer;
import org.hl7.fhir.r5.renderers.PatientRenderer;
import org.hl7.fhir.r5.renderers.ResourceRenderer;
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.RendererWrapperImpl;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.WrapperBaseImpl;
import org.hl7.fhir.r5.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class DirectWrappers {
public static class PropertyWrapperDirect extends RendererWrapperImpl implements PropertyWrapper {
private Property wrapped;
private List<BaseWrapper> list;
public PropertyWrapperDirect(ResourceRenderer renderer, Property wrapped) {
super(renderer);
if (wrapped == null)
throw new Error("wrapped == null");
this.wrapped = wrapped;
}
@Override
public String getName() {
return wrapped.getName();
}
public Property getWrapped() {
return wrapped;
}
@Override
public boolean hasValues() {
return wrapped.hasValues();
}
@Override
public List<BaseWrapper> getValues() {
if (list == null) {
list = new ArrayList<BaseWrapper>();
for (Base b : wrapped.getValues())
list.add(b == null ? null : new BaseWrapperDirect(renderer, b));
}
return list;
}
@Override
public String getTypeCode() {
return wrapped.getTypeCode();
}
@Override
public String getDefinition() {
return wrapped.getDefinition();
}
@Override
public int getMinCardinality() {
return wrapped.getMinCardinality();
}
@Override
public int getMaxCardinality() {
return wrapped.getMinCardinality();
}
@Override
public StructureDefinition getStructure() {
return wrapped.getStructure();
}
@Override
public BaseWrapper value() {
if (getValues().size() != 1)
throw new Error("Access single value, but value count is "+getValues().size());
return getValues().get(0);
}
public String toString() {
return "#."+wrapped.toString();
}
}
public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper {
private Base wrapped;
private List<PropertyWrapper> list;
public BaseWrapperDirect(ResourceRenderer renderer, Base wrapped) {
super(renderer);
if (wrapped == null)
throw new Error("wrapped == null");
this.wrapped = wrapped;
}
@Override
public Base getBase() {
return wrapped;
}
@Override
public List<PropertyWrapper> children() {
if (list == null) {
list = new ArrayList<PropertyWrapper>();
for (Property p : wrapped.children())
list.add(new PropertyWrapperDirect(renderer, p));
}
return list;
}
@Override
public PropertyWrapper getChildByName(String name) {
Property p = wrapped.getChildByName(name);
if (p == null)
return null;
else
return new PropertyWrapperDirect(renderer, p);
}
}
public static class ResourceWrapperDirect extends WrapperBaseImpl implements ResourceWrapper {
private Resource wrapped;
public ResourceWrapperDirect(ResourceRenderer renderer, Resource wrapped) {
super(renderer);
if (wrapped == null)
throw new Error("wrapped == null");
this.wrapped = wrapped;
}
@Override
public List<ResourceWrapper> getContained() {
List<ResourceWrapper> list = new ArrayList<ResourceWrapper>();
if (wrapped instanceof DomainResource) {
DomainResource dr = (DomainResource) wrapped;
for (Resource c : dr.getContained()) {
list.add(new ResourceWrapperDirect(renderer, c));
}
}
return list;
}
@Override
public String getId() {
return wrapped.getId();
}
@Override
public XhtmlNode getNarrative() {
if (wrapped instanceof DomainResource) {
DomainResource dr = (DomainResource) wrapped;
if (dr.hasText() && dr.getText().hasDiv())
return dr.getText().getDiv();
}
return null;
}
@Override
public String getName() {
return wrapped.getResourceType().toString();
}
@Override
public List<PropertyWrapper> children() {
List<PropertyWrapper> list = new ArrayList<PropertyWrapper>();
if (wrapped.children() != null) {
for (Property c : wrapped.children())
list.add(new PropertyWrapperDirect(renderer, c));
}
return list;
}
@Override
public void describe(XhtmlNode x) {
if (wrapped instanceof CanonicalResource) {
x.tx(((CanonicalResource) wrapped).present());
} else if (wrapped instanceof Patient) {
new PatientRenderer(getRenderer().getContext()).describe(x, (Patient) wrapped);
} else if (wrapped instanceof Encounter) {
new EncounterRenderer(getRenderer().getContext()).describe(x, (Encounter) wrapped);
}
}
}
}

View File

@ -0,0 +1,230 @@
package org.hl7.fhir.r5.renderers.utils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.XmlParser;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.renderers.ResourceRenderer;
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.RendererWrapperImpl;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.WrapperBaseImpl;
import org.hl7.fhir.r5.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ElementWrappers {
public static class BaseWrapperMetaElement extends WrapperBaseImpl implements BaseWrapper {
private Element element;
private String type;
private StructureDefinition structure;
private ElementDefinition definition;
private List<ElementDefinition> children;
private List<PropertyWrapper> list;
public BaseWrapperMetaElement(ResourceRenderer renderer, Element element, String type, StructureDefinition structure, ElementDefinition definition) {
super(renderer);
this.element = element;
this.type = type;
this.structure = structure;
this.definition = definition;
}
@Override
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
return null;
if (element.hasElementProperty())
return null;
ByteArrayOutputStream xml = new ByteArrayOutputStream();
try {
new XmlParser(renderer.getContext().getWorker()).compose(element, xml, OutputStyle.PRETTY, null);
} catch (Exception e) {
throw new FHIRException(e.getMessage(), e);
}
return renderer.parseType(xml.toString(), type);
}
@Override
public List<PropertyWrapper> children() {
if (list == null) {
children = renderer.getContext().getProfileUtilities().getChildList(structure, definition);
list = new ArrayList<PropertyWrapper>();
for (ElementDefinition child : children) {
List<Element> elements = new ArrayList<Element>();
String name = tail(child.getPath());
if (name.endsWith("[x]"))
element.getNamedChildrenWithWildcard(name, elements);
else
element.getNamedChildren(name, elements);
list.add(new PropertyWrapperMetaElement(renderer, structure, child, elements));
}
}
return list;
}
@Override
public PropertyWrapper getChildByName(String name) {
for (PropertyWrapper p : children())
if (p.getName().equals(name))
return p;
return null;
}
}
public static class ResourceWrapperMetaElement extends WrapperBaseImpl implements ResourceWrapper {
private Element wrapped;
private List<ResourceWrapper> list;
private List<PropertyWrapper> list2;
private StructureDefinition definition;
public ResourceWrapperMetaElement(ResourceRenderer renderer, Element wrapped) {
super(renderer);
this.wrapped = wrapped;
this.definition = wrapped.getProperty().getStructure();
}
@Override
public List<ResourceWrapper> getContained() {
if (list == null) {
List<Element> children = wrapped.getChildrenByName("contained");
list = new ArrayList<ResourceWrapper>();
for (Element e : children) {
list.add(new ResourceWrapperMetaElement(renderer, e));
}
}
return list;
}
@Override
public String getId() {
return wrapped.getNamedChildValue("id");
}
@Override
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException {
Element txt = wrapped.getNamedChild("text");
if (txt == null)
return null;
Element div = txt.getNamedChild("div");
if (div == null)
return null;
else
return div.getXhtml();
}
@Override
public String getName() {
return wrapped.getName();
}
@Override
public List<PropertyWrapper> children() {
if (list2 == null) {
List<ElementDefinition> children = renderer.getContext().getProfileUtilities().getChildList(definition, definition.getSnapshot().getElement().get(0));
list2 = new ArrayList<PropertyWrapper>();
for (ElementDefinition child : children) {
List<Element> elements = new ArrayList<Element>();
if (child.getPath().endsWith("[x]"))
wrapped.getNamedChildrenWithWildcard(tail(child.getPath()), elements);
else
wrapped.getNamedChildren(tail(child.getPath()), elements);
list2.add(new PropertyWrapperMetaElement(renderer, definition, child, elements));
}
}
return list2;
}
@Override
public void describe(XhtmlNode x) {
if (wrapped.hasChild("title") && wrapped.getChildValue("title") != null) {
x.tx(wrapped.getChildValue("title"));
} else if (wrapped.hasChild("name") && wrapped.getChildValue("name") != null) {
x.tx(wrapped.getChildValue("name"));
} else {
x.tx("?ngen-1?");
}
}
}
public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper {
private StructureDefinition structure;
private ElementDefinition definition;
private List<Element> values;
private List<BaseWrapper> list;
public PropertyWrapperMetaElement(ResourceRenderer renderer, StructureDefinition structure, ElementDefinition definition, List<Element> values) {
super(renderer);
this.structure = structure;
this.definition = definition;
this.values = values;
}
@Override
public String getName() {
return tail(definition.getPath());
}
@Override
public boolean hasValues() {
return values.size() > 0;
}
@Override
public List<BaseWrapper> getValues() {
if (list == null) {
list = new ArrayList<BaseWrapper>();
for (Element e : values)
list.add(new BaseWrapperMetaElement(renderer, e, e.fhirType(), structure, definition));
}
return list;
}
@Override
public String getTypeCode() {
return definition.typeSummary();
}
@Override
public String getDefinition() {
return definition.getDefinition();
}
@Override
public int getMinCardinality() {
return definition.getMin();
}
@Override
public int getMaxCardinality() {
return "*".equals(definition.getMax()) ? Integer.MAX_VALUE : Integer.valueOf(definition.getMax());
}
@Override
public StructureDefinition getStructure() {
return structure;
}
@Override
public BaseWrapper value() {
if (getValues().size() != 1)
throw new Error("Access single value, but value count is "+getValues().size());
return getValues().get(0);
}
}
}

View File

@ -0,0 +1,140 @@
package org.hl7.fhir.r5.renderers.utils;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.IReferenceResolver;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.validation.ValidationOptions;
public class RenderingContext {
public enum ResourceRendererMode{
RESOURCE, IG
}
protected IWorkerContext worker;
protected MarkDownProcessor markdown;
protected String lang;
protected String prefix;
protected ValidationOptions terminologyServiceOptions;
protected ProfileUtilities profileUtilities;
private boolean canonicalUrlsAsLinks;
protected ResourceRendererMode mode;
private IReferenceResolver resolver;
private int headerLevelContext;
private String tooCostlyNoteEmpty;
private String tooCostlyNoteNotEmpty;
private String tooCostlyNoteEmptyDependent;
private String tooCostlyNoteNotEmptyDependent;
/**
*
* @param context - access to all related resources that might be needed
* @param markdown - appropriate markdown processing engine
* @param terminologyServiceOptions - options to use when looking up codes
* @param prefix - path to FHIR specification
* @param lang - langauage to render in
*/
public RenderingContext(IWorkerContext worker, MarkDownProcessor markdown, ValidationOptions terminologyServiceOptions, String prefix, String lang, ResourceRendererMode mode) {
super();
this.worker = worker;
this.markdown = markdown;
this.lang = lang;
this.prefix = prefix;
this.mode = mode;
this.terminologyServiceOptions = terminologyServiceOptions;
profileUtilities = new ProfileUtilities(worker, null, null);
}
public IWorkerContext getContext() {
return worker;
}
// -- 2. Markdown support -------------------------------------------------------
public ProfileUtilities getProfileUtilities() {
return profileUtilities;
}
public IWorkerContext getWorker() {
return worker;
}
public boolean isCanonicalUrlsAsLinks() {
return canonicalUrlsAsLinks;
}
public void setCanonicalUrlsAsLinks(boolean canonicalUrlsAsLinks) {
this.canonicalUrlsAsLinks = canonicalUrlsAsLinks;
}
public MarkDownProcessor getMarkdown() {
return markdown;
}
public String getLang() {
return lang;
}
public String getPrefix() {
return prefix;
}
public ValidationOptions getTerminologyServiceOptions() {
return terminologyServiceOptions;
}
public String getTooCostlyNoteEmpty() {
return tooCostlyNoteEmpty;
}
public void setTooCostlyNoteEmpty(String tooCostlyNoteEmpty) {
this.tooCostlyNoteEmpty = tooCostlyNoteEmpty;
}
public String getTooCostlyNoteNotEmpty() {
return tooCostlyNoteNotEmpty;
}
public void setTooCostlyNoteNotEmpty(String tooCostlyNoteNotEmpty) {
this.tooCostlyNoteNotEmpty = tooCostlyNoteNotEmpty;
}
public String getTooCostlyNoteEmptyDependent() {
return tooCostlyNoteEmptyDependent;
}
public void setTooCostlyNoteEmptyDependent(String tooCostlyNoteEmptyDependent) {
this.tooCostlyNoteEmptyDependent = tooCostlyNoteEmptyDependent;
}
public String getTooCostlyNoteNotEmptyDependent() {
return tooCostlyNoteNotEmptyDependent;
}
public void setTooCostlyNoteNotEmptyDependent(String tooCostlyNoteNotEmptyDependent) {
this.tooCostlyNoteNotEmptyDependent = tooCostlyNoteNotEmptyDependent;
}
public int getHeaderLevelContext() {
return headerLevelContext;
}
public void setHeaderLevelContext(int headerLevelContext) {
this.headerLevelContext = headerLevelContext;
}
public IReferenceResolver getResolver() {
return resolver;
}
public void setResolver(IReferenceResolver resolver) {
this.resolver = resolver;
}
public void setTerminologyServiceOptions(ValidationOptions terminologyServiceOptions) {
this.terminologyServiceOptions = terminologyServiceOptions;
}
}

View File

@ -0,0 +1,122 @@
package org.hl7.fhir.r5.renderers.utils;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.w3c.dom.Element;
public class Resolver {
public interface IReferenceResolver {
ResourceWithReference resolve(String url);
}
public static class ResourceContext {
Bundle bundleResource;
org.hl7.fhir.r5.elementmodel.Element bundleElement;
DomainResource resourceResource;
org.hl7.fhir.r5.elementmodel.Element resourceElement;
public ResourceContext(Bundle bundle, DomainResource dr) {
super();
this.bundleResource = bundle;
this.resourceResource = dr;
}
public ResourceContext(org.hl7.fhir.r5.elementmodel.Element bundle, org.hl7.fhir.r5.elementmodel.Element dr) {
this.bundleElement = bundle;
this.resourceElement = dr;
}
public ResourceContext(Object bundle, Element doc) {
// TODO Auto-generated constructor stub
}
public Bundle getBundleResource() {
return bundleResource;
}
public org.hl7.fhir.r5.elementmodel.Element getBundleElement() {
return bundleElement;
}
public DomainResource getResourceResource() {
return resourceResource;
}
public org.hl7.fhir.r5.elementmodel.Element getResourceElement() {
return resourceElement;
}
public BundleEntryComponent resolve(String value) {
if (value.startsWith("#")) {
if (resourceResource != null) {
for (Resource r : resourceResource.getContained()) {
if (r.getId().equals(value.substring(1))) {
BundleEntryComponent be = new BundleEntryComponent();
be.setResource(r);
return be;
}
}
}
return null;
}
if (bundleResource != null) {
for (BundleEntryComponent be : bundleResource.getEntry()) {
if (be.getFullUrl().equals(value))
return be;
if (value.equals(be.getResource().fhirType()+"/"+be.getResource().getId()))
return be;
}
}
return null;
}
public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value) {
if (value.startsWith("#")) {
if (resourceElement != null) {
for (org.hl7.fhir.r5.elementmodel.Element r : resourceElement.getChildrenByName("contained")) {
if (r.getChildValue("id").equals(value.substring(1)))
return r;
}
}
return null;
}
if (bundleElement != null) {
for (org.hl7.fhir.r5.elementmodel.Element be : bundleElement.getChildren("entry")) {
org.hl7.fhir.r5.elementmodel.Element res = be.getNamedChild("resource");
if (value.equals(be.getChildValue("fullUrl")))
return be;
if (value.equals(res.fhirType()+"/"+res.getChildValue("id")))
return be;
}
}
return null;
}
}
public static class ResourceWithReference {
private String reference;
private ResourceWrapper resource;
public ResourceWithReference(String reference, ResourceWrapper resource) {
this.reference = reference;
this.resource = resource;
}
public String getReference() {
return reference;
}
public ResourceWrapper getResource() {
return resource;
}
}
}

View File

@ -22,39 +22,13 @@ package org.hl7.fhir.r5.utils;
import java.io.IOException;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/*
Copyright (c) 2011+, HL7, Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -65,7 +39,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.NotImplementedException;
@ -184,18 +157,12 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.terminologies.CodeSystemRenderer;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.CodeSystemNavigator;
import org.hl7.fhir.r5.terminologies.ConceptMapRenderer;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer.ConceptMapRenderInstructions;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer.TerminologyRendererMode;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.ValueSetRenderer;
import org.hl7.fhir.r5.renderers.CodeSystemRenderer;
import org.hl7.fhir.r5.renderers.ConceptMapRenderer;
import org.hl7.fhir.r5.renderers.TerminologyRenderer;
import org.hl7.fhir.r5.renderers.ValueSetRenderer;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.r5.utils.NarrativeGenerator.ResourceContext;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
@ -222,75 +189,6 @@ public class NarrativeGenerator implements INarrativeGenerator {
Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ;
}
public static class ResourceContext {
Bundle bundleResource;
org.hl7.fhir.r5.elementmodel.Element bundleElement;
DomainResource resourceResource;
org.hl7.fhir.r5.elementmodel.Element resourceElement;
public ResourceContext(Bundle bundle, DomainResource dr) {
super();
this.bundleResource = bundle;
this.resourceResource = dr;
}
public ResourceContext(org.hl7.fhir.r5.elementmodel.Element bundle, org.hl7.fhir.r5.elementmodel.Element dr) {
this.bundleElement = bundle;
this.resourceElement = dr;
}
public ResourceContext(Object bundle, Element doc) {
// TODO Auto-generated constructor stub
}
public BundleEntryComponent resolve(String value) {
if (value.startsWith("#")) {
if (resourceResource != null) {
for (Resource r : resourceResource.getContained()) {
if (r.getId().equals(value.substring(1))) {
BundleEntryComponent be = new BundleEntryComponent();
be.setResource(r);
return be;
}
}
}
return null;
}
if (bundleResource != null) {
for (BundleEntryComponent be : bundleResource.getEntry()) {
if (be.getFullUrl().equals(value))
return be;
if (value.equals(be.getResource().fhirType()+"/"+be.getResource().getId()))
return be;
}
}
return null;
}
public org.hl7.fhir.r5.elementmodel.Element resolveElement(String value) {
if (value.startsWith("#")) {
if (resourceElement != null) {
for (org.hl7.fhir.r5.elementmodel.Element r : resourceElement.getChildrenByName("contained")) {
if (r.getChildValue("id").equals(value.substring(1)))
return r;
}
}
return null;
}
if (bundleElement != null) {
for (org.hl7.fhir.r5.elementmodel.Element be : bundleElement.getChildren("entry")) {
org.hl7.fhir.r5.elementmodel.Element res = be.getNamedChild("resource");
if (value.equals(be.getChildValue("fullUrl")))
return be;
if (value.equals(res.fhirType()+"/"+res.getChildValue("id")))
return be;
}
}
return null;
}
}
public interface IReferenceResolver {
ResourceWithReference resolve(String url);
}
@ -1225,12 +1123,12 @@ public class NarrativeGenerator implements INarrativeGenerator {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().b().tx("Generated Narrative"+(showCodeDetails ? " with Details" : ""));
try {
generateByProfile(rc.resourceResource, profile, rc.resourceResource, profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile.getSnapshot().getElement(), rc.resourceResource.getResourceType().toString()), x, rc.resourceResource.getResourceType().toString(), showCodeDetails, rc);
generateByProfile(rc.getResourceResource(), profile, rc.getResourceResource(), profile.getSnapshot().getElement(), profile.getSnapshot().getElement().get(0), getChildrenForPath(profile.getSnapshot().getElement(), rc.getResourceResource().getResourceType().toString()), x, rc.getResourceResource().getResourceType().toString(), showCodeDetails, rc);
} catch (Exception e) {
e.printStackTrace();
x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage());
}
inject(rc.resourceResource, x, NarrativeStatus.GENERATED);
inject(rc.getResourceResource(), x, NarrativeStatus.GENERATED);
return true;
}
@ -1557,7 +1455,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
renderContactPoint(c, x);
}
} else if (e instanceof UriType) {
renderUri((UriType) e, x, defn.getPath(), rc != null && rc.resourceResource != null ? rc.resourceResource.getId() : null);
renderUri((UriType) e, x, defn.getPath(), rc != null && rc.getResourceResource() != null ? rc.getResourceResource().getId() : null);
} else if (e instanceof Timing) {
renderTiming((Timing) e, x);
} else if (e instanceof Range) {
@ -2420,8 +2318,8 @@ public class NarrativeGenerator implements INarrativeGenerator {
public boolean generate(ResourceContext rcontext, ConceptMap cm) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
ConceptMapRenderer renderer = new ConceptMapRenderer(TerminologyRendererMode.RESOURCE, context, markdown, prefix, null);
boolean res = renderer.generate(rcontext, cm, x);
ConceptMapRenderer renderer = new ConceptMapRenderer(new RenderingContext(context, markdown, terminologyServiceOptions, prefix, null, ResourceRendererMode.RESOURCE), rcontext);
boolean res = renderer.render(x, cm);
inject(cm, x, NarrativeStatus.GENERATED);
return res;
}
@ -2545,11 +2443,11 @@ public class NarrativeGenerator implements INarrativeGenerator {
*/
public boolean generate(ResourceContext rcontext, CodeSystem cs, boolean header, String lang) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
CodeSystemRenderer renderer = new CodeSystemRenderer(TerminologyRendererMode.RESOURCE, context, markdown, prefix, lang);
CodeSystemRenderer renderer = new CodeSystemRenderer(new RenderingContext(context, markdown, terminologyServiceOptions, prefix, lang, ResourceRendererMode.RESOURCE), rcontext);
renderer.getCodeSystemPropList().addAll(getCodeSystemPropList());
renderer.setHeaderLevelContext(headerLevelContext);
renderer.setTerminologyServiceOptions(terminologyServiceOptions);
boolean hasExtensions = renderer.generate(x, cs, header);
renderer.getContext().setHeaderLevelContext(headerLevelContext);
renderer.getContext().setTerminologyServiceOptions(terminologyServiceOptions);
boolean hasExtensions = renderer.render(x, cs, header);
inject(cs, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
return true;
}
@ -2572,16 +2470,16 @@ public class NarrativeGenerator implements INarrativeGenerator {
public void generate(ResourceContext rcontext, ValueSet vs, ValueSet src, boolean header) throws FHIRException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
ValueSetRenderer renderer = new ValueSetRenderer(TerminologyRendererMode.RESOURCE, context, markdown, prefix, null);
renderer.setTooCostlyNoteEmpty(tooCostlyNoteEmpty);
renderer.setTooCostlyNoteNotEmpty(tooCostlyNoteNotEmpty);
renderer.setTooCostlyNoteEmptyDependent(tooCostlyNoteEmptyDependent);
renderer.setTooCostlyNoteNotEmptyDependent(tooCostlyNoteNotEmptyDependent);
ValueSetRenderer renderer = new ValueSetRenderer(new RenderingContext(context, markdown, terminologyServiceOptions, prefix, null, ResourceRendererMode.RESOURCE), rcontext);
renderer.getContext().setTooCostlyNoteEmpty(tooCostlyNoteEmpty);
renderer.getContext().setTooCostlyNoteNotEmpty(tooCostlyNoteNotEmpty);
renderer.getContext().setTooCostlyNoteEmptyDependent(tooCostlyNoteEmptyDependent);
renderer.getContext().setTooCostlyNoteNotEmptyDependent(tooCostlyNoteNotEmptyDependent);
renderer.setNoSlowLookup(noSlowLookup);
renderer.setHeaderLevelContext(headerLevelContext);
renderer.setTerminologyServiceOptions(terminologyServiceOptions);
renderer.getContext().setHeaderLevelContext(headerLevelContext);
renderer.getContext().setTerminologyServiceOptions(terminologyServiceOptions);
boolean hasExtensions = renderer.render(rcontext, x, vs, src, header);
boolean hasExtensions = renderer.render(x, vs, header);
inject(vs, x, hasExtensions ? NarrativeStatus.EXTENSIONS : NarrativeStatus.GENERATED);
}

View File

@ -102,7 +102,7 @@ import org.hl7.fhir.r5.model.TypeDetails.ProfiledType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.terminologies.TerminologyRenderer;
import org.hl7.fhir.r5.renderers.TerminologyRenderer;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;

View File

@ -518,8 +518,8 @@ public class SnapShotGenerationTests {
pu.setThrowException(false);
pu.setDebug(test.isDebug());
pu.setIds(test.getSource(), false);
if (!TestingUtilities.context().hasPackage("hl7.fhir.xver-extensions", "0.0.3")) {
NpmPackage npm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION).loadPackage("hl7.fhir.xver-extensions", "0.0.3");
if (!TestingUtilities.context().hasPackage("hl7.fhir.xver-extensions", "0.0.4")) {
NpmPackage npm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION).loadPackage("hl7.fhir.xver-extensions", "0.0.4");
TestingUtilities.context().loadFromPackage(npm, new TestLoader(new String[]{"StructureDefinition"}), new String[]{"StructureDefinition"});
}
pu.setXver(new XVerExtensionManager(TestingUtilities.context()));

View File

@ -342,7 +342,7 @@ public class ValidationEngine implements IValidatorResourceFetcher {
context = SimpleWorkerContext.fromDefinitions(source, loaderForVersion(), new PackageVersion(src));
context.setAllowLoadingDuplicates(true); // because of Forge
context.setExpansionProfile(makeExpProfile());
NpmPackage npm = pcm.loadPackage("hl7.fhir.xver-extensions", "0.0.3");
NpmPackage npm = pcm.loadPackage("hl7.fhir.xver-extensions", "0.0.4");
context.loadFromPackage(npm, null);
grabNatives(source, "http://hl7.org/fhir");
}