dapper91 / pydantic-xml

python xml for humans
https://pydantic-xml.readthedocs.io
The Unlicense
141 stars 14 forks source link

Unable get list of subelements in proper order. #141

Closed vkouts closed 6 months ago

vkouts commented 8 months ago

I have xml document:

xml_text = '''<Periods>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>18.02.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>30.05.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>06.04.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>28.02.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>19.06.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>07.06.2023 0:00:00</Date_from>
</Periods>'''

and following code:

import pprint
from typing import List

from pydantic_xml import BaseXmlModel, element
from pydantic_xml.element.element import SearchMode

class Periods(BaseXmlModel, tag='Periods', search_mode=SearchMode.UNORDERED):
    year: List[str] = element(tag='Year', default_factory=list)
    date_from: List[str] = element(tag='Date_from', default_factory=list)

data = Periods.from_xml(xml_text)
pprint.pprint(data.date_from)

With search mode UNORDERED I getting list with wrong ordering:


 '28.02.2023 0:00:00',
 '18.02.2023 0:00:00',
 '19.06.2023 0:00:00',
 '06.04.2023 0:00:00',
 '07.06.2023 0:00:00']```

 Search modes **ORDERING** and **STRICT** returns only one element: 
 ```['07.06.2023 0:00:00']
 ['18.02.2023 0:00:00']```
 respectively. Trying to get list with needed ordering have no success.
dapper91 commented 7 months ago

@vkouts Hi

UNORDERED mode doesn't keep fields order by design so they are serialized in an arbitrary order.

Starting from version 2.5.0 it is possible to group adjacent elements in tuples. See the documentation.

In your case the model may be described like this:

import pprint
from typing import List, Tuple

from pydantic_xml import RootXmlModel

class Year(RootXmlModel[str], tag='Year'): pass
class DateFrom(RootXmlModel[str], tag='Date_from'): pass

class Periods(RootXmlModel, tag='Periods'):
    root: List[Tuple[Year, DateFrom]] = []

xml_text = '''<Periods>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>18.02.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>30.05.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>06.04.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>28.02.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>19.06.2023 0:00:00</Date_from>
    <Year>01.01.2023 0:00:00</Year>
    <Date_from>07.06.2023 0:00:00</Date_from>
</Periods>'''

data = Periods.from_xml(xml_text)
pprint.pprint(data)