org.hl7.fhir.r5.renderers.DiagnosticReportRenderer Maven / Gradle / Ivy
package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceWithReference;
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
@MarkedToMoveToAdjunctPackage
public class DiagnosticReportRenderer extends ResourceRenderer {
public class ObservationNode {
private String ref;
private ResourceWithReference resolution;
private List contained;
}
public DiagnosticReportRenderer(RenderingContext context) {
super(context);
}
@Override
public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper dr) throws IOException, FHIRException, EOperationOutcome {
renderDiagnosticReport(status, x, dr);
}
public void renderDiagnosticReport(RenderingStatus status, XhtmlNode x, ResourceWrapper dr) throws IOException, FHIRException, EOperationOutcome {
renderResourceTechDetails(dr, x);
XhtmlNode h2 = x.h2();
renderDataType(status, h2, dr.child("code"));
h2.tx(" ");
List cats = dr.children("category");
if (!cats.isEmpty()) {
h2.tx("(");
boolean first = true;
for (ResourceWrapper b : cats) {
if (first) first = false; else h2.tx(", ");
renderDataType(status, h2, b);
}
h2.tx(") ");
}
XhtmlNode tbl = x.table("grid", false);
XhtmlNode tr;
if (dr.has("subject")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_SUBJ));
populateSubjectSummary(status, tr.td(), dr.child("subject"));
}
ResourceWrapper eff = null;
ResourceWrapper iss = null;
if (dr.has("effective[x]")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN));
eff = dr.child("effective[x]");
renderDataType(status, tr.td(), eff);
}
if (dr.has("issued")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP));
iss = dr.child("issued");
renderDataType(status, tr.td(), iss);
}
addTableRow(status, tbl, dr, RenderingContext.DIAG_REP_REND_PER, "performer");
addTableRow(status, tbl, dr, RenderingContext.DIAG_REP_REND_IDENTIFIER, "identifier");
addTableRow(status, tbl, dr, RenderingContext.GENERAL_REQUEST, "request");
x.para().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REPDET));
List items = dr.children("result");
if (!items.isEmpty()) {
List observations = fetchObservations(items);
buildObservationsTable(status, x, observations, eff, iss);
}
if (dr.has("conclusion")) {
ResourceWrapper conc = dr.child("conclusion");
if (conc.fhirType().equals("markdown")) {
renderDataType(status, x, conc);
} else {
renderDataType(status, x.para(), conc);
}
}
if (dr.hasMN("conclusionCode", "codedDiagnosis")) {
x.para().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_CODECON));
addListRows(status, x.ul(), dr, RenderingContext.DIAG_REP_REND_CODECON, "conclusionCode", "codedDiagnosis");
}
for (ResourceWrapper cont : dr.children("contained")) {
x.hr();
RendererFactory.factory(cont, context.forContained()).setInner(true).buildNarrative(status, x, cont);
}
}
private void addTableRow(RenderingStatus status, XhtmlNode tbl, ResourceWrapper dr, String constName, String... names) throws FHIRFormatError, DefinitionException, IOException {
List items = dr.childrenMN(names);
if (!items.isEmpty()) {
XhtmlNode tr = tbl.tr();
tr.td().tx(Utilities.pluralize(context.formatPhrase(constName), items.size()));
XhtmlNode tdr = tr.td();
for (ResourceWrapper v : items) {
tdr.tx(" ");
renderDataType(status, tdr, v);
}
}
}
private void addListRows(RenderingStatus status, XhtmlNode ul, ResourceWrapper dr, String constName, String... names) throws FHIRFormatError, DefinitionException, IOException {
List items = dr.childrenMN(names);
if (!items.isEmpty()) {
for (ResourceWrapper v : items) {
XhtmlNode li = ul.li();
renderDataType(status, li, v);
}
}
}
public void describeDiagnosticReport(XhtmlNode x, ResourceWrapper dr) {
x.tx(displayDiagnosticReport(dr));
}
public String displayDiagnosticReport(ResourceWrapper dr) {
ResourceWrapper c = dr.child("code");
String cd = c == null ? context.formatPhrase(RenderingContext.DIAG_REP_UNSPECIFIED_CODE) : displayCodeableConcept(c);
ResourceWrapper s = dr.child("subject");
String sd = s == null ? context.formatPhrase(RenderingContext.DIAG_REP_UNSPECIFIED_SUBJECT) : displayReference(s);
return context.formatPhrase(RenderingContext.DIAG_REP_SUMMARY, cd, sd);
}
@Override
public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException {
return displayDiagnosticReport(r);
}
private void populateSubjectSummary(RenderingStatus status, XhtmlNode container, ResourceWrapper subject) throws UnsupportedEncodingException, FHIRException, IOException, EOperationOutcome {
ResourceWithReference r = resolveReference(subject);
if (r == null)
container.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_UNABLE));
else if (r.getResource().fhirType().equals("Patient"))
generatePatientSummary(status, container, r.getResource());
else
container.tx(context.formatPhrase(RenderingContext.GENERAL_TODO));
}
private void generatePatientSummary(RenderingStatus status, XhtmlNode c, ResourceWrapper r) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome {
new PatientRenderer(context).buildSummary(status, c, r);
}
private List fetchObservations(List list) throws UnsupportedEncodingException, FHIRException, IOException {
List res = new ArrayList();
for (ResourceWrapper b : list) {
if (b.has("reference")) {
ObservationNode obs = new ObservationNode();
obs.ref = b.primitiveValue("reference");
obs.resolution = resolveReference(b.child("reference"));
if (obs.resolution != null && obs.resolution.getResource() != null) {
List t = obs.resolution.getResource().children("contained");
if (!t.isEmpty()) {
obs.contained = fetchObservations(t);
}
}
res.add(obs);
}
}
return res;
}
private void buildObservationsTable(RenderingStatus status, XhtmlNode root, List observations, ResourceWrapper eff, ResourceWrapper iss) throws UnsupportedEncodingException, FHIRException, IOException {
XhtmlNode tbl = root.table("grid", false);
boolean refRange = scanObsForRefRange(observations);
boolean flags = scanObsForFlags(observations);
boolean note = scanObsForNote(observations);
boolean effectiveTime = scanObsForEffective(observations, eff);
boolean issued = scanObsForIssued(observations, iss);
int cs = 2;
if (refRange) cs++;
if (flags) cs++;
if (note) cs++;
if (issued) cs++;
if (effectiveTime) cs++;
XhtmlNode tr = tbl.tr();
tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_CODE));
tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_VALUE));
if (refRange) {
tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REFRAN));
}
if (flags) {
tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_FLAGS));
}
if (note) {
tr.td().b().tx(context.formatPhrase(RenderingContext.GENERAL_NOTE));
}
if (effectiveTime) {
tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_WHEN));
}
if (issued) {
tr.td().b().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_REP));
}
for (ObservationNode o : observations) {
addObservationToTable(status, tbl, o, 0, Integer.toString(cs), refRange, flags, note, effectiveTime, issued, eff, iss);
}
}
private boolean scanObsForRefRange(List observations) {
for (ObservationNode o : observations) {
if (o.resolution != null) {
ResourceWrapper obs = o.resolution.getResource();
if (obs != null && obs.has("referenceRange")) {
return true;
}
if (o.contained != null) {
if (scanObsForRefRange(o.contained)) {
return true;
}
}
}
}
return false;
}
private boolean scanObsForNote(List observations) {
for (ObservationNode o : observations) {
if (o.resolution != null) {
ResourceWrapper obs = o.resolution.getResource();
if (obs != null && obs.has("note")) {
return true;
}
if (o.contained != null) {
if (scanObsForNote(o.contained)) {
return true;
}
}
}
}
return false;
}
private boolean scanObsForIssued(List observations, ResourceWrapper iss) throws UnsupportedEncodingException, FHIRException, IOException {
for (ObservationNode o : observations) {
if (o.resolution != null) {
ResourceWrapper obs = o.resolution.getResource();
if (obs != null && obs.has("issued") && (iss == null || !iss.matches(obs.child("issued")))) {
return true;
}
if (o.contained != null) {
if (scanObsForIssued(o.contained, iss)) {
return true;
}
}
}
}
return false;
}
private boolean scanObsForEffective(List observations, ResourceWrapper eff) throws UnsupportedEncodingException, FHIRException, IOException {
for (ObservationNode o : observations) {
if (o.resolution != null) {
ResourceWrapper obs = o.resolution.getResource();
if (obs != null && obs.has("effective[x]") && (eff == null || !eff.matches(obs.child("effective[x]")))) {
return true;
}
if (o.contained != null) {
if (scanObsForEffective(o.contained, eff)) {
return true;
}
}
}
}
return false;
}
private boolean scanObsForFlags(List observations) throws UnsupportedEncodingException, FHIRException, IOException {
for (ObservationNode o : observations) {
if (o.resolution != null) {
ResourceWrapper obs = o.resolution.getResource();
if (obs != null && (obs.has("interpretation") || obs.has("status"))) {
return true;
}
if (o.contained != null) {
if (scanObsForFlags(o.contained)) {
return true;
}
}
}
}
return false;
}
private void addObservationToTable(RenderingStatus status, XhtmlNode tbl, ObservationNode o, int i, String cs, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, ResourceWrapper eff, ResourceWrapper iss) throws UnsupportedEncodingException, FHIRException, IOException {
XhtmlNode tr = tbl.tr();
if (o.resolution == null) {
XhtmlNode td = tr.td().colspan(cs);
td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_NOTRES, o.ref));
} else {
if (o.resolution.getResource() != null) {
addObservationToTable(status, tr, o.resolution.getResource(), i, o.resolution.getWebPath(), refRange, flags, note, effectiveTime, issued, eff, iss);
} else {
XhtmlNode td = tr.td().colspan(cs);
td.i().tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_OBS));
}
if (o.contained != null) {
for (ObservationNode c : o.contained) {
addObservationToTable(status, tbl, c, i+1, cs, refRange, flags, note, effectiveTime, issued, eff, iss);
}
}
}
}
private void addObservationToTable(RenderingStatus status, XhtmlNode tr, ResourceWrapper obs, int i, String ref, boolean refRange, boolean flags, boolean note, boolean effectiveTime, boolean issued, ResourceWrapper eff, ResourceWrapper iss) throws UnsupportedEncodingException, FHIRException, IOException {
// code (+bodysite)
XhtmlNode td = tr.td();
if (obs.has("code")) {
renderDataType(status, td.ah(context.prefixLocalHref(ref)), obs.child("code"));
}
if (obs.has("bodySite")) {
td.tx(" (");
renderDataType(status, td, obs.child("bodySite"));
td.tx(")");
}
// value / dataAbsentReason (in red)
td = tr.td();
if (obs.has("value[x]")) {
renderDataType(status, td, obs.child("value[x]"));
} else if (obs.has("dataAbsentReason")) {
XhtmlNode span = td.span("color: maroon", "Error");
span.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_ERR) + " ");
renderDataType(status, span.b(), obs.child("dataAbsentReason"));
}
if (refRange) {
// reference range
td = tr.td();
List items = obs.children("referenceRange");
if (!items.isEmpty()) {
boolean first = true;
for (ResourceWrapper v : items) {
if (first) first = false; else td.br();
ResourceWrapper pwr = v.child("type");
if (pwr != null) {
renderDataType(status, td, pwr);
td.tx(": ");
}
ResourceWrapper pwt = v.child("text");
if (pwt != null) {
renderDataType(status, td, pwt);
} else {
ResourceWrapper pwl = v.child("low");
ResourceWrapper pwh = v.child("high");
if (pwl != null && pwh != null) {
renderDataType(status, td, pwl);
td.tx(" - ");
renderDataType(status, td, pwh);
} else if (pwl != null) {
td.tx(">");
renderDataType(status, td, pwl);
} else if (pwh != null) {
td.tx("<");
renderDataType(status, td, pwh);
} else {
td.tx("??");
}
}
List pwrF = v.children("appliesTo");
ResourceWrapper pwrA = v.child("age");
if (!pwrF.isEmpty() || pwrA != null) {
boolean firstA = true;
td.tx(" "+ (context.formatPhrase(RenderingContext.DIAG_REP_REND_FOR)) + " ");
if (!pwrF.isEmpty()) {
for (ResourceWrapper va : pwrF) {
if (firstA) firstA = false; else td.tx(", ");
renderDataType(status, td, va);
}
}
if (pwrA != null) {
if (firstA) firstA = false; else td.tx(", ");
td.tx(context.formatPhrase(RenderingContext.DIAG_REP_REND_AGE) + " ");
renderDataType(status, td, pwrA);
}
}
}
}
}
addCellToTable(flags, status, tr, obs, null, "status", "interpretation");
addCellToTable(note, status, tr, obs, null, "note");
addCellToTable(effectiveTime, status, tr, obs, eff, "effective[x]");
addCellToTable(issued, status, tr, obs, iss, "issued");
}
private void addCellToTable(boolean included, RenderingStatus status, XhtmlNode tr, ResourceWrapper obs, ResourceWrapper diff, String... names) throws FHIRFormatError, DefinitionException, IOException {
if (included) {
XhtmlNode td = tr.td();
List list = obs.childrenMN(names);
if (!list.isEmpty()) {
boolean first = true;
for (ResourceWrapper b : list) {
if (diff == null || !diff.matches(b)) {
if (first) first = false; else td.tx(", ");
renderDataType(status, td, b);
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy