Merge pull request #1170 from hapifhir/gg-202303-xhtml-mapping

Gg 202303 xhtml mapping
This commit is contained in:
Grahame Grieve 2023-03-16 16:59:57 +11:00 committed by GitHub
commit e0fdb97301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 387 additions and 126 deletions

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.convertors.loaders.loaderR5;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
@ -36,12 +38,12 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
protected final String URL_ELEMENT_DEF_NAMESPACE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace";
protected boolean patchUrls;
@Getter @Setter protected boolean killPrimitives;
@Getter protected String[] types;
@Getter protected List<String> types = new ArrayList<>();
protected ILoaderKnowledgeProviderR5 lkp;
public BaseLoaderR5(String[] types, ILoaderKnowledgeProviderR5 lkp) {
public BaseLoaderR5(List<String> types, ILoaderKnowledgeProviderR5 lkp) {
super();
this.types = types;
this.types.addAll(types);
this.lkp = lkp;
}

View File

@ -59,7 +59,7 @@ public class R2016MayToR5Loader extends BaseLoaderR5 {
private final BaseAdvisor_14_50 advisor = new BaseAdvisor_14_50();
public R2016MayToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
public R2016MayToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp) {
super(types, lkp);
}

View File

@ -59,7 +59,7 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
private final BaseAdvisor_10_50 advisor = new BaseAdvisor_10_50();
public R2ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
public R2ToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp) {
super(types, lkp);
}

View File

@ -59,7 +59,7 @@ public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
private final BaseAdvisor_30_50 advisor = new BaseAdvisor_30_50();
public R3ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
public R3ToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp) {
super(types, lkp);
}

View File

@ -62,7 +62,7 @@ public class R4BToR5Loader extends BaseLoaderR5 implements IContextResourceLoade
private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
private String version;
public R4BToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
public R4BToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
super(types, lkp);
this.version = version;
}

View File

@ -62,7 +62,7 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
private String version;
public R4ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
public R4ToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
super(types, lkp);
this.version = version;
}

View File

@ -57,7 +57,7 @@ public class R5ToR5Loader extends BaseLoaderR5 {
// TODO Grahame, will this ever be populated? No conversion is being done?
private final List<CodeSystem> cslist = new ArrayList<>();
public R5ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
public R5ToR5Loader(List<String> types, ILoaderKnowledgeProviderR5 lkp) {
super(types, lkp);
}

View File

@ -274,7 +274,7 @@ public interface IWorkerContext {
/**
* @return List of the resource types that should be loaded
*/
String[] getTypes();
List<String> getTypes();
/**
* Request to actually load the resources and do whatever is required
@ -804,7 +804,7 @@ public interface IWorkerContext {
* @return the number of resources loaded
*/
@Deprecated
int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FileNotFoundException, IOException, FHIRException;
int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws FileNotFoundException, IOException, FHIRException;
/**
* Load relevant resources of the appropriate types (as specified by the loader) from the nominated package

View File

@ -423,16 +423,16 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
return loadFromPackageInt(pi, loader, loader == null ? defaultTypesToLoad() : loader.getTypes());
}
public static String[] defaultTypesToLoad() {
public static List<String> defaultTypesToLoad() {
// there's no penalty for listing resources that don't exist, so we just all the relevant possibilities for all versions
return new String[] {"CodeSystem", "ValueSet", "ConceptMap", "NamingSystem",
return Utilities.strings("CodeSystem", "ValueSet", "ConceptMap", "NamingSystem",
"StructureDefinition", "StructureMap",
"SearchParameter", "OperationDefinition", "CapabilityStatement", "Conformance",
"Questionnaire", "ImplementationGuide", "Measure" };
"Questionnaire", "ImplementationGuide", "Measure" );
}
@Override
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws IOException, FHIRException {
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws IOException, FHIRException {
return loadFromPackageInt(pi, loader, types);
}
@ -457,7 +457,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
}
public int loadFromPackageInt(NpmPackage pi, IContextResourceLoader loader, String... types) throws IOException, FHIRException {
public int loadFromPackageInt(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws IOException, FHIRException {
int t = 0;
if (progress) {
System.out.println("Load Package "+pi.name()+"#"+pi.version());
@ -471,13 +471,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
packageTracker.packageLoaded(pi.id(), pi.version());
}
if ((types == null || types.length == 0) && loader != null) {
if ((types == null || types.size() == 0) && loader != null) {
types = loader.getTypes();
}
if (VersionUtilities.isR2Ver(pi.fhirVersion()) || !pi.canLazyLoad() || !allowLazyLoading) {
// can't lazy load R2 because of valueset/codesystem implementation
if (types.length == 0) {
types = new String[] { "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" };
if (types == null || types.size() == 0) {
types = Utilities.strings("StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" );
}
for (String s : pi.listResources(types)) {
try {
@ -488,8 +488,8 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
}
}
} else {
if (types.length == 0) {
types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem", "Measures" };
if (types == null || types.size() == 0) {
types = Utilities.strings("StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem", "Measures" );
}
for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
if (!pri.getFilename().contains("ig-r4")) {

View File

@ -77,7 +77,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class Element extends Base {
public enum SpecialElement {
CONTAINED, BUNDLE_ENTRY, BUNDLE_OUTCOME, PARAMETER, LOGICAL;
CONTAINED, BUNDLE_ENTRY, BUNDLE_OUTCOME, BUNDLE_ISSUES, PARAMETER, LOGICAL;
public static SpecialElement fromProperty(Property property) {
if (property.getStructure().getType().equals("Parameters"))
@ -86,6 +86,8 @@ public class Element extends Base {
return BUNDLE_ENTRY;
if (property.getStructure().getType().equals("Bundle") && property.getName().equals("outcome"))
return BUNDLE_OUTCOME;
if (property.getStructure().getType().equals("Bundle") && property.getName().equals("issues"))
return BUNDLE_ISSUES;
if (property.getName().equals("contained"))
return CONTAINED;
if (property.getStructure().getKind() == StructureDefinitionKind.LOGICAL)
@ -97,6 +99,7 @@ public class Element extends Base {
switch (this) {
case BUNDLE_ENTRY: return "entry";
case BUNDLE_OUTCOME: return "outcome";
case BUNDLE_ISSUES: return "issues";
case CONTAINED: return "contained";
case PARAMETER: return "parameter";
case LOGICAL: return "logical";

View File

@ -249,10 +249,12 @@ public class Property {
* @param E.g. "integer"
*/
public boolean isPrimitive(String code) {
return TypesUtilities.isPrimitive(code);
// was this... but this can be very inefficient compared to hard coding the list
// StructureDefinition sd = context.fetchTypeDefinition(code);
// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
if (Utilities.isAbsoluteUrl(code)) {
StructureDefinition sd = context.fetchTypeDefinition(code);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
} else {
return TypesUtilities.isPrimitive(code);
}
}
public boolean isPrimitive() {

View File

@ -472,6 +472,8 @@ public class TurtleParser extends ParserBase {
en = "resource";
else if (element.getSpecial() == SpecialElement.BUNDLE_OUTCOME)
en = "outcome";
else if (element.getSpecial() == SpecialElement.BUNDLE_ISSUES)
en = "issues";
else if (element.getSpecial() == SpecialElement.PARAMETER)
en = element.getElementProperty().getDefinition().getPath();
else // CONTAINED

View File

@ -303,7 +303,7 @@ public class Narrative extends BaseNarrative implements INarrative {
public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException {
switch (hash) {
case -892481550: /*status*/ return this.status == null ? new Base[0] : new Base[] {this.status}; // Enumeration<NarrativeStatus>
case 99473: /*div*/ return this.div == null ? new Base[0] : new Base[] {new StringType(new org.hl7.fhir.utilities.xhtml.XhtmlComposer(true).composeEx(this.div))}; // XhtmlNode
case 99473: /*div*/ return this.div == null ? new Base[0] : new Base[] {new XhtmlType(this)}; // XhtmlNode
default: return super.getProperty(hash, name, checkValid);
}
@ -318,6 +318,7 @@ public class Narrative extends BaseNarrative implements INarrative {
return value;
case 99473: // div
this.div = TypeConvertor.castToXhtml(value); // XhtmlNode
((XhtmlType) value).setPlace(this);
return value;
default: return super.setProperty(hash, name, value);
}

View File

@ -707,13 +707,17 @@ public class ResourceFactory extends Factory {
case -330210563: return new RelatedArtifact();
case 1824308900: return new SampledData();
case -1217415016: return new Signature();
case -1789797270: return new Timing();
case -1789797270: return new Timing();
case 770498827: return new TriggerDefinition();
case 1071332590: return new UsageContext();
case 1218149947: return new VirtualServiceDetail();
default:
throw new FHIRException("Unknown Resource or Type Name '"+name+"'");
if (name.equals("xhtml")) {
return new XhtmlType();
} else {
throw new FHIRException("Unknown Resource or Type Name '"+name+"'");
}
}
}

View File

@ -133,6 +133,14 @@ public class XhtmlType extends PrimitiveType<String> {
protected String parse(String theValue) {
return theValue;
}
public Narrative getPlace() {
return place;
}
public void setPlace(Narrative place) {
this.place = place;
}
}

View File

@ -16,9 +16,9 @@ import org.hl7.fhir.utilities.npm.NpmPackage;
public class TestPackageLoader implements IContextResourceLoader {
private String[] types;
private List<String> types;
public TestPackageLoader(String[] types) {
public TestPackageLoader(List<String> types) {
this.types = types;
}
@ -33,7 +33,7 @@ public class TestPackageLoader implements IContextResourceLoader {
}
@Override
public String[] getTypes() {
public List<String> getTypes() {
return types;
}

View File

@ -126,12 +126,12 @@ public class TestingUtilities extends BaseTestingUtilities {
if (!fcontext.hasPackage("hl7.terminology.r5", null)) {
NpmPackage utg = pcm.loadPackage("hl7.terminology.r5");
System.out.println("Loading THO: "+utg.name()+"#"+utg.version());
fcontext.loadFromPackage(utg, new TestPackageLoader(new String[]{"CodeSystem", "ValueSet"}));
fcontext.loadFromPackage(utg, new TestPackageLoader(Utilities.strings("CodeSystem", "ValueSet")));
}
if (!fcontext.hasPackage("hl7.fhir.uv.extensions", null)) {
NpmPackage ext = pcm.loadPackage("hl7.fhir.uv.extensions", "current");
System.out.println("Loading Extensions: "+ext.name()+"#"+ext.version());
fcontext.loadFromPackage(ext, new TestPackageLoader(new String[]{"CodeSystem", "ValueSet", "StructureDefinition"}));
fcontext.loadFromPackage(ext, new TestPackageLoader(Utilities.strings("CodeSystem", "ValueSet", "StructureDefinition")));
}
R5Hacker.fixR5BrokenResources(fcontext);
return fcontext;

View File

@ -2347,7 +2347,7 @@ public class FHIRPathEngine {
return makeBoolean(!res);
}
private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"};
private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url", "xhtml"};
private List<Base> opLessThan(List<Base> left, List<Base> right, ExpressionNode expr) throws FHIRException {
if (left.size() == 0 || right.size() == 0)

View File

@ -115,6 +115,7 @@ public class StructureMapUtilities {
private ValidationOptions terminologyServiceOptions = new ValidationOptions();
private final ProfileUtilities profileUtilities;
private boolean exceptionsForChecks = true;
private boolean debug;
public StructureMapUtilities(IWorkerContext worker, ITransformerServices services, ProfileKnowledgeProvider pkp) {
super();
@ -1217,10 +1218,12 @@ public class StructureMapUtilities {
}
private void log(String cnt) {
if (getServices() != null)
getServices().log(cnt);
else
System.out.println(cnt);
if (debug) {
if (getServices() != null)
getServices().log(cnt);
else
System.out.println(cnt);
}
}
/**
@ -1308,7 +1311,7 @@ public class StructureMapUtilities {
if (source != null) {
for (Variables v : source) {
for (StructureMapGroupRuleTargetComponent t : rule.getTarget()) {
processTarget(rule.getName(), context, v, map, group, t, rule.getSource().size() == 1 ? rule.getSourceFirstRep().getVariable() : null, atRoot, vars);
processTarget(map.getName()+"|"+group.getName()+"|"+rule.getName(), context, v, map, group, t, rule.getSource().size() == 1 ? rule.getSourceFirstRep().getVariable() : null, atRoot, vars);
}
if (rule.hasRule()) {
for (StructureMapGroupRuleComponent childrule : rule.getRule()) {
@ -1320,7 +1323,9 @@ public class StructureMapUtilities {
}
} else if (rule.getSource().size() == 1 && rule.getSourceFirstRep().hasVariable() && rule.getTarget().size() == 1 && rule.getTargetFirstRep().hasVariable() && rule.getTargetFirstRep().getTransform() == StructureMapTransform.CREATE && !rule.getTargetFirstRep().hasParameter()) {
// simple inferred, map by type
System.out.println(v.summary());
if (debug) {
log(v.summary());
}
Base src = v.get(VariableMode.INPUT, rule.getSourceFirstRep().getVariable());
Base tgt = v.get(VariableMode.OUTPUT, rule.getTargetFirstRep().getVariable());
String srcType = src.fhirType();
@ -1702,18 +1707,18 @@ public class StructureMapUtilities {
return type.equals(item.fhirType());
}
private void processTarget(String ruleId, TransformContext context, Variables vars, StructureMap map, StructureMapGroupComponent group, StructureMapGroupRuleTargetComponent tgt, String srcVar, boolean atRoot, Variables sharedVars) throws FHIRException {
private void processTarget(String rulePath, TransformContext context, Variables vars, StructureMap map, StructureMapGroupComponent group, StructureMapGroupRuleTargetComponent tgt, String srcVar, boolean atRoot, Variables sharedVars) throws FHIRException {
Base dest = null;
if (tgt.hasContext()) {
dest = vars.get(VariableMode.OUTPUT, tgt.getContext());
if (dest == null)
throw new FHIRException("Rule \"" + ruleId + "\": target context not known: " + tgt.getContext());
throw new FHIRException("Rule \"" + rulePath + "\": target context not known: " + tgt.getContext());
if (!tgt.hasElement())
throw new FHIRException("Rule \"" + ruleId + "\": Not supported yet");
throw new FHIRException("Rule \"" + rulePath + "\": Not supported yet");
}
Base v = null;
if (tgt.hasTransform()) {
v = runTransform(ruleId, context, map, group, tgt, vars, dest, tgt.getElement(), srcVar, atRoot);
v = runTransform(rulePath, context, map, group, tgt, vars, dest, tgt.getElement(), srcVar, atRoot);
if (v != null && dest != null)
v = dest.setProperty(tgt.getElement().hashCode(), tgt.getElement(), v); // reset v because some implementations may have to rewrite v when setting the value
} else if (dest != null) {
@ -1731,7 +1736,7 @@ public class StructureMapUtilities {
vars.add(VariableMode.OUTPUT, tgt.getVariable(), v);
}
private Base runTransform(String ruleId, TransformContext context, StructureMap map, StructureMapGroupComponent group, StructureMapGroupRuleTargetComponent tgt, Variables vars, Base dest, String element, String srcVar, boolean root) throws FHIRException {
private Base runTransform(String rulePath, TransformContext context, StructureMap map, StructureMapGroupComponent group, StructureMapGroupRuleTargetComponent tgt, Variables vars, Base dest, String element, String srcVar, boolean root) throws FHIRException {
try {
switch (tgt.getTransform()) {
case CREATE:
@ -1755,7 +1760,7 @@ public class StructureMapUtilities {
}
}
}
Base res = services != null ? services.createType(context.getAppInfo(), tn) : ResourceFactory.createResourceOrType(tn);
Base res = services != null ? services.createType(context.getAppInfo(), tn) : typeFactory(tn);
if (res.isResource() && !res.fhirType().equals("Parameters")) {
// res.setIdBase(tgt.getParameter().size() > 1 ? getParamString(vars, tgt.getParameter().get(0)) : UUID.randomUUID().toString().toLowerCase());
if (services != null)
@ -1776,7 +1781,7 @@ public class StructureMapUtilities {
if (v.size() == 0)
return null;
else if (v.size() != 1)
throw new FHIRException("Rule \"" + ruleId + "\": Evaluation of " + expr.toString() + " returned " + v.size() + " objects");
throw new FHIRException("Rule \"" + rulePath+ "\": Evaluation of " + expr.toString() + " returned " + v.size() + " objects");
else
return v.get(0);
@ -1790,7 +1795,7 @@ public class StructureMapUtilities {
}
return new StringType(src);
case ESCAPE:
throw new Error("Rule \"" + ruleId + "\": Transform " + tgt.getTransform().toCode() + " not supported yet");
throw new Error("Rule \"" + rulePath + "\": Transform " + tgt.getTransform().toCode() + " not supported yet");
case CAST:
src = getParamString(vars, tgt.getParameter().get(0));
if (tgt.getParameter().size() == 1)
@ -1849,9 +1854,9 @@ public class StructureMapUtilities {
case REFERENCE:
Base b = getParam(vars, tgt.getParameter().get(0));
if (b == null)
throw new FHIRException("Rule \"" + ruleId + "\": Unable to find parameter " + ((IdType) tgt.getParameter().get(0).getValue()).asStringValue());
throw new FHIRException("Rule \"" + rulePath + "\": Unable to find parameter " + ((IdType) tgt.getParameter().get(0).getValue()).asStringValue());
if (!b.isResource())
throw new FHIRException("Rule \"" + ruleId + "\": Transform engine cannot point at an element of type " + b.fhirType());
throw new FHIRException("Rule \"" + rulePath + "\": Transform engine cannot point at an element of type " + b.fhirType());
else {
String id = b.getIdBase();
if (id == null) {
@ -1861,7 +1866,7 @@ public class StructureMapUtilities {
return new StringType(b.fhirType() + "/" + id);
}
case DATEOP:
throw new Error("Rule \"" + ruleId + "\": Transform " + tgt.getTransform().toCode() + " not supported yet");
throw new Error("Rule \"" + rulePath + "\": Transform " + tgt.getTransform().toCode() + " not supported yet");
case UUID:
return new IdType(UUID.randomUUID().toString());
case POINTER:
@ -1869,7 +1874,7 @@ public class StructureMapUtilities {
if (b instanceof Resource)
return new UriType("urn:uuid:" + ((Resource) b).getId());
else
throw new FHIRException("Rule \"" + ruleId + "\": Transform engine cannot point at an element of type " + b.fhirType());
throw new FHIRException("Rule \"" + rulePath + "\": Transform engine cannot point at an element of type " + b.fhirType());
case CC:
CodeableConcept cc = new CodeableConcept();
cc.addCoding(buildCoding(getParamStringNoNull(vars, tgt.getParameter().get(0), tgt.toString()), getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString())));
@ -1878,10 +1883,28 @@ public class StructureMapUtilities {
Coding c = buildCoding(getParamStringNoNull(vars, tgt.getParameter().get(0), tgt.toString()), getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString()));
return c;
default:
throw new Error("Rule \"" + ruleId + "\": Transform Unknown: " + tgt.getTransform().toCode());
throw new Error("Rule \"" + rulePath + "\": Transform Unknown: " + tgt.getTransform().toCode());
}
} catch (Exception e) {
throw new FHIRException("Exception executing transform " + tgt.toString() + " on Rule \"" + ruleId + "\": " + e.getMessage(), e);
throw new FHIRException("Exception executing transform " + tgt.toString() + " on Rule \"" + rulePath + "\": " + e.getMessage(), e);
}
}
private Base typeFactory(String tn) {
if (Utilities.isAbsoluteUrl(tn) && !tn.startsWith("http://hl7.org/fhir/StructureDefinition")) {
StructureDefinition sd = worker.fetchTypeDefinition(tn);
if (sd == null) {
if (Utilities.existsInList(tn, "http://hl7.org/fhirpath/System.String")) {
sd = worker.fetchTypeDefinition("string");
}
}
if (sd == null) {
throw new FHIRException("Unable to create type "+tn);
} else {
return Manager.build(worker, sd);
}
} else {
return ResourceFactory.createResourceOrType(tn);
}
}
@ -2787,4 +2810,12 @@ public class StructureMapUtilities {
}
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}

View File

@ -22,6 +22,7 @@ import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
import org.hl7.fhir.r5.profilemodel.PEInstance.PEInstanceDataKind;
import org.hl7.fhir.r5.test.utils.TestPackageLoader;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.junit.jupiter.api.Assertions;
@ -38,7 +39,7 @@ public class PETests {
ctxt = TestingUtilities.getSharedWorkerContext();
FilesystemPackageCacheManager pc = new FilesystemPackageCacheManager(true);
NpmPackage npm = pc.loadPackage("hl7.fhir.us.core", "5.0.0");
ctxt.loadFromPackage(npm, new TestPackageLoader(new String[] { "StructureDefinition" }));
ctxt.loadFromPackage(npm, new TestPackageLoader(Utilities.strings("StructureDefinition" )));
ctxt.cacheResource(new JsonParser().parse(TestingUtilities.loadTestResource("r5", "profiles", "pe-extension-simple.json")));
ctxt.cacheResource(new JsonParser().parse(TestingUtilities.loadTestResource("r5", "profiles", "pe-extension-complex.json")));

View File

@ -215,7 +215,7 @@ public class NarrativeGenerationTests {
context = TestingUtilities.getSharedWorkerContext("5.0.0");
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true);
NpmPackage ips = pcm.loadPackage("hl7.fhir.uv.ips#1.1.0");
context.loadFromPackage(ips, new TestPackageLoader(new String[] { "StructureDefinition", "ValueSet" }));
context.loadFromPackage(ips, new TestPackageLoader(Utilities.strings("StructureDefinition", "ValueSet" )));
}
@ParameterizedTest(name = "{index}: file {0}")

View File

@ -536,7 +536,7 @@ public class SnapShotGenerationTests {
pu.setAllowUnknownProfile(test.allow);
if (!TestingUtilities.getSharedWorkerContext().hasPackage(CommonPackages.ID_XVER, CommonPackages.VER_XVER)) {
NpmPackage npm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION).loadPackage(CommonPackages.ID_XVER, CommonPackages.VER_XVER);
TestingUtilities.getSharedWorkerContext().loadFromPackage(npm, new TestPackageLoader(new String[]{"StructureDefinition"}), new String[]{"StructureDefinition"});
TestingUtilities.getSharedWorkerContext().loadFromPackage(npm, new TestPackageLoader(Utilities.strings("StructureDefinition")), Utilities.strings("StructureDefinition"));
}
pu.setXver(new XVerExtensionManager(TestingUtilities.getSharedWorkerContext()));
if (test.isSort()) {

View File

@ -1994,6 +1994,14 @@ public class Utilities {
}
}
public static List<String> strings(String... members) {
List<String> ret = new ArrayList<>();
for (String m : members) {
ret.add(m);
}
return ret;
}
//public static boolean !isWhitespace(String s) {

View File

@ -850,6 +850,7 @@ public class I18nConstants {
public static final String CONCEPTMAP_GROUP_SOURCE_INCOMPLETE = "CONCEPTMAP_GROUP_SOURCE_INCOMPLETE";
public static final String CONCEPTMAP_GROUP_TARGET_INCOMPLETE = "CONCEPTMAP_GROUP_TARGET_INCOMPLETE";
public static final String UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE = "UNABLE_TO_RESOLVE_SYSTEM_SYSTEM_IS_INDETERMINATE";
public static final String SD_NO_TYPE_CODE_ON_CODE = "SD_NO_TYPE_CODE_ON_CODE";
}

View File

@ -548,9 +548,13 @@ public class NpmPackage {
}
public List<String> listResources(String... types) throws IOException {
return listResources(Utilities.strings(types));
}
public List<String> listResources(List<String> types) throws IOException {
List<String> res = new ArrayList<String>();
NpmPackageFolder folder = folders.get("package");
if (types.length == 0) {
if (types.size() == 0) {
for (String s : folder.types.keySet()) {
if (folder.types.containsKey(s)) {
res.addAll(folder.types.get(s));
@ -568,6 +572,10 @@ public class NpmPackage {
}
public List<PackageResourceInformation> listIndexedResources(String... types) throws IOException {
return listIndexedResources(Utilities.strings(types));
}
public List<PackageResourceInformation> listIndexedResources(List<String> types) throws IOException {
List<PackageResourceInformation> res = new ArrayList<PackageResourceInformation>();
for (NpmPackageFolder folder : folders.values()) {
if (folder.index != null) {

View File

@ -837,4 +837,8 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
}
return this;
}
public boolean isError() {
return level == IssueSeverity.ERROR || level == IssueSeverity.FATAL;
}
}

View File

@ -508,15 +508,14 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
try {
XhtmlDocument fragment = new XhtmlParser().parse(val, "div");
this.attributes = fragment.attributes;
this.childNodes = fragment.childNodes;
// Strip the <? .. ?> declaration if one was present
if (childNodes.size() > 0 && childNodes.get(0) != null && childNodes.get(0).getNodeType() == NodeType.Instruction) {
childNodes.remove(0);
}
this.content = fragment.getContent();
this.name = fragment.getName();
this.nodeType= fragment.getNodeType();
// Skip the <? .. ?> declaration if one was present
XhtmlNodeList nodes = fragment.getChildNodes();
XhtmlNode root = nodes.get((nodes.size() > 0 && nodes.get(0) != null && nodes.get(0).getNodeType() == NodeType.Instruction) ? 1 : 0);
this.attributes = root.attributes;
this.childNodes = root.childNodes;
this.content = root.getContent();
this.name = root.getName();
this.nodeType= root.getNodeType();
} catch (Exception e) {
// TODO: composer shouldn't throw exception like this
throw new RuntimeException(e);

View File

@ -899,4 +899,7 @@ CONCEPTMAP_GROUP_TARGET_PROPERTY_CODE_INVALID = The code {0} is invalid in the s
CONCEPTMAP_GROUP_TARGET_PROPERTY_TYPE_UNKNOWN_SYSTEM = The system {0} is unknown, so code values can''t be checked
SM_DEPENDENT_PARAM_TYPE_MISMATCH_DUPLICATE = The group {0} has alr
CONCEPTMAP_GROUP_SOURCE_INCOMPLETE = Source Code System {0} doesn''t have all content (content = {1}), so the source codes cannot be checked
CONCEPTMAP_GROUP_TARGET_INCOMPLETE = Target Code System {0} doesn''t have all content (content = {1}), so the source codes cannot be checked
CONCEPTMAP_GROUP_TARGET_INCOMPLETE = Target Code System {0} doesn''t have all content (content = {1}), so the source codes cannot be checked
SD_NO_TYPE_CODE_ON_CODE = Snapshot for {1} element {0} has type.code without a value

View File

@ -1,12 +1,15 @@
package org.hl7.fhir.validation;
import java.io.File;
import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.hl7.fhir.convertors.loaders.loaderR5.R4BToR5Loader;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -72,6 +75,7 @@ import org.hl7.fhir.utilities.FileFormat;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.json.JsonException;
import org.hl7.fhir.utilities.npm.CommonPackages;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ComparisonService;
@ -79,6 +83,7 @@ import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.Display;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import org.hl7.fhir.validation.cli.utils.Params;
import org.hl7.fhir.validation.special.R4R5MapTester;
import org.hl7.fhir.validation.testexecutor.TestExecutor;
import org.hl7.fhir.validation.testexecutor.TestExecutorParams;
@ -132,13 +137,28 @@ public class ValidatorCli {
}
} else if (Params.hasParam(args, Params.TEST)) {
parseTestParamsAndExecute(args);
}
else {
} else if (Params.hasParam(args, Params.SPECIAL)) {
executeSpecial(args);
} else {
Display.printCliArgumentsAndInfo(args);
doValidation(tt, tts, cliContext);
}
}
private static void executeSpecial(String[] args) throws JsonException, IOException {
String specialMode = Params.getParam(args, Params.SPECIAL);
if ("r4r5tests".equals(specialMode)) {
final String target = Params.getParam(args, Params.TARGET);
final String source = Params.getParam(args, Params.SOURCE);
final String filter = Params.getParam(args, Params.FILTER);
if (new File(target).exists()) {
new R4R5MapTester().testMaps(target, source, filter);
}
} else {
System.out.println("Unknown SpecialMode "+specialMode);
}
}
private static void setJavaSystemProxyParamsFromParams(String[] args) {
setJavaSystemProxyHostFromParams(args, Params.PROXY, HTTP_PROXY_HOST, HTTP_PROXY_PORT);

View File

@ -51,23 +51,23 @@ public class ValidatorUtils {
if (Utilities.noString(version)) {
return null;
}
if (VersionUtilities.isR2Ver(version)) {
return new R2ToR5Loader(new String[]{"Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
if (VersionUtilities.isR2Ver(version)) {
return new R2ToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5());
}
if (VersionUtilities.isR2BVer(version)) {
return new R2016MayToR5Loader(new String[]{"Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5()); // special case
return new R2016MayToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5()); // special case
}
if (VersionUtilities.isR3Ver(version)) {
return new R3ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
return new R3ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5());
}
if (VersionUtilities.isR4Ver(version)) {
return new R4ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5(), version);
return new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5(), version);
}
if (VersionUtilities.isR4BVer(version)) {
return new R4BToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5(), version);
return new R4BToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5(), version);
}
if (VersionUtilities.isR5Ver(version)) {
return new R5ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
return new R5ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5());
}
return null;
}

View File

@ -83,6 +83,10 @@ public class Params {
public static final String TEST_MODULES = "-test-modules";
public static final String TEST_NAME_FILTER = "-test-classname-filter";
public static final String SPECIAL = "-special";
public static final String TARGET = "-target";
public static final String SOURCE = "-source";
public static final String FILTER = "-filter";
/**
* Checks the list of passed in params to see if it contains the passed in param.

View File

@ -2545,7 +2545,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.XHTML_NS.equals(ns), I18nConstants.XHTML_XHTML_NS_INVALID, ns, FormatUtilities.XHTML_NS) && ok;
// check that inner namespaces are all correct
checkInnerNS(errors, e, path, xhtml.getChildNodes());
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "div".equals(xhtml.getName()), I18nConstants.XHTML_XHTML_NAME_INVALID, ns) && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, "div".equals(xhtml.getName()), I18nConstants.XHTML_XHTML_NAME_INVALID, xhtml.getName()) && ok;
// check that no illegal elements and attributes have been used
ok = checkInnerNames(errors, e, path, xhtml.getChildNodes(), false) && ok;
ok = checkUrls(errors, e, path, xhtml.getChildNodes()) && ok;
@ -5179,7 +5179,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (containedValidationPolicy.checkValid()) {
// special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise
ValidatorHostContext hc = null;
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.BUNDLE_ISSUES || special == SpecialElement.PARAMETER) {
resource = element;
assert Utilities.existsInList(hostContext.getResource().fhirType(), "Bundle", "Parameters") : "Containing Resource is "+hostContext.getResource().fhirType()+", expected Bundle or Parameters at "+stack.getLiteralPath();
hc = hostContext.forEntry(element, hostContext.getResource()); // root becomes the grouping resource (should be either bundle or parameters)
@ -5531,7 +5531,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean checkDisplay = true;
SpecialElement special = ei.getElement().getSpecial();
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.BUNDLE_ISSUES || special == SpecialElement.PARAMETER) {
ok = checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false) && ok;
} else {
ok = checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, false) && ok;

View File

@ -169,7 +169,7 @@ public class StructureDefinitionValidator extends BaseValidator {
}
if (Utilities.noString(tc) && type.hasChild("code")) {
if (VersionUtilities.isR4Plus(context.getVersion())) {
throw new Error("Snapshot for " + sd.getId() +" element " + path + " has type.code without a value ");
rule(errors, "2023-03-16", IssueType.INVALID, stack.getLiteralPath(), false, I18nConstants.SD_NO_TYPE_CODE_ON_CODE, path, sd.getId());
}
}
if (!Utilities.noString(tc)) {

View File

@ -2,14 +2,24 @@ package org.hl7.fhir.validation.special;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.ResourceFactory;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureMap;
@ -18,17 +28,19 @@ import org.hl7.fhir.convertors.loaders.loaderR5.R4ToR5Loader;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.ResourceFactory;
import org.hl7.fhir.r4.test.utils.TestingUtilities;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r5.context.SimpleWorkerContext.SimpleWorkerContextBuilder;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.r5.utils.structuremap.VariableMode;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -39,11 +51,13 @@ import org.hl7.fhir.utilities.json.model.JsonProperty;
import org.hl7.fhir.utilities.json.parser.JsonParser;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.validation.IgLoader;
import org.hl7.fhir.validation.ValidatorUtils;
import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.validation.special.R4R5MapTester.Stats;
public class R4R5MapTester {
public class R4R5MapTester implements IValidatorResourceFetcher {
public class Stats {
@ -51,6 +65,9 @@ public class R4R5MapTester {
private int total;
private int parsed;
private int forward;
private int validated;
private int error;
private int back;
public void example() {
total++;
@ -76,6 +93,22 @@ public class R4R5MapTester {
return parsed;
}
public int forwardCount() {
return forward;
}
public int validatedCount() {
return validated;
}
public int errorCount() {
return error;
}
public int backCount() {
return back;
}
public String summary() {
if (errors.size() == 0) {
return "All OK";
@ -87,22 +120,36 @@ public class R4R5MapTester {
public boolean ok() {
return errors.size() == 0;
}
public void valid(boolean valid) {
validated++;
if (!valid) {
error++;
}
}
public void back() {
back++;
}
}
private boolean saveProcess = false;
private boolean saveProcess = true;
private SimpleWorkerContext context;
private FilesystemPackageCacheManager pcm;
private StructureMapUtilities utils;
private List<StructureMap> allMaps;
private InstanceValidator validator;
public static void main(String[] args) throws JsonException, IOException {
// arg[0] is the location of the fhir-extensions repo
new R4R5MapTester().testMaps(args[0]);
new R4R5MapTester().testMaps(args[0], args[1], args[2]);
}
public void testMaps(String src) throws JsonException, IOException {
public void testMaps(String src, String maps, String filter) throws JsonException, IOException {
log("Load Test Outcomes");
JsonObject json = JsonParser.parseObjectFromFile(Utilities.path(src, "input", "_data", "conversions.json"));
log("Load R5");
@ -111,17 +158,37 @@ public class R4R5MapTester {
log("Load Maps");
// context.loadFromPackage(pcm.loadPackage(), null);
loadPackage("hl7.fhir.uv.extensions#dev");
loadPackage("hl7.fhir.r4.core#4.0.1");
loadPackage("hl7.fhir.r4b.core#4.3.0");
loadPackage("hl7.terminology.r5#5.0.0", false);
utils = new StructureMapUtilities(context);
utils.setDebug(false);
loadPackage("hl7.fhir.uv.extensions#dev", maps == null);
if (maps != null) {
loadFromFolder(Utilities.path(maps, "r4-2-r5"));
loadFromFolder(Utilities.path(maps, "r4b-2-r5"));
loadFromFolder(Utilities.path(maps, "r5-2-r4"));
loadFromFolder(Utilities.path(maps, "r5-2-r4b"));
}
loadPackage("hl7.fhir.r4.core#4.0.1", false);
loadPackage("hl7.fhir.r4b.core#4.3.0", false);
validator = new InstanceValidator(context, null, null);
validator.setSuppressLoincSnomedMessages(true);
validator.setResourceIdRule(IdStatus.REQUIRED);
validator.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
validator.getExtensionDomains().add("http://hl7.org/fhir/us");
validator.setFetcher(this);
validator.setAllowExamples(true);
validator.setDebug(false);
validator.setForPublication(true);
validator.setNoTerminologyChecks(true);
context.setExpansionProfile(new Parameters());
log("Load R4 Examples");
NpmPackage r4Examples = pcm.loadPackage("hl7.fhir.r4.examples");
log("Load R4B Examples");
NpmPackage r4bExamples = pcm.loadPackage("hl7.fhir.r4b.examples");
utils = new StructureMapUtilities(context);
allMaps = context.fetchResourcesByType(StructureMap.class);
log("Go. "+context.getResourceNames().size()+" types of resources");
@ -129,17 +196,19 @@ public class R4R5MapTester {
boolean changed = false;
for (JsonProperty jp : json.getProperties()) {
String rn = jp.getName();
log(" "+rn);
JsonObject o = json.getJsonObject(rn);
StructureDefinition sd = context.fetchTypeDefinition(rn);
List<StructureMap> mapSrc = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.SOURCE);
List<StructureMap> mapTgt = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.TARGET);
changed = checkMaps(sd, o.getJsonObject("r4"), "http://hl7.org/fhir/4.0", mapSrc, mapTgt, r4Examples) || changed;
changed = checkMaps(sd, o.getJsonObject("r4b"), "http://hl7.org/fhir/4.3", mapSrc, mapTgt, r4bExamples) || changed;
}
if (changed) {
JsonParser.compose(json, new FileOutputStream(Utilities.path(src, "input", "_data", "conversions.json")), true);
if ("*".equals(filter) || rn.equals(filter)) {
log(" "+rn);
JsonObject o = json.getJsonObject(rn);
StructureDefinition sd = context.fetchTypeDefinition(rn);
List<StructureMap> mapSrc = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.SOURCE);
List<StructureMap> mapTgt = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.TARGET);
changed = checkMaps(sd, o.getJsonObject("r4"), "r4", "http://hl7.org/fhir/4.0", mapSrc, mapTgt, r4Examples) || changed;
changed = checkMaps(sd, o.getJsonObject("r4b"), "r4b", "http://hl7.org/fhir/4.3", mapSrc, mapTgt, r4bExamples) || changed;
JsonParser.compose(json, new FileOutputStream(Utilities.path(src, "input", "_data", "conversions.json")), true);
System.out.println(" .. done");
}
}
log("Done!");
// load R4
// load R4B
// load the maps
@ -157,15 +226,31 @@ public class R4R5MapTester {
}
private void loadPackage(String pid) throws FHIRException, IOException {
private void loadFromFolder(String path) throws FHIRFormatError, FHIRException, FileNotFoundException, IOException {
log("Load "+path);
for (File f : new File(path).listFiles()) {
if (f.getName().endsWith(".json")) {
context.cacheResource(new org.hl7.fhir.r5.formats.JsonParser().parse(new FileInputStream(f)));
}
if (f.getName().endsWith(".fml")) {
context.cacheResource(utils.parse(TextFile.fileToString(f), f.getName()));
}
}
}
private void loadPackage(String pid, boolean loadMaps) throws FHIRException, IOException {
log("Load "+pid);
NpmPackage npm = pcm.loadPackage(pid);
IContextResourceLoader loader = ValidatorUtils.loaderForVersion(npm.fhirVersion());
if (!loadMaps && loader.getTypes().contains("StructureMap")) {
loader.getTypes().remove("StructureMap");
}
loader.setPatchUrls(VersionUtilities.isCorePackage(npm.id()));
int count = context.loadFromPackage(npm, loader);
context.loadFromPackage(npm, loader);
}
private boolean checkMaps(StructureDefinition sd, JsonObject json, String ns, List<StructureMap> mapSrc, List<StructureMap> mapTgt, NpmPackage examples) throws IOException {
private boolean checkMaps(StructureDefinition sd, JsonObject json, String code, String ns, List<StructureMap> mapSrc, List<StructureMap> mapTgt, NpmPackage examples) throws IOException {
List<StructureMap> src = utils.getMapsForUrlPrefix(mapSrc, ns, StructureMapInputMode.TARGET);
List<StructureMap> tgt = utils.getMapsForUrlPrefix(mapTgt, ns, StructureMapInputMode.SOURCE);
if (src.size() + tgt.size() == 0) {
@ -199,7 +284,7 @@ public class R4R5MapTester {
if (tsd == null) {
json.set("testMessage", "Undefined type "+srcU);
} else {
testRoundTrips(sd, json, tgtG, srcG, tsd, examples);
testRoundTrips(sd, json, tgtG, srcG, tsd, examples, code);
}
}
} else {
@ -213,41 +298,85 @@ public class R4R5MapTester {
return true;
}
private void testRoundTrips(StructureDefinition sd, JsonObject json, ResolvedGroup tgtG, ResolvedGroup srcG, StructureDefinition tsd, NpmPackage examples) throws IOException {
private void testRoundTrips(StructureDefinition sd, JsonObject json, ResolvedGroup tgtG, ResolvedGroup srcG, StructureDefinition tsd, NpmPackage examples, String code) throws IOException {
Stats stats = new Stats();
for (String s : examples.listResources(tsd.getType())) {
log(" Test "+examples.id()+"::"+s);
try {
testRoundTrip(sd, tsd, tgtG, srcG, stats, examples.load("package", s));
testRoundTrip(json, sd, tsd, tgtG, srcG, stats, examples.load("package", s), code);
} catch (Exception e) {
log("error: "+e.getMessage());
stats.error("Error: "+e.getMessage());
}
}
json.set("total", stats.totalCount());
json.set("parsed", stats.parseCount());
json.set("totalInstances", stats.totalCount());
json.set("parsedOk", stats.parseCount());
json.set("convertToR5OK", stats.forwardCount());
json.set("testMessage", stats.summary());
json.set("r5validated", stats.validatedCount());
json.set("r5InError", stats.errorCount());
json.remove("r5validatedOK");
json.set("convertToR4OK", stats.backCount());
if (stats.ok()) {
json.set("testColor", "#d4ffdf");
}
}
private void testRoundTrip(StructureDefinition sd, StructureDefinition tsd, ResolvedGroup tgtG, ResolvedGroup srcG, Stats stats, InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
private void testRoundTrip(JsonObject json, StructureDefinition sd, StructureDefinition tsd, ResolvedGroup tgtG, ResolvedGroup srcG, Stats stats, InputStream stream, String code) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
stats.example();
Element r4 = new org.hl7.fhir.r5.elementmodel.JsonParser(context).setLogical(tsd).parseSingle(stream);
stats.parsed();
String id = r4.getIdBase();
checkSave(id, "src.loaded", r4);
json.remove(id);
checkSave(id+"."+code, "loaded", r4);
Resource r5 = ResourceFactory.createResource(sd.getType());
utils.transform(context, r4, tgtG.getTargetMap(), r4);
stats.forward();
Resource r5 = null;
try {
r5 = ResourceFactory.createResource(sd.getType());
utils.transform(context, r4, tgtG.getTargetMap(), r5);
stats.forward();
checkSave(id+"."+code,"converted", r5);
} catch (Exception e) {
json.forceObject(id).set("conversion-error", e.getMessage());
throw e;
}
try {
List<ValidationMessage> r5validationErrors = new ArrayList<ValidationMessage>();
validator.validate(null, r5validationErrors, r5);
boolean valid = true;
for (ValidationMessage vm : r5validationErrors) {
if (vm.isError()) {
// json.forceObject(id).forceArray("r5-errors").add(vm.summary());
valid = false;
}
}
stats.valid(valid);
} catch (Exception e) {
json.forceObject(id).set("validation-error", e.getMessage());
throw e;
}
try {
Element rt4 = Manager.build(context, tsd);
utils.transform(context, r5, srcG.getTargetMap(), rt4);
stats.back();
checkSave(id+"."+code, "returned", r4);
} catch (Exception e) {
json.forceObject(id).set("return-error", e.getMessage());
throw e;
}
}
private void checkSave(String id, String state, Element e) {
private void checkSave(String id, String state, Element e) throws FHIRException, FileNotFoundException, IOException {
if (saveProcess) {
// new org.hl7.fhir.r4.elementmodel.JsonParser(context).compose(r3, bso, OutputStyle.PRETTY, null);
new org.hl7.fhir.r5.elementmodel.JsonParser(context).compose(e, new FileOutputStream(Utilities.path("[tmp]", "r4r5", e.fhirType()+"-"+id+"-"+state+".json")), OutputStyle.PRETTY, id);
}
}
private void checkSave(String id, String state, Resource r) throws FHIRException, FileNotFoundException, IOException {
if (saveProcess) {
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "r4r5", r.fhirType()+"-"+id+"-"+state+".json")), r);
}
}
@ -255,4 +384,35 @@ public class R4R5MapTester {
System.out.println(msg);
}
@Override
public Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException {
return null;
}
@Override
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type)
throws IOException, FHIRException {
return true;
}
@Override
public byte[] fetchRaw(IResourceValidator validator, String url) throws IOException {
throw new Error("Not done yet");
}
@Override
public IValidatorResourceFetcher setLocale(Locale locale) {
throw new Error("Not done yet");
}
@Override
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException {
return null;
}
@Override
public boolean fetchesCanonicalResource(IResourceValidator validator, String url) {
return false;
}
}

View File

@ -114,7 +114,7 @@ public class ComparisonTests {
BaseWorkerContext bc = (BaseWorkerContext) context;
boolean dupl = bc.isAllowLoadingDuplicates();
bc.setAllowLoadingDuplicates(true);
context.loadFromPackage(npm, new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"},
context.loadFromPackage(npm, new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"),
new NullLoaderKnowledgeProviderR5(), context.getVersion()));
bc.setAllowLoadingDuplicates(dupl);
}

View File

@ -105,13 +105,13 @@ public class UtilitiesXTests {
if (Utilities.noString(version))
return null;
if (version.startsWith("1.0"))
return new R2ToR5Loader(new String[] { "Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
return new R2ToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5());
if (version.startsWith("1.4"))
return new R2016MayToR5Loader(new String[] { "Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5()); // special case
return new R2016MayToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5()); // special case
if (version.startsWith("3.0"))
return new R3ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
return new R3ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5());
if (version.startsWith("4.0"))
return new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5(), version);
return new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5(), version);
return null;
}