Add support for bundle profile parameter

This commit is contained in:
Grahame Grieve 2020-08-11 06:40:11 +10:00
parent 83dc198dd1
commit 20a7682c96
10 changed files with 234 additions and 88 deletions

View File

@ -43,6 +43,8 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import com.google.gson.JsonObject;
@ -56,6 +58,30 @@ import com.google.gson.JsonObject;
*/
public interface IResourceValidator {
public class BundleValidationRule {
private String rule;
private String profile;
private boolean checked;
public BundleValidationRule(String rule, String profile) {
super();
this.rule = rule;
this.profile = profile;
}
public String getRule() {
return rule;
}
public String getProfile() {
return profile;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
}
public enum ReferenceValidationPolicy {
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
@ -189,6 +215,14 @@ public interface IResourceValidator {
public void setCrumbTrails(boolean crumbTrails);
/**
* Bundle validation rules allow for requesting particular entries in a bundle get validated against particular profiles
* Typically this is used from the command line to avoid having to construct profile just to validate a particular resource
* in a bundle against a particular profile
*
* @return
*/
public List<BundleValidationRule> getBundleValidationRules();
/**
* Validate suite
*

View File

@ -543,6 +543,7 @@ public class I18nConstants {
public static final String VALIDATION_VAL_PROFILE_SIGNPOST = "VALIDATION_VAL_PROFILE_SIGNPOST";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = "VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_META = "VALIDATION_VAL_PROFILE_SIGNPOST_META";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM = "VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM";
public static final String VALIDATION_VAL_PROFILE_SLICEORDER = "Validation_VAL_Profile_SliceOrder";
public static final String VALIDATION_VAL_PROFILE_OTHER_VERSION = "VALIDATION_VAL_PROFILE_OTHER_VERSION";
public static final String VALIDATION_VAL_PROFILE_THIS_VERSION_OK = "VALIDATION_VAL_PROFILE_THIS_VERSION_OK";
@ -577,5 +578,11 @@ public class I18nConstants {
public static final String _HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_ = "_has_children__and_multiple_types__in_profile_";
public static final String _HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE = "_has_children__for_type__in_profile__but_cant_find_type";
public static final String _HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_ = "_has_no_children__and_no_types_in_profile_";
public static final String BUNDLE_RULE_NONE = "BUNDLE_RULE_NONE";
public static final String BUNDLE_RULE_UNKNOWN = "BUNDLE_RULE_UNKNOWN";
public static final String BUNDLE_RULE_INVALID_INDEX = "BUNDLE_RULE_INVALID_INDEX";
public static final String BUNDLE_RULE_PROFILE_UNKNOWN = "BUNDLE_RULE_PROFILE_UNKNOWN";
}

View File

@ -1,18 +1,18 @@
#InstanceValidator
Bad_file_path_error = \n********************\n* The file name you passed in, "{0}", doesn't exist on the local filesystem.\n* Please verify that this is valid file location.\n********************\n\n
Bad_file_path_error = \n********************\n* The file name you passed in, '{0}', doesn't exist on the local filesystem.\n* Please verify that this is valid file location.\n********************\n\n
Bundle_BUNDLE_Entry_Canonical = The canonical URL ({0}) cannot match the fullUrl ({1}) unless on the canonical server itself
Bundle_BUNDLE_Entry_Document = The first entry in a document must be a composition
Bundle_BUNDLE_Entry_IdUrlMismatch = Resource ID does not match the ID in the entry full URL ("{0}" vs "{1}")
Bundle_BUNDLE_Entry_IdUrlMismatch = Resource ID does not match the ID in the entry full URL ('{0}' vs '{1}')
Bundle_BUNDLE_Entry_MismatchIdUrl = The canonical URL ({0}) cannot match the fullUrl ({1}) unless the resource id ({2}) also matches
Bundle_BUNDLE_Entry_NoFirst = Documents or Messages must contain at least one entry
Bundle_BUNDLE_Entry_NoFirstResource = No resource on first entry
Bundle_BUNDLE_Entry_NoFullUrl = Bundle entry missing fullUrl
Bundle_BUNDLE_Entry_NoProfile = No profile found for contained resource of type "{0}"
Bundle_BUNDLE_Entry_NotFound = Can''t find "{0}" in the bundle ({1})
Bundle_BUNDLE_Entry_NoProfile = No profile found for contained 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_Type = The type "{0}" is not valid - no resources allowed here
Bundle_BUNDLE_Entry_Type2 = The type "{0}" is not valid - must be {1}
Bundle_BUNDLE_Entry_Type3 = The type "{0}" is not valid - must be one of {1}
Bundle_BUNDLE_Entry_Type = The type '{0}' is not valid - no resources allowed here
Bundle_BUNDLE_Entry_Type2 = The type '{0}' is not valid - must be {1}
Bundle_BUNDLE_Entry_Type3 = The type '{0}' is not valid - must be one of {1}
Bundle_BUNDLE_FullUrl_Missing = Relative Reference appears inside Bundle whose entry is missing a fullUrl
Bundle_BUNDLE_FullUrl_NeedVersion = Entries matching fullURL {0} should declare meta/versionId because there are version-specific references
Bundle_BUNDLE_MultipleMatches = Multiple matches in bundle for reference {0}
@ -20,7 +20,7 @@ Bundle_BUNDLE_Not_Local = URN reference is not locally contained within the bund
Bundle_MSG_Event_Count = Expected {0} but found {1} event elements
Bundle_Document_Date_Missing = A document must have a date
Bundle_Document_Date_Missing_html = [(type = 'document') implies (meta.lastUpdated.hasValue())]
CapabalityStatement_CS_SP_WrongType = Type mismatch - SearchParameter "{0}" type is {1}, but type here is {2}
CapabalityStatement_CS_SP_WrongType = Type mismatch - SearchParameter '{0}' type is {1}, but type here is {2}
CodeSystem_CS_VS_IncludeDetails = CodeSystem {0} has an ''all system'' value set of {1}, but the include has extra details
CodeSystem_CS_VS_Invalid = CodeSystem {0} has an ''all system'' value set of {1}, but doesn''t have a single include
CodeSystem_CS_VS_MisMatch = CodeSystem {0} has an ''all system'' value set of {1}, but it is an expansion
@ -31,19 +31,19 @@ Extension_EXT_Count_NotFound = Extension count mismatch: unable to find extensio
Extension_EXT_Fixed_Banned = No extensions allowed, as the specified fixed value doesn''t contain any extensions
Extension_EXT_Modifier_MismatchN = Extension modifier mismatch: the extension element is not labelled as a modifier, but the underlying extension is
Extension_EXT_Modifier_MismatchY = Extension modifier mismatch: the extension element is labelled as a modifier, but the underlying extension is not
Extension_EXT_Modifier_N = The Extension "{0}" must not be used as an extension (it''s a modifierExtension)
Extension_EXT_Modifier_Y = The Extension "{0}" must be used as a modifierExtension
Extension_EXT_Simple = The Extension "{0}" definition is for a simple extension, so it must contain a value, not extensions
Extension_EXT_SubExtension_Invalid = Sub-extension url "{0}" is not defined by the Extension {1}
Extension_EXT_Type = The Extension "{0}" definition allows for the types {1} but found type {2}
Extension_EXT_Modifier_N = The Extension '{0}' must not be used as an extension (it''s a modifierExtension)
Extension_EXT_Modifier_Y = The Extension '{0}' must be used as a modifierExtension
Extension_EXT_Simple = The Extension '{0}' definition is for a simple extension, so it must contain a value, not extensions
Extension_EXT_SubExtension_Invalid = Sub-extension url '{0}' is not defined by the Extension {1}
Extension_EXT_Type = The Extension '{0}' definition allows for the types {1} but found type {2}
Extension_EXT_URL_Absolute = Extension.url must be an absolute URL
Extension_EXT_Unknown = Unknown extension {0}
Extension_EXT_Unknown_NotHere = The extension {0} is unknown, and not allowed here
Extension_EXT_Url_NotFound = Extension.url is required
Extension_EXT_Version_Internal = Extension url "{0}" evaluation state illegal
Extension_EXT_Version_Invalid = Extension url "{0}" is not valid (invalid Version "{1}")
Extension_EXT_Version_InvalidId = Extension url "{0}" is not valid (invalid Element id "{1}")
Extension_EXT_Version_NoChange = Extension url "{0}" is not valid (Element id "{1}" is valid, but cannot be used in a cross-version paradigm because there has been no changes across the relevant versions)
Extension_EXT_Version_Internal = Extension url '{0}' evaluation state illegal
Extension_EXT_Version_Invalid = Extension url '{0}' is not valid (invalid Version '{1}')
Extension_EXT_Version_InvalidId = Extension url '{0}' is not valid (invalid Element id '{1}')
Extension_EXT_Version_NoChange = Extension url '{0}' is not valid (Element id '{1}' is valid, but cannot be used in a cross-version paradigm because there has been no changes across the relevant versions)
Fixed_Type_Checks_DT_Address_Line = Expected {0} but found {1} line elements
Fixed_Type_Checks_DT_Name_Family = Expected {0} but found {1} family elements
Fixed_Type_Checks_DT_Name_Given = Expected {0} but found {1} given elements
@ -57,11 +57,11 @@ Language_XHTML_Lang_Missing2 = Resource has a language, but the XHTML does not h
Language_XHTML_Lang_Missing3 = Resource has a language, but the XHTML does not have an xml:lang tag (needs both lang and xml:lang - see https://www.w3.org/TR/i18n-html-tech-lang/#langvalues)
Meta_RES_Security_Duplicate = Duplicate Security Label {0}
MustSupport_VAL_MustSupport = The element {0} is not marked as ''mustSupport'' in the profile {1}. Consider not using the element, or marking the element as must-Support in the profile
Profile_EXT_Not_Here = The extension {0} is not allowed to be used at this point (based on context invariant "{1}")
Profile_VAL_MissingElement = Missing element "{0}" - required by fixed value assigned in profile {1}
Profile_EXT_Not_Here = The extension {0} is not allowed to be used at this point (based on context invariant '{1}')
Profile_VAL_MissingElement = Missing element '{0}' - required by fixed value assigned in profile {1}
Profile_VAL_NotAllowed = The element {0} is present in the instance but not allowed in the applicable {1} specified in profile
Measure_MR_M_None = No Measure is identified, so no validation can be performed against the Measure
Measure_MR_M_NotFound = The Measure "{0}" could not be resolved, so no validation can be performed against the Measure
Measure_MR_M_NotFound = The Measure '{0}' could not be resolved, so no validation can be performed against the Measure
Questionnaire_QR_Item_BadOption = The value provided ({0}::{1}) is not in the options value set in the questionnaire
Questionnaire_QR_Item_Coding = Error {0} validating Coding against Questionnaire Options
Questionnaire_QR_Item_CodingNoOptions = Cannot validate Coding option because no option list is provided
@ -70,7 +70,7 @@ Questionnaire_QR_Item_Display = Items not of type DISPLAY should not have items
Questionnaire_QR_Item_Group = Items of type group should not have answers
Questionnaire_QR_Item_GroupAnswer = Items not of type group should not have items outside answers (use answer.item not .item)
Questionnaire_QR_Item_IntNoOptions = Cannot validate integer answer option because no option list is provided
Questionnaire_QR_Item_Missing = No response answer found for required item "{0}"
Questionnaire_QR_Item_Missing = No response answer found for required item '{0}'
Questionnaire_QR_Item_NoCoding = The code {0}::{1} is not a valid option
Questionnaire_QR_Item_NoDate = The date {0} is not a valid option
Questionnaire_QR_Item_NoInteger = The integer {0} is not a valid option
@ -85,8 +85,8 @@ Questionnaire_QR_Item_NoString = The string {0} is not a valid option
Questionnaire_QR_Item_NoTime = The time {0} is not a valid option
Questionnaire_QR_Item_NoType = Definition for item {0} does not contain a type
Questionnaire_QR_Item_NotEnabled = Item has answer (2), even though it is not enabled {0}
Questionnaire_QR_Item_NotEnabled2 = Item has answer, even though it is not enabled (item id = "{0}")
Questionnaire_QR_Item_NotFound = LinkId "{0}" not found in questionnaire
Questionnaire_QR_Item_NotEnabled2 = Item has answer, even though it is not enabled (item id = '{0}')
Questionnaire_QR_Item_NotFound = LinkId '{0}' not found in questionnaire
Questionnaire_QR_Item_OnlyOneA = Only one response answer item with this linkId allowed
Questionnaire_QR_Item_OnlyOneI = Only one response item with this linkId allowed - {0}
Questionnaire_QR_Item_Order = Structural Error: items are out of order
@ -96,19 +96,19 @@ Questionnaire_QR_Item_TimeNoOptions = Cannot validate time answer option because
Questionnaire_QR_Item_WrongType = Answer value must be of type {0}
Questionnaire_QR_Item_WrongType2 = Answer value must be one of the types {0}
Questionnaire_QR_Q_None = No questionnaire is identified, so no validation can be performed against the base questionnaire
Questionnaire_QR_Q_NotFound = The questionnaire "{0}" could not be resolved, so no validation can be performed against the base questionnaire
Questionnaire_QR_Q_NotFound = The questionnaire '{0}' could not be resolved, so no validation can be performed against the base questionnaire
Questionnaire_Q_EnableWhen_After = The target of this enableWhen rule ({0}) comes after the question itself
Questionnaire_Q_EnableWhen_IsInner = Questions with an enableWhen cannot refer to an inner question for it''s enableWhen condition
Questionnaire_Q_EnableWhen_NoLink = Questions with an enableWhen must have a value for the question link
Questionnaire_Q_EnableWhen_NoTarget = Unable to find an item with the linkId "{0}" which is referenced in the enableWhen for "{1}"
Questionnaire_Q_EnableWhen_NoTarget = Unable to find an item with the linkId '{0}' which is referenced in the enableWhen for '{1}'
Questionnaire_Q_EnableWhen_Self = Target for this question enableWhen can''t reference itself
Reference_REF_Aggregation = Reference is {0} which isn''t supported by the specified aggregation mode(s) for the reference
Reference_REF_BadTargetType = Invalid Resource target type. Found {0}, but expected one of ({1})
Reference_REF_BadTargetType2 = The type "{0}" implied by the reference URL {1} is not a valid Target for this element (must be one of {2})
Reference_REF_BadTargetType2 = The type '{0}' implied by the reference URL {1} is not a valid Target for this element (must be one of {2})
Reference_REF_CantMatchChoice = Unable to find matching profile for {0} among choices: {1}
Reference_REF_CantMatchType = Unable to find matching profile for {0} (by type) among choices: {1}
Reference_REF_CantResolve = Unable to resolve resource "{0}"
Reference_REF_CantResolveProfile = Unable to resolve the profile reference "{0}"
Reference_REF_CantResolve = Unable to resolve resource '{0}'
Reference_REF_CantResolveProfile = Unable to resolve the profile reference '{0}'
Reference_REF_Format1 = Relative URLs must be of the format [ResourceName]/[id], or a search URL is allowed ([type]?parameters. Encountered {0})
Reference_REF_Format2 = Relative URLs must be of the format [ResourceName]/[id]. Encountered {0}
Reference_REF_MultipleMatches = Found multiple matching profiles for {0} among choices: {1}
@ -116,10 +116,10 @@ Reference_REF_NoDisplay = A Reference without an actual reference or identifier
Reference_REF_NoType = Unable to determine type of target resource
Reference_REF_NotFound_Bundle = Bundled or contained reference not found within the bundle/resource {0}
Reference_REF_ResourceType = Matching reference for reference {0} has resourceType {1}
Reference_REF_WrongTarget = The type "{0}" is not a valid Target for this element (must be one of {1})
Reference_REF_WrongTarget = The type '{0}' is not a valid Target for this element (must be one of {1})
Resource_RES_ID_Missing = Resource requires an id, but none is present
Resource_RES_ID_Prohibited = Resource has an id, but none is allowed
Terminology_PassThrough_TX_Message = {0} for "{1}#{2}"
Terminology_PassThrough_TX_Message = {0} for '{1}#{2}'
Terminology_TX_Binding_CantCheck = Binding by URI reference cannot be checked
Terminology_TX_Binding_Missing = Binding for {0} missing (cc)
Terminology_TX_Binding_Missing2 = Binding for {0} missing
@ -138,7 +138,7 @@ Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the
Terminology_TX_Confirm_4 = Could not confirm that the codes provided are in the value set {0}, and a code from this value set is required
Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code
Terminology_TX_Confirm_6 = Could not confirm that the codes provided are in the value set {0}, and a code is recommended to come from this value set
Terminology_TX_Display_Wrong = Display should be "{0}"
Terminology_TX_Display_Wrong = Display should be '{0}'
Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept
Terminology_TX_Error_CodeableConcept_Max = Error {0} validating CodeableConcept using maxValueSet
Terminology_TX_Error_Coding1 = Error {0} validating Coding
@ -149,10 +149,10 @@ Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0
Terminology_TX_NoValid_12 = The Coding provided is not in the value set {0}, and a code is required from this value set. {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1}
Terminology_TX_NoValid_14 = The Coding provided is not in the value set {0}, and a code is recommended to come from this value set. {1}
Terminology_TX_NoValid_15 = The value provided ("{0}") could not be validated in the absence of a terminology server
Terminology_TX_NoValid_16 = The value provided ("{0}") is not in the value set {1} ({2}), and a code is required from this value set){3}
Terminology_TX_NoValid_17 = The value provided ("{0}") is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code){3}
Terminology_TX_NoValid_18 = The value provided ("{0}") is not in the value set {1} ({2}), and a code is recommended to come from this value set){3}
Terminology_TX_NoValid_15 = The value provided ('{0}') could not be validated in the absence of a terminology server
Terminology_TX_NoValid_16 = The value provided ('{0}') is not in the value set {1} ({2}), and a code is required from this value set){3}
Terminology_TX_NoValid_17 = The value provided ('{0}') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code){3}
Terminology_TX_NoValid_18 = The value provided ('{0}') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3}
Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2})
Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2})
Terminology_TX_NoValid_4 = The Coding provided is not in the value set {0}, and a code is required from this value set{1}
@ -162,37 +162,37 @@ Terminology_TX_NoValid_7 = None of the codes provided could be validated against
Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2})
Terminology_TX_NoValid_9 = The code provided could not be validated against the maximum value set {0} ({1}), (error = {2})
Terminology_TX_System_Invalid = Invalid System URI: {0}
Terminology_TX_System_NotKnown = Code System URI "{0}" is unknown so the code cannot be validated
Terminology_TX_System_NotKnown = Code System URI '{0}' is unknown so the code cannot be validated
Terminology_TX_System_Relative = Coding.system must be an absolute reference, not a local reference
Terminology_TX_System_Unknown = Unknown Code System "{0}"
Terminology_TX_System_Unknown = Unknown Code System '{0}'
Terminology_TX_System_ValueSet = Invalid System URI: {0} - cannot use a value set URI as a system
Terminology_TX_System_ValueSet2 = The Coding references a value set, not a code system ("{0}")
Terminology_TX_System_ValueSet2 = The Coding references a value set, not a code system ('{0}')
Terminology_TX_ValueSet_NotFound = ValueSet {0} not found by validator
Terminology_TX_ValueSet_NotFound2 = ValueSet {0} not found by validator
Type_Specific_Checks_DT_Base64_Valid = The value "{0}" is not a valid Base64 value
Type_Specific_Checks_DT_Base64_Valid = The value '{0}' is not a valid Base64 value
Type_Specific_Checks_DT_Boolean_Value = boolean values must be ''true'' or ''false''
Type_Specific_Checks_DT_Code_WS = The code "{0}" is not valid (whitespace rules)
Type_Specific_Checks_DT_DateTime_Reasonable = The value "{0}" is outside the range of reasonable years - check for data entry error
Type_Specific_Checks_DT_DateTime_Regex = The instant "{0}" is not valid (by regex)
Type_Specific_Checks_DT_Code_WS = The code '{0}' is not valid (whitespace rules)
Type_Specific_Checks_DT_DateTime_Reasonable = The value '{0}' is outside the range of reasonable years - check for data entry error
Type_Specific_Checks_DT_DateTime_Regex = The instant '{0}' is not valid (by regex)
Type_Specific_Checks_DT_DateTime_TZ = if a date has a time, it must have a timezone
Type_Specific_Checks_DT_DateTime_Valid = Not a valid date/time ({0})
Type_Specific_Checks_DT_Date_Valid = Not a valid date ({0})
Type_Specific_Checks_DT_Decimal_Range = The value "{0}" is outside the range of commonly/reasonably supported decimals
Type_Specific_Checks_DT_Decimal_Valid = The value "{0}" is not a valid decimal
Type_Specific_Checks_DT_ID_Valid = id value "{0}" is not valid
Type_Specific_Checks_DT_Decimal_Range = The value '{0}' is outside the range of commonly/reasonably supported decimals
Type_Specific_Checks_DT_Decimal_Valid = The value '{0}' is not a valid decimal
Type_Specific_Checks_DT_ID_Valid = id value '{0}' is not valid
Type_Specific_Checks_DT_Identifier_System = Identifier.system must be an absolute reference, not a local reference
Type_Specific_Checks_DT_Instant_Valid = Not a valid instant ({0})
Type_Specific_Checks_DT_Integer64_Valid = The value "{0}" is not a valid integer64
Type_Specific_Checks_DT_Integer64_Valid = The value '{0}' is not a valid integer64
Type_Specific_Checks_DT_Integer_GT = value is greater than permitted maximum value of {0}
Type_Specific_Checks_DT_Integer_LT = value is less than permitted minimum value of {0}
Type_Specific_Checks_DT_Integer_LT0 = value is less than permitted minimum value of 0
Type_Specific_Checks_DT_Integer_LT1 = value is less than permitted minimum value of 1
Type_Specific_Checks_DT_Integer_Valid = The value "{0}" is not a valid integer
Type_Specific_Checks_DT_Integer_Valid = The value '{0}' is not a valid integer
Type_Specific_Checks_DT_OID_Start = OIDs must start with urn:oid:
Type_Specific_Checks_DT_OID_Valid = OIDs must be valid
Type_Specific_Checks_DT_Primitive_Length = value is longer than permitted maximum length of {0}
Type_Specific_Checks_DT_Primitive_NotEmpty = @value cannot be empty
Type_Specific_Checks_DT_Primitive_Regex = Element value "{0}" does not meet regex "{1}"
Type_Specific_Checks_DT_Primitive_Regex = Element value '{0}' does not meet regex '{1}'
Type_Specific_Checks_DT_Primitive_ValueExt = Primitive types must have a value or must have child extensions
Type_Specific_Checks_DT_Primitive_WS = Primitive types should not only be whitespace
Type_Specific_Checks_DT_String_Length = value is longer than permitted maximum length of 1 MB (1048576 bytes)
@ -200,8 +200,8 @@ Type_Specific_Checks_DT_String_WS = value should not start or finish with whites
Type_Specific_Checks_DT_Time_Valid = Not a valid time ({0})
Type_Specific_Checks_DT_URI_OID = URI values cannot start with oid:
Type_Specific_Checks_DT_URI_UUID = URI values cannot start with uuid:
Type_Specific_Checks_DT_URI_WS = URI values cannot have whitespace("{0}")
Type_Specific_Checks_DT_URL_Resolve = URL value "{0}" does not resolve
Type_Specific_Checks_DT_URI_WS = URI values cannot have whitespace('{0}')
Type_Specific_Checks_DT_URL_Resolve = URL value '{0}' does not resolve
Type_Specific_Checks_DT_UUID_Strat = UUIDs must start with urn:uuid:
Type_Specific_Checks_DT_UUID_Vaid = UUIDs must be valid ({0})
Validation_BUNDLE_Message = The first entry in a message must be a MessageHeader
@ -212,30 +212,30 @@ Validation_VAL_Profile_Maximum = {0}: max allowed = {1}, but found {2}
Validation_VAL_Profile_Minimum = {0}: minimum required = {1}, but only found {2}
Validation_VAL_Profile_MultipleMatches = Found multiple matching profiles among choices: {0}
Validation_VAL_Profile_NoCheckMax = {0}: Unable to check max allowed ({1}) due to lack of slicing validation
Validation_VAL_Profile_NoCheckMin = {0}": Unable to check minimum required ({1}) due to lack of slicing validation
Validation_VAL_Profile_NoDefinition = No definition found for resource type "{0}"
Validation_VAL_Profile_NoCheckMin = {0}': Unable to check minimum required ({1}) due to lack of slicing validation
Validation_VAL_Profile_NoDefinition = No definition found for resource type '{0}'
Validation_VAL_Profile_NoMatch = Unable to find matching 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_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}
Validation_VAL_Profile_OutOfOrder = As specified by profile {0}, Element "{1}" is out of order
Validation_VAL_Profile_SliceOrder = As specified by profile {0}, Element "{1}" is out of order in ordered slice
Validation_VAL_Profile_Unknown = Profile reference "{0}" could not be resolved, so has not been checked
Validation_VAL_Profile_WrongType = Specified profile type was "{0}", but found type "{1}"
Validation_VAL_Profile_OutOfOrder = As specified by profile {0}, Element '{1}' is out of order
Validation_VAL_Profile_SliceOrder = As specified by profile {0}, Element '{1}' is out of order in ordered slice
Validation_VAL_Profile_Unknown = Profile reference '{0}' could not be resolved, so has not been checked
Validation_VAL_Profile_WrongType = Specified profile type was '{0}', but found type '{1}'
Validation_VAL_Unknown_Profile = Unknown profile {0}
XHTML_XHTML_Attribute_Illegal = Illegal attribute name in the XHTML ("{0}" on "{1}")
XHTML_XHTML_Element_Illegal = Illegal element name in the XHTML ("{0}")
XHTML_XHTML_NS_InValid = Wrong namespace on the XHTML ("{0}", should be "{1}")
XHTML_XHTML_Name_Invalid = Wrong name on the XHTML ("{0}") - must start with div
_DT_Fixed_Wrong = Value is "{0}" but must be "{1}"
XHTML_XHTML_Attribute_Illegal = Illegal attribute name in the XHTML ('{0}' on '{1}')
XHTML_XHTML_Element_Illegal = Illegal element name in the XHTML ('{0}')
XHTML_XHTML_NS_InValid = Wrong namespace on the XHTML ('{0}', should be '{1}')
XHTML_XHTML_Name_Invalid = Wrong name on the XHTML ('{0}') - must start with div
_DT_Fixed_Wrong = Value is '{0}' but must be '{1}'
All_observations_should_have_an_effectiveDateTime_or_an_effectivePeriod = All observations should have an effectiveDateTime or an effectivePeriod
All_observations_should_have_a_performer = All observations should have a performer
All_observations_should_have_a_subject = All observations should have a subject
Unable_to_resolve_slice_matching__no_fixed_value_or_required_value_set = Unable to resolve slice matching - no fixed value or required value set
Unable_to_resolve_slice_matching__slice_matching_by_value_set_not_done = Unable to resolve slice matching - slice matching by value set not done
Problem_processing_expression__in_profile__path__ = Problem processing expression {0} in profile {1} path {2}: {3}
Unable_to_find_element_with_id_ = Unable to find element with id "{0}"
Unable_to_find_element_with_id_ = Unable to find element with id '{0}'
Slice_encountered_midway_through_set_path___id___ = Slice encountered midway through set (path = {0}, id = {1}); {2}
Unable_to_resolve_actual_type_ = Unable to resolve actual type {0}
Unsupported_version_R1 = Unsupported version R1
@ -264,7 +264,7 @@ Unable_to_resolve_element__in_profile_ = Unable to resolve element {0} in profil
Unable_to_resolve_profile_ = Unable to resolve profile {0}
Resource_resolution_services_not_provided = Resource resolution services not provided
Unrecognised_extension_context_ = Unrecognised extension context {0}
Unable_to_locate_the_profile__in_order_to_validate_against_it = Unable to locate the profile "{0}" in order to validate against it
Unable_to_locate_the_profile__in_order_to_validate_against_it = Unable to locate the profile '{0}' in order to validate against it
Reference__refers_to_a__not_a_ValueSet = Reference {0} refers to a {1} not a ValueSet
Not_done_yet_ValidatorHostServicesconformsToProfile_when_item_is_not_an_element = Not done yet (ValidatorHostServices.conformsToProfile), when item is not an element
Not_supported_yet = Not supported yet
@ -349,14 +349,14 @@ element__null_ = element = null: {0}
getSliceList_should_only_be_called_when_the_element_has_slicing = getSliceList should only be called when the element has slicing
Unable_to_resolve_name_reference__at_path_ = Unable to resolve name reference {0} at path {1}
Details_for__matching_against_Profile_ = Details for {0} matching against Profile{1}
Does_not_match_slice_ = Does not match slice "{0}"
Does_not_match_slice_ = Does not match slice '{0}'
Profile__does_not_match_for__because_of_the_following_profile_issues__ = Profile {0} does not match for {1} because of the following profile issues: {2}
This_element_does_not_match_any_known_slice_ = This element does not match any known slice{0}
defined_in_the_profile = defined in the profile
This_does_not_appear_to_be_a_FHIR_resource_unknown_name_ = This does not appear to be a FHIR resource (unknown name "{0}")
This_does_not_appear_to_be_a_FHIR_resource_unknown_name_ = This does not appear to be a FHIR resource (unknown name '{0}')
This_cannot_be_parsed_as_a_FHIR_object_no_name = This cannot be parsed as a FHIR object (no name)
This_does_not_appear_to_be_a_FHIR_resource_unknown_namespacename_ = This does not appear to be a FHIR resource (unknown namespace/name "{0}::{1}")
This__cannot_be_parsed_as_a_FHIR_object_no_namespace = This "{0}" cannot be parsed as a FHIR object (no namespace)
This_does_not_appear_to_be_a_FHIR_resource_unknown_namespacename_ = This does not appear to be a FHIR resource (unknown namespace/name '{0}::{1}')
This__cannot_be_parsed_as_a_FHIR_object_no_namespace = This '{0}' cannot be parsed as a FHIR object (no namespace)
Unable_to_find_resourceType_property = Unable to find resourceType property
Error_parsing_JSON_the_primitive_value_must_be_a_string = Error parsing JSON: the primitive value must be a string
Error_parsing_JSON_the_primitive_value_must_be_a_number = Error parsing JSON: the primitive value must be a number
@ -437,7 +437,7 @@ This_property_must_be_an_Array_not_a_ = This property must be an Array, not a {0
documentmsg = (document)
xml_attr_value_invalid = The XML Attribute {0} has an illegal character
xml_encoding_invalid = The XML encoding is invalid (must be UTF-8)
xml_stated_encoding_invalid = The XML encoding stated in the header is invalid (must be "UTF-8" if stated)
xml_stated_encoding_invalid = The XML encoding stated in the header is invalid (must be 'UTF-8' if stated)
XHTML_URL_INVALID = The URL {0} is not valid ({1})
MEASURE_MR_GRP_NO_CODE = Group should have a code that matches the group definition in the measure
MEASURE_MR_GRP_UNK_CODE = The code for this group has no match in the measure definition
@ -496,7 +496,7 @@ TYPE_SPECIFIC_CHECKS_DT_ATT_TOO_LONG = Attachment size is {0} bytes which exceed
TYPE_SPECIFIC_CHECKS_DT_ATT_NO_CONTENT = Attachments have data and/or url, or else SHOULD have either contentType and/or language
TYPE_SPECIFIC_CHECKS_DT_BASE64_TOO_LONG = Base64 size is {0} bytes which exceeds the stated limit of {1} bytes
TYPE_SPECIFIC_CHECKS_DT_DECIMAL_CHARS = Found {0} decimal places which exceeds the stated limit of {1} digits
Validation_VAL_Profile_WrongType = Specified profile type was "{0}", but found type "{1}"
Validation_VAL_Profile_WrongType = Specified profile type was '{0}', but found type '{1}'
Validation_VAL_Profile_WrongType2 = Type mismatch processing profile {0} at path {1}: The element type is {4}, but the profile {3} is for a different type {2}
VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT = Illegal constraint in profile {0} at path {1} - cannot constrain to type {2} from base types {3}
EXTENSION_EXT_CONTEXT_WRONG_XVER = The extension {0} from FHIR version {3} is not allowed to be used at this point (allowed = {1}; this element is [{2}; this is a warning since contexts may be renamed between FHIR versions)
@ -506,21 +506,22 @@ ALL_OK = All OK
SEARCHPARAMETER_NOTFOUND = Unable to find the base Search Parameter {0} so can't check that this SearchParameter is a proper derivation from it
SEARCHPARAMETER_BASE_WRONG = The resource type {1} is not listed as a base in the SearchParameter this is derived from ({0})
SEARCHPARAMETER_TYPE_WRONG = The type {1} is different to the type {0} in the derivedFrom SearchParameter
SEARCHPARAMETER_EXP_WRONG = The expression "{2}" is not compatible with the expression "{1}" in the derivedFrom SearchParameter {0}, and this likely indicates that the derivation relationship is not valid
SEARCHPARAMETER_EXP_WRONG = The expression '{2}' is not compatible with the expression '{1}' in the derivedFrom SearchParameter {0}, and this likely indicates that the derivation relationship is not valid
VALUESET_NO_SYSTEM_WARNING = No System specified, so Concepts and Filters can't be checked
VALUESET_INCLUDE_INVALID_CONCEPT_CODE = The code {1} is not valid in the system {0}
VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER = The code {2} is not valid in the system {0} version {1}
VALUESET_UNC_SYSTEM_WARNING = Unknown System specified, so Concepts and Filters can't be checked
VALUESET_UNC_SYSTEM_WARNING_VER = Unknown System/Version specified, so Concepts and Filters can't be checked
Extension_PROF_Type = The Profile "{0}" definition allows for the type {1} but found type {2}
TYPE_CHECKS_PATTERN_CC = The pattern [system {0}, code {1}, and display "{2}"] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_PATTERN_CC_US = The pattern [system {0}, code {1}, display "{2}" and userSelected {5}] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_FIXED_CC = The pattern [system {0}, code {1}, and display "{2}"] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_FIXED_CC_US = The pattern [system {0}, code {1}, display "{2}" and userSelected {5}] defined in the profile {3} not found. Issues: {4}
Extension_PROF_Type = The Profile '{0}' definition allows for the type {1} but found type {2}
TYPE_CHECKS_PATTERN_CC = The pattern [system {0}, code {1}, and display '{2}'] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_PATTERN_CC_US = The pattern [system {0}, code {1}, display '{2}' and userSelected {5}] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_FIXED_CC = The pattern [system {0}, code {1}, and display '{2}'] defined in the profile {3} not found. Issues: {4}
TYPE_CHECKS_FIXED_CC_US = The pattern [system {0}, code {1}, display '{2}' and userSelected {5}] defined in the profile {3} not found. Issues: {4}
Internal_error = Internal error: {0}
VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN = Global Profile reference "{0}" from IG {1} could not be resolved, so has not been checked
VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN = Global Profile reference '{0}' from IG {1} could not be resolved, so has not been checked
VALIDATION_VAL_PROFILE_SIGNPOST = Validate resource against profile {0}
VALIDATION_VAL_PROFILE_SIGNPOST_META = Validate resource against profile {0} - listed in meta
VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM = Validate resource against profile {0} - provided as bundle param
VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = Validate resource against profile {0} - a global profile in {1}
ERROR_GENERATING_SNAPSHOT = Error generating Snapshot: {0} (this usually arises from a problem in the differential)
SNAPSHOT_EXISTING_PROBLEM = The generated snapshot has a different number of elements {1} that the originally provided snapshot {0}
@ -547,7 +548,7 @@ FHIRPATH_NO_COLLECTION = Error evaluating FHIRPath expression: The function {0}
FHIRPATH_NOT_IMPLEMENTED = Error evaluating FHIRPath expression: The function {0} is not implemented
FHIRPATH_PARAM_WRONG = Error evaluating FHIRPath expression: The expression type {0} is not supported for parameter {1} on function {2}
FHIRPATH_CHECK_FAILED = Error evaluating FHIRPath expression: The check {0} failed
FHIRPATH_NO_TYPE = Error evaluating FHIRPath expression: The type "{0}" is unknown or not supported at {1}
FHIRPATH_NO_TYPE = Error evaluating FHIRPath expression: The type '{0}' is unknown or not supported at {1}
FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED = Error in discriminator at {0}: found a sliced element while resolving the fixed value for one of the slices
FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND = Problem with use of resolve() - profile {0} on {1} could not be resolved
FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE = illegal use of resolve() in discriminator - no type on element {0}
@ -591,3 +592,7 @@ RENDER_BUNDLE_IF_NON_MATCH = If-None-Match = {0}
RENDER_BUNDLE_IF_MOD = If-Modified-Since = {0}
RENDER_BUNDLE_IF_MATCH = If-Match = {0}
RENDER_BUNDLE_IF_NONE = If-None-Exist = {0}
BUNDLE_RULE_NONE = No Rule
BUNDLE_RULE_UNKNOWN = Bundle Rule refers to invalid resource {0}
BUNDLE_RULE_INVALID_INDEX = Bundle Rules index is invalid ({0})
BUNDLE_RULE_PROFILE_UNKNOWN = Bundle Rules profile {1} is unknown for {0}

View File

@ -307,6 +307,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
private Locale locale;
private List<ImplementationGuide> igs = new ArrayList<>();
private boolean showTimes;
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
private class AsteriskFilter implements FilenameFilter {
String dir;
@ -1558,6 +1559,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
validator.getContext().setLocale(locale);
validator.setFetcher(this);
validator.getImplementationGuides().addAll(igs);
validator.getBundleValidationRules().addAll(bundleValidationRules);
return validator;
}
@ -2368,6 +2370,10 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
public FilesystemPackageCacheManager getPcm() {
return pcm;
}
public List<BundleValidationRule> getBundleValidationRules() {
return bundleValidationRules;
}
}

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.validation.cli.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.validation.Validator;
import java.util.*;
@ -77,6 +79,9 @@ public class CliContext {
@JsonProperty("locations")
private Map<String, String> locations = new HashMap<String, String>();
// TODO: Mark what goes here?
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
@JsonProperty("map")
public String getMap() {
@ -100,6 +105,11 @@ public class CliContext {
return this;
}
// TODO: Mark what goes here?
public List<BundleValidationRule> getBundleValidationRules() {
return bundleValidationRules;
}
public CliContext addIg(String ig) {
if (this.igs == null) {
this.igs = new ArrayList<>();

View File

@ -216,6 +216,7 @@ public class ValidationService {
validator.setCrumbTrails(cliContext.isCrumbTrails());
validator.setShowTimes(cliContext.isShowTimes());
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator));
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
return validator;
}

View File

@ -1,5 +1,6 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.Validator;
import org.hl7.fhir.validation.cli.model.CliContext;
@ -15,6 +16,7 @@ public class Params {
public static final String OUTPUT = "-output";
public static final String PROXY = "-proxy";
public static final String PROFILE = "-profile";
public static final String BUNDLE = "-bundle";
public static final String QUESTIONNAIRE = "-questionnaire";
public static final String NATIVE = "-native";
public static final String ASSUME_VALID_REST_REF = "-assumeValidRestReferences";
@ -102,15 +104,21 @@ public class Params {
} else {
p = args[++i];
cliContext.addProfile(p);
}
} else if (args[i].equals(BUNDLE)) {
String p = null;
String r = null;
if (i + 1 == args.length) {
throw new Error("Specified -profile without indicating bundle rule ");
} else {
r = args[++i];
}
if (p != null && i + 1 < args.length && args[i + 1].equals("@")) {
i++;
if (i + 1 == args.length) {
throw new Error("Specified -profile with @ without indicating profile location");
} else {
cliContext.addLocation(p, args[++i]);
}
if (i + 1 == args.length) {
throw new Error("Specified -profile without indicating profile source");
} else {
p = args[++i];
}
cliContext.getBundleValidationRules().add(new BundleValidationRule(r, p));
} else if (args[i].equals(QUESTIONNAIRE)) {
if (i + 1 == args.length)
throw new Error("Specified -questionnaire without indicating questionnaire file");

View File

@ -364,6 +364,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean securityChecks;
private ProfileUtilities profileUtilities;
private boolean crumbTrails;
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices) {
super(theContext);
@ -3624,7 +3625,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public void checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials) {
// specific known special validations
if (element.getType().equals(BUNDLE)) {
new BundleValidator(context, serverBase).validateBundle(errors, element, stack, checkSpecials);
new BundleValidator(context, serverBase, this).validateBundle(errors, element, stack, checkSpecials, hostContext);
} else if (element.getType().equals("Observation")) {
validateObservation(errors, element, stack);
} else if (element.getType().equals("Questionnaire")) {
@ -4818,4 +4819,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
this.securityChecks = securityChecks;
}
@Override
public List<BundleValidationRule> getBundleValidationRules() {
return bundleValidationRules ;
}
}

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.validation.instance.type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -11,26 +12,32 @@ import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.validation.instance.utils.EntrySummary;
import org.hl7.fhir.validation.instance.utils.IndexedElement;
import org.hl7.fhir.validation.instance.utils.NodeStack;
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
public class BundleValidator extends BaseValidator{
public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?";
private String serverBase;
private InstanceValidator validator;
public BundleValidator(IWorkerContext context, String serverBase) {
public BundleValidator(IWorkerContext context, String serverBase, InstanceValidator validator) {
super(context);
this.serverBase = serverBase;
this.validator = validator;
}
public void validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials) {
public void validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext) {
List<Element> entries = new ArrayList<Element>();
bundle.getNamedChildren(ENTRY, entries);
String type = bundle.getNamedChildValue(TYPE);
@ -68,7 +75,12 @@ public class BundleValidator extends BaseValidator{
// We do not yet have rules requiring that the id and fullUrl match when dealing with messaging Bundles
// validateResourceIds(errors, entries, stack);
}
int count = 0;
Map<String, Integer> counter = new HashMap<>();
for (Element entry : entries) {
NodeStack estack = stack.push(entry, count, null, null);
String fullUrl = entry.getNamedChildValue(FULL_URL);
String url = getCanonicalURLForEntry(entry);
String id = getIdForEntry(entry);
@ -77,7 +89,30 @@ public class BundleValidator extends BaseValidator{
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id);
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild(RESOURCE).fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl);
}
// check bundle profile requests
if (entry.hasChild(RESOURCE)) {
String rtype = entry.getNamedChild(RESOURCE).fhirType();
int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0;
counter.put(rtype, rcount);
for (BundleValidationRule bvr : validator.getBundleValidationRules()) {
if (meetsRule(bvr, rtype, rcount, count)) {
StructureDefinition defn = validator.getContext().fetchResource(StructureDefinition.class, bvr.getProfile());
if (defn == null) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_PROFILE_UNKNOWN, bvr.getRule(), bvr.getProfile()));
} else {
Element res = entry.getNamedChild(RESOURCE);
NodeStack rstack = estack.push(res, -1, null, null);
signpost(errors, IssueType.INFORMATIONAL, res.line(), res.col(), stack.getLiteralPath(), !validator.isCrumbTrails(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_BUNDLE_PARAM, defn.getUrl());
stack.resetIds();
validator.startInner(hostContext, errors, res, res, defn, rstack, false);
}
}
}
}
// todo: check specials
count++;
}
}
@ -372,4 +407,33 @@ public class BundleValidator extends BaseValidator{
}
public boolean meetsRule(BundleValidationRule bvr, String rtype, int rcount, int count) {
if (bvr.getRule() == null) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_NONE));
}
String rule = bvr.getRule();
String t = rule.contains(":") ? rule.substring(0, rule.indexOf(":")) : Utilities.isInteger(rule) ? null : rule;
String index = rule.contains(":") ? rule.substring(rule.indexOf(":")+1) : Utilities.isInteger(rule) ? rule : null;
if (Utilities.noString(t) && Utilities.noString(index)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_NONE));
}
if (!Utilities.noString(t)) {
if (!validator.getContext().getResourceNames().contains(t)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_UNKNOWN, t));
}
}
if (!Utilities.noString(index)) {
if (!Utilities.isInteger(index)) {
throw new Error(validator.getContext().formatMessage(I18nConstants.BUNDLE_RULE_INVALID_INDEX, index));
}
}
if (t == null) {
return Integer.toString(count).equals(index);
} else if (index == null) {
return t.equals(rtype);
} else {
return t.equals(rtype) && Integer.toString(rcount).equals(index);
}
}
}

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.r5.utils.IResourceValidator.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.TextFile;
@ -185,6 +186,10 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
}
}
}
val.getBundleValidationRules().clear();
if (content.has("bundle-param")) {
val.getBundleValidationRules().add(new BundleValidationRule(content.getAsJsonObject("bundle-param").get("rule").getAsString(), content.getAsJsonObject("bundle-param").get("profile").getAsString()));
}
if (content.has("profiles")) {
for (JsonElement je : content.getAsJsonArray("profiles")) {
String filename = je.getAsString();