use of org.hl7.elm.r1.Expression in project org.hl7.fhir.core by hapifhir.
the class OperationOutcomeUtilities method convertToIssue.
public static OperationOutcomeIssueComponent convertToIssue(ValidationMessage message, OperationOutcome op) {
OperationOutcomeIssueComponent issue = new OperationOutcome.OperationOutcomeIssueComponent();
issue.setUserData("source.vm", message);
issue.setCode(convert(message.getType()));
if (message.getLocation() != null) {
// message location has a fhirPath in it. We need to populate the expression
issue.addExpression(message.getLocation());
}
// pass through line/col if they're present
if (message.getLine() >= 0)
issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_LINE).setValue(new IntegerType(message.getLine()));
if (message.getCol() >= 0)
issue.addExtension().setUrl(ToolingExtensions.EXT_ISSUE_COL).setValue(new IntegerType(message.getCol()));
issue.setSeverity(convert(message.getLevel()));
CodeableConcept c = new CodeableConcept();
c.setText(message.getMessage());
issue.setDetails(c);
if (message.getSource() != null) {
issue.getExtension().add(ToolingExtensions.makeIssueSource(message.getSource()));
}
issue.setUserData("source.msg", message);
return issue;
}
use of org.hl7.elm.r1.Expression in project org.hl7.fhir.core by hapifhir.
the class GraphDefinitionEngine method processLinkPath.
private void processLinkPath(String focusPath, Resource focus, GraphDefinitionLinkComponent link, int depth) {
String path = focusPath + " -> " + link.getPath();
check(link.hasPath(), "Path is needed at " + path);
check(!link.hasSliceName(), "SliceName is not yet supported at " + path);
ExpressionNode node;
if (link.getPathElement().hasUserData(TAG_NAME)) {
node = (ExpressionNode) link.getPathElement().getUserData(TAG_NAME);
} else {
node = engine.parse(link.getPath());
link.getPathElement().setUserData(TAG_NAME, node);
}
List<Base> matches = engine.evaluate(null, focus, focus, focus, node);
check(!validating || matches.size() >= (link.hasMin() ? link.getMin() : 0), "Link at path " + path + " requires at least " + link.getMin() + " matches, but only found " + matches.size());
check(!validating || matches.size() <= (link.hasMax() ? Integer.parseInt(link.getMax()) : Integer.MAX_VALUE), "Link at path " + path + " requires at most " + link.getMax() + " matches, but found " + matches.size());
for (Base sel : matches) {
// todo: should a URL be ok?
check(sel.fhirType().equals("Reference"), "Selected node from an expression must be a Reference");
ReferenceResolution res = services.lookup(appInfo, focus, (Reference) sel);
if (res != null) {
// todo
check(res.getTargetContext() != focus, "how to handle contained resources is not yet resolved");
for (GraphDefinitionLinkTargetComponent tl : link.getTarget()) {
if (tl.getType().equals(res.getTarget().fhirType())) {
Resource r = (Resource) res.getTarget();
if (!isInBundle(r)) {
addToBundle(r);
for (GraphDefinitionLinkComponent l : graphDefinition.getLink()) {
processLink(focus.fhirType(), r, l, depth + 1);
}
}
}
}
}
}
}
use of org.hl7.elm.r1.Expression in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method buildHumanNameExpression.
private void buildHumanNameExpression(ElementDefinition ed, StringBuilder expression, String discriminator, HumanName name) throws DefinitionException {
if (name.hasExtension())
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN__EXTENSIONS_ARE_NOT_ALLOWED__FOR_DISCRIMINATOR_FOR_SLICE_, discriminator, ed.getId()));
boolean first = true;
expression.append(discriminator + ".where(");
if (name.hasUse()) {
first = false;
expression.append("use = '" + name.getUse().toCode() + "'");
}
if (name.hasText()) {
if (first)
first = false;
else
expression.append(" and ");
expression.append("text = '" + name.getText() + "'");
}
if (name.hasFamily()) {
if (first)
first = false;
else
expression.append(" and ");
expression.append("family = '" + name.getFamily() + "'");
}
if (name.hasGiven()) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE, discriminator, ed.getId(), name.fhirType(), "given"));
}
if (name.hasPrefix()) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE, discriminator, ed.getId(), name.fhirType(), "prefix"));
}
if (name.hasSuffix()) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE, discriminator, ed.getId(), name.fhirType(), "suffix"));
}
if (name.hasPeriod()) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE, discriminator, ed.getId(), name.fhirType(), "period"));
}
if (first) {
throw new DefinitionException(context.formatMessage(I18nConstants.UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE, discriminator, ed.getId(), name.fhirType()));
}
expression.append(").exists()");
}
use of org.hl7.elm.r1.Expression in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method sliceMatches.
/**
* @param element - the candidate that might be in the slice
* @param path - for reporting any errors. the XPath for the element
* @param slicer - the definition of how slicing is determined
* @param ed - the slice for which to test membership
* @param errors
* @param stack
* @param srcProfile
* @return
* @throws DefinitionException
* @throws DefinitionException
* @throws IOException
* @throws FHIRException
*/
private boolean sliceMatches(ValidatorHostContext hostContext, Element element, String path, ElementDefinition slicer, ElementDefinition ed, StructureDefinition profile, List<ValidationMessage> errors, List<ValidationMessage> sliceInfo, NodeStack stack, StructureDefinition srcProfile) throws DefinitionException, FHIRException {
if (!slicer.getSlicing().hasDiscriminator())
// cannot validate in this case
return false;
ExpressionNode n = (ExpressionNode) ed.getUserData("slice.expression.cache");
if (n == null) {
long t = System.nanoTime();
// GG: this approach is flawed because it treats discriminators individually rather than collectively
StringBuilder expression = new StringBuilder("true");
boolean anyFound = false;
Set<String> discriminators = new HashSet<>();
for (ElementDefinitionSlicingDiscriminatorComponent s : slicer.getSlicing().getDiscriminator()) {
String discriminator = s.getPath();
discriminators.add(discriminator);
List<ElementDefinition> criteriaElements = getCriteriaForDiscriminator(path, ed, discriminator, profile, s.getType() == DiscriminatorType.PROFILE, srcProfile);
boolean found = false;
for (ElementDefinition criteriaElement : criteriaElements) {
found = true;
if (s.getType() == DiscriminatorType.TYPE) {
String type = null;
if (!criteriaElement.getPath().contains("[") && discriminator.contains("[")) {
discriminator = discriminator.substring(0, discriminator.indexOf('['));
String lastNode = tail(discriminator);
type = tail(criteriaElement.getPath()).substring(lastNode.length());
type = type.substring(0, 1).toLowerCase() + type.substring(1);
} else if (!criteriaElement.hasType() || criteriaElement.getType().size() == 1) {
if (discriminator.contains("["))
discriminator = discriminator.substring(0, discriminator.indexOf('['));
if (criteriaElement.hasType()) {
type = criteriaElement.getType().get(0).getWorkingCode();
} else if (!criteriaElement.getPath().contains(".")) {
type = criteriaElement.getPath();
} else {
throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl()));
}
} else if (criteriaElement.getType().size() > 1) {
throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_MULTIPLE_TYPES_, discriminator, ed.getId(), profile.getUrl(), criteriaElement.typeSummary()));
} else
throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl()));
if (discriminator.isEmpty())
expression.append(" and $this is " + type);
else
expression.append(" and " + discriminator + " is " + type);
} else if (s.getType() == DiscriminatorType.PROFILE) {
if (criteriaElement.getType().size() == 0) {
throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
}
if (criteriaElement.getType().size() != 1) {
throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_ONLY_ONE_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
}
List<CanonicalType> list = discriminator.endsWith(".resolve()") || discriminator.equals("resolve()") ? criteriaElement.getType().get(0).getTargetProfile() : criteriaElement.getType().get(0).getProfile();
if (list.size() == 0) {
throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE_WITH_A_PROFILE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
} else if (list.size() > 1) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" or ");
for (CanonicalType c : list) {
b.append(discriminator + ".conformsTo('" + c.getValue() + "')");
}
expression.append(" and (" + b + ")");
} else {
expression.append(" and " + discriminator + ".conformsTo('" + list.get(0).getValue() + "')");
}
} else if (s.getType() == DiscriminatorType.EXISTS) {
if (criteriaElement.hasMin() && criteriaElement.getMin() >= 1)
expression.append(" and (" + discriminator + ".exists())");
else if (criteriaElement.hasMax() && criteriaElement.getMax().equals("0"))
expression.append(" and (" + discriminator + ".exists().not())");
else
throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_ELEMENT_EXISTENCE_BUT_SLICE__NEITHER_SETS_MIN1_OR_MAX0, discriminator, ed.getId()));
} else if (criteriaElement.hasFixed()) {
buildFixedExpression(ed, expression, discriminator, criteriaElement);
} else if (criteriaElement.hasPattern()) {
buildPattternExpression(ed, expression, discriminator, criteriaElement);
} else if (criteriaElement.hasBinding() && criteriaElement.getBinding().hasStrength() && criteriaElement.getBinding().getStrength().equals(BindingStrength.REQUIRED) && criteriaElement.getBinding().hasValueSet()) {
expression.append(" and (" + discriminator + " memberOf '" + criteriaElement.getBinding().getValueSet() + "')");
} else {
found = false;
}
if (found)
break;
}
if (found)
anyFound = true;
}
if (!anyFound) {
if (slicer.getSlicing().getDiscriminator().size() > 1)
throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_ANY_DISCRIMINATORS__FOR_SLICE__IN_PROFILE___NONE_OF_THE_DISCRIMINATOR__HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators));
else
throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_DISCRIMINATOR__FOR_SLICE__IN_PROFILE___THE_DISCRIMINATOR__DOES_NOT_HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators));
}
try {
n = fpe.parse(fixExpr(expression.toString(), null));
} catch (FHIRLexerException e) {
if (STACK_TRACE)
e.printStackTrace();
throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, expression, profile.getUrl(), path, e.getMessage()));
}
timeTracker.fpe(t);
ed.setUserData("slice.expression.cache", n);
}
ValidatorHostContext shc = hostContext.forSlicing();
boolean pass = evaluateSlicingExpression(shc, element, path, profile, n);
if (!pass) {
slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, isProfile(slicer), (context.formatMessage(I18nConstants.DOES_NOT_MATCH_SLICE_, ed.getSliceName())), "discriminator = " + Utilities.escapeXml(n.toString()), null);
for (String url : shc.getSliceRecords().keySet()) {
slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, isProfile(slicer), context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, stack.getLiteralPath(), url), context.formatMessage(I18nConstants.PROFILE__DOES_NOT_MATCH_FOR__BECAUSE_OF_THE_FOLLOWING_PROFILE_ISSUES__, url, stack.getLiteralPath(), errorSummaryForSlicingAsHtml(shc.getSliceRecords().get(url))), errorSummaryForSlicingAsText(shc.getSliceRecords().get(url)));
}
}
return pass;
}
use of org.hl7.elm.r1.Expression in project org.hl7.fhir.core by hapifhir.
the class ValidationEngine method evaluateFhirPath.
public String evaluateFhirPath(String source, String expression) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
FHIRPathEngine fpe = this.getValidator(null).getFHIRPathEngine();
Element e = Manager.parseSingle(context, new ByteArrayInputStream(cnt.focus), cnt.cntType);
ExpressionNode exp = fpe.parse(expression);
return fpe.evaluateToString(new ValidatorHostContext(context, e), e, e, e, exp);
}
Aggregations