pabigot / pyxb

Python XML Schema Bindings
Apache License 2.0
130 stars 74 forks source link

toxml(), is it possible to keep sequence order? #85

Closed yhwu closed 7 years ago

yhwu commented 7 years ago

If I have the following in part of a schema

<xs:sequence>
    <xs:element name="A" type="xs:string" minOccurs="1" maxOccurs="1"/>
    <xs:element name="B" type="xs:string" minOccurs="1" maxOccurs="1"/>
    <xs:element name="C" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>

and I have an object created obj = obj(A='testA', B='testB', C='testC'), I would like to have obj.toxml() output always in the order of A,B,C like

<ns1:A>testA</ns1:A>
<ns1:B>testB</ns1:B>
<ns1:C>testC</ns1:C>

Is that possible to do that? Every time I run toxml(), it gives me different orders.

pabigot commented 7 years ago

I suspect the problem is Python doesn't retain the order of the key-value parameters. If you do:

instance = element('testA', 'testB', 'testC');

does it work? Alternatively, do:

instance = element(();
instance.append('testA');
instance.append('testB');
instance.append('testC');
pabigot commented 7 years ago

No, wait, you're not doing something right. The schema example you gave enforces order. This works just fine:

# -*- coding: utf-8 -*-
import logging
if __name__ == '__main__':
    logging.basicConfig()
_log = logging.getLogger(__name__)
import pyxb.binding.generate
import pyxb.utils.domutils
from xml.dom import Node

import os.path
xsd='''<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="tElt">
    <xs:sequence>
      <xs:element name="A" type="xs:string" minOccurs="1" maxOccurs="1"/>
      <xs:element name="B" type="xs:string" minOccurs="1" maxOccurs="1"/>
      <xs:element name="C" type="xs:string" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="elt" type="tElt"/>
</xs:schema>'''

code = pyxb.binding.generate.GeneratePython(schema_text=xsd)

rv = compile(code, 'test', 'exec')
eval(rv)

from pyxb.exceptions_ import *

import unittest
import sys

class TestX (unittest.TestCase):
    def testKey (self):
        instance = elt(A='testA', B='testB', C='testC');
        print(instance.toxml());
        instance = elt(C='testC', B='testB', A='testA');
        print(instance.toxml());

if __name__ == '__main__':
    unittest.main()

producing:

<?xml version="1.0" ?><elt><A>testA</A><B>testB</B><C>testC</C></elt>
<?xml version="1.0" ?><elt><A>testA</A><B>testB</B><C>testC</C></elt>

Either your schema is something else (e.g. a choice rather than sequence group) or you've disabled validation.

yhwu commented 7 years ago

Thank you so much! That was indeed the case. I turned off validation when I was trouble shooting my own error, but forgot to turn it back on.