Parsing of element with substitutionGroup fails
ArminWiebigke opened this issue · comments
Steps
Given a XSD with an abstract type, for which concrete elements are provided via substitutionGroup
:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="AnimalType" abstract="true">
<xs:sequence>
<xs:element name="species" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Animal" type="AnimalType" abstract="true"/>
<xs:element name="Dog" substitutionGroup="Animal">
<xs:complexType>
<xs:complexContent>
<xs:extension base="AnimalType">
<xs:sequence>
<xs:element name="furColor" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="Fish" substitutionGroup="Animal">
<xs:complexType>
<xs:complexContent>
<xs:extension base="AnimalType">
<xs:sequence>
<xs:element name="scalesColor" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="PetType">
<xs:sequence>
<xs:element ref="Animal"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Pet" type="PetType"/>
</xs:schema>
Try to parse a valid XML file for that schema:
<Pet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Dog>
<species>dog</species>
<furColor>brown</furColor>
</Dog>
</Pet>
Problem
Parsing fails with
scalaxb.ParserFailure: Error while parsing <Pet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Dog>
<species>dog</species>
<furColor>brown</furColor>
</Dog>
</Pet>: parser error "'Animal' expected but Dog found" while parsing /Pet/Dog
The generated parser for PetType
tries to parse the abstract type directly, instead of the subtypes:
def parser(node: scala.xml.Node, stack: List[scalaxb.ElemName]): Parser[PetType] =
phrase((scalaxb.ElemName(None, "Animal")) ^^
{ case p1 =>
PetType(scalaxb.fromXML[AnimalType](p1, scalaxb.ElemName(node) :: stack)) })
Expected
The generated parser/writer should be able to handle all elements that are provided via substitutionGroup
for the abstract type.
Notes
I took a look at the code an stumbled upon
def isSubstitutionGroup(elem: ElemDecl) =
elem.global && (elem.namespace map { x =>
context.substituteGroups.contains((elem.namespace, elem.name))
} getOrElse { false })
Why does this always return false
if the namespace is None
? Changing it to
elem.global && context.substituteGroups.contains((elem.namespace, elem.name))
results in the parser picking up the concrete types
def parser(node: scala.xml.Node, stack: List[scalaxb.ElemName]): Parser[PetType] =
phrase((((scalaxb.ElemName(None, "Dog")) ^^
(x => scalaxb.DataRecord(x.namespace, Some(x.name), scalaxb.fromXML[Dog](x, scalaxb.ElemName(node) :: stack)))) |
((scalaxb.ElemName(None, "Fish")) ^^
(x => scalaxb.DataRecord(x.namespace, Some(x.name), scalaxb.fromXML[Fish](x, scalaxb.ElemName(node) :: stack))))) ^^
{ case p1 =>
PetType(p1) })
but the element loses its type:
case class PetType(Animal: scalaxb.DataRecord[Any])