Open ArminWiebigke opened 1 year ago
Given a XSD with an abstract type, for which concrete elements are provided via substitutionGroup:
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>
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:
PetType
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)) })
The generated parser/writer should be able to handle all elements that are provided via substitutionGroup for the abstract type.
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
false
None
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])
Steps
Given a XSD with an abstract type, for which concrete elements are provided via
substitutionGroup
:Try to parse a valid XML file for that schema:
Problem
Parsing fails with
The generated parser for
PetType
tries to parse the abstract type directly, instead of the subtypes: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
Why does this always return
false
if the namespace isNone
? Changing it toresults in the parser picking up the concrete types
but the element loses its type: