Merge pull request #697 from hapifhir/gg-202112-r5-update-2

Gg 202112 r5 update 2
This commit is contained in:
Grahame Grieve 2021-12-22 23:16:22 +11:00 committed by GitHub
commit 873c699831
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 259 additions and 150 deletions

View File

@ -0,0 +1,14 @@
## Validator Changes:
* ignore canonical resources found in core examples packages
* get .ofType() working in discriminators (round #1!)
* fix bug checking enableWhen - ignoring items in answers
* Improved Error messages validating bundle entries
## Other Code Changes
* Improve rendering of uris that point to known resources
* Fix wrong reference rendering questionnaire
* Fix rendering of QuestionnaireResponses - render items in answers properly
* Improve Error message when snapshot can't be generated
* fix up support for R5

View File

@ -312,64 +312,66 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
map = new HashMap<String, ResourceProxy>();
allResourcesById.put(r.getType(), map);
}
map.put(r.getId(), new ResourceProxy(r));
if ((packageInfo == null || !packageInfo.isExamplesPackage()) || !map.containsKey(r.getId())) {
map.put(r.getId(), new ResourceProxy(r));
}
String url = r.getUrl();
if (!allowLoadingDuplicates && hasResource(r.getType(), url)) {
// spcial workaround for known problems with existing packages
if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) {
return;
}
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url));
String url = r.getUrl();
if (!allowLoadingDuplicates && hasResource(r.getType(), url)) {
// spcial workaround for known problems with existing packages
if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) {
return;
}
switch(r.getType()) {
case "StructureDefinition":
if ("1.4.0".equals(version)) {
StructureDefinition sd = (StructureDefinition) r.getResource();
fixOldSD(sd);
}
structures.register(r, packageInfo);
break;
case "ValueSet":
valueSets.register(r, packageInfo);
break;
case "CodeSystem":
codeSystems.register(r, packageInfo);
break;
case "ImplementationGuide":
guides.register(r, packageInfo);
break;
case "CapabilityStatement":
capstmts.register(r, packageInfo);
break;
case "Measure":
measures.register(r, packageInfo);
break;
case "Library":
libraries.register(r, packageInfo);
break;
case "SearchParameter":
searchParameters.register(r, packageInfo);
break;
case "PlanDefinition":
plans.register(r, packageInfo);
break;
case "OperationDefinition":
operations.register(r, packageInfo);
break;
case "Questionnaire":
questionnaires.register(r, packageInfo);
break;
case "ConceptMap":
maps.register(r, packageInfo);
break;
case "StructureMap":
transforms.register(r, packageInfo);
break;
case "NamingSystem":
systems.register(r, packageInfo);
break;
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url));
}
switch(r.getType()) {
case "StructureDefinition":
if ("1.4.0".equals(version)) {
StructureDefinition sd = (StructureDefinition) r.getResource();
fixOldSD(sd);
}
structures.register(r, packageInfo);
break;
case "ValueSet":
valueSets.register(r, packageInfo);
break;
case "CodeSystem":
codeSystems.register(r, packageInfo);
break;
case "ImplementationGuide":
guides.register(r, packageInfo);
break;
case "CapabilityStatement":
capstmts.register(r, packageInfo);
break;
case "Measure":
measures.register(r, packageInfo);
break;
case "Library":
libraries.register(r, packageInfo);
break;
case "SearchParameter":
searchParameters.register(r, packageInfo);
break;
case "PlanDefinition":
plans.register(r, packageInfo);
break;
case "OperationDefinition":
operations.register(r, packageInfo);
break;
case "Questionnaire":
questionnaires.register(r, packageInfo);
break;
case "ConceptMap":
maps.register(r, packageInfo);
break;
case "StructureMap":
transforms.register(r, packageInfo);
break;
case "NamingSystem":
systems.register(r, packageInfo);
break;
}
}
}
@ -382,12 +384,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
if ((packageInfo == null || !packageInfo.isExamplesPackage()) || !map.containsKey(r.getId())) {
map.put(r.getId(), new ResourceProxy(r));
} else {
System.out.println("Ingore "+r.fhirType()+"/"+r.getId()+" from package "+packageInfo.toString());
}
if (r instanceof CodeSystem || r instanceof NamingSystem) {
oidCache.clear();
}
if (r instanceof CanonicalResource) {
CanonicalResource m = (CanonicalResource) r;
String url = m.getUrl();

View File

@ -218,7 +218,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
if (cr.getPackageInfo() != null && cr.getPackageInfo().getId() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology") && "http://nucc.org/provider-taxonomy".equals(cr.getUrl())) {
return;
}
if (enforceUniqueId && map.containsKey(cr.getId())) {
drop(cr.getId());
}
@ -236,7 +236,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
}
}
CachedCanonicalResource<T> existing = cr.hasVersion() ? map.get(cr.getUrl()+"|"+cr.getVersion()) : map.get(cr.getUrl()+"|#0");
if (existing != null && (cr.getPackageInfo() != null && cr.getPackageInfo().isExamplesPackage())) {
if (map.get(cr.getUrl()) != null && (cr.getPackageInfo() != null && cr.getPackageInfo().isExamplesPackage())) {
return;
}
if (existing != null) {
@ -245,6 +245,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
list.add(cr);
map.put(cr.getId(), cr); // we do this so we can drop by id
map.put(cr.getUrl(), cr);
if (cr.getUrl() != null) {
// first, this is the correct reosurce for this version (if it has a version)

View File

@ -171,8 +171,14 @@ public interface IWorkerContext {
return version;
}
public boolean isExamplesPackage() {
return !(id.startsWith("hl7.fhir.") && id.endsWith(".example"));
boolean b = id.startsWith("hl7.fhir.") && id.endsWith(".examples");
return b;
}
@Override
public String toString() {
return id+"#"+version;
}
}
public class PackageDetails extends PackageVersion {

View File

@ -86,6 +86,16 @@ public class Element extends Base {
return CONTAINED;
throw new FHIRException("Unknown resource containing a native resource: "+property.getDefinition().getId());
}
public String toHuman() {
switch (this) {
case BUNDLE_ENTRY: return "entry";
case BUNDLE_OUTCOME: return "outcome";
case CONTAINED: return "contained";
case PARAMETER: return "parameter";
default: return "??";
}
}
}
private List<String> comments;// not relevant for production, but useful in documentation

View File

@ -53,6 +53,7 @@ import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Quantity;
import org.hl7.fhir.r5.model.Range;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.SampledData;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -559,7 +560,11 @@ public class DataRenderer extends Renderer {
} else if (uri.getValue().startsWith("mailto:")) {
x.ah(uri.getValue()).addText(uri.getValue().substring(7));
} else {
if (uri.getValue().contains("|")) {
Resource target = context.getContext().fetchResource(Resource.class, uri.getValue());
if (target != null && target.hasUserData("path")) {
String title = target instanceof CanonicalResource ? ((CanonicalResource) target).present() : uri.getValue();
x.ah(target.getUserString("path")).addText(title);
} else if (uri.getValue().contains("|")) {
x.ah(uri.getValue().substring(0, uri.getValue().indexOf("|"))).addText(uri.getValue());
} else if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("ftp:")) {
x.ah(uri.getValue()).addText(uri.getValue());

View File

@ -211,7 +211,14 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
r.getCells().add(gen.new Cell(null, null, q.getDescription(), null, null));
return r;
}
private String getSpecLink(String path) {
return Utilities.pathURL(context.getSpecificationLink(), path);
}
private String getSDCLink(String path) {
return Utilities.pathURL("http://hl7.org/fhir/uv/sdc", path); // for now?
}
private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, Questionnaire q, QuestionnaireItemComponent i, boolean hasFlags) throws IOException {
Row r = gen.new Row();
@ -238,25 +245,25 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, "Is Readonly").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-readonly.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) {
flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-isSubject.html"), null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden")) {
flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png"))));
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay")) {
flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png"))));
}
if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) {
flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-observationLinkPeriod"), null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png"))));
}
if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation")) {
String code = ToolingExtensions.readStringExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation");
flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
}
if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory")) {
CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory").getValueCodeableConcept();
String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category");
flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory", null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-displayCategory"), null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
}
}
Cell defn = gen.new Cell();

View File

@ -62,7 +62,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
public boolean render(XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException {
switch (context.getQuestionnaireMode()) {
case FORM: return renderForm(x, qr);
case FORM: return renderTree(x, qr);
case LINKS: return renderLinks(x, qr);
// case LOGIC: return renderLogic(x, q);
// case DEFNS: return renderDefns(x, q);
@ -74,7 +74,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
public boolean renderTree(XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context.getDestDir(), context.isInlineGraphics(), true);
TableModel model = gen.new TableModel("qtree="+qr.getId(), true);
TableModel model = gen.new TableModel("qtree="+qr.getId(), false);
model.setAlternating(true);
model.setDocoImg(context.getSpecificationLink() +"help16.png");
model.setDocoRef(context.getSpecificationLink()+"formats.html#table");
@ -175,26 +175,44 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
}
} else if (answers.size() == 1) {
BaseWrapper ans = answers.get(0);
Base b = ans.get("value[x]");
if (b == null) {
r.getCells().add(gen.new Cell(null, null, "null!", null, null));
} else if (b.isPrimitive()) {
r.getCells().add(gen.new Cell(null, null, b.primitiveValue(), null, null));
} else {
XhtmlNode x = new XhtmlNode(NodeType.Element, "span");
Cell cell = gen.new Cell(null, null, null, null, null);
Piece p = gen.new Piece("span");
p.getChildren().add(x);
cell.addPiece(p);
render(x, (DataType) b);
r.getCells().add(cell);
}
renderAnswer(gen, q, r, ans);
} else {
r.getCells().add(gen.new Cell(null, null, "{todo #2}", null, null));
r.getCells().add(gen.new Cell(null, null, null, null, null));
for (BaseWrapper ans : answers) {
Row ar = gen.new Row();
ar.setIcon("icon-q-string.png", "Item");
ar.getSubRows().add(ar);
ar.getCells().add(gen.new Cell(null, null, null, null, null));
ar.getCells().add(gen.new Cell(null, null, text, null, null));
ar.getCells().add(gen.new Cell(null, null, null, null, null));
renderAnswer(gen, q, ar, ans);
}
}
return hasExt;
}
public void renderAnswer(HierarchicalTableGenerator gen, ResourceWrapper q, Row r, BaseWrapper ans) throws UnsupportedEncodingException, IOException {
List<BaseWrapper> items;
Base b = ans.get("value[x]");
if (b == null) {
r.getCells().add(gen.new Cell(null, null, "null!", null, null));
} else if (b.isPrimitive()) {
r.getCells().add(gen.new Cell(null, null, b.primitiveValue(), null, null));
} else {
XhtmlNode x = new XhtmlNode(NodeType.Element, "span");
Cell cell = gen.new Cell(null, null, null, null, null);
Piece p = gen.new Piece("span");
p.getChildren().add(x);
cell.addPiece(p);
render(x, (DataType) b);
r.getCells().add(cell);
}
items = ans.children("item");
for (BaseWrapper si : items) {
renderTreeItem(gen, r.getSubRows(), q, si);
}
}
private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, QuestionnaireResponse q, QuestionnaireResponseItemComponent i) throws IOException {
Row r = gen.new Row();

View File

@ -117,6 +117,9 @@ public class RendererFactory {
if ("DiagnosticReport".equals(resource.getName())) {
return new DiagnosticReportRenderer(context);
}
if ("QuestionnaireResponse".equals(resource.getName())) {
return new QuestionnaireResponseRenderer(context);
}
return new ProfileDrivenRenderer(context, resourceContext);
}

View File

@ -208,6 +208,34 @@ public class FHIRPathEngine {
}
}
public static class TypedElementDefinition {
private ElementDefinition element;
private String type;
public TypedElementDefinition(ElementDefinition element, String type) {
super();
this.element = element;
this.type = type;
}
public TypedElementDefinition(ElementDefinition element) {
super();
this.element = element;
}
public ElementDefinition getElement() {
return element;
}
public String getType() {
return type;
}
public List<TypeRefComponent> getTypes() {
List<TypeRefComponent> res = new ArrayList<ElementDefinition.TypeRefComponent>();
for (TypeRefComponent tr : element.getType()) {
if (type == null || type.equals(tr.getCode())) {
res.add(tr);
}
}
return res;
}
}
private IWorkerContext worker;
private IEvaluationContext hostServices;
private StringBuilder log = new StringBuilder();
@ -5442,63 +5470,63 @@ public class FHIRPathEngine {
* @throws PathEngineException
* @throws DefinitionException
*/
public ElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, ElementDefinition element, StructureDefinition source) throws DefinitionException {
public TypedElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, TypedElementDefinition element, StructureDefinition source) throws DefinitionException {
StructureDefinition sd = profile;
ElementDefinition focus = null;
TypedElementDefinition focus = null;
boolean okToNotResolve = false;
if (expr.getKind() == Kind.Name) {
if (element.hasSlicing()) {
ElementDefinition slice = pickMandatorySlice(sd, element);
if (element.getElement().hasSlicing()) {
ElementDefinition slice = pickMandatorySlice(sd, element.getElement());
if (slice == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getElement().getId());
}
element = slice;
element = new TypedElementDefinition(slice);
}
if (expr.getName().equals("$this")) {
focus = element;
} else {
List<ElementDefinition> childDefinitions;
childDefinitions = profileUtilities.getChildMap(sd, element);
childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
// if that's empty, get the children of the type
if (childDefinitions.isEmpty()) {
sd = fetchStructureByType(element, expr);
if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId());
}
childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
}
for (ElementDefinition t : childDefinitions) {
if (tailMatches(t, expr.getName()) && !t.hasSlicing()) { // GG: slicing is a problem here. This is for an exetnsion with a fixed value (type slicing)
focus = t;
focus = new TypedElementDefinition(t);
break;
}
}
}
} else if (expr.getKind() == Kind.Function) {
if ("resolve".equals(expr.getName())) {
if (!element.hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId());
if (element.getTypes().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getElement().getId());
}
if (element.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId());
if (element.getTypes().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getElement().getId());
}
if (!element.getType().get(0).hasTarget()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")");
if (!element.getTypes().get(0).hasTarget()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getElement().getId(), element.getElement().getType().get(0).getCode()+")");
}
if (element.getType().get(0).getTargetProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId());
if (element.getTypes().get(0).getTargetProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getElement().getId());
}
sd = worker.fetchResource(StructureDefinition.class, element.getType().get(0).getTargetProfile().get(0).getValue());
sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue());
if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getTypes().get(0).getTargetProfile(), element.getElement().getId());
}
focus = sd.getSnapshot().getElementFirstRep();
focus = new TypedElementDefinition(sd.getSnapshot().getElementFirstRep());
} else if ("extension".equals(expr.getName())) {
String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue();
List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element);
List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
for (ElementDefinition t : childDefinitions) {
if (t.getPath().endsWith(".extension") && t.hasSliceName()) {
System.out.println("t: "+t.getId());
@ -5511,29 +5539,33 @@ public class FHIRPathEngine {
if (profileUtilities.getChildMap(sd, t).isEmpty()) {
sd = exsd;
}
focus = t;
focus = new TypedElementDefinition(t);
break;
}
}
}
if (focus == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getId(), sd.getUrl());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getElement().getId(), sd.getUrl());
}
} else if ("ofType".equals(expr.getName())) {
if (!element.hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId());
if (!element.getElement().hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getElement().getId());
}
if (element.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId());
List<String> atn = new ArrayList<>();
for (TypeRefComponent tr : element.getTypes()) {
if (!tr.hasCode()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getElement().getId());
}
atn.add(tr.getCode());
}
if (!element.getType().get(0).hasCode()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId());
}
String atn = element.getType().get(0).getCode();
String stn = expr.getParameters().get(0).getName();
okToNotResolve = true;
if ((atn.equals(stn))) {
focus = element;
if ((atn.contains(stn))) {
if (element.getTypes().size() > 1) {
focus = new TypedElementDefinition(element.getElement(), stn);
} else {
focus = element;
}
}
} else {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName());
@ -5548,7 +5580,7 @@ public class FHIRPathEngine {
if (okToNotResolve) {
return null;
} else {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getId(), profile.getUrl());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getElement().getId(), profile.getUrl());
}
} else if (expr.getInner() == null) {
return focus;
@ -5568,20 +5600,20 @@ public class FHIRPathEngine {
}
private StructureDefinition fetchStructureByType(ElementDefinition ed, ExpressionNode expr) throws DefinitionException {
if (ed.getType().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId());
private StructureDefinition fetchStructureByType(TypedElementDefinition ed, ExpressionNode expr) throws DefinitionException {
if (ed.getTypes().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getElement().getId());
}
if (ed.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId());
if (ed.getTypes().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getElement().getId());
}
if (ed.getType().get(0).getProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId());
if (ed.getTypes().get(0).getProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getElement().getId());
}
if (ed.getType().get(0).hasProfile()) {
return worker.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue());
if (ed.getTypes().get(0).hasProfile()) {
return worker.fetchResource(StructureDefinition.class, ed.getTypes().get(0).getProfile().get(0).getValue());
} else {
return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs()));
return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getTypes().get(0).getCode(), worker.getOverrideVersionNs()));
}
}

View File

@ -130,7 +130,7 @@ public class VersionUtilities {
if (version.contains("-")) {
version = version.substring(0, version.indexOf("-"));
}
return Utilities.existsInList(version, "1.0.2", "1.4.0", "3.0.2", "4.0.1", "4.1.0", "4.3.0",CURRENT_FULL_VERSION);
return Utilities.existsInList(version, "1.0.2", "1.4.0", "3.0.2", "4.0.1", "4.1.0", "4.3.0", "5.0.0", CURRENT_FULL_VERSION);
}
public static String listSupportedVersions() {

View File

@ -29,7 +29,8 @@ public class I18nConstants {
public static final String BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE = "Bundle_BUNDLE_Entry_NoFirstResource";
public static final String BUNDLE_BUNDLE_ENTRY_NOFULLURL = "Bundle_BUNDLE_Entry_NoFullUrl";
public static final String BUNDLE_BUNDLE_ENTRY_FULLURL_REQUIRED = "BUNDLE_BUNDLE_ENTRY_FULLURL_REQUIRED";
public static final String BUNDLE_BUNDLE_ENTRY_NOPROFILE = "Bundle_BUNDLE_Entry_NoProfile";
public static final String BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL = "Bundle_BUNDLE_Entry_NoProfile_EXPL";
public static final String BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE = "Bundle_BUNDLE_Entry_NoProfile_TYPE";
public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES";
public static final String BUNDLE_BUNDLE_ENTRY_NOTFOUND = "Bundle_BUNDLE_Entry_NotFound";
public static final String BUNDLE_BUNDLE_ENTRY_ORPHAN = "Bundle_BUNDLE_Entry_Orphan";

View File

@ -8,7 +8,8 @@ Bundle_BUNDLE_Entry_NoFirst = Documents or Messages must contain at least one en
Bundle_BUNDLE_Entry_NoFirstResource = No resource on first entry
Bundle_BUNDLE_Entry_NoFullUrl = Bundle entry missing fullUrl
BUNDLE_BUNDLE_ENTRY_FULLURL_REQUIRED = Except for transactions and batches, each entry in a Bundle must have a fullUrl which is the identity of the resource in the entry
Bundle_BUNDLE_Entry_NoProfile = No profile found for contained resource of type ''{0}''
Bundle_BUNDLE_Entry_NoProfile_TYPE = No profile found for {0} resource of type ''{1}''
Bundle_BUNDLE_Entry_NoProfile_EXPL = Specified profile {2} not found for {0} resource of type ''{0}''
Bundle_BUNDLE_Entry_NotFound = Can''t find ''{0}'' in the bundle ({1})
Bundle_BUNDLE_Entry_Orphan = Entry {0} isn''t reachable by traversing from first Bundle entry
BUNDLE_BUNDLE_ENTRY_REVERSE = Entry {0} isn''t reachable by traversing forwards from first Bundle entry, and isn''t a resource type that is typically used that way - check this is not missed somewhere
@ -225,7 +226,7 @@ Validation_VAL_Profile_NoCheckMin = {2}: Unable to check minimum required ({1})
Validation_VAL_Profile_MultipleMatches = Found multiple matching profiles among choices: {0}
Validation_VAL_Profile_NoDefinition = No definition found for resource type ''{0}''
Validation_VAL_Profile_NoMatch = Unable to find a match for the specified profile among choices: {0}
Validation_VAL_Profile_NoSnapshot = StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided
Validation_VAL_Profile_NoSnapshot = StructureDefinition {0} has no snapshot - validation is against the snapshot, so it must be provided
Validation_VAL_Profile_NoType = The type of element {0} is not known, which is illegal. Valid types at this point are {1}
Validation_VAL_Profile_NotAllowed = This element is not allowed by the profile {0}
Validation_VAL_Profile_NotSlice = This element does not match any known slice {0} and slicing is CLOSED: {1}
@ -589,7 +590,7 @@ SD_MUST_HAVE_DERIVATION = StructureDefinition {0} must have a derivation, since
VALIDATION_VAL_PROFILE_OTHER_VERSION = Profile is for a different version of FHIR ({0}) so has been ignored
VALIDATION_VAL_PROFILE_THIS_VERSION_OK = Profile for this version of FHIR - all OK
VALIDATION_VAL_PROFILE_THIS_VERSION_OTHER = Profile is for this version of FHIR, but is an invalid type {0}
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES = Multiple profiles found for contained resource. This is not supported at this time. (Type {0}: {1})
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES = Multiple profiles found for {0} resource. This is not supported at this time. (Type {1}: {2})
RENDER_BUNDLE_HEADER_ROOT = Bundle {0} of type {1}
RENDER_BUNDLE_HEADER_ENTRY = Entry {0}
RENDER_BUNDLE_HEADER_ENTRY_URL = Entry {0} - Full URL = {1}

View File

@ -156,10 +156,10 @@ public class EnableWhenEvaluator {
return true;
}
List<EnableWhenResult> evaluationResults = qitem.getEnableWhen()
.stream()
.map(enableCondition -> evaluateCondition(enableCondition, qitem, qstack))
.collect(Collectors.toList());
List<EnableWhenResult> evaluationResults = new ArrayList<>();
for (QuestionnaireItemEnableWhenComponent enableCondition : qitem.getEnableWhen()) {
evaluationResults.add(evaluateCondition(enableCondition, qitem, qstack));
}
return checkConditionResults(evaluationResults, qitem);
}
@ -206,9 +206,10 @@ public class EnableWhenEvaluator {
}
return new EnableWhenResult(((BooleanType) answer).booleanValue() != answerItems.isEmpty(), enableCondition);
}
boolean result = answerItems
.stream()
.anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator()));
boolean result = false;
for (Element answer : answerItems) {
result = result || evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator());
}
return new EnableWhenResult(result, enableCondition);
}
@ -339,6 +340,11 @@ public class EnableWhenEvaluator {
}
retVal.addAll(findOnItem(item, question));
}
// didn't find it? look inside the items on the answers too
List<Element> answerChildren = focus.getChildren(ANSWER_ELEMENT);
for (Element answer : answerChildren) {
retVal.addAll(findOnItem(answer, question));
}
// In case the question with the enableWhen is a direct child of the question with
// the answer that it depends on. There is an example of this in the

View File

@ -135,6 +135,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition;
import org.hl7.fhir.r5.utils.validation.*;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
@ -3370,7 +3371,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
discriminator = discriminator.substring(0, discriminator.length() - 10);
}
ElementDefinition ed = null;
TypedElementDefinition ted = null;
String fp = fixExpr(discriminator, null);
ExpressionNode expr = null;
try {
@ -3380,10 +3381,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR_BAD_PATH, e.getMessage(), fp), e);
}
long t2 = System.nanoTime();
ed = fpe.evaluateDefinition(expr, profile, element, srcProfile);
ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile);
timeTracker.sd(t2);
if (ed != null)
elements.add(ed);
if (ted != null)
elements.add(ted.getElement());
for (TypeRefComponent type : element.getType()) {
for (CanonicalType p : type.getProfile()) {
@ -3405,10 +3406,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
expr = fpe.parse(fp);
t2 = System.nanoTime();
ed = fpe.evaluateDefinition(expr, profile, element, srcProfile);
ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile);
timeTracker.sd(t2);
if (ed != null)
elements.add(ed);
if (ted != null)
elements.add(ted.getElement());
}
}
return elements;
@ -4452,7 +4453,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
return;
}
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT)) {
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT, defn.getUrl())) {
List<ValidationMessage> localErrors = new ArrayList<ValidationMessage>();
resTracker.startValidating(defn);
trackUsage(defn, hostContext, element);
@ -4644,7 +4645,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else if (typeForResource.getProfile().isEmpty()) {
@ -4654,7 +4655,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special.toHuman(), resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else {
@ -4663,7 +4664,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
b.append(u.asStringValue());
}
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, typeForResource.getCode(), b.toString());
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, special.toHuman(), typeForResource.getCode(), b.toString());
}
}
} else {