Menu

Help with choice field usage

Help
2013-07-24
2013-07-24
  • Andreas Porevopoulos

    Hello,
    First, I would like to thank you for this excellent module.

    I have an xsd which, among others, has the following definition:

        <xs:complexType name="AttributesType">
            <xs:annotation>
                <xs:documentation>Foreign and Native choice</xs:documentation>
            </xs:annotation>
            <xs:sequence>
                <xs:element name="Foreign">
                    <xs:annotation>
                        <xs:documentation>Foreign</xs:documentation>
                    </xs:annotation>
                    <xs:complexType>
                        <xs:choice>
                            <xs:element name="Yes" type="xs:boolean" fixed="true"/>
                            <xs:element name="No" type="xs:boolean" fixed="true"/>
                        </xs:choice>
                    </xs:complexType>
                </xs:element>
                <xs:element name="Native">
                    <xs:annotation>
                        <xs:documentation>Native</xs:documentation>
                    </xs:annotation>
                    <xs:complexType>
                        <xs:choice>
                            <xs:element name="Yes" type="xs:boolean" fixed="true"/>
                            <xs:element name="No" type="xs:boolean" fixed="true"/>
                        </xs:choice>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
        <xs:complexType name="YesNoChoice">
            <xs:annotation>
                <xs:documentation>Yes No Choice</xs:documentation>
            </xs:annotation>
            <xs:choice>
                <xs:element name="Yes" type="xs:boolean" fixed="true"/>
                <xs:element name="No" type="xs:boolean" fixed="true"/>
            </xs:choice>
        </xs:complexType>
    

    I have successfully created my classes with:

    pyxbgen -u tpv1.0.xsd -m tp
    

    In my script I do:

    import tp
    import pyxb
    Attributes = tp.AttributesType()
    Attributes.Foreign = ?????? What goes here?
    

    I have tried:

    Attributes.Foreign = pyxb.BIND(Yes=True)
    Attributes.Foreign = pyxb.BIND(Yes=True, No=False)  # This gives error: No is fixed
    YN = YesNoChoice()
    Attributes.Foreign = YN.Yes   # Error
    Attributes.Foreign = pyxb.BIND(YN.Yes)
    

    The ones that don't produce an error, when I do .toxml() I am getting both choices as "true".

    Any help will be much appreciated.

    Best regards,
    Andreas

     
  • Peter A. Bigot

    Peter A. Bigot - 2013-07-24

    If you were expecting No=False to produce a value where the No element contains "false" it won't: with the "fixed" attribute present the element content cannot be anything other than the value of the "fixed" attribute, in this case the boolean constant "true". You will always get both choices as "true" because the elements all specify that their content is fixed to be "true". Setting No=False is invalid per the content model. This is an XML issue and PyXB is behaving correctly.

    You can't create a valid instance because the choice group has two alternatives both of which are fixed to have content. On first review, PyXB appears to automatically incorporate both alternatives, which is invalid. It may be that XML disallows choice between fixed elements, but it's more likely that this is a PyXB bug. I'll look into this more.

     
  • Andreas Porevopoulos

    Hi Peter,

    Thanks for your answer.
    As for the first part I understand that this is the correct behavior.

    Taking the "fixed" out of the definition, regenerating my classes
    and giving:

    Attributes.Foreign(pyxb.BIND(Yes=True))
    Attributes.Native(pyxb.BIND(No=True))
    

    Gives correct only one answer:

      <ns1:Attributes>
        <ns1:Foreign>
          <ns1:Yes>true</ns1:Yes>
        </ns1:Foreign>
        <ns1:Native>
          <ns1:No>true</ns1:No>
        </ns1:Native>
      </ns1:Attributes>
    

    BUT the next one produces two lines. pyxb does not care if it's a choice field:

    Attributes.Foreign(pyxb.BIND(Yes=True, No=False))
    Attributes.Foreign(pyxb.BIND(No=True, Yes=False))
    
      <ns1:Attributes>
        <ns1:Foreign>
          <ns1:Yes>true</ns1:Yes>
          <ns1:No>false</ns1:No>
        </ns1:Foreign>
        <ns1:Native>
          <ns1:No>true</ns1:No>
          <ns1:Yes>false</ns1:Yes>
        </ns1:Native>
      </ns1:Attributes>
    

    Maybe this is the problem when the "fixed" attribute is in place. I also suspect if it's a choice field with 3 strings and you BIND all three, all three will be in the output. It doesn't matter the it's boolean in this situation.

    I can send you the complete xsd, if you thing it will help you.

    Best regards
    Andreas

     
  • Peter A. Bigot

    Peter A. Bigot - 2013-07-24

    The bug is now registered as: https://sourceforge.net/apps/trac/pyxb/ticket/204

    A patch is available in the ticket and on the next branch of the git repository. I don't promise the patch applies cleanly to anything other than its predecessor on the next branch.

    In short, yes, this was because PyXB improperly created an element with a default value regardless of whether the content model allowed it. The fix does revert behavior that somebody might be expecting, but that behavior has only been there since PyXB 1.2.1 and I've decided it was wrong.

    Regarding your discoveries when "fixed" is removed: With the following example from the original schema with the patch applied and elements that permit creating instances of the types:

    import pyxb
    import xx
    
    a = xx.attributesType()
    a.Native = pyxb.BIND(Yes=True)
    
    a.Foreign = pyxb.BIND(Yes=True)
    a.validateBinding()
    a.Foreign = pyxb.BIND(No=True)
    a.validateBinding()
    a.Foreign = pyxb.BIND(Yes=True, No=True)
    try:
        a.validateBinding()
    except pyxb.ValidationError as e:
        print e.details()
    

    everything will be good except that the final assignment to Foreign will be allowed, but will not validate. This is because you explicitly instantiate both elements even though the content model does not allow both to be present. You get this error, which is correct:

    The containing element Foreign is defined at xx.xsd[8:12].
    The containing element type <class 'xx.CTD_ANON'> is defined at xx.xsd[12:16]
    The <class 'xx.CTD_ANON'> automaton is in an accepting state.
    The last accepted content was Yes
    No elements or wildcards would be accepted at this point.
    The following content was not processed by the automaton:
        No (1 instances)
    

    PyXB does not diagnose this error when the instance is created because both elements are assigned explicitly rather than by parsing them from a stream of content.

    I can't replicate your output showing both Yes and No elements in this case; I get a ValidationError trying to generate the xml.

     
  • Andreas Porevopoulos

    Thanks Peter for looking into it.

    I have cloned the next branch and installed it and now works fine.
    Only one of the choices can be set. Setting more than one throughs an excpetion.

    Best regards
    Andreas

     

Log in to post a comment.