Skip to content
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

Order of next_value in XmlSerializer #565

Closed
strongly-typed opened this issue Jul 24, 2021 · 3 comments
Closed

Order of next_value in XmlSerializer #565

strongly-typed opened this issue Jul 24, 2021 · 3 comments
Labels
question Further information is requested

Comments

@strongly-typed
Copy link

I suspect that next_value of XmlSerializer does not maintain the order of elements in the XML file.

Full example here

The XSD is from here.

The excerpt of the XML is

                  <Contour DepthBounded="no">
                     <StartPoint Y="838.72" X="0" Z="0"/>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="152.655" X="1406.36" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="0" X="1688.37" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="19.1397" X="2089.08" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="159.521" X="2375.38" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="577.952" X="3353.32" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="724.208" X="3622.04" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="1073.13" X="3622.03" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="1073.13" X="1964.64" Z="0"/>
                     </Line>
                     <Arc Recess="automatic" Inclination="1.84741111297626e-13">
                        <EndPoint Y="1073.13" X="1620.74" Z="0"/>
                        <PointOnArc Y="901.18" X="1792.69" Z="0"/>
                     </Arc>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="1073.13" X="0.003709" Z="0"/>
                     </Line>
                     <Line Recess="automatic" Inclination="0">
                        <EndPoint Y="838.72" X="0" Z="0"/>
                     </Line>
                  </Contour>

A Line is explicitly defined by an EndPoint and implicitly by the previous point. That is a least a questionable design choice ...

I use xsdata to access the XML which is awesome!

Given the model generated by the XSD the order of the Arc and Line is separated in two lists:

btlx.project.parts.part[0].processings.mill_contour[0].contour.line
btlx.project.parts.part[0].processings.mill_contour[0].contour.arc

but it loses of course the order.

According to the hint in #261 I tried next_value:

contour = btlx.project.parts.part[0].processings.mill_contour[0].contour

context = XmlContext()
meta = context.fetch(contour.__class__)

for var, value in XmlSerializer.next_value(contour, meta):
    print(value)

But the result has a different order than the original XML>

PointType(x=0.0, y=838.72, z=0.0)
LineType(end_point=CoordinateType(x=1406.36, y=152.655, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
ArcType(end_point=CoordinateType(x=1620.74, y=1073.13, z=0.0), inclination=1.84741111297626e-13, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None, point_on_arc=CoordinateType(x=1792.69, y=901.18, z=0.0))
LineType(end_point=CoordinateType(x=1688.37, y=0.0, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=2089.08, y=19.1397, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=2375.38, y=159.521, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3353.32, y=577.952, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3622.04, y=724.208, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3622.03, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=1964.64, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=0.003709, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=0.0, y=838.72, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)

Arc is the 10th entry in the XML, but the 3rd output of xsdata.

Would be awesome if XmlSerializer maintains the order. Or is there any other possibility to get the elements in the order they appear in the XML?

Tested on Python 3.9.6 on macOS 10.15.7, xsdata 21.7, and on Python 3.9.6 in a Docker container.

@strongly-typed strongly-typed changed the title Order of Childs in Order of next_value in XmlSerializer Jul 24, 2021
@tefra
Copy link
Owner

tefra commented Jul 24, 2021

oh It's a repeatable choice, which means the elements can appear in any order, the only way to maintain the ordering between binding operations is to enable compound fields during generation

<xs:complexType name="SimpleContourType">
  <xs:annotation>
    <xs:documentation>Defintion of a simple contour (one point and multiple lines and arcs)</xs:documentation>
  </xs:annotation>
  <xs:sequence>
    <xs:element name="StartPoint" type="PointType" />
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="Line" type="LineType" />
      <xs:element name="Arc" type="ArcType" />
    </xs:choice>
  </xs:sequence>
</xs:complexType>
@dataclass
class SimpleContourType:
    """
    Defintion of a simple contour (one point and multiple lines and arcs)
    """
    start_point: Optional[PointType] = field(
        default=None,
        metadata={
            "name": "StartPoint",
            "type": "Element",
            "namespace": "http://www.design2machine.com",
            "required": True,
        }
    )
    line_or_arc: List[object] = field(
        default_factory=list,
        metadata={
            "type": "Elements",
            "choices": (
                {
                    "name": "Line",
                    "type": LineType,
                    "namespace": "http://www.design2machine.com",
                },
                {
                    "name": "Arc",
                    "type": ArcType,
                    "namespace": "http://www.design2machine.com",
                },
            ),
        }
    )

@tefra tefra added enhancement New feature or request question Further information is requested and removed enhancement New feature or request labels Jul 24, 2021
@strongly-typed
Copy link
Author

Thank you so much for the hint. Works like a charm!

Just to recap:

contour = btlx.project.parts.part[0].processings.choice[0].contour

for loa in contour.line_or_arc:
    print(loa)

gives all choices in the correct order:

LineType(end_point=CoordinateType(x=1406.36, y=152.655, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=1688.37, y=0.0, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=2089.08, y=19.1397, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=2375.38, y=159.521, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3353.32, y=577.952, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3622.04, y=724.208, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=3622.03, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=1964.64, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
ArcType(end_point=CoordinateType(x=1620.74, y=1073.13, z=0.0), inclination=1.84741111297626e-13, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None, point_on_arc=CoordinateType(x=1792.69, y=901.18, z=0.0))
LineType(end_point=CoordinateType(x=0.003709, y=1073.13, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)
LineType(end_point=CoordinateType(x=0.0, y=838.72, z=0.0), inclination=0.0, nail_spacing=None, recess=<ContourRecessType.AUTOMATIC: 'automatic'>, process=None)

From an XML design: Is there a (better) alternative?

@tefra
Copy link
Owner

tefra commented Jul 25, 2021

Unfortunately there is no other way without keeping some sort of ordering in a not xml field, but that would be extremely tricky without additional code inside each model.

The idea for the compound fields is baed on the jaxb modeling, but I am open to suggestions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants