use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method checkMustSupport.
public void checkMustSupport(StructureDefinition profile, ElementInfo ei) {
String usesMustSupport = profile.getUserString("usesMustSupport");
if (usesMustSupport == null) {
usesMustSupport = "N";
for (ElementDefinition pe : profile.getSnapshot().getElement()) {
if (pe.getMustSupport()) {
usesMustSupport = "Y";
break;
}
}
profile.setUserData("usesMustSupport", usesMustSupport);
}
if (usesMustSupport.equals("Y")) {
String elementSupported = ei.getElement().getUserString("elementSupported");
if (elementSupported == null || ei.definition.getMustSupport())
if (ei.definition.getMustSupport()) {
ei.getElement().setUserData("elementSupported", "Y");
}
}
}
use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method listChildren.
public List<ElementInfo> listChildren(Element element, NodeStack stack) {
// 1. List the children, and remember their exact path (convenience)
List<ElementInfo> children = new ArrayList<ElementInfo>();
ChildIterator iter = new ChildIterator(this, stack.getLiteralPath(), element);
while (iter.next()) children.add(new ElementInfo(iter.name(), iter.element(), iter.path(), iter.count()));
return children;
}
use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method assignChildren.
public List<String> assignChildren(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, Element resource, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children) throws DefinitionException {
// 2. assign children to a definition
// for each definition, for each child, check whether it belongs in the slice
ElementDefinition slicer = null;
boolean unsupportedSlicing = false;
List<String> problematicPaths = new ArrayList<String>();
String slicingPath = null;
int sliceOffset = 0;
for (int i = 0; i < childDefinitions.size(); i++) {
ElementDefinition ed = childDefinitions.get(i);
boolean childUnsupportedSlicing = false;
boolean process = true;
if (ed.hasSlicing() && !ed.getSlicing().getOrdered()) {
slicingPath = ed.getPath();
} else if (slicingPath != null && ed.getPath().equals(slicingPath)) {
// nothing
;
} else if (slicingPath != null && !ed.getPath().startsWith(slicingPath)) {
slicingPath = null;
}
// where are we with slicing
if (ed.hasSlicing()) {
if (slicer != null && slicer.getPath().equals(ed.getPath())) {
String errorContext = "profile " + profile.getUrl();
if (!resource.getChildValue(ID).isEmpty()) {
errorContext += "; instance " + resource.getChildValue("id");
}
throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
}
slicer = ed;
process = false;
sliceOffset = i;
} else if (slicer != null && !slicer.getPath().equals(ed.getPath()))
slicer = null;
for (ElementInfo ei : children) {
if (ei.sliceInfo == null) {
ei.sliceInfo = new ArrayList<>();
}
unsupportedSlicing = matchSlice(hostContext, errors, ei.sliceInfo, profile, stack, slicer, unsupportedSlicing, problematicPaths, sliceOffset, i, ed, childUnsupportedSlicing, ei);
}
}
int last = -1;
ElementInfo lastei = null;
int lastSlice = -1;
for (ElementInfo ei : children) {
String sliceInfo = "";
if (slicer != null) {
sliceInfo = " (slice: " + slicer.getPath() + ")";
}
if (!unsupportedSlicing) {
if (ei.additionalSlice && ei.definition != null) {
if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true) /* TODO: replace "true" with condition to check that this element is at "end" */
{
slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, isProfile(slicer) || isCritical(ei.sliceInfo), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : " defined in the profile " + profile.getUrl()), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : I18nConstants.DEFINED_IN_THE_PROFILE + profile.getUrl()) + errorSummaryForSlicingAsHtml(ei.sliceInfo), errorSummaryForSlicingAsText(ei.sliceInfo));
} else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) {
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTSLICE, (profile == null ? "" : " defined in the profile " + profile.getUrl()), errorSummaryForSlicing(ei.sliceInfo));
}
} else {
// Don't raise this if we're in an abstract profile, like Resource
if (!profile.getAbstract()) {
rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.getPath(), (ei.definition != null), I18nConstants.VALIDATION_VAL_PROFILE_NOTALLOWED, profile.getUrl());
}
}
}
// TODO: Should get the order of elements correct when parsing elements that are XML attributes vs. elements
boolean isXmlAttr = false;
if (ei.definition != null) {
for (Enumeration<PropertyRepresentation> r : ei.definition.getRepresentation()) {
if (r.getValue() == PropertyRepresentation.XMLATTR) {
isXmlAttr = true;
break;
}
}
}
if (!ToolingExtensions.readBoolExtension(profile, "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-no-order")) {
boolean ok = (ei.definition == null) || (ei.index >= last) || isXmlAttr;
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), ok, I18nConstants.VALIDATION_VAL_PROFILE_OUTOFORDER, profile.getUrl(), ei.getName(), lastei == null ? "(null)" : lastei.getName());
}
if (ei.slice != null && ei.index == last && ei.slice.getSlicing().getOrdered()) {
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), (ei.definition == null) || (ei.sliceindex >= lastSlice) || isXmlAttr, I18nConstants.VALIDATION_VAL_PROFILE_SLICEORDER, profile.getUrl(), ei.getName());
}
if (ei.definition == null || !isXmlAttr) {
last = ei.index;
lastei = ei;
}
if (ei.slice != null) {
lastSlice = ei.sliceindex;
} else {
lastSlice = -1;
}
}
return problematicPaths;
}
use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method validateElement.
private void validateElement(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl) throws FHIRException {
String id = element.getChildValue("id");
if (!Utilities.noString(id)) {
if (stack.getIds().containsKey(id) && stack.getIds().get(id) != element) {
rule(errors, IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.DUPLICATE_ID, id);
}
if (!stack.isResetPoint()) {
stack.getIds().put(id, element);
}
}
if (definition.getPath().equals("StructureDefinition.snapshot")) {
// work around a known issue in the spec, that ids are duplicated in snapshot and differential
stack.resetIds();
}
// check type invariants
checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false);
if (definition.getFixed() != null) {
checkFixedValue(errors, stack.getLiteralPath(), element, definition.getFixed(), profile.getUrl(), definition.getSliceName(), null, false);
}
if (definition.getPattern() != null) {
checkFixedValue(errors, stack.getLiteralPath(), element, definition.getPattern(), profile.getUrl(), definition.getSliceName(), null, true);
}
// get the list of direct defined children, including slices
List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(profile, definition);
if (childDefinitions.isEmpty()) {
if (actualType == null)
// there'll be an error elsewhere in this case, and we're going to stop.
return;
childDefinitions = getActualTypeChildren(hostContext, element, actualType);
} else if (definition.getType().size() > 1) {
// this only happens when the profile constrains the abstract children but leaves th choice open.
if (actualType == null)
// there'll be an error elsewhere in this case, and we're going to stop.
return;
List<ElementDefinition> typeChildDefinitions = getActualTypeChildren(hostContext, element, actualType);
// what were going to do is merge them - the type is not allowed to constrain things that the child definitions already do (well, if it does, it'll be ignored)
mergeChildLists(childDefinitions, typeChildDefinitions, definition.getPath(), actualType);
}
List<ElementInfo> children = listChildren(element, stack);
List<String> problematicPaths = assignChildren(hostContext, errors, profile, resource, stack, childDefinitions, children);
checkCardinalities(errors, profile, element, stack, childDefinitions, children, problematicPaths);
// 5. inspect each child for validity
for (ElementInfo ei : children) {
checkChild(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl);
}
}
use of org.hl7.fhir.validation.instance.utils.ElementInfo in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method checkCardinalities.
public void checkCardinalities(List<ValidationMessage> errors, StructureDefinition profile, Element element, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children, List<String> problematicPaths) throws DefinitionException {
// 3. report any definitions that have a cardinality problem
for (ElementDefinition ed : childDefinitions) {
if (ed.getRepresentation().isEmpty()) {
// ignore xml attributes
int count = 0;
List<ElementDefinition> slices = null;
if (ed.hasSlicing())
slices = profileUtilities.getSliceList(profile, ed);
for (ElementInfo ei : children) if (ei.definition == ed)
count++;
else if (slices != null) {
for (ElementDefinition sed : slices) {
if (ei.definition == sed) {
count++;
break;
}
}
}
if (ed.getMin() > 0) {
if (problematicPaths.contains(ed.getPath()))
hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMIN, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()));
else {
if (count < ed.getMin()) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
}
}
}
if (ed.hasMax() && !ed.getMax().equals("*")) {
if (problematicPaths.contains(ed.getPath()))
hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count <= Integer.parseInt(ed.getMax()), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMAX, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax());
else if (count > Integer.parseInt(ed.getMax())) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MAXIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax(), Integer.toString(count));
}
}
}
}
}
Aggregations