-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: optional elements are not appearing as optional when children of another element #410
Comments
Okay, so I think this might be a bug with xmlschema after further tinkering. If I change it to: <xs:element name="muclient">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="include"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="plugin"/>
<xs:element ref="world"/>
<xs:element ref="triggers"/>
<xs:element ref="aliases"/>
<xs:element ref="timers"/>
<xs:element ref="macros"/>
<xs:element ref="variables"/>
<xs:element ref="colours"/>
<xs:element ref="keypad"/>
<xs:element ref="printing"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element> It still shows as having 1 minimum and maximum occurrence when evaluated: >>> schema=xmlschema.XMLSchema11("..\\..\\mushclient-schemas\\mushclient.xsd")
>>> list(schema.elements["muclient"].iterchildren())
[Xsd11Element(ref='include', occurs=[0, None]), Xsd11Element(ref='plugin', occurs=[1, 1]), Xsd11Element(ref='world', occurs=[1, 1]), Xsd11Element(ref='triggers', occurs=[1, 1]), Xsd11Element(ref='aliases', occurs=[1, 1]), Xsd11Element(ref='timers', occurs=[1, 1]), Xsd11Element(ref='macros', occurs=[1, 1]), Xsd11Element(ref='variables', occurs=[1, 1]), Xsd11Element(ref='colours', occurs=[1, 1]), Xsd11Element(ref='keypad', occurs=[1, 1]), Xsd11Element(ref='printing', occurs=[1, 1])] I could be wrong but this definitely looks like a bug to me. |
Hi,
I will check the problem using that sample schema as a base: <?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="muclient">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="include"/>
<xs:choice>
<xs:element name="plugin"/>
<xs:element name="world"/>
<xs:element name="triggers"/>
<xs:element name="aliases"/>
<xs:element name="timers"/>
<xs:element name="macros"/>
<xs:element name="variables"/>
<xs:element name="colours"/>
<xs:element name="keypad"/>
<xs:element name="printing"/>
</xs:choice>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema> |
I didn't know that, good to know. I raised this as a bug because I need to be able to tell what elements are optional or not for code generation so I don't go assuming all elements are optional and then someone uses my tool and they run an XML document that is missing a (required) element and it works anyway. I thought that |
Any update on this? |
Hi, <?xml version="1.0" encoding="utf-8" ?>
<muclient xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mushclient.xsd">
</muclient>
<?xml version="1.0" encoding="utf-8" ?>
<muclient xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mushclient.xsd">
<include name="foo"/>
</muclient>
<?xml version="1.0" encoding="utf-8" ?>
<muclient xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mushclient.xsd">
<include name="foo"/>
<world port="80" id="1" name="http" site="example.test"/>
</muclient>
<?xml version="1.0" encoding="utf-8" ?>
<muclient xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="mushclient.xsd">
<world port="80" id="1" name="http" site="example.test"/>
</muclient> The only general mode for checking if an element is optional or not in a model group is to use a ModelVisitor instance and run on a children elements. This is done for As a starting point for doing this is to create a |
Anyway a generic method (e.g.
|
An example to show how the model visitor can be used for that purpose: >>> import xmlschema
>>> from xmlschema.validators import ModelVisitor
>>> from random import randint
>>>
>>> schema = xmlschema.XMLSchema("mushclient.xsd")
>>> model = ModelVisitor(schema.elements['muclient'].type.content)
>>>
>>> model.element
XsdElement(ref='include', occurs=[0, None])
>>>
>>> model.expected
[]
>>> while model.element is not None:
... expected = model.expected
... if not expected:
... children.append(model.element)
... else:
... k = randint(1, len(expected)) - 1
... children.append(expected[k])
... if len(children) > 10:
... break
... assert not list(model.advance(True))
...
>>> children
[XsdElement(ref='include', occurs=[0, None]), XsdElement(ref='colours', occurs=[1, 1]), XsdElement(ref='macros', occurs=[1, 1]), XsdElement(ref='colours', occurs=[1, 1]), XsdElement(ref='printing', occurs=[1, 1]), XsdElement(ref='colours', occurs=[1, 1]), XsdElement(ref='macros', occurs=[1, 1]), XsdElement(ref='variables', occurs=[1, 1]), XsdElement(ref='keypad', occurs=[1, 1]), XsdElement(ref='macros', occurs=[1, 1]), XsdElement(ref='world', occurs=[1, 1])]
>>> Anyway for letting this usable for all the models the |
@brunato Ah, okay. Is there a way I could use this from within my Ginja2 template, or would I need to write a custom filter? |
You have to write a custom filter. The current version of If you want to generate a valid content (a sequence of child elements) there is no way out of using a model validator that keeps track of the occurrences of the particles (elements, wildcards and groups) and their status (groups stack). |
@brunato Yeah, it might be worth either extending the library with this functionality in the model visitor or adding this filter. I'm uncertain how to do this other than in the generator |
Also, it looks as though the model visitor still doesn't really detect optional elements. It sees the |
For checking if a particle of a model group is optional I will add a new method to def is_optional(self, particle: ModelParticleType) -> bool:
"""
Returns `True` if a particle can be optional in the model. This a raw check,
because the optionality can depend on the presence and the position of other
elements, that can be checked only using a `ModelVisitor` instance. Raises an
`XMLSchemaValueError` if the particle is not part of the model group.
"""
if self.max_occurs == 0:
raise XMLSchemaValueError("the model group is empty")
groups = [self]
iterators: List[Iterator[ModelParticleType]] = []
particles = iter(self)
while True:
for item in particles:
if item is particle:
if item.min_occurs == 0:
return True
for group in reversed(groups):
if group.min_occurs == 0:
return True
elif group.model == 'choice' and len(group) > 1:
return True
else:
return False
if isinstance(item, XsdGroup):
if item.max_occurs == 0:
continue
groups.append(item)
iterators.append(particles)
particles = iter(item.content)
if len(iterators) > limits.MAX_MODEL_DEPTH:
raise XMLSchemaModelDepthError(self)
break
else:
try:
groups.pop()
particles = iterators.pop()
except IndexError:
msg = "The provided particle is not part of the model group"
raise XMLSchemaValueError(msg) |
- Related to issue #410: a check of optionality of particles in a model group.
Hi @ethindp, thank you |
I have this (RelaxNG compact):
As an XSD it renders as (via trang):
My hope was that it would allow elements to be specified in any order, but either this schema is broken or it doesn't look like that's how this works. (This is my first time ever writing an XML schema, so...) Is this a bug in xmlschema, or a bug in my XSD?
The text was updated successfully, but these errors were encountered: