improvements to code system rendering + fix date/time rendering tests

This commit is contained in:
Grahame Grieve 2021-11-29 16:10:58 +11:00
parent 162cf6f049
commit 6a735d4319
5 changed files with 115 additions and 64 deletions

View File

@ -498,6 +498,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
@Override
public CodeSystem fetchCodeSystem(String system) {
if (system.contains("|")) {
String s = system.substring(0, system.indexOf("|"));
String v = system.substring(system.indexOf("|")+1);
return fetchCodeSystem(s, v);
}
CodeSystem cs;
synchronized (lock) {
cs = codeSystems.get(system);
@ -511,6 +516,23 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return cs;
}
public CodeSystem fetchCodeSystem(String system, String version) {
if (version == null) {
return fetchCodeSystem(system);
}
CodeSystem cs;
synchronized (lock) {
cs = codeSystems.get(system, version);
}
if (cs == null && locator != null) {
locator.findResource(this, system);
synchronized (lock) {
cs = codeSystems.get(system);
}
}
return cs;
}
@Override
public boolean supportsSystem(String system) throws TerminologyServiceException {
synchronized (lock) {

View File

@ -476,6 +476,7 @@ public interface IWorkerContext {
* @return
*/
public CodeSystem fetchCodeSystem(String system);
public CodeSystem fetchCodeSystem(String system, String version);
/**
* True if the underlying terminology service provider will do

View File

@ -94,8 +94,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
private void generateProperties(XhtmlNode x, CodeSystem cs) {
if (cs.hasProperty()) {
boolean hasRendered = false;
boolean hasURI = false;
for (PropertyComponent p : cs.getProperty()) {
hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
hasURI = hasURI || p.hasUri();
}
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
@ -105,18 +107,22 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Name", getContext().getLang()));
}
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()));
if (hasURI) {
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", "Type", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
for (PropertyComponent p : cs.getProperty()) {
tr = tbl.tr();
if (hasRendered) {
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
}
tr.td().tx(p.getCode());
tr.td().tx(p.getUri());
tr.td().tx(p.getDescription());
if (hasURI) {
tr.td().tx(p.getUri());
}
tr.td().tx(p.hasType() ? p.getType().toCode() : "");
tr.td().tx(p.getDescription());
}
}
}
@ -141,6 +147,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
boolean hierarchy = false;
boolean version = false;
boolean ignoreStatus = false;
boolean isSupplement = cs.getContent() == CodeSystemContentMode.SUPPLEMENT;
List<PropertyComponent> properties = new ArrayList<>();
for (PropertyComponent cp : cs.getProperty()) {
if (showPropertyInTable(cp)) {
@ -170,7 +177,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
List<String> langs = new ArrayList<>();
addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, false), maps);
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions;
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs, isSupplement) || hasExtensions;
}
if (langs.size() > 0) {
Collections.sort(langs);
@ -223,10 +230,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
return true;
}
String uri = cp.getUri();
String code = null;
if (Utilities.noString(uri)){
return false;
return true; // do we always want to render properties in this case? Not sure...
}
String code = null;
if (uri.contains("#")) {
code = uri.substring(uri.indexOf("#")+1);
uri = uri.substring(0, uri.indexOf("#"));
@ -290,7 +297,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, List<PropertyComponent> properties, CodeSystemNavigator csNav, List<String> langs) throws FHIRFormatError, DefinitionException, IOException {
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, List<PropertyComponent> properties, CodeSystemNavigator csNav, List<String> langs, boolean isSupplement) throws FHIRFormatError, DefinitionException, IOException {
boolean hasExtensions = false;
XhtmlNode tr = t.tr();
XhtmlNode td = tr.td();
@ -300,7 +307,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
String s = Utilities.padLeft("", '\u00A0', level*2);
td.addText(s);
}
td.attribute("style", "white-space:nowrap").addText(c.getCode());
String link = isSupplement ? getLinkForCode(cs.getSupplements(), null, c.getCode()) : null;
if (link != null) {
td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
} else {
td.attribute("style", "white-space:nowrap").addText(c.getCode());
}
XhtmlNode a;
if (c.hasCodeElement()) {
td.an(cs.getId()+"-" + Utilities.nmtokenize(c.getCode()));
@ -450,7 +462,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
List<ConceptDefinitionComponent> ocl = csNav.getOtherChildren(c);
for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) {
hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions;
hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs, isSupplement) || hasExtensions;
}
for (ConceptDefinitionComponent cc : ocl) {
tr = t.tr();

View File

@ -711,6 +711,38 @@ public class DataRenderer extends Renderer {
}
}
protected String getLinkForCode(String system, String version, String code) {
if ("http://snomed.info/sct".equals(system)) {
if (!Utilities.noString(code)) {
return "http://snomed.info/id/"+code;
} else {
return "https://browser.ihtsdotools.org/";
}
} else if ("http://loinc.org".equals(system)) {
if (!Utilities.noString(code)) {
return "https://loinc.org/"+code;
} else {
return "https://loinc.org/";
}
} else if ("http://www.nlm.nih.gov/research/umls/rxnorm".equals(system)) {
if (!Utilities.noString(code)) {
return "https://mor.nlm.nih.gov/RxNav/search?searchBy=RXCUI&searchTerm="+code;
} else {
return "https://www.nlm.nih.gov/research/umls/rxnorm/index.html";
}
} else {
CodeSystem cs = context.getWorker().fetchCodeSystem(system, version);
if (cs != null && cs.hasUserData("path")) {
if (!Utilities.noString(code)) {
return cs.getUserString("path")+"#"+Utilities.nmtokenize(code);
} else {
return cs.getUserString("path");
}
}
}
return null;
}
protected void renderCodingWithDetails(XhtmlNode x, Coding c) {
String s = "";
if (c.hasDisplayElement())
@ -720,22 +752,13 @@ public class DataRenderer extends Renderer {
String sn = describeSystem(c.getSystem());
if ("http://snomed.info/sct".equals(c.getSystem())) {
if (c.hasCode()) {
x.ah("http://snomed.info/id/"+c.getCode()).tx(sn);
} else {
x.ah("https://browser.ihtsdotools.org/").tx(sn);
}
} else if ("http://loinc.org".equals(c.getSystem())) {
x.ah("https://loinc.org/").tx(sn);
String link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode());
if (link != null) {
x.ah(link).tx(sn);
} else {
CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem());
if (cs != null && cs.hasUserData("path")) {
x.ah(cs.getUserString("path")).tx(sn);
} else {
x.tx(sn);
}
x.tx(sn);
}
x.tx(" ");
x.tx(c.getCode());
if (!Utilities.noString(s)) {

View File

@ -55,15 +55,17 @@ public class NarrativeGeneratorTests {
}
private void checkDateTimeRendering(String src, String lang, String country, ZoneId tz, FormatStyle fmt, ResourceRendererMode mode, String expected) throws FHIRFormatError, DefinitionException, IOException {
private void checkDateTimeRendering(String src, String lang, String country, ZoneId tz, String fmt, ResourceRendererMode mode, String expected) throws FHIRFormatError, DefinitionException, IOException {
rc.setLocale(new java.util.Locale(lang, country));
rc.setTimeZoneId(tz);
if (fmt == null) {
rc.setDateTimeFormat(null);
rc.setDateFormat(null);
} else {
rc.setDateTimeFormat(DateTimeFormatter.ofLocalizedDateTime(fmt).withLocale(rc.getLocale()));
rc.setDateFormat(DateTimeFormatter.ofLocalizedDate(fmt).withLocale(rc.getLocale()));
// really, it would be better to test patterns based on FormatStyle here, since
// that's what will be used in the real world, but
rc.setDateTimeFormat(DateTimeFormatter.ofPattern(fmt));
rc.setDateFormat(DateTimeFormatter.ofPattern(fmt));
}
rc.setMode(mode);
@ -76,42 +78,33 @@ public class NarrativeGeneratorTests {
Assert.assertEquals("<p>"+expected+"</p>", actual);
}
// @Test
// public void testDateTimeLocaleConsistency() throws FHIRFormatError, DefinitionException, IOException {
// Locale locale = new java.util.Locale("en", "AU");
// DateTimeFormatter fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(locale);
// ZonedDateTime zdt = ZonedDateTime.parse("2021-11-19T14:13:12Z");
// Assert.assertEquals("19 Nov. 2021, 2:13:12 pm", fmt.format(zdt));
// }
//
//
// @Test
// public void testDateTimeRendering1() throws FHIRFormatError, DefinitionException, IOException {
// checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.TECHNICAL, "2021-11-19T14:13:12Z");
// }
//
//
// @Test
// public void testDateTimeRendering2() throws FHIRFormatError, DefinitionException, IOException {
// checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("Australia/Sydney"), null, ResourceRendererMode.TECHNICAL, "2021-11-20T01:13:12+11:00");
// }
//
// @Test
// public void testDateTimeRendering3() throws FHIRFormatError, DefinitionException, IOException {
// checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), FormatStyle.SHORT, ResourceRendererMode.TECHNICAL, "19/11/21, 2:13 pm");
// }
//
//
// @Test
// public void testDateTimeRendering4() throws FHIRFormatError, DefinitionException, IOException {
// checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.END_USER, "19/11/21, 2:13 pm");
// }
//
//
// @Test
// public void testDateTimeRendering5() throws FHIRFormatError, DefinitionException, IOException {
// checkDateTimeRendering("2021-11-19", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.END_USER, "19/11/21");
// }
//
@Test
public void testDateTimeRendering1() throws FHIRFormatError, DefinitionException, IOException {
checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.TECHNICAL, "2021-11-19T14:13:12Z");
}
@Test
public void testDateTimeRendering2() throws FHIRFormatError, DefinitionException, IOException {
checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("Australia/Sydney"), null, ResourceRendererMode.TECHNICAL, "2021-11-20T01:13:12+11:00");
}
@Test
public void testDateTimeRendering3() throws FHIRFormatError, DefinitionException, IOException {
checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), "yyyy/MM/dd hh:mm:ss", ResourceRendererMode.TECHNICAL, "2021/11/19 02:13:12");
}
@Test
public void testDateTimeRendering4() throws FHIRFormatError, DefinitionException, IOException {
checkDateTimeRendering("2021-11-19T14:13:12Z", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.END_USER, "19/11/21, 2:13 pm");
}
@Test
public void testDateTimeRendering5() throws FHIRFormatError, DefinitionException, IOException {
checkDateTimeRendering("2021-11-19", "en", "AU", ZoneId.of("UTC"), null, ResourceRendererMode.END_USER, "19/11/21");
}
}