Summary
In elementpath 4.8.x, inside a quantified expression:
every $x in E1 satisfies E2
the focus / context item (.) stays the outer context item, and $x is only a variable. This matches XPath 2.0 / 3.1.
In elementpath 5.x (pulled in by recent xmlschema releases), evaluation of E2 appears to treat . as the bound variable ($x). This breaks valid XSD 1.1 xs:assert expressions that intentionally use . to refer to the element under assertion while iterating children with $var.
According to the XPath 3.1 spec, quantified expressions bind variables but do not change the focus. Constructs that create a new focus are path (E1/E2), predicate (E1[E2]), and simple map (E1!E2) — not every / some.
Reference: https://www.w3.org/TR/xpath-31/#id-quantified-expressions
Also: https://www.w3.org/TR/xpath-31/#dt-focus
Minimal reproduction
Schema (demo.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://example.com/demo"
targetNamespace="http://example.com/demo"
elementFormDefault="qualified"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1">
<xs:element name="Parent" type="t:Parent"/>
<xs:complexType name="Parent">
<xs:sequence>
<xs:element name="Child" type="t:Child" maxOccurs="unbounded"/>
<xs:element name="Sibling" type="xs:string"/>
</xs:sequence>
<!--
Intentionally uses "." (= Parent, the assertion context)
while iterating Child via $c.
If "." is wrongly rebound to $c, ./t:Sibling is searched under Child and the assert fails.
-->
<xs:assert test="every $c in t:Child satisfies exists(./t:Sibling)"/>
</xs:complexType>
<xs:complexType name="Child">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Instance (demo.xml) — should be valid
<?xml version="1.0" encoding="UTF-8"?>
<Parent xmlns="http://example.com/demo">
<Child><id>1</id></Child>
<Child><id>2</id></Child>
<Sibling>ok</Sibling>
</Parent>
Script (main.py)
from xmlschema import XMLSchema11
schema = XMLSchema11("demo.xsd")
print("elementpath:", __import__("elementpath").__version__)
print("xmlschema:", __import__("xmlschema").__version__)
print("is_valid:", schema.is_valid("demo.xml"))
for err in schema.iter_errors("demo.xml"):
print("error:", err.reason, "path:", err.path)
Observed behavior
| elementpath |
xmlschema |
Result |
| 5.1.3 |
4.3.2 |
is_valid: False — assertion test is false at /Parent |
| 4.8.0 |
3.4.3 |
is_valid: True |
Downgrading only elementpath back to 4.8.0 (without changing the schema/instance) restores correct validation. So the regression is in elementpath.
Expected behavior
demo.xml must be valid: inside satisfies, . remains Parent (assertion context item), and $c is each Child.
Environment
- OS: macOS/Linux Ubuntu/Windows 11
- Python: 3.10.x
- Confirmed broken:
elementpath==5.1.3, xmlschema==4.3.2
- Confirmed working:
elementpath==4.8.0, xmlschema==3.4.3
Why this matters
We validate real telecom MOM XSD 1.1 schemas with many asserts of the form:
every $cpri in ./*:Cpri satisfies
if (...) then not(./*:LteFunction/*:DuCell[...]) else true()
Here . must stay on the parent managed object, while $cpri is the loop variable. With elementpath 5.x these asserts fail on known-valid configuration files (they still pass with Xerces and with elementpath 4.8.0).
Happy to provide more details or a PR test case if useful. Thanks!
Summary
In
elementpath4.8.x, inside a quantified expression:the focus / context item (
.) stays the outer context item, and$xis only a variable. This matches XPath 2.0 / 3.1.In
elementpath5.x (pulled in by recentxmlschemareleases), evaluation ofE2appears to treat.as the bound variable ($x). This breaks valid XSD 1.1xs:assertexpressions that intentionally use.to refer to the element under assertion while iterating children with$var.According to the XPath 3.1 spec, quantified expressions bind variables but do not change the focus. Constructs that create a new focus are path (
E1/E2), predicate (E1[E2]), and simple map (E1!E2) — notevery/some.Reference: https://www.w3.org/TR/xpath-31/#id-quantified-expressions
Also: https://www.w3.org/TR/xpath-31/#dt-focus
Minimal reproduction
Schema (
demo.xsd)Instance (
demo.xml) — should be validScript (
main.py)Observed behavior
is_valid: False—assertion test is falseat/Parentis_valid: TrueDowngrading only
elementpathback to 4.8.0 (without changing the schema/instance) restores correct validation. So the regression is inelementpath.Expected behavior
demo.xmlmust be valid: insidesatisfies,.remainsParent(assertion context item), and$cis eachChild.Environment
elementpath==5.1.3,xmlschema==4.3.2elementpath==4.8.0,xmlschema==3.4.3Why this matters
We validate real telecom MOM XSD 1.1 schemas with many asserts of the form:
Here
.must stay on the parent managed object, while$cpriis the loop variable. With elementpath 5.x these asserts fail on known-valid configuration files (they still pass with Xerces and with elementpath 4.8.0).Happy to provide more details or a PR test case if useful. Thanks!