xsdata icon indicating copy to clipboard operation
xsdata copied to clipboard

Problem with XmlSerializer and choice elements

Open martinwiesmann opened this issue 2 years ago • 2 comments

I found a new potential bug, that is connected with the fix for this issue: https://github.com/tefra/xsdata/issues/737 .

When you have a choice element in an xsd, the dataclass contains only the element with the name 'choice' and not the names of the different choice elements.

E.g. this xsd element:

    <xs:complexType name="sqfLimitValue">

        <xs:annotation>
 
           <xs:documentation>Choice of datatype of Static Quality Flags limits and its value</xs:documentation>

        </xs:annotation>
 
       <xs:choice>
 
           <xs:element name="ByteValue" type="xs:byte"/>
 
           <xs:element name="IntValue" type="xs:int"/>

            <xs:element name="FloatValue" type="xs:float"/>

            <xs:element name="DoubleValue" type="xs:double"/>

        </xs:choice>

    </xs:complexType>


becomes this dataclass:

@dataclass
class SqfLimitValue:
    """
    Choice of datatype of Static Quality Flags limits and its value.
    """
    class Meta:
        name = "sqfLimitValue"

    choice: Optional[object] = field(
        default=None,
        metadata={
            "type": "Elements",
            "choices": (
                {
                    "name": "ByteValue",
                    "type": int,
                    "namespace": "",
                },
                {
                    "name": "IntValue",
                    "type": int,
                    "namespace": "",
                },
                {
                    "name": "FloatValue",
                    "type": float,
                    "namespace": "",
                },
                {
                    "name": "DoubleValue",
                    "type": float,
                    "namespace": "",
                },
            ),
        }
    )

So far, so good. But when you instantiate this class and assign a value, it looks like this:

limit.choice = 4

Now, the interpreter has no way to know, which of the choices you meant to take. And if you save the data in an xml file using XmlSerializer from xsdata.formats.dataclass.serializers, it seems that the serializer chooses which one of the choices it uses, by picking the first one that fits the given data. Since the xml-file must have an element with the name of one of the choices, and not 'choice'.

I.e. in this example:

<Limit>
    <ByteValue>4</ByteValue>
</Limit>

If the choices are different enough so that it is unambiguous, there is no problem. But in some of my cases, such as the example above, the choice is sometimes ambiguous.

So, it happens that the serializer picks the unwanted choice, i.e. ByteValue instead of IntValue, which is not what we want.

Is there a way to make it explicit which choice element it is supposed to use? Or is this possibly a bug?

The xml file is saved correctly otherwise.

Furthermore, I get an error message, which I think is connected to this problem. This error seems to appear whenever the serializer can't decide unambiguously which choice to use:

qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 1877, resource id: 15612321, major code: 40 (TranslateCoords), minor code: 0

Note: I use PyQt5 and this program has a GUI, so this error message could stem from Qt, but it seems to only appear in the cases mentioned above...

martinwiesmann avatar Oct 23 '23 10:10 martinwiesmann

How do we solve this ambiguous issue in python, that doesn't have specific types for these cases?

I am open to suggestions

tefra avatar Nov 04 '23 18:11 tefra

Maybe it's time for XmlByte and XmlDouble builtin types

tefra avatar Nov 05 '23 09:11 tefra

Fixed in https://github.com/tefra/xsdata/pull/946

tefra avatar Mar 09 '24 18:03 tefra

Great. Thank you very much. I confirm that the ambiguity has gone.

martinwiesmann avatar Mar 12 '24 09:03 martinwiesmann