Work on StructureMap validation
This commit is contained in:
parent
d3a407e369
commit
2bd73c650e
|
@ -3,8 +3,21 @@ package org.hl7.fhir.convertors.loaders.loaderR5;
|
|||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.UriType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
||||
|
@ -18,12 +31,8 @@ import lombok.experimental.Accessors;
|
|||
public abstract class BaseLoaderR5 implements IContextResourceLoader {
|
||||
|
||||
protected final String URL_BASE = "http://hl7.org/fhir/";
|
||||
protected final String URL_DSTU2 = "http://hl7.org/fhir/1.0/";
|
||||
protected final String URL_DSTU2016MAY = "http://hl7.org/fhir/1.4/";
|
||||
protected final String URL_DSTU3 = "http://hl7.org/fhir/3.0/";
|
||||
protected final String URL_R4 = "http://hl7.org/fhir/4.0/";
|
||||
protected final String URL_ELEMENT_DEF_NAMESPACE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace";
|
||||
@Getter @Setter protected boolean patchUrls;
|
||||
protected boolean patchUrls;
|
||||
@Getter @Setter protected boolean killPrimitives;
|
||||
@Getter protected String[] types;
|
||||
protected ILoaderKnowledgeProviderR5 lkp;
|
||||
|
@ -73,4 +82,83 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
public boolean isPatchUrls() {
|
||||
return patchUrls;
|
||||
}
|
||||
|
||||
public void setPatchUrls(boolean patchUrls) {
|
||||
this.patchUrls = patchUrls;
|
||||
}
|
||||
|
||||
protected abstract String versionString();
|
||||
|
||||
|
||||
@Override
|
||||
public String patchUrl(String url, String type) {
|
||||
if (!patchUrls || url == null) {
|
||||
return url;
|
||||
} else if (url.startsWith("http://hl7.org/fhir/"+type+"/")) {
|
||||
return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20);
|
||||
} else if ("CodeSystem".equals(type) && url.startsWith("http://hl7.org/fhir/")) {
|
||||
return "http://hl7.org/fhir/"+versionString()+"/"+url.substring(20);
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
// we don't patch everything. It's quite hard work to do that,
|
||||
// and we only patch URLs to support version transforms
|
||||
// so we just patch sd/od -> vs -> cs
|
||||
protected void doPatchUrls(Resource resource) {
|
||||
if (resource instanceof CanonicalResource) {
|
||||
CanonicalResource cr = (CanonicalResource) resource;
|
||||
cr.setUrl(patchUrl(cr.getUrl(), cr.fhirType()));
|
||||
if (cr instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) cr;
|
||||
new ProfileUtilities(null, null, null, null).setIds(sd, false);
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
|
||||
if (cr instanceof ValueSet) {
|
||||
ValueSet vs = (ValueSet) cr;
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
||||
inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem"));
|
||||
}
|
||||
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
|
||||
inc.setSystem(patchUrl(inc.getSystem(), "CodeSystem"));
|
||||
}
|
||||
}
|
||||
if (cr instanceof OperationDefinition) {
|
||||
OperationDefinition od = (OperationDefinition) cr;
|
||||
for (OperationDefinitionParameterComponent param : od.getParameter()) {
|
||||
patchUrls(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void patchUrls(OperationDefinitionParameterComponent param) {
|
||||
if (param.hasBinding()) {
|
||||
param.getBinding().setValueSet(patchUrl(param.getBinding().getValueSet(), "ValueSet"));
|
||||
}
|
||||
for (OperationDefinitionParameterComponent p : param.getPart()) {
|
||||
patchUrls(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(patchUrl(s.getValue(), "StructureDefinitino"));
|
||||
}
|
||||
}
|
||||
if (ed.hasBinding()) {
|
||||
ed.getBinding().setValueSet(patchUrl(ed.getBinding().getValueSet(), "ValueSet"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -98,13 +98,10 @@ public class R2016MayToR5Loader extends BaseLoaderR5 {
|
|||
}
|
||||
b.getEntry().removeAll(remove);
|
||||
}
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
new ProfileUtilities(null, null, null, null).setIds(sd, false);
|
||||
if (patchUrls) {
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_DSTU2016MAY));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,33 +125,20 @@ public class R2016MayToR5Loader extends BaseLoaderR5 {
|
|||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU2016MAY));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU2016MAY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "4.3";
|
||||
}
|
||||
|
||||
}
|
|
@ -102,10 +102,8 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
}
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_DSTU2));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,30 +124,11 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU2));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
List<CodeSystem> list = new ArrayList<>();
|
||||
|
@ -160,4 +139,9 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
}
|
|
@ -99,15 +99,9 @@ public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
}
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_DSTU3));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
|
@ -130,33 +124,19 @@ public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU3));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_DSTU3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "3.0";
|
||||
}
|
||||
|
||||
}
|
|
@ -103,14 +103,8 @@ public class R4BToR5Loader extends BaseLoaderR5 implements IContextResourceLoade
|
|||
}
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,34 +131,20 @@ public class R4BToR5Loader extends BaseLoaderR5 implements IContextResourceLoade
|
|||
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType("http://hl7.org/fhir"));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "4.3";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -103,14 +103,8 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
}
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,34 +131,21 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
|||
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType("http://hl7.org/fhir"));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, "http://hl7.org/fhir/4.0/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "4.0";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -96,14 +96,8 @@ public class R5ToR5Loader extends BaseLoaderR5 {
|
|||
}
|
||||
if (patchUrls) {
|
||||
for (BundleEntryComponent be : b.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) be.getResource();
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
if (be.hasResource()) {
|
||||
doPatchUrls(be.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,34 +120,20 @@ public class R5ToR5Loader extends BaseLoaderR5 {
|
|||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||
}
|
||||
if (patchUrls) {
|
||||
if (r5 instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r5;
|
||||
sd.setUrl(sd.getUrl().replace(URL_BASE, URL_R4));
|
||||
sd.addExtension().setUrl(URL_ELEMENT_DEF_NAMESPACE).setValue(new UriType(URL_BASE));
|
||||
for (ElementDefinition ed : sd.getSnapshot().getElement())
|
||||
patchUrl(ed);
|
||||
for (ElementDefinition ed : sd.getDifferential().getElement())
|
||||
patchUrl(ed);
|
||||
}
|
||||
doPatchUrls(r5);
|
||||
}
|
||||
return r5;
|
||||
}
|
||||
|
||||
private void patchUrl(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
for (CanonicalType s : tr.getTargetProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_R4));
|
||||
}
|
||||
for (CanonicalType s : tr.getProfile()) {
|
||||
s.setValue(s.getValue().replace(URL_BASE, URL_R4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeSystem> getCodeSystems() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String versionString() {
|
||||
return "5.0";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -265,8 +265,10 @@ public class StructureMapUtilities {
|
|||
public StructureMapUtilities(IWorkerContext worker) {
|
||||
super();
|
||||
this.worker = worker;
|
||||
fpe = new FHIRPathEngine(worker);
|
||||
fpe.setHostServices(new FFHIRPathHostServices());
|
||||
if (worker != null) {
|
||||
fpe = new FHIRPathEngine(worker);
|
||||
fpe.setHostServices(new FFHIRPathHostServices());
|
||||
}
|
||||
}
|
||||
|
||||
public static String render(StructureMap map) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hl7.fhir.r5.model.NamingSystem.NamingSystemIdentifierType;
|
|||
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemUniqueIdComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r5.model.StructureMap;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
|
@ -390,5 +391,18 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
|
|||
return concreteResourceNames;
|
||||
}
|
||||
|
||||
public List<StructureMap> listMaps(String url) {
|
||||
List<StructureMap> res = new ArrayList<>();
|
||||
String start = url.substring(0, url.indexOf("*"));
|
||||
String end = url.substring(url.indexOf("*")+1);
|
||||
for (StructureMap map : context.fetchResourcesByType(StructureMap.class)) {
|
||||
String u = map.getUrl();
|
||||
if (u.startsWith(start) && u.endsWith(end)) {
|
||||
res.add(map);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -320,7 +320,23 @@ public interface IWorkerContext {
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
List<CodeSystem> getCodeSystems();
|
||||
List<CodeSystem> getCodeSystems();
|
||||
|
||||
/**
|
||||
* if this is true, then the loader will patch canonical URLs and cross-links
|
||||
* to add /X.X/ into the URL so that different versions can be loaded safely
|
||||
*
|
||||
* default is false
|
||||
*/
|
||||
void setPatchUrls(boolean value);
|
||||
|
||||
/**
|
||||
* patch the URL if necessary
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
String patchUrl(String url, String resourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,7 +97,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
private final IContextResourceLoader loader;
|
||||
|
||||
public PackageResourceLoader(PackageResourceInformation pri, IContextResourceLoader loader) {
|
||||
super(pri.getResourceType(), pri.getId(), pri.getUrl(),pri.getVersion());
|
||||
super(pri.getResourceType(), pri.getId(), loader == null ? pri.getUrl() :loader.patchUrl(pri.getUrl(), pri.getResourceType()), pri.getVersion());
|
||||
this.filename = pri.getFilename();
|
||||
this.loader = loader;
|
||||
}
|
||||
|
|
|
@ -55,18 +55,29 @@ public class FmlParser extends ParserBase {
|
|||
}
|
||||
|
||||
public Element parse(String text) throws FHIRException {
|
||||
FHIRLexer lexer = new FHIRLexer(text, "source");
|
||||
FHIRLexer lexer = new FHIRLexer(text, "source", true);
|
||||
if (lexer.done())
|
||||
throw lexer.error("Map Input cannot be empty");
|
||||
lexer.token("map");
|
||||
Element result = Manager.build(context, context.fetchTypeDefinition("StructureMap"));
|
||||
try {
|
||||
result.makeElement("url").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("url"));
|
||||
lexer.token("=");
|
||||
result.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("name"));
|
||||
if (lexer.hasComments()) {
|
||||
result.makeElement("description").markLocation(lexer.getCurrentLocation()).setValue(lexer.getAllComments());
|
||||
if (lexer.hasToken("map")) {
|
||||
lexer.token("map");
|
||||
result.makeElement("url").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("url"));
|
||||
lexer.token("=");
|
||||
result.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("name"));
|
||||
if (lexer.hasComments()) {
|
||||
result.makeElement("description").markLocation(lexer.getCurrentLocation()).setValue(lexer.getAllComments());
|
||||
}
|
||||
} else {
|
||||
while (lexer.hasToken("///")) {
|
||||
lexer.next();
|
||||
String fid = lexer.takeDottedToken();
|
||||
Element e = result.makeElement(fid).markLocation(lexer.getCurrentLocation());
|
||||
lexer.token("=");
|
||||
e.setValue(lexer.readConstant("meta value"));
|
||||
}
|
||||
}
|
||||
lexer.setMetadataFormat(false);
|
||||
while (lexer.hasToken("conceptmap"))
|
||||
parseConceptMap(result, lexer);
|
||||
|
||||
|
@ -366,7 +377,7 @@ public class FmlParser extends ParserBase {
|
|||
|
||||
private void parseRuleReference(Element rule, FHIRLexer lexer) throws FHIRLexerException {
|
||||
Element ref = rule.addElement("dependent");
|
||||
rule.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take());
|
||||
ref.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take());
|
||||
lexer.token("(");
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
|
|
|
@ -52,4 +52,14 @@ public class TestPackageLoader implements IContextResourceLoader {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPatchUrls(boolean value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String patchUrl(String url, String resourceType) {
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ public class FHIRLexer {
|
|||
private String name;
|
||||
private boolean liquidMode; // in liquid mode, || terminates the expression and hands the parser back to the host
|
||||
private SourceLocation commentLocation;
|
||||
private boolean metadataFormat;
|
||||
|
||||
public FHIRLexer(String source, String name) throws FHIRLexerException {
|
||||
this.source = source == null ? "" : source;
|
||||
|
@ -102,6 +103,13 @@ public class FHIRLexer {
|
|||
currentLocation = new SourceLocation(1, 1);
|
||||
next();
|
||||
}
|
||||
public FHIRLexer(String source, String name, boolean metadataFormat) throws FHIRLexerException {
|
||||
this.source = source == null ? "" : source;
|
||||
this.name = name == null ? "??" : name;
|
||||
this.metadataFormat = metadataFormat;
|
||||
currentLocation = new SourceLocation(1, 1);
|
||||
next();
|
||||
}
|
||||
public String getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
@ -211,10 +219,13 @@ public class FHIRLexer {
|
|||
} else if (ch == '/') {
|
||||
cursor++;
|
||||
if (cursor < source.length() && (source.charAt(cursor) == '/')) {
|
||||
// this is en error - should already have been skipped
|
||||
error("This shouldn't happen?");
|
||||
// we've run into metadata
|
||||
cursor++;
|
||||
cursor++;
|
||||
current = source.substring(currentStart, cursor);
|
||||
} else {
|
||||
current = source.substring(currentStart, cursor);
|
||||
}
|
||||
current = source.substring(currentStart, cursor);
|
||||
} else if (ch == '$') {
|
||||
cursor++;
|
||||
while (cursor < source.length() && (source.charAt(cursor) >= 'a' && source.charAt(cursor) <= 'z'))
|
||||
|
@ -309,7 +320,7 @@ public class FHIRLexer {
|
|||
boolean last13 = false;
|
||||
boolean done = false;
|
||||
while (cursor < source.length() && !done) {
|
||||
if (cursor < source.length() -1 && "//".equals(source.substring(cursor, cursor+2))) {
|
||||
if (cursor < source.length() -1 && "//".equals(source.substring(cursor, cursor+2)) && !isMetadataStart()) {
|
||||
commentLocation = currentLocation;
|
||||
int start = cursor+2;
|
||||
while (cursor < source.length() && !((source.charAt(cursor) == '\r') || source.charAt(cursor) == '\n')) {
|
||||
|
@ -338,6 +349,10 @@ public class FHIRLexer {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isMetadataStart() {
|
||||
return metadataFormat && cursor < source.length() - 2 && "///".equals(source.substring(cursor, cursor+3));
|
||||
}
|
||||
|
||||
private boolean isDateChar(char ch,int start) {
|
||||
int eot = source.charAt(start+1) == 'T' ? 10 : 20;
|
||||
|
||||
|
@ -550,5 +565,11 @@ public class FHIRLexer {
|
|||
public SourceLocation getCommentLocation() {
|
||||
return this.commentLocation;
|
||||
}
|
||||
public boolean isMetadataFormat() {
|
||||
return metadataFormat;
|
||||
}
|
||||
public void setMetadataFormat(boolean metadataFormat) {
|
||||
this.metadataFormat = metadataFormat;
|
||||
}
|
||||
|
||||
}
|
|
@ -6352,5 +6352,8 @@ public class FHIRPathEngine {
|
|||
this.liquidMode = liquidMode;
|
||||
}
|
||||
|
||||
public ProfileUtilities getProfileUtilities() {
|
||||
return profileUtilities;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -619,16 +619,38 @@ public class StructureMapUtilities {
|
|||
}
|
||||
|
||||
public StructureMap parse(String text, String srcName) throws FHIRException {
|
||||
FHIRLexer lexer = new FHIRLexer(text, srcName);
|
||||
FHIRLexer lexer = new FHIRLexer(Utilities.stripBOM(text), srcName, true);
|
||||
if (lexer.done())
|
||||
throw lexer.error("Map Input cannot be empty");
|
||||
lexer.token("map");
|
||||
StructureMap result = new StructureMap();
|
||||
result.setUrl(lexer.readConstant("url"));
|
||||
lexer.token("=");
|
||||
result.setName(lexer.readConstant("name"));
|
||||
result.setDescription(lexer.getAllComments());
|
||||
result.setStatus(PublicationStatus.DRAFT);
|
||||
if (lexer.hasToken("map")) {
|
||||
lexer.token("map");
|
||||
result.setUrl(lexer.readConstant("url"));
|
||||
lexer.token("=");
|
||||
result.setName(lexer.readConstant("name"));
|
||||
result.setDescription(lexer.getAllComments());
|
||||
result.setStatus(PublicationStatus.DRAFT);
|
||||
} else {
|
||||
while (lexer.hasToken("///")) {
|
||||
lexer.next();
|
||||
String fid = lexer.takeDottedToken();
|
||||
lexer.token("=");
|
||||
switch (fid) {
|
||||
case "url" :
|
||||
result.setUrl(lexer.readConstant("url"));
|
||||
break;
|
||||
case "name" :
|
||||
result.setName(lexer.readConstant("name"));
|
||||
break;
|
||||
case "title" :
|
||||
result.setTitle(lexer.readConstant("title"));
|
||||
break;
|
||||
default:
|
||||
lexer.readConstant("nothing");
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
while (lexer.hasToken("conceptmap"))
|
||||
parseConceptMap(result, lexer);
|
||||
|
||||
|
@ -978,11 +1000,11 @@ public class StructureMapUtilities {
|
|||
// type and cardinality
|
||||
lexer.token(":");
|
||||
source.setType(lexer.takeDottedToken());
|
||||
if (!lexer.hasToken("as", "first", "last", "not_first", "not_last", "only_one", "default")) {
|
||||
source.setMin(lexer.takeInt());
|
||||
lexer.token("..");
|
||||
source.setMax(lexer.take());
|
||||
}
|
||||
}
|
||||
if (Utilities.isInteger(lexer.getCurrent())) {
|
||||
source.setMin(lexer.takeInt());
|
||||
lexer.token("..");
|
||||
source.setMax(lexer.take());
|
||||
}
|
||||
if (lexer.hasToken("default")) {
|
||||
lexer.token("default");
|
||||
|
|
|
@ -214,9 +214,17 @@ public class VersionUtilities {
|
|||
} else if (Utilities.charCount(version, '.') == 2) {
|
||||
String[] p = version.split("\\.");
|
||||
return p[0]+"."+p[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (Utilities.existsInList(version, "R2", "R2B", "R3", "R4", "R4B", "R5")) {
|
||||
switch (version) {
|
||||
case "R2": return "1.0";
|
||||
case "R2B": return "1.4";
|
||||
case "R3": return "3.0";
|
||||
case "R4": return "4.0";
|
||||
case "R4B": return "4.3";
|
||||
case "R5": return "5.0";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getPatch(String version) {
|
||||
|
|
|
@ -775,7 +775,7 @@ public class I18nConstants {
|
|||
public static final String ILLEGAL_COMMENT_TYPE = "ILLEGAL_COMMENT_TYPE";
|
||||
public static final String SD_NO_SLICING_ON_ROOT = "SD_NO_SLICING_ON_ROOT";
|
||||
public static final String REFERENCE_REF_QUERY_INVALID = "REFERENCE_REF_QUERY_INVALID";
|
||||
public static final String SM_EXTENDS_NOT_SUPPORTED = "";
|
||||
public static final String SM_RULEGROUP_NOT_FOUND = "SM_RULEGROUP_NOT_FOUND";
|
||||
public static final String SM_NAME_INVALID = "SM_NAME_INVALID";
|
||||
public static final String SM_GROUP_INPUT_DUPLICATE = "SM_GROUP_INPUT_DUPLICATE";
|
||||
public static final String SM_GROUP_INPUT_MODE_INVALID = "SM_GROUP_INPUT_MODE_INVALID";
|
||||
|
@ -803,6 +803,7 @@ public class I18nConstants {
|
|||
public static final String SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE = "SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE";
|
||||
public static final String SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE = "SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE";
|
||||
public static final String SM_TARGET_TRANSFORM_EXPRESSION_ERROR = "SM_TARGET_TRANSFORM_EXPRESSION_ERROR";
|
||||
public static final String SM_IMPORT_NOT_FOUND = "SM_IMPORT_NOT_FOUND";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -825,13 +825,13 @@ EXT_VER_URL_REVERSION = The extension URL must not contain a version. The extens
|
|||
ILLEGAL_COMMENT_TYPE = The fhir_comments property must be an array of strings
|
||||
SD_NO_SLICING_ON_ROOT = Slicing is not allowed at the root of a profile
|
||||
REFERENCE_REF_QUERY_INVALID = The query part of the conditional reference is not a valid query string ({0})
|
||||
SM_EXTENDS_NOT_SUPPORTED = Group.extends is not supported
|
||||
SM_RULEGROUP_NOT_FOUND = The group {0} could not be resolved
|
||||
SM_NAME_INVALID = The name {0} is not valid
|
||||
SM_GROUP_INPUT_DUPLICATE = The name {0} is already used
|
||||
SM_GROUP_INPUT_MODE_INVALID = The group parameter {0} mode {1} isn't valid
|
||||
SM_GROUP_INPUT_MODE_INVALID = The group parameter {0} mode {1} isn''t valid
|
||||
SM_GROUP_INPUT_NO_TYPE = The group parameter {0} has no type, so the paths cannot be validated
|
||||
SM_GROUP_INPUT_TYPE_NOT_DECLARED = The type {0} was not declared and is unknown
|
||||
SM_GROUP_INPUT_MODE_MISMATCH = The type {0} has mode {1} which doesn't match the structure definition {2}
|
||||
SM_GROUP_INPUT_MODE_MISMATCH = The type {0} has mode {1} which doesn''t match the structure definition {2}
|
||||
SM_GROUP_INPUT_TYPE_UNKNOWN = The type {0} which maps to the canonical URL {1} is not known, so the paths cannot be validated
|
||||
SM_SOURCE_CONTEXT_UNKNOWN = The source context {0} is not known at this point
|
||||
SM_SOURCE_PATH_INVALID = The source path {0}.{1} refers to the path {2} which is unknown
|
||||
|
@ -842,17 +842,17 @@ SM_TARGET_CONTEXT_UNKNOWN = The target context {0} is not known at this point
|
|||
SM_TARGET_PATH_INVALID = The target path {0}.{1} refers to the path {2} which is unknown
|
||||
SM_NO_LIST_MODE_NEEDED = A list mode should not be provided since this is a rule that can only be executed once
|
||||
SM_NO_LIST_RULE_ID_NEEDED = A list ruleId should not be provided since this is a rule that can only be executed once
|
||||
SM_LIST_RULE_ID_ONLY_WHEN_SHARE = A ruleId should only be provided when the rule mode is 'share'
|
||||
SM_RULE_SOURCE_UNASSIGNED = The source statement doesn't assign a variable to the source - check that this is what is intended
|
||||
SM_LIST_RULE_ID_ONLY_WHEN_SHARE = A ruleId should only be provided when the rule mode is ''share''
|
||||
SM_RULE_SOURCE_UNASSIGNED = The source statement doesn''t assign a variable to the source - check that this is what is intended
|
||||
SM_TARGET_PATH_MULTIPLE_MATCHES = The target path {0}.{1} refers to the path {2} which is could be a reference to multiple elements ({3}). No further checking can be performed
|
||||
SM_SOURCE_TYPE_INVALID = The type {0} is not valid in this context {1}. The possible types are [{2}]
|
||||
SM_SOURCE_TYPE_INVALID = The type {0} is not valid in this source context {1}. The possible types are [{2}]
|
||||
SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE = Transform {0} takes {1}-{2} parameter(s) but {3} were found
|
||||
SM_TARGET_TRANSFORM_PARAM_COUNT_SINGLE = Transform {0} takes {1} parameter(s) but {2} were found
|
||||
SM_TARGET_TRANSFORM_NOT_CHECKED = Transform {0} not checked yet
|
||||
SM_TARGET_NO_TRANSFORM_NO_CHECKED = When there is no transform, parameters can't be provided
|
||||
SM_TARGET_NO_TRANSFORM_NO_CHECKED = When there is no transform, parameters can''t be provided
|
||||
SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE = The value of the type parameter could not be processed
|
||||
SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE = The parameter at index {0} could not be processed (type = {1})
|
||||
SM_TARGET_TRANSFORM_EXPRESSION_ERROR = The FHIRPath expression passed as the evaluate parameter is invalid: {0}
|
||||
|
||||
SM_IMPORT_NOT_FOUND = No maps were found to match {0} - validation may be wrong
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
|
|||
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
|
||||
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_43_50;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
|
@ -112,7 +113,9 @@ public class IgLoader {
|
|||
if (!srcPackage.contains("#")) {
|
||||
System.out.print("#" + npm.version());
|
||||
}
|
||||
int count = getContext().loadFromPackage(npm, ValidatorUtils.loaderForVersion(npm.fhirVersion()));
|
||||
IContextResourceLoader loader = ValidatorUtils.loaderForVersion(npm.fhirVersion());
|
||||
loader.setPatchUrls(VersionUtilities.isCorePackage(npm.id()));
|
||||
int count = getContext().loadFromPackage(npm, loader);
|
||||
System.out.println(" - " + count + " resources (" + getContext().clock().milestone() + ")");
|
||||
} else {
|
||||
System.out.print(" Load " + srcPackage);
|
||||
|
@ -183,8 +186,10 @@ public class IgLoader {
|
|||
res.cntType = Manager.FhirFormat.TURTLE;
|
||||
else if (t.getKey().endsWith(".shc"))
|
||||
res.cntType = Manager.FhirFormat.SHC;
|
||||
else if (t.getKey().endsWith(".txt") || t.getKey().endsWith(".map"))
|
||||
else if (t.getKey().endsWith(".txt"))
|
||||
res.cntType = Manager.FhirFormat.TEXT;
|
||||
else if (t.getKey().endsWith(".fml") || t.getKey().endsWith(".map"))
|
||||
res.cntType = Manager.FhirFormat.FML;
|
||||
else
|
||||
throw new FHIRException("Todo: Determining resource type is not yet done");
|
||||
}
|
||||
|
@ -762,6 +767,7 @@ public class IgLoader {
|
|||
if (isDebug() || ((e.getMessage() != null && e.getMessage().contains("cannot be cast")))) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -774,7 +780,7 @@ public class IgLoader {
|
|||
res = new org.hl7.fhir.dstu3.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
res = new org.hl7.fhir.dstu3.utils.StructureMapUtilities(null).parse(new String(content));
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -785,7 +791,7 @@ public class IgLoader {
|
|||
res = new org.hl7.fhir.r4.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.r4.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
res = new org.hl7.fhir.r4.utils.StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -796,7 +802,7 @@ public class IgLoader {
|
|||
res = new org.hl7.fhir.r4b.formats.XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
res = new org.hl7.fhir.r4b.formats.JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
res = new org.hl7.fhir.r4b.utils.structuremap.StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -819,15 +825,15 @@ public class IgLoader {
|
|||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
r = VersionConvertorFactory_10_50.convertResource(res, new org.hl7.fhir.convertors.misc.IGR2ConvertorAdvisor5());
|
||||
} else if (fhirVersion.startsWith("5.0")) {
|
||||
} else if (fhirVersion.startsWith("5.0") || "current".equals(fhirVersion)) {
|
||||
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
|
||||
r = new XmlParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
r = new JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt"))
|
||||
r = new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(content), fn);
|
||||
else if (fn.endsWith(".map"))
|
||||
r = new StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else if (fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
r = new StructureMapUtilities(context).parse(new String(content), fn);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
} else
|
||||
|
|
|
@ -219,6 +219,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
@Getter @Setter private Coding jurisdiction;
|
||||
|
||||
|
||||
private ContextUtilities cu = null;
|
||||
|
||||
/**
|
||||
* Creating a validation engine is an expensive operation - takes seconds.
|
||||
* Once you have a validation engine created, you can quickly clone it to
|
||||
|
@ -842,7 +844,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
new org.hl7.fhir.dstu3.formats.XmlParser().setOutputStyle(org.hl7.fhir.dstu3.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new org.hl7.fhir.dstu3.formats.JsonParser().setOutputStyle(org.hl7.fhir.dstu3.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(org.hl7.fhir.dstu3.utils.StructureMapUtilities.render((org.hl7.fhir.dstu3.model.StructureMap) res), s, false);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -852,7 +854,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
new org.hl7.fhir.r4.formats.XmlParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(org.hl7.fhir.r4.utils.StructureMapUtilities.render((org.hl7.fhir.r4.model.StructureMap) res), s, false);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -877,7 +879,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
new XmlParser().setOutputStyle(org.hl7.fhir.r5.formats.IParser.OutputStyle.PRETTY).compose(s, r);
|
||||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new JsonParser().setOutputStyle(org.hl7.fhir.r5.formats.IParser.OutputStyle.PRETTY).compose(s, r);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map"))
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(StructureMapUtilities.render((org.hl7.fhir.r5.model.StructureMap) r), s, false);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
|
@ -1061,6 +1063,16 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
resolvedUrls.put(type+"|"+url, false);
|
||||
return false; // todo... how to access settings from here?
|
||||
}
|
||||
if (url.contains("*") && !url.contains("?")) {
|
||||
if (cu == null) {
|
||||
cu = new ContextUtilities(context);
|
||||
}
|
||||
List<StructureMap> maps = cu.listMaps(url);
|
||||
if (!maps.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
if (fetcher != null) {
|
||||
try {
|
||||
boolean ok = fetcher.resolveURL(validator, appContext, path, url, type);
|
||||
|
|
|
@ -105,6 +105,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
}
|
||||
if (base.equals("http://terminology.hl7.org")) {
|
||||
pid = "hl7.terminology";
|
||||
} else if (base.equals("http://hl7.org/fhir")) {
|
||||
return false;
|
||||
} else if (url.startsWith("http://hl7.org/fhir")) {
|
||||
pid = pcm.getPackageId(base);
|
||||
} else {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
|||
public class Params {
|
||||
|
||||
public static final String VERSION = "-version";
|
||||
public static final String ALT_VERSION = "-alt-version";
|
||||
public static final String OUTPUT = "-output";
|
||||
|
||||
public static final String OUTPUT_SUFFIX = "-outputSuffix";
|
||||
|
@ -307,9 +308,29 @@ public class Params {
|
|||
if (version == null) {
|
||||
cliContext.addIg(s);
|
||||
} else {
|
||||
cliContext.setSv(version);
|
||||
String v = getParam(args, VERSION);
|
||||
if (v != null && !v.equals(version)) {
|
||||
throw new Error("Parameters are inconsistent: specified version is "+v+" but -ig parameter "+s+" implies a different version");
|
||||
} else if (cliContext.getSv() != null && !version.equals(cliContext.getSv())) {
|
||||
throw new Error("Parameters are inconsistent: multiple -ig parameters implying differetion versions ("+cliContext.getSv()+","+version+")");
|
||||
} else {
|
||||
cliContext.setSv(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (args[i].equals(ALT_VERSION)) {
|
||||
if (i + 1 == args.length)
|
||||
throw new Error("Specified " + args[i] + " without indicating version");
|
||||
else {
|
||||
String s = args[++i];
|
||||
String v = VersionUtilities.getMajMin(s);
|
||||
if (v == null) {
|
||||
throw new Error("Unsupported FHIR Version "+s);
|
||||
}
|
||||
String pid = VersionUtilities.packageForVersion(v);
|
||||
pid = pid + "#"+VersionUtilities.getCurrentPackageVersion(v);
|
||||
cliContext.addIg(pid);
|
||||
}
|
||||
} else if (args[i].equals(MAP)) {
|
||||
if (cliContext.getMap() == null) {
|
||||
if (i + 1 == args.length)
|
||||
|
@ -336,6 +357,7 @@ public class Params {
|
|||
cliContext.addSource(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return cliContext;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.hl7.fhir.exceptions.DefinitionException;
|
|||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.ContextUtilities;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
@ -34,6 +35,9 @@ import org.hl7.fhir.r5.model.StructureDefinition;
|
|||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r5.model.StructureMap;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupComponent;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupInputComponent;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapInputMode;
|
||||
import org.hl7.fhir.r5.model.TypeDetails;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
|
@ -226,6 +230,8 @@ public class StructureMapValidator extends BaseValidator {
|
|||
|
||||
private FHIRPathEngine fpe;
|
||||
private ProfileUtilities profileUtilities;
|
||||
private ContextUtilities cu;
|
||||
private List<StructureMap> imports = new ArrayList<>();
|
||||
|
||||
public StructureMapValidator(IWorkerContext context, TimeTracker timeTracker, FHIRPathEngine fpe, XVerExtensionManager xverManager, ProfileUtilities profileUtilities, Coding jurisdiction) {
|
||||
super(context, xverManager);
|
||||
|
@ -234,13 +240,21 @@ public class StructureMapValidator extends BaseValidator {
|
|||
this.timeTracker = timeTracker;
|
||||
this.jurisdiction = jurisdiction;
|
||||
this.profileUtilities = profileUtilities;
|
||||
this.cu = new ContextUtilities(context);
|
||||
|
||||
}
|
||||
|
||||
public boolean validateStructureMap(List<ValidationMessage> errors, Element src, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
List<Element> groups = src.getChildrenByName("group");
|
||||
List<Element> imports = src.getChildrenByName("import");
|
||||
int cc = 0;
|
||||
for (Element import_ : imports) {
|
||||
ok = validateImport(errors, src, import_, stack.push(import_, cc, null, null)) && ok;
|
||||
cc++;
|
||||
}
|
||||
|
||||
List<Element> groups = src.getChildrenByName("group");
|
||||
cc = 0;
|
||||
for (Element group : groups) {
|
||||
ok = validateGroup(errors, src, group, stack.push(group, cc, null, null)) && ok;
|
||||
cc++;
|
||||
|
@ -248,14 +262,34 @@ public class StructureMapValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateImport(List<ValidationMessage> errors, Element src, Element import_, NodeStack stack) {
|
||||
String url = import_.primitiveValue();
|
||||
boolean ok = false;
|
||||
StructureMap map = context.fetchResource(StructureMap.class, url);
|
||||
if (map != null) {
|
||||
imports.add(map);
|
||||
ok = true;
|
||||
} else if (url.contains("*")) {
|
||||
List<StructureMap> maps = cu.listMaps(url);
|
||||
ok = !maps.isEmpty();
|
||||
imports.addAll(maps);
|
||||
}
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, import_.line(), import_.col(), stack.getLiteralPath(), ok, I18nConstants.SM_IMPORT_NOT_FOUND, url);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean validateGroup(List<ValidationMessage> errors, Element src, Element group, NodeStack stack) {
|
||||
String name = group.getChildValue("name");
|
||||
boolean ok = rule(errors, "2023-02-17", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
||||
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
||||
|
||||
Element extend = src.getNamedChild("extends");
|
||||
Element extend = group.getNamedChild("extends");
|
||||
if (extend != null) {
|
||||
rule(errors, "2023-02-17", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), false, I18nConstants.SM_EXTENDS_NOT_SUPPORTED, extend.primitiveValue());
|
||||
ok = false;
|
||||
StructureMapGroupComponent grp = resolveGroup(extend.primitiveValue(), src);
|
||||
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, extend.primitiveValue())) {
|
||||
// check inputs
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
VariableSet variables = new VariableSet();
|
||||
|
@ -280,24 +314,62 @@ public class StructureMapValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private StructureMapGroupComponent resolveGroup(String grpName, Element src) {
|
||||
if (grpName == null) {
|
||||
return null;
|
||||
}
|
||||
List<Element> groups = src.getChildrenByName("group");
|
||||
for (Element group : groups) {
|
||||
String name = group.getChildValue("name");
|
||||
if (grpName.equals(name)) {
|
||||
return makeGroupComponent(group);
|
||||
}
|
||||
}
|
||||
for (StructureMap map : imports) {
|
||||
for (StructureMapGroupComponent grp : map.getGroup()) {
|
||||
if (grpName.equals(grp.getName())) {
|
||||
return grp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private StructureMapGroupComponent makeGroupComponent(Element group) {
|
||||
StructureMapGroupComponent grp = new StructureMapGroupComponent();
|
||||
grp.setName(group.getChildValue("name"));
|
||||
List<Element> inputs = group.getChildrenByName("input");
|
||||
for (Element input : inputs) {
|
||||
StructureMapGroupInputComponent inp = grp.addInput();
|
||||
inp.setName(input.getChildValue("name"));
|
||||
inp.setType(input.getChildValue("type"));
|
||||
try {
|
||||
inp.setMode(StructureMapInputMode.fromCode(input.getChildValue("mode")));
|
||||
} catch (Exception e) {
|
||||
// nothing; will be an error elsewhere
|
||||
}
|
||||
}
|
||||
return grp;
|
||||
}
|
||||
|
||||
private boolean validateInput(List<ValidationMessage> errors, Element src, Element group, Element input, NodeStack stack, List<Element> structures, VariableSet variables) {
|
||||
boolean ok = false;
|
||||
String name = input.getChildValue("name");
|
||||
String type = input.getChildValue("type");
|
||||
String mode = input.getChildValue("mode");
|
||||
|
||||
if (rule(errors, "2023-02-17", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name) && // the name {0} is not valid)
|
||||
rule(errors, "2023-02-17", IssueType.DUPLICATE, input.line(), input.col(), stack.getLiteralPath(), !variables.hasVariable(name), I18nConstants.SM_GROUP_INPUT_DUPLICATE, name)) { // the name {0} is not valid)
|
||||
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name) && // the name {0} is not valid)
|
||||
rule(errors, "2023-03-01", IssueType.DUPLICATE, input.line(), input.col(), stack.getLiteralPath(), !variables.hasVariable(name), I18nConstants.SM_GROUP_INPUT_DUPLICATE, name)) { // the name {0} is not valid)
|
||||
VariableDefn v = variables.add(name, mode);
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), Utilities.existsInList(mode, "source", "target"), I18nConstants.SM_GROUP_INPUT_MODE_INVALID, name, mode) && // the group parameter {0} mode {1} isn't valid
|
||||
warning(errors, "2023-02-17", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), type != null, I18nConstants.SM_GROUP_INPUT_NO_TYPE, name)) { // the group parameter {0} has no type, so the paths cannot be validated
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), Utilities.existsInList(mode, "source", "target"), I18nConstants.SM_GROUP_INPUT_MODE_INVALID, name, mode) && // the group parameter {0} mode {1} isn't valid
|
||||
warning(errors, "2023-03-01", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), type != null, I18nConstants.SM_GROUP_INPUT_NO_TYPE, name)) { // the group parameter {0} has no type, so the paths cannot be validated
|
||||
Element structure = findStructure(structures, type);
|
||||
if (rule(errors, "2023-02-17", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), structure != null, I18nConstants.SM_GROUP_INPUT_TYPE_NOT_DECLARED, type)) { // the type {0} was not declared and is unknown
|
||||
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), structure != null, I18nConstants.SM_GROUP_INPUT_TYPE_NOT_DECLARED, type)) { // the type {0} was not declared and is unknown
|
||||
String url = structure.getChildValue("url");
|
||||
String smode = structure.getChildValue("mode");
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||
if (rule(errors, "2023-02-17", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), mode.equals(smode), I18nConstants.SM_GROUP_INPUT_MODE_MISMATCH, type, mode, smode) && // the type {0} has mode {1} which doesn't match the structure definition {2}
|
||||
rule(errors, "2023-02-17", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), sd != null, I18nConstants.SM_GROUP_INPUT_TYPE_UNKNOWN, type, url)) { // the type {0} which maps to the canonical URL {1} is not known, so the paths cannot be validated
|
||||
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, input.line(), input.col(), stack.getLiteralPath(), mode.equals(smode), I18nConstants.SM_GROUP_INPUT_MODE_MISMATCH, type, mode, smode) && // the type {0} has mode {1} which doesn't match the structure definition {2}
|
||||
rule(errors, "2023-03-01", IssueType.INVALID, input.line(), input.col(), stack.getLiteralPath(), sd != null, I18nConstants.SM_GROUP_INPUT_TYPE_UNKNOWN, type, url)) { // the type {0} which maps to the canonical URL {1} is not known, so the paths cannot be validated
|
||||
v.setType(1, sd, sd.getSnapshot().getElementFirstRep(), null);
|
||||
ok = true;
|
||||
}
|
||||
|
@ -323,7 +395,7 @@ public class StructureMapValidator extends BaseValidator {
|
|||
|
||||
private boolean validateRule(List<ValidationMessage> errors, Element src, Element group, Element rule, NodeStack stack, VariableSet variables) {
|
||||
String name = rule.getChildValue("name");
|
||||
boolean ok = rule(errors, "2023-02-17", IssueType.INVALID, rule.line(), rule.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
||||
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, rule.line(), rule.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name);
|
||||
|
||||
RuleInformation ruleInfo = new RuleInformation();
|
||||
// process the sources
|
||||
|
@ -350,14 +422,19 @@ public class StructureMapValidator extends BaseValidator {
|
|||
cc++;
|
||||
}
|
||||
// todo: check dependents
|
||||
|
||||
List<Element> dependents = rule.getChildrenByName("dependent");
|
||||
cc = 0;
|
||||
for (Element dependent : dependents) {
|
||||
ok = validateDependent(errors, src, group, dependent, stack.push(dependent, cc, null, null), lvars) && ok;
|
||||
cc++;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateRuleSource(List<ValidationMessage> errors, Element src, Element group, Element rule, Element source, NodeStack stack, VariableSet variables, RuleInformation ruleInfo) {
|
||||
String context = source.getChildValue("context");
|
||||
boolean ok = rule(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), idIsValid(context), I18nConstants.SM_NAME_INVALID, context) &&
|
||||
rule(errors, "2023-02-17", IssueType.UNKNOWN, source.line(), source.col(), stack.getLiteralPath(), variables.hasVariable(context, SOURCE), I18nConstants.SM_SOURCE_CONTEXT_UNKNOWN, context);
|
||||
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), idIsValid(context), I18nConstants.SM_NAME_INVALID, context) &&
|
||||
rule(errors, "2023-03-01", IssueType.UNKNOWN, source.line(), source.col(), stack.getLiteralPath(), variables.hasVariable(context, SOURCE), I18nConstants.SM_SOURCE_CONTEXT_UNKNOWN, context);
|
||||
if (ok) {
|
||||
VariableDefn v = variables.getVariable(context, SOURCE);
|
||||
if (v.hasTypeInfo()) { // if it doesn't, that's already an issue elsewhere
|
||||
|
@ -369,8 +446,8 @@ public class StructureMapValidator extends BaseValidator {
|
|||
String path = v.getEd().getPath()+"."+element;
|
||||
String variable = source.getChildValue("variable");
|
||||
VariableDefn vn = null;
|
||||
if (hint(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), variable != null, I18nConstants.SM_RULE_SOURCE_UNASSIGNED)) {
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), idIsValid(variable), I18nConstants.SM_NAME_INVALID, variable)) {
|
||||
if (hint(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), variable != null, I18nConstants.SM_RULE_SOURCE_UNASSIGNED)) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), idIsValid(variable), I18nConstants.SM_NAME_INVALID, variable)) {
|
||||
vn = variables.add(variable, v.getMode()); // may overwrite
|
||||
} else {
|
||||
ok = false;
|
||||
|
@ -378,20 +455,20 @@ public class StructureMapValidator extends BaseValidator {
|
|||
}
|
||||
|
||||
List<ElementDefinitionSource> els = getElementDefinitions(v.getSd(), v.getEd(), v.getType(), element);
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), !els.isEmpty(), I18nConstants.SM_SOURCE_PATH_INVALID, context, element, path)) {
|
||||
if (warning(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), els.size() == 1, I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), !els.isEmpty(), I18nConstants.SM_SOURCE_PATH_INVALID, context, element, path)) {
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), els.size() == 1, I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
|
||||
ElementDefinitionSource el = els.get(0);
|
||||
String type = source.getChildValue("type");
|
||||
if (type != null) {
|
||||
ok = rule(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), hasType(el.getEd(), type), I18nConstants.SM_SOURCE_TYPE_INVALID, type, path, el.getEd().typeSummary()) && ok;
|
||||
ok = rule(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), hasType(el.getEd(), type), I18nConstants.SM_SOURCE_TYPE_INVALID, type, path, el.getEd().typeSummary()) && ok;
|
||||
}
|
||||
String min = source.getChildValue("min");
|
||||
hint(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), min == null || isMoreOrEqual(min, v.getEd().getMin()), I18nConstants.SM_RULE_SOURCE_MIN_REDUNDANT, min, v.getEd().getMin());
|
||||
hint(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), min == null || isMoreOrEqual(min, v.getEd().getMin()), I18nConstants.SM_RULE_SOURCE_MIN_REDUNDANT, min, v.getEd().getMin());
|
||||
|
||||
int existingMax = multiplyCardinality(v.getMax(), el.getEd().getMax());
|
||||
String max = source.getChildValue("max");
|
||||
int iMax = readMax(max, existingMax);
|
||||
warning(errors, "2023-02-17", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), iMax <= existingMax, I18nConstants.SM_RULE_SOURCE_MAX_REDUNDANT, max, v.getMax());
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, source.line(), source.col(), stack.getLiteralPath(), iMax <= existingMax, I18nConstants.SM_RULE_SOURCE_MAX_REDUNDANT, max, v.getMax());
|
||||
ruleInfo.seeCardinality(iMax);
|
||||
|
||||
|
||||
|
@ -440,22 +517,22 @@ public class StructureMapValidator extends BaseValidator {
|
|||
if (context == null) {
|
||||
return true;
|
||||
}
|
||||
boolean ok = rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), idIsValid(context), I18nConstants.SM_NAME_INVALID, context) &&
|
||||
rule(errors, "2023-02-17", IssueType.UNKNOWN, target.line(), target.col(), stack.getLiteralPath(), variables.hasVariable(context, TARGET), I18nConstants.SM_TARGET_CONTEXT_UNKNOWN, context);
|
||||
boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), idIsValid(context), I18nConstants.SM_NAME_INVALID, context) &&
|
||||
rule(errors, "2023-03-01", IssueType.UNKNOWN, target.line(), target.col(), stack.getLiteralPath(), variables.hasVariable(context, TARGET), I18nConstants.SM_TARGET_CONTEXT_UNKNOWN, context);
|
||||
if (ok) {
|
||||
VariableDefn v = variables.getVariable(context, TARGET);
|
||||
if (v.hasTypeInfo()) {
|
||||
String listMode = target.getChildValue("listMode");
|
||||
String listRuleId = target.getChildValue("listRuleId");
|
||||
warning(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listRuleId == null || "share".equals(listMode), I18nConstants.SM_LIST_RULE_ID_ONLY_WHEN_SHARE);
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listRuleId == null || "share".equals(listMode), I18nConstants.SM_LIST_RULE_ID_ONLY_WHEN_SHARE);
|
||||
if (!ruleInfo.isList()) {
|
||||
warning(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listMode == null, I18nConstants.SM_NO_LIST_MODE_NEEDED);
|
||||
warning(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listRuleId == null, I18nConstants.SM_NO_LIST_RULE_ID_NEEDED);
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listMode == null, I18nConstants.SM_NO_LIST_MODE_NEEDED);
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), listRuleId == null, I18nConstants.SM_NO_LIST_RULE_ID_NEEDED);
|
||||
}
|
||||
VariableDefn vn = null;
|
||||
String variable = target.getChildValue("variable");
|
||||
if (variable != null) {
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), idIsValid(variable), I18nConstants.SM_NAME_INVALID, variable)) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), idIsValid(variable), I18nConstants.SM_NAME_INVALID, variable)) {
|
||||
vn = variables.add(variable, v.getMode()); // may overwrite
|
||||
} else {
|
||||
ok = false;
|
||||
|
@ -465,21 +542,21 @@ public class StructureMapValidator extends BaseValidator {
|
|||
String element = target.getChildValue("element");
|
||||
if (element != null) {
|
||||
List<ElementDefinitionSource> els = getElementDefinitions(v.getSd(), v.getEd(), v.getType(), element);
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), !els.isEmpty(), I18nConstants.SM_TARGET_PATH_INVALID, context, element, v.getEd().getPath()+"."+element)) {
|
||||
if (warning(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), els.size() == 1, I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), !els.isEmpty(), I18nConstants.SM_TARGET_PATH_INVALID, context, element, v.getEd().getPath()+"."+element)) {
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), els.size() == 1, I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
|
||||
ElementDefinitionSource el = els.get(0);
|
||||
String type = null; // maybe inferred / derived from transform in the future
|
||||
String transform = target.getChildValue("transform");
|
||||
List<Element> params = target.getChildren("parameter");
|
||||
if (transform == null) {
|
||||
rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 0, I18nConstants.SM_TARGET_NO_TRANSFORM_NO_CHECKED, transform);
|
||||
rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 0, I18nConstants.SM_TARGET_NO_TRANSFORM_NO_CHECKED, transform);
|
||||
} else {
|
||||
switch (transform) {
|
||||
case "create":
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() < 2, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE, "create", "0", "1", params.size())) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() < 2, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE, "create", "0", "1", params.size())) {
|
||||
if (params.size() == 1) {
|
||||
type = params.get(0).primitiveValue();
|
||||
warning(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(),type != null, I18nConstants.SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE);
|
||||
warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(),type != null, I18nConstants.SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE);
|
||||
} else {
|
||||
// maybe can guess? maybe not ... type =
|
||||
}
|
||||
|
@ -488,23 +565,23 @@ public class StructureMapValidator extends BaseValidator {
|
|||
}
|
||||
break;
|
||||
case "reference":
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 1, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE, "reference", "0", "1", params.size())) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 1, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE, "reference", "0", "1", params.size())) {
|
||||
type = "string";
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case "evaluate":
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 1, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_SINGLE, "evaluate", "1", params.size())) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 1, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_SINGLE, "evaluate", "1", params.size())) {
|
||||
String exp = params.get(0).primitiveValue();
|
||||
if (rule(errors, "2023-02-17", IssueType.INVALID, params.get(0).line(), params.get(0).col(), stack.getLiteralPath(), exp != null, I18nConstants.SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE, "0", params.size())) {
|
||||
if (rule(errors, "2023-03-01", IssueType.INVALID, params.get(0).line(), params.get(0).col(), stack.getLiteralPath(), exp != null, I18nConstants.SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE, "0", params.size())) {
|
||||
try {
|
||||
TypeDetails td = fpe.check(null, v.getSd().getType(), v.getEd().getPath(), fpe.parse(exp));
|
||||
if (td.getTypes().size() == 1) {
|
||||
type = td.getType();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
rule(errors, "2023-02-17", IssueType.INVALID, params.get(0).line(), params.get(0).col(), stack.getLiteralPath(), false, I18nConstants.SM_TARGET_TRANSFORM_EXPRESSION_ERROR, e.getMessage());
|
||||
rule(errors, "2023-03-01", IssueType.INVALID, params.get(0).line(), params.get(0).col(), stack.getLiteralPath(), false, I18nConstants.SM_TARGET_TRANSFORM_EXPRESSION_ERROR, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
|
@ -514,7 +591,7 @@ public class StructureMapValidator extends BaseValidator {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
rule(errors, "2023-02-17", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), false, I18nConstants.SM_TARGET_TRANSFORM_NOT_CHECKED, transform);
|
||||
rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), false, I18nConstants.SM_TARGET_TRANSFORM_NOT_CHECKED, transform);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
@ -590,4 +667,17 @@ public class StructureMapValidator extends BaseValidator {
|
|||
return true; // no issue in this case
|
||||
}
|
||||
|
||||
|
||||
private boolean validateDependent(List<ValidationMessage> errors, Element src, Element group, Element dependent, NodeStack stack, VariableSet lvars) {
|
||||
boolean ok = true;
|
||||
String name = dependent.getChildValue("name");
|
||||
StructureMapGroupComponent grp = resolveGroup(name, src);
|
||||
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, dependent.line(), dependent.col(), stack.push(dependent, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, name)) {
|
||||
// check inputs
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue