Merge pull request #670 from hapifhir/gg-202111-xver-modifiers
Gg 202111 xver modifiers
This commit is contained in:
commit
804c80b009
|
@ -4,7 +4,7 @@
|
|||
| :---: |
|
||||
| [![Build Status][Badge-BuildPipeline]][Link-BuildPipeline] |
|
||||
|
||||
This is the core object handling code, with utilities (including validator), for the FHIR specification.
|
||||
This is the java core object handling code, with utilities (including validator), for the FHIR specification.
|
||||
included in this repo:
|
||||
|
||||
* org.fhir.fhir.utilities: Shared code used by all the other projects - including the internationalization code
|
||||
|
@ -17,6 +17,11 @@ included in this repo:
|
|||
* org.fhir.fhir.validation: The FHIR Java validator (note: based on R5 internally, but validates all the above versions)
|
||||
* org.fhir.fhir.validation.cli: Holder project for releasing the FHIR validator as as single fat jar (will be removed in the future)
|
||||
|
||||
This code is used in all HAPI servers and clients, and also is the HL7 maintained
|
||||
FHIR Validator. In addition, this is the core code for the HL7 maintained IG publisher
|
||||
and FHIR main build publisher. As such, this code is considered an authoritatively
|
||||
correct implementation of the core FHIR specification that it implements.
|
||||
|
||||
### CI/CD
|
||||
|
||||
All integration and delivery done on Azure pipelines. Azure project can be viewed [here][Link-AzureProject].
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Validator:
|
||||
* fix processing of modifier extensions and cross-version modifier extensions
|
||||
|
||||
Other changes:
|
||||
* improvements to data types rendering based on new test cases (URLs, Money, Markdown)
|
||||
* add locale to rendering context, and fix up timezone related rendering based on locale
|
|
@ -0,0 +1,387 @@
|
|||
package org.hl7.fhir.convertors.misc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.naming.ldap.StartTlsRequest;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class XVerPackegeFixer {
|
||||
|
||||
private static final String R5_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r5.core\\package";
|
||||
private static final String R4_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.core\\package";
|
||||
private static final String R3_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r3.core\\package";
|
||||
private static final String R2B_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r2b.core\\package";
|
||||
private static final String R2_FOLDER = "C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r2.core\\package";
|
||||
private static int mod;
|
||||
|
||||
private static Map<String, org.hl7.fhir.r5.model.StructureDefinition> map5 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.r4.model.StructureDefinition> map4 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu3.model.StructureDefinition> map3 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu2.model.StructureDefinition> map2 = new HashMap<>();
|
||||
private static Map<String, org.hl7.fhir.dstu2016may.model.StructureDefinition> map2b = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException, ParserConfigurationException, SAXException, IOException {
|
||||
mod = 0;
|
||||
for (File f : new File(args[0]).listFiles()) {
|
||||
if (f.getName().startsWith("xver-")) {
|
||||
JsonObject j = JsonTrackingParser.parseJson(f);
|
||||
fixUp(j, f.getName());
|
||||
JsonTrackingParser.write(j, f, true);
|
||||
}
|
||||
}
|
||||
System.out.println("all done: "+mod+" modifiers");
|
||||
}
|
||||
|
||||
private static void fixUp(JsonObject j, String name) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
name = name.replace(".json", "");
|
||||
System.out.println("Process "+name);
|
||||
String version = name.substring(name.lastIndexOf("-")+1);
|
||||
int i = 0;
|
||||
for (Entry<String, JsonElement> e : j.entrySet()) {
|
||||
if (i == 50) {
|
||||
i = 0;
|
||||
System.out.print(".");
|
||||
}
|
||||
i++;
|
||||
String n = e.getKey();
|
||||
JsonObject o = ((JsonObject) e.getValue());
|
||||
boolean ok = (o.has("types") && o.getAsJsonArray("types").size() > 0) || (o.has("elements") && o.getAsJsonArray("elements").size() > 0);
|
||||
if (!ok) {
|
||||
List<String> types = new ArrayList<>();
|
||||
List<String> elements = new ArrayList<>();
|
||||
getElementInfo(version, n, types, elements);
|
||||
if (elements.size() > 0) {
|
||||
JsonArray arr = o.getAsJsonArray("elements");
|
||||
if (arr == null) {
|
||||
arr = new JsonArray();
|
||||
o.add("elements", arr);
|
||||
}
|
||||
for (String s : types) {
|
||||
arr.add(s);
|
||||
}
|
||||
} else if (types.size() > 0) {
|
||||
JsonArray arr = o.getAsJsonArray("types");
|
||||
if (arr == null) {
|
||||
arr = new JsonArray();
|
||||
o.add("types", arr);
|
||||
}
|
||||
for (String s : types) {
|
||||
arr.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done");
|
||||
}
|
||||
|
||||
private static boolean getElementInfo(String version, String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
if ("contained".equals(n.substring(n.indexOf(".")+1))) {
|
||||
return false;
|
||||
}
|
||||
switch (version) {
|
||||
case "4.6": return getElementInfoR5(n, types, elements);
|
||||
case "4.0": return getElementInfoR4(n, types, elements);
|
||||
case "3.0": return getElementInfoR3(n, types, elements);
|
||||
case "1.4": return getElementInfoR2B(n, types, elements);
|
||||
case "1.0": return getElementInfoR2(n, types, elements);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Object tail(String value) {
|
||||
return value.contains("/") ? value.substring(value.lastIndexOf("/")+1) : value;
|
||||
}
|
||||
|
||||
private static boolean getElementInfoR5(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.r5.model.StructureDefinition sd = null;
|
||||
if (map5.containsKey(tn)) {
|
||||
sd = map5.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.r5.model.StructureDefinition) new org.hl7.fhir.r5.formats.JsonParser().parse(new FileInputStream(Utilities.path(R5_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map5.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.r5.model.ElementDefinition> children = listChildrenR5(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getWorkingCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.r5.model.CanonicalType u : t.getTargetProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.r5.model.ElementDefinition> listChildrenR5(List<org.hl7.fhir.r5.model.ElementDefinition> list, org.hl7.fhir.r5.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.r5.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.r5.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static boolean getElementInfoR4(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.r4.model.StructureDefinition sd = null;
|
||||
if (map4.containsKey(tn)) {
|
||||
sd = map4.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.r4.model.StructureDefinition) new org.hl7.fhir.r4.formats.JsonParser().parse(new FileInputStream(Utilities.path(R4_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map4.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.r4.model.ElementDefinition> children = listChildrenR4(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getWorkingCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.r4.model.CanonicalType u : t.getTargetProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.r4.model.ElementDefinition> listChildrenR4(List<org.hl7.fhir.r4.model.ElementDefinition> list, org.hl7.fhir.r4.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.r4.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR3(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu3.model.StructureDefinition sd = null;
|
||||
if (map3.containsKey(tn)) {
|
||||
sd = map3.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu3.model.StructureDefinition) new org.hl7.fhir.dstu3.formats.JsonParser().parse(new FileInputStream(Utilities.path(R3_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map3.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu3.model.ElementDefinition> children = listChildrenR3(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasTargetProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
b.append(tail(t.getTargetProfile()));
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu3.model.ElementDefinition> listChildrenR3(List<org.hl7.fhir.dstu3.model.ElementDefinition> list, org.hl7.fhir.dstu3.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu3.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu3.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR2(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu2.model.StructureDefinition sd = null;
|
||||
if (map2.containsKey(tn)) {
|
||||
sd = map2.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu2.model.StructureDefinition) new org.hl7.fhir.dstu2.formats.JsonParser().parse(new FileInputStream(Utilities.path(R2_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map2.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu2.model.ElementDefinition> children = listChildrenR2(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.dstu2.model.UriType u : t.getProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu2.model.ElementDefinition> listChildrenR2(List<org.hl7.fhir.dstu2.model.ElementDefinition> list, org.hl7.fhir.dstu2.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu2.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu2.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getElementInfoR2B(String n, List<String> types, List<String> elements) throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
String tn = n.substring(0, n.indexOf("."));
|
||||
org.hl7.fhir.dstu2016may.model.StructureDefinition sd = null;
|
||||
if (map2b.containsKey(tn)) {
|
||||
sd = map2b.get(tn);
|
||||
} else {
|
||||
sd = (org.hl7.fhir.dstu2016may.model.StructureDefinition) new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(new FileInputStream(Utilities.path(R2B_FOLDER, "StructureDefinition-"+tn+".json")));
|
||||
map2b.put(tn, sd);
|
||||
}
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals(n)) {
|
||||
List<org.hl7.fhir.dstu2016may.model.ElementDefinition> children = listChildrenR2B(sd.getSnapshot().getElement(), ed);
|
||||
if (children.size() > 0) {
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition c : children) {
|
||||
String en = c.getPath().substring(ed.getPath().length()+1);
|
||||
elements.add(en);
|
||||
}
|
||||
} else {
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition.TypeRefComponent t : ed.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(t.getCode());
|
||||
b.append("(");
|
||||
boolean first = true;
|
||||
for (org.hl7.fhir.dstu2016may.model.UriType u : t.getProfile()) {
|
||||
if (first) first = false; else b.append("|");
|
||||
b.append(tail(u.getValue()));
|
||||
}
|
||||
b.append(")");
|
||||
types.add(b.toString());
|
||||
} else {
|
||||
types.add(t.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static List<org.hl7.fhir.dstu2016may.model.ElementDefinition> listChildrenR2B(List<org.hl7.fhir.dstu2016may.model.ElementDefinition> list, org.hl7.fhir.dstu2016may.model.ElementDefinition ed) {
|
||||
List<org.hl7.fhir.dstu2016may.model.ElementDefinition> res = new ArrayList<>();
|
||||
for (org.hl7.fhir.dstu2016may.model.ElementDefinition t : list) {
|
||||
String p = t.getPath();
|
||||
if (p.startsWith(ed.getPath()+".")) {
|
||||
p = p.substring(ed.getPath().length()+1);
|
||||
if (!p.contains(".")) {
|
||||
res.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,7 +2,18 @@ package org.hl7.fhir.r5.renderers;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -33,8 +44,10 @@ import org.hl7.fhir.r5.model.Expression;
|
|||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.HumanName;
|
||||
import org.hl7.fhir.r5.model.HumanName.NameUse;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.InstantType;
|
||||
import org.hl7.fhir.r5.model.MarkdownType;
|
||||
import org.hl7.fhir.r5.model.Money;
|
||||
import org.hl7.fhir.r5.model.Period;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Quantity;
|
||||
|
@ -64,6 +77,9 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
|
|||
import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
|
||||
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
|
||||
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
|
||||
|
||||
|
@ -373,6 +389,8 @@ public class DataRenderer extends Renderer {
|
|||
return displayTiming((Timing) type);
|
||||
} else if (type instanceof SampledData) {
|
||||
return displaySampledData((SampledData) type);
|
||||
} else if (type.isDateTime()) {
|
||||
return displayDateTime((BaseDateTimeType) type);
|
||||
} else if (type.isPrimitive()) {
|
||||
return type.primitiveValue();
|
||||
} else {
|
||||
|
@ -380,11 +398,58 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
private String displayDateTime(BaseDateTimeType type) {
|
||||
if (!type.hasPrimitiveValue()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// relevant inputs in rendering context:
|
||||
// timeZone, dateTimeFormat, locale, mode
|
||||
// timezone - application specified timezone to use.
|
||||
// null = default to the time of the date/time itself
|
||||
// dateTimeFormat - application specified format for date times
|
||||
// null = default to ... depends on mode
|
||||
// mode - if rendering mode is technical, format defaults to XML format
|
||||
// locale - otherwise, format defaults to SHORT for the Locale (which defaults to default Locale)
|
||||
if (isOnlyDate(type.getPrecision())) {
|
||||
DateTimeFormatter fmt = context.getDateFormat();
|
||||
if (fmt == null) {
|
||||
if (context.isTechnicalMode()) {
|
||||
fmt = DateTimeFormatter.ISO_DATE;
|
||||
} else {
|
||||
fmt = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(context.getLocale());
|
||||
}
|
||||
}
|
||||
|
||||
LocalDate date = LocalDate.of(type.getYear(), type.getMonth()+1, type.getDay());
|
||||
return fmt.format(date);
|
||||
}
|
||||
|
||||
DateTimeFormatter fmt = context.getDateTimeFormat();
|
||||
if (fmt == null) {
|
||||
if (context.isTechnicalMode()) {
|
||||
fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
} else {
|
||||
fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(context.getLocale());
|
||||
}
|
||||
}
|
||||
ZonedDateTime zdt = ZonedDateTime.parse(type.primitiveValue());
|
||||
ZoneId zone = context.getTimeZoneId();
|
||||
if (zone != null) {
|
||||
zdt = zdt.withZoneSameInstant(zone);
|
||||
}
|
||||
return fmt.format(zdt);
|
||||
}
|
||||
|
||||
private boolean isOnlyDate(TemporalPrecisionEnum temporalPrecisionEnum) {
|
||||
return temporalPrecisionEnum == TemporalPrecisionEnum.YEAR || temporalPrecisionEnum == TemporalPrecisionEnum.MONTH || temporalPrecisionEnum == TemporalPrecisionEnum.DAY;
|
||||
}
|
||||
|
||||
public String display(BaseWrapper type) {
|
||||
return "to do";
|
||||
}
|
||||
|
||||
public void render(XhtmlNode x, BaseWrapper type) {
|
||||
public void render(XhtmlNode x, BaseWrapper type) throws FHIRFormatError, DefinitionException, IOException {
|
||||
Base base = null;
|
||||
try {
|
||||
base = type.getBase();
|
||||
|
@ -399,7 +464,7 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
public void renderBase(XhtmlNode x, Base b) {
|
||||
public void renderBase(XhtmlNode x, Base b) throws FHIRFormatError, DefinitionException, IOException {
|
||||
if (b instanceof DataType) {
|
||||
render(x, (DataType) b);
|
||||
} else {
|
||||
|
@ -407,9 +472,9 @@ public class DataRenderer extends Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
public void render(XhtmlNode x, DataType type) {
|
||||
if (type instanceof DateTimeType) {
|
||||
renderDateTime(x, (DateTimeType) type);
|
||||
public void render(XhtmlNode x, DataType type) throws FHIRFormatError, DefinitionException, IOException {
|
||||
if (type instanceof BaseDateTimeType) {
|
||||
x.tx(displayDateTime((BaseDateTimeType) type));
|
||||
} else if (type instanceof UriType) {
|
||||
renderUri(x, (UriType) type);
|
||||
} else if (type instanceof Annotation) {
|
||||
|
@ -424,6 +489,10 @@ public class DataRenderer extends Renderer {
|
|||
renderHumanName(x, (HumanName) type);
|
||||
} else if (type instanceof Address) {
|
||||
renderAddress(x, (Address) type);
|
||||
} else if (type instanceof Expression) {
|
||||
renderExpression(x, (Expression) type);
|
||||
} else if (type instanceof Money) {
|
||||
renderMoney(x, (Money) type);
|
||||
} else if (type instanceof ContactPoint) {
|
||||
renderContactPoint(x, (ContactPoint) type);
|
||||
} else if (type instanceof Quantity) {
|
||||
|
@ -438,10 +507,8 @@ public class DataRenderer extends Renderer {
|
|||
renderSampledData(x, (SampledData) type);
|
||||
} else if (type instanceof Reference) {
|
||||
renderReference(x, (Reference) type);
|
||||
} else if (type instanceof InstantType) {
|
||||
x.tx(((InstantType) type).toHumanDisplay());
|
||||
} else if (type instanceof BaseDateTimeType) {
|
||||
x.tx(((BaseDateTimeType) type).toHumanDisplay());
|
||||
} else if (type instanceof MarkdownType) {
|
||||
addMarkdown(x, ((MarkdownType) type).asStringValue());
|
||||
} else if (type.isPrimitive()) {
|
||||
x.tx(type.primitiveValue());
|
||||
} else {
|
||||
|
@ -461,22 +528,24 @@ public class DataRenderer extends Renderer {
|
|||
|
||||
public void renderDateTime(XhtmlNode x, Base e) {
|
||||
if (e.hasPrimitiveValue()) {
|
||||
x.addText(((DateTimeType) e).toHumanDisplay());
|
||||
x.addText(displayDateTime((DateTimeType) e));
|
||||
}
|
||||
}
|
||||
|
||||
public void renderDateTime(XhtmlNode x, String s) {
|
||||
if (s != null) {
|
||||
DateTimeType dt = new DateTimeType(s);
|
||||
x.addText(dt.toHumanDisplay());
|
||||
x.addText(displayDateTime(dt));
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderUri(XhtmlNode x, UriType uri) {
|
||||
if (uri.getValue().startsWith("mailto:")) {
|
||||
x.ah(uri.getValue()).addText(uri.getValue().substring(7));
|
||||
} else {
|
||||
} else if (Utilities.isAbsoluteUrlLinkable(uri.getValue()) && !(uri instanceof IdType)) {
|
||||
x.ah(uri.getValue()).addText(uri.getValue());
|
||||
} else {
|
||||
x.addText(uri.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -904,6 +973,27 @@ public class DataRenderer extends Renderer {
|
|||
return s.toString();
|
||||
}
|
||||
|
||||
protected String getLocalizedBigDecimalValue(BigDecimal input, Currency c) {
|
||||
NumberFormat numberFormat = NumberFormat.getNumberInstance(context.getLocale());
|
||||
numberFormat.setGroupingUsed(true);
|
||||
numberFormat.setMaximumFractionDigits(c.getDefaultFractionDigits());
|
||||
numberFormat.setMinimumFractionDigits(c.getDefaultFractionDigits());
|
||||
return numberFormat.format(input);
|
||||
}
|
||||
|
||||
protected void renderMoney(XhtmlNode x, Money money) {
|
||||
Currency c = Currency.getInstance(money.getCurrency());
|
||||
if (c != null) {
|
||||
XhtmlNode s = x.span(null, c.getDisplayName());
|
||||
s.tx(c.getSymbol(context.getLocale()));
|
||||
s.tx(getLocalizedBigDecimalValue(money.getValue(), c));
|
||||
x.tx(" ("+c.getCurrencyCode()+")");
|
||||
} else {
|
||||
x.tx(money.getCurrency());
|
||||
x.tx(money.getValue().toPlainString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderExpression(XhtmlNode x, Expression expr) {
|
||||
// there's two parts: what the expression is, and how it's described.
|
||||
// we start with what it is, and then how it's desceibed
|
||||
|
@ -1077,19 +1167,19 @@ public class DataRenderer extends Renderer {
|
|||
x.tx(" "+q.getLow().getUnit());
|
||||
}
|
||||
|
||||
public static String displayPeriod(Period p) {
|
||||
String s = !p.hasStart() ? "(?)" : p.getStartElement().toHumanDisplay();
|
||||
public String displayPeriod(Period p) {
|
||||
String s = !p.hasStart() ? "(?)" : displayDateTime(p.getStartElement());
|
||||
s = s + " --> ";
|
||||
return s + (!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
|
||||
return s + (!p.hasEnd() ? "(ongoing)" : displayDateTime(p.getEndElement()));
|
||||
}
|
||||
|
||||
public void renderPeriod(XhtmlNode x, Period p) {
|
||||
x.addText(!p.hasStart() ? "??" : p.getStartElement().toHumanDisplay());
|
||||
x.addText(!p.hasStart() ? "??" : displayDateTime(p.getStartElement()));
|
||||
x.tx(" --> ");
|
||||
x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
|
||||
x.addText(!p.hasEnd() ? "(ongoing)" : displayDateTime(p.getEndElement()));
|
||||
}
|
||||
|
||||
public void renderDataRequirement(XhtmlNode x, DataRequirement dr) {
|
||||
public void renderDataRequirement(XhtmlNode x, DataRequirement dr) throws FHIRFormatError, DefinitionException, IOException {
|
||||
XhtmlNode tbl = x.table("grid");
|
||||
XhtmlNode tr = tbl.tr();
|
||||
XhtmlNode td = tr.td().colspan("2");
|
||||
|
@ -1194,7 +1284,7 @@ public class DataRenderer extends Renderer {
|
|||
CommaSeparatedStringBuilder c = new CommaSeparatedStringBuilder();
|
||||
for (DateTimeType p : s.getEvent()) {
|
||||
if (p.hasValue()) {
|
||||
c.append(p.toHumanDisplay());
|
||||
c.append(displayDateTime(p));
|
||||
} else if (!renderExpression(c, p)) {
|
||||
c.append("??");
|
||||
}
|
||||
|
@ -1205,7 +1295,7 @@ public class DataRenderer extends Renderer {
|
|||
if (s.hasRepeat()) {
|
||||
TimingRepeatComponent rep = s.getRepeat();
|
||||
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart())
|
||||
b.append("Starting "+rep.getBoundsPeriod().getStartElement().toHumanDisplay());
|
||||
b.append("Starting "+displayDateTime(rep.getBoundsPeriod().getStartElement()));
|
||||
if (rep.hasCount())
|
||||
b.append("Count "+Integer.toString(rep.getCount())+" times");
|
||||
if (rep.hasDuration())
|
||||
|
@ -1237,7 +1327,7 @@ public class DataRenderer extends Renderer {
|
|||
b.append("Do "+st);
|
||||
}
|
||||
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd())
|
||||
b.append("Until "+rep.getBoundsPeriod().getEndElement().toHumanDisplay());
|
||||
b.append("Until "+displayDateTime(rep.getBoundsPeriod().getEndElement()));
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ 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.Money;
|
||||
import org.hl7.fhir.r5.model.Narrative;
|
||||
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
|
@ -352,6 +353,8 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
|
|||
renderContactPoint(x, (ContactPoint) e);
|
||||
} else if (e instanceof Expression) {
|
||||
renderExpression(x, (Expression) e);
|
||||
} else if (e instanceof Money) {
|
||||
renderMoney(x, (Money) e);
|
||||
} else if (e instanceof ContactDetail) {
|
||||
ContactDetail cd = (ContactDetail) e;
|
||||
if (cd.hasName()) {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
package org.hl7.fhir.r5.renderers.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
|
@ -117,6 +123,11 @@ public class RenderingContext {
|
|||
private boolean addGeneratedNarrativeHeader = true;
|
||||
|
||||
private FhirPublication targetVersion;
|
||||
private Locale locale;
|
||||
private ZoneId timeZoneId;
|
||||
private DateTimeFormatter dateTimeFormat;
|
||||
private DateTimeFormatter dateFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context - access to all related resources that might be needed
|
||||
|
@ -136,6 +147,8 @@ public class RenderingContext {
|
|||
if (terminologyServiceOptions != null) {
|
||||
this.terminologyServiceOptions = terminologyServiceOptions;
|
||||
}
|
||||
// default to US locale - discussion here: https://github.com/hapifhir/org.hl7.fhir.core/issues/666
|
||||
this.locale = new Locale.Builder().setLanguageTag("en-US").build();
|
||||
profileUtilities = new ProfileUtilities(worker, null, null);
|
||||
}
|
||||
|
||||
|
@ -427,4 +440,79 @@ public class RenderingContext {
|
|||
return mode == ResourceRendererMode.TECHNICAL;
|
||||
}
|
||||
|
||||
public boolean hasLocale() {
|
||||
return locale != null;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
if (locale == null) {
|
||||
return Locale.getDefault();
|
||||
} else {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* if the timezone is null, the rendering will default to the source timezone
|
||||
* in the resource
|
||||
*
|
||||
* Note that if you're working server side, the FHIR project recommends the use
|
||||
* of the Date header so that clients know what timezone the server defaults to,
|
||||
*
|
||||
* There is no standard way for the server to know what the client timezone is.
|
||||
* In the case where the client timezone is unknown, the timezone should be null
|
||||
*
|
||||
* @return the specified timezone to render in
|
||||
*/
|
||||
public ZoneId getTimeZoneId() {
|
||||
return timeZoneId;
|
||||
}
|
||||
|
||||
public void setTimeZoneId(ZoneId timeZoneId) {
|
||||
this.timeZoneId = timeZoneId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In the absence of a specified format, the renderers will default to
|
||||
* the FormatStyle.MEDIUM for the current locale.
|
||||
*
|
||||
* @return the format to use
|
||||
*/
|
||||
public DateTimeFormatter getDateTimeFormat() {
|
||||
return this.dateTimeFormat;
|
||||
}
|
||||
|
||||
public void setDateTimeFormat(DateTimeFormatter dateTimeFormat) {
|
||||
this.dateTimeFormat = dateTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the absence of a specified format, the renderers will default to
|
||||
* the FormatStyle.MEDIUM for the current locale.
|
||||
*
|
||||
* @return the format to use
|
||||
*/
|
||||
public DateTimeFormatter getDateFormat() {
|
||||
return this.dateFormat;
|
||||
}
|
||||
|
||||
public void setDateFormat(DateTimeFormatter dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
public ResourceRendererMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(ResourceRendererMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -151,13 +151,14 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
String result = compareXml(f1, f2);
|
||||
if (result != null && SHOW_DIFF) {
|
||||
String diff = Utilities.path(System.getenv("ProgramFiles"), "WinMerge", "WinMergeU.exe");
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
builder.directory(new CSFile("c:\\temp"));
|
||||
builder.start();
|
||||
if (new File(diff).exists()) {
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
builder.directory(new CSFile("c:\\temp"));
|
||||
builder.start();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
}
|
||||
|
||||
private static String compareElements(String path, Element e1, Element e2) {
|
||||
if (!e1.getNamespaceURI().equals(e2.getNamespaceURI()))
|
||||
if (!namespacesMatch(e1.getNamespaceURI(), e2.getNamespaceURI()))
|
||||
return "Namespaces differ at " + path + ": " + e1.getNamespaceURI() + "/" + e2.getNamespaceURI();
|
||||
if (!e1.getLocalName().equals(e2.getLocalName()))
|
||||
return "Names differ at " + path + ": " + e1.getLocalName() + "/" + e2.getLocalName();
|
||||
|
@ -209,6 +210,10 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static boolean namespacesMatch(String ns1, String ns2) {
|
||||
return ns1 == null ? ns2 == null : ns1.equals(ns2);
|
||||
}
|
||||
|
||||
private static Object normalise(String text) {
|
||||
String result = text.trim().replace('\r', ' ').replace('\n', ' ').replace('\t', ' ');
|
||||
while (result.contains(" "))
|
||||
|
|
|
@ -133,6 +133,11 @@ public class XVerExtensionManager {
|
|||
} else {
|
||||
throw new FHIRException("Internal error - attempt to define extension for "+url+" when it is invalid");
|
||||
}
|
||||
if (path.has("modifier") && path.get("modifier").getAsBoolean()) {
|
||||
ElementDefinition baseDef = new ElementDefinition("Extension");
|
||||
sd.getDifferential().getElement().add(0, baseDef);
|
||||
baseDef.setIsModifier(true);
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package org.hl7.fhir.r5.test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -56,7 +61,6 @@ public class NarrativeGenerationTests {
|
|||
public Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException {
|
||||
return new org.hl7.fhir.r5.formats.XmlParser().parseType(xml, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final String WINDOWS = "WINDOWS";
|
||||
|
@ -77,12 +81,14 @@ public class NarrativeGenerationTests {
|
|||
private String id;
|
||||
private boolean header;
|
||||
private boolean meta;
|
||||
private boolean technical;
|
||||
|
||||
public TestDetails(Element test) {
|
||||
super();
|
||||
id = test.getAttribute("id");
|
||||
header = "true".equals(test.getAttribute("header"));
|
||||
meta = "true".equals(test.getAttribute("meta"));
|
||||
technical = "technical".equals(test.getAttribute("mode"));
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -133,6 +139,15 @@ public class NarrativeGenerationTests {
|
|||
rc.setDefinitionsTarget("test.html");
|
||||
rc.setTerminologyServiceOptions(TerminologyServiceOptions.defaults());
|
||||
rc.setParser(new TestTypeParser());
|
||||
|
||||
// getting timezones correct (well, at least consistent, so tests pass on any computer)
|
||||
rc.setLocale(new java.util.Locale("en", "AU"));
|
||||
rc.setTimeZoneId(ZoneId.of("Australia/Sydney"));
|
||||
rc.setDateTimeFormat(null);
|
||||
rc.setDateFormat(null);
|
||||
rc.setMode(test.technical ? ResourceRendererMode.TECHNICAL : ResourceRendererMode.END_USER);
|
||||
|
||||
|
||||
Resource source;
|
||||
if (TestingUtilities.findTestResource("r5", "narrative", test.getId() + ".json")) {
|
||||
source = (Resource) new JsonParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".json"));
|
||||
|
@ -143,9 +158,12 @@ public class NarrativeGenerationTests {
|
|||
XhtmlNode x = RendererFactory.factory(source, rc).build(source);
|
||||
String target = TextFile.streamToString(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".html"));
|
||||
String output = HEADER+new XhtmlComposer(true, true).compose(x)+FOOTER;
|
||||
TextFile.stringToFile(target, TestingUtilities.tempFile("narrative", test.getId() + ".target.html"));
|
||||
TextFile.stringToFile(output, TestingUtilities.tempFile("narrative", test.getId() + ".output.html"));
|
||||
Assertions.assertTrue(output.equals(target), "Output does not match expected");
|
||||
String tfn = TestingUtilities.tempFile("narrative", test.getId() + ".target.html");
|
||||
String ofn = TestingUtilities.tempFile("narrative", test.getId() + ".output.html");
|
||||
TextFile.stringToFile(target, tfn);
|
||||
TextFile.stringToFile(output, ofn);
|
||||
String msg = TestingUtilities.checkXMLIsSame(ofn, tfn);
|
||||
Assertions.assertTrue(msg == null, "Output does not match expected: "+msg);
|
||||
|
||||
if (test.isMeta()) {
|
||||
org.hl7.fhir.r5.elementmodel.Element e = Manager.parseSingle(context, TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".xml"), FhirFormat.XML);
|
||||
|
@ -153,8 +171,10 @@ public class NarrativeGenerationTests {
|
|||
|
||||
target = TextFile.streamToString(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-meta.html"));
|
||||
output = HEADER+new XhtmlComposer(true, true).compose(x)+FOOTER;
|
||||
TextFile.stringToFile(output, TestingUtilities.tempFile("narrative", test.getId() + "-meta.output.html"));
|
||||
Assertions.assertTrue(output.equals(target), "Output does not match expected (meta)");
|
||||
ofn = TestingUtilities.tempFile("narrative", test.getId() + "-meta.output.html");
|
||||
TextFile.stringToFile(output, ofn);
|
||||
msg = TestingUtilities.checkXMLIsSame(ofn, tfn);
|
||||
Assertions.assertTrue(msg == null, "Meta output does not match expected: "+msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,22 +4,34 @@ import java.io.FileNotFoundException;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.formats.XmlParser;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.renderers.DataRenderer;
|
||||
import org.hl7.fhir.r5.renderers.RendererFactory;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
|
||||
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r5.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class NarrativeGeneratorTests {
|
||||
|
||||
|
||||
private static RenderingContext rc;
|
||||
|
||||
@BeforeAll
|
||||
|
@ -40,4 +52,58 @@ public class NarrativeGeneratorTests {
|
|||
new XmlParser().compose(s, r, true);
|
||||
s.close();
|
||||
}
|
||||
|
||||
|
||||
private void checkDateTimeRendering(String src, String lang, String country, ZoneId tz, FormatStyle 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()));
|
||||
}
|
||||
rc.setMode(mode);
|
||||
|
||||
DateTimeType dt = new DateTimeType(src);
|
||||
String actual = new DataRenderer(rc).display(dt);
|
||||
Assert.assertEquals(expected, actual);
|
||||
XhtmlNode node = new XhtmlNode(NodeType.Element, "p");
|
||||
new DataRenderer(rc).render(node, dt);
|
||||
actual = new XhtmlComposer(true, false).compose(node);
|
||||
Assert.assertEquals("<p>"+expected+"</p>", actual);
|
||||
}
|
||||
|
||||
|
||||
@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");
|
||||
// }
|
||||
//
|
||||
|
||||
}
|
|
@ -664,6 +664,12 @@ public class JsonTrackingParser {
|
|||
TextFile.stringToFile(jcnt, file);
|
||||
}
|
||||
|
||||
public static void write(JsonObject json, File file, boolean pretty) throws IOException {
|
||||
Gson gson = pretty ? new GsonBuilder().setPrettyPrinting().create() : new GsonBuilder().create();
|
||||
String jcnt = gson.toJson(json);
|
||||
TextFile.stringToFile(jcnt, file);
|
||||
}
|
||||
|
||||
public static void write(JsonObject json, String fileName) throws IOException {
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String jcnt = gson.toJson(json);
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.hl7.fhir.utilities.npm;
|
|||
public class CommonPackages {
|
||||
|
||||
public static final String ID_XVER = "hl7.fhir.xver-extensions";
|
||||
public static final String VER_XVER = "0.0.7";
|
||||
public static final String VER_XVER = "0.0.8";
|
||||
|
||||
public static final String ID_PUBPACK = "hl7.fhir.pubpack";
|
||||
public static final String VER_PUBPACK = "0.0.9";
|
||||
|
|
|
@ -30,7 +30,7 @@ class UtilitiesTest {
|
|||
public static final String WIN_JAVA_HOME = System.getenv("JAVA_HOME") + "\\";
|
||||
|
||||
public static final String OSX_USER_DIR = System.getProperty("user.home") + "/";
|
||||
public static final String OSX_JAVA_HOME = Paths.get(System.getenv("JAVA_HOME")).normalize().toString() + "/";
|
||||
public static final String OSX_JAVA_HOME = System.getenv("JAVA_HOME") == null ? null : Paths.get(System.getenv("JAVA_HOME")).normalize().toString() + "/";
|
||||
|
||||
@Test
|
||||
@DisplayName("Test Utilities.path maps temp directory correctly")
|
||||
|
|
|
@ -1476,7 +1476,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private String describeValueSet(String url) {
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, url);
|
||||
if (vs != null) {
|
||||
return "\""+vs.present()+"\" ("+url+")";
|
||||
return "'"+vs.present()+"' ("+url+")";
|
||||
} else {
|
||||
return "("+url+")";
|
||||
}
|
||||
|
@ -1656,7 +1656,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private StructureDefinition checkExtension(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl) throws FHIRException {
|
||||
String url = element.getNamedChildValue("url");
|
||||
boolean isModifier = element.getName().equals("modifierExtension");
|
||||
|
||||
assert def.getIsModifier() == isModifier;
|
||||
|
||||
long t = System.nanoTime();
|
||||
StructureDefinition ex = Utilities.isAbsoluteUrl(url) ? context.fetchResource(StructureDefinition.class, url) : null;
|
||||
timeTracker.sd(t);
|
||||
|
@ -1676,10 +1677,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
if (ex != null) {
|
||||
trackUsage(ex, hostContext, element);
|
||||
if (def.getIsModifier()) {
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHY);
|
||||
// check internal definitions are coherent
|
||||
if (isModifier) {
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHY);
|
||||
} else {
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", !ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHN);
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHN);
|
||||
}
|
||||
// two questions
|
||||
// 1. can this extension be used here?
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -19,7 +19,7 @@
|
|||
|
||||
<properties>
|
||||
<hapi_fhir_version>5.1.0</hapi_fhir_version>
|
||||
<validator_test_case_version>1.1.74</validator_test_case_version>
|
||||
<validator_test_case_version>1.1.77</validator_test_case_version>
|
||||
<junit_jupiter_version>5.7.1</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
|
||||
<maven_surefire_version>3.0.0-M5</maven_surefire_version>
|
||||
|
|
Loading…
Reference in New Issue