Bug description
YamlConverter::getElementNamespace assigns a namespace to a local element even when that element explicitly declares form="unqualified" in the XSD, producing invalid JMS Serializer metadata.
Root cause
protected function getElementNamespace(Schema $schema, ElementItem $element)
{
if ($element->getSchema()->getTargetNamespace() &&
($schema->getElementsQualification() // ← bug
|| ($element instanceof Element && $element->isQualified())
|| !$element->isLocal())
) {
return $element->getSchema()->getTargetNamespace();
}
return null;
}
When the containing schema has elementFormDefault="qualified", $schema->getElementsQualification() returns true and short-circuits the entire OR. An element that explicitly declares form="unqualified" still receives a namespace entry in the generated YAML — the xsd-reader's correct isQualified()=false result is silently ignored.
Reproducer
<!-- schema: elementFormDefault="qualified" -->
<xs:complexType name="CodeType">
<xs:sequence>
<xs:element name="code" type="xs:token" form="unqualified"/>
<xs:element name="name" type="xs:normalizedString" form="unqualified" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
Generated YAML (wrong):
code:
xml_element:
namespace: 'urn:example:schema' # must not be here
name:
xml_element:
namespace: 'urn:example:schema' # must not be here
JMS Serializer then produces <ns:code> / <ns:name> instead of <code> / <name>, which schema validators reject with:
Invalid content was found starting with element '{urn:example:schema}name'. One of '{name}' is expected.
Expected behaviour
Elements with an explicit form="unqualified" must not receive a namespace entry, regardless of the parent schema's elementFormDefault.
Suggested fix
Remove $schema->getElementsQualification() from the condition. $element->isQualified() already incorporates elementFormDefault as a fallback when no explicit form attribute is present, making the removed check both redundant and incorrect.
- protected function getElementNamespace(Schema $schema, ElementItem $element)
+ protected function getElementNamespace(Schema $_schema, ElementItem $element)
{
if ($element->getSchema()->getTargetNamespace() &&
- ($schema->getElementsQualification() || ($element instanceof Element && $element->isQualified()) || !$element->isLocal())
+ (($element instanceof Element && $element->isQualified()) || !$element->isLocal())
) {
A PR with this fix is already open: #195
Behaviour matrix after fix
Schema elementFormDefault |
Element form |
Before |
After |
qualified |
(none) |
namespace set ✓ |
namespace set ✓ |
qualified |
form="unqualified" |
namespace set ✗ |
no namespace ✓ |
qualified |
form="qualified" |
namespace set ✓ |
namespace set ✓ |
unqualified |
(none) |
no namespace ✓ |
no namespace ✓ |
unqualified |
form="qualified" |
namespace set ✓ |
namespace set ✓ |
Context
Discovered while generating JMS metadata for the German XÖV/XÖV-Standard xoev-code.xsd, where code and name child elements are intentionally form="unqualified" for cross-schema interoperability — a common pattern in German e-government standards.
Version
xsd2php 0.4.13
Bug description
YamlConverter::getElementNamespaceassigns a namespace to a local element even when that element explicitly declaresform="unqualified"in the XSD, producing invalid JMS Serializer metadata.Root cause
When the containing schema has
elementFormDefault="qualified",$schema->getElementsQualification()returnstrueand short-circuits the entire OR. An element that explicitly declaresform="unqualified"still receives anamespaceentry in the generated YAML — the xsd-reader's correctisQualified()=falseresult is silently ignored.Reproducer
Generated YAML (wrong):
JMS Serializer then produces
<ns:code>/<ns:name>instead of<code>/<name>, which schema validators reject with:Expected behaviour
Elements with an explicit
form="unqualified"must not receive anamespaceentry, regardless of the parent schema'selementFormDefault.Suggested fix
Remove
$schema->getElementsQualification()from the condition.$element->isQualified()already incorporateselementFormDefaultas a fallback when no explicitformattribute is present, making the removed check both redundant and incorrect.A PR with this fix is already open: #195
Behaviour matrix after fix
elementFormDefaultformqualifiedqualifiedform="unqualified"qualifiedform="qualified"unqualifiedunqualifiedform="qualified"Context
Discovered while generating JMS metadata for the German XÖV/XÖV-Standard
xoev-code.xsd, wherecodeandnamechild elements are intentionallyform="unqualified"for cross-schema interoperability — a common pattern in German e-government standards.Version
xsd2php 0.4.13