Description
hl7apy.validation.Validator does not differentiate between sequence and choice group types. Both fall into the same branch in _check_known_element, which iterates all child references and calls _check_repetitions on each individually. For choice groups, this is incorrect because only one child needs to be present, not all of them.
Steps to Reproduce
from hl7apy.parser import parse_message
from hl7apy.validation import Validator, VALIDATION_LEVEL
msg_text = (
"MSH|^~\\&|SND|SND|RCV|RCV|20260101120000||ORM^O01|MSG001|P|2.3\r"
"PID|1||12345||DOE^JOHN|||19800101|M\r"
"ORC|NW||||||1^^^20260101120000|20260101120000\r"
"OBR|1|||SPEC-001|PANEL|||20260101090000|||||||CSF||||||||||||1^^^20260101120000\r"
)
msg = parse_message(msg_text, find_groups=True)
Validator(VALIDATION_LEVEL.TOLERANT).validate(msg)
Expected
Validation should pass because OBR satisfies ORM_O01_CHOICE (a choice group). See ORM_O01 message structure
Actual
hl7apy.exceptions.ValidationError: Missing required child ORM_O01_CHOICE.RQD
Root Cause
|
if ref[0] in ('sequence', 'choice'): |
|
element_children = {c.name for c in el.children if not c.is_z_element()} |
|
valid_children, valid_children_refs = _get_valid_children_info(ref) |
|
|
|
# check that the children are all allowed children |
|
if not element_children <= valid_children: |
|
errs.append(ValidationError("Invalid children detected for {}: {}". |
|
format(el, list(element_children - valid_children)))) |
|
|
|
# iterates the valid children |
|
for child_ref in valid_children_refs: |
|
# it gets the structure of the children to check |
|
child_name, cardinality = _get_child_reference_info(child_ref) |
|
try: |
|
# it gets all the occurrences of the children of a type |
|
children = el.children.get(child_name) |
|
except Exception: |
|
# TODO: it is due to the lack of element in the official reference files... should |
|
# we raise an exception here? |
|
pass |
|
else: |
|
_check_repetitions(el, children, cardinality, child_name, errs) |
|
# calls validation for every children |
|
for c in children: |
|
_is_valid(c, child_ref[1], errs, warns) |
|
|
sequence and choice share the same code path. For ORM_O01_CHOICE, valid_children_refs contains OBR, RQD, RQ1, RXO, ODS, ODT each with cardinality (1, 1). The loop enforces all six as required. The correct semantics for choice is exactly one of the options must be present.
Description
hl7apy.validation.Validatordoes not differentiate betweensequenceandchoicegroup types. Both fall into the same branch in_check_known_element, which iterates all child references and calls_check_repetitionson each individually. Forchoicegroups, this is incorrect because only one child needs to be present, not all of them.Steps to Reproduce
Expected
Validation should pass because
OBRsatisfiesORM_O01_CHOICE(achoicegroup). See ORM_O01 message structureActual
Root Cause
hl7apy/hl7apy/validation.py
Lines 151 to 176 in 0297526
sequenceandchoiceshare the same code path. ForORM_O01_CHOICE,valid_children_refscontains OBR, RQD, RQ1, RXO, ODS, ODT each with cardinality (1, 1). The loop enforces all six as required. The correct semantics forchoiceis exactly one of the options must be present.