Menu

Get XML text from content of xsd:any DOM

Help
2016-10-26
2016-10-28
  • Richard Neumann

    Richard Neumann - 2016-10-26

    I am having an element like:

    <xsd:element name="user_defined_anyfield">
        <xsd:complexType mixed="true">
            <xsd:sequence minOccurs="0" maxOccurs="unbounded">
                <xsd:any processContents="lax"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    

    within a DOM using PyXB 1.2.6-DEV. Unfortunately I cannot find a way to access any possible XML content as a string from the DOM:

    >>> xml = '<user_defined_anyfield><foo bar="baz"><spamm>eggs</spamm></foo></user_defined_anyfield>'
    >>> udf = openimmo.CreateFromDocument(xml)
    >>> udf.toxml()
    '<?xml version="1.0" ?><user_defined_anyfield><foo bar="baz"><spamm>eggs</spamm></foo></user_defined_anyfield>'
    >>> for e in udf.orderedContent():
    ...     print(e.value, dir(e.value))
    ... 
    <pyxb.utils.saxdom.Element object at 0x7ff2638daba8> ['ATTRIBUTE_NODE', 'CDATA_SECTION_NODE', 'COMMENT_NODE', 'DOCUMENT_FRAGMENT_NODE', 'DOCUMENT_NODE', 'DOCUMENT_TYPE_NODE', 'ELEMENT_NODE', 'ENTITY_NODE', 'ENTITY_REFERENCE_NODE', 'NOTATION_NODE', 'PROCESSING_INSTRUCTION_NODE', 'TEXT_NODE', '_Locatable_mixin__location', '_NamespaceContext__namespaceContext', '_Node__attributes', '_Node__childIfPresent', '_Node__childNodes', '_Node__expandedName', '_Node__indexInParent', '_Node__localName', '_Node__namespaceContext', '_Node__namespaceURI', '_Node__nodeType', '_Node__parentNode', '_Node__prefix', '_Node__tagName', '_Node__value', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_expandedName', '_indexInParent', '_location', '_setAttributes', '_setLocation', '_setParentNode', 'appendChild', 'attributes', 'childNodes', 'firstChild', 'getAttributeNS', 'getAttributeNodeNS', 'hasAttributeNS', 'localName', 'location', 'namespaceURI', 'nextSibling', 'nodeName', 'nodeType', 'parentNode', 'prefix', 'tagName', 'value']
    >>> for e in udf.orderedContent():
    ...     print(e.toxml())
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    AttributeError: 'ElementContent' object has no attribute 'toxml'
    

    How can I get the content '<foo bar="baz"><spamm>eggs</spamm></foo>' of the element from the DOM in this case?

    Thank you in advance and best regards.

     
  • Peter A. Bigot

    Peter A. Bigot - 2016-10-26

    Here the value is a DOM element already, but it's in a micro implementation of DOM used by PyXB which doesn't support the toxml() method. You need to convert it from saxdom to minidom. This is done using the BindingDOMSupport class, which normally defaults to working with minidom.

    The full details for converting a complex type instance into a DOM instance are here, but the code below handles the simple case for your example.

    import xml.dom
    from pyxb.utils import domutils
    from pyxb.binding import basis
    
    xmlt = '<user_defined_anyfield><foo bar="baz"><spamm>eggs</spamm></foo></user_defined_anyfield>';
    udf = CreateFromDocument(xmlt);
    print(udf.toxml());
    bds = domutils.BindingDOMSupport()
    for e in udf.orderedContent():
        if isinstance(e, basis.NonElementContent):
            print('text', e.value);
        elif e.elementDeclaration is None:
            if isinstance(e.value, xml.dom.Node):
                print('other', bds.cloneIntoImplementation(e.value).toxml('utf8'))
            else:
                print('dom', e.value.toDOM(bds))
        else:
            print(e.value.toXML());
    

    which produces:

    <?xml version="1.0" ?><user_defined_anyfield><foo bar="baz"><spamm>eggs</spamm></foo></user_defined_anyfield>
    ('other', '<foo bar="baz"><spamm>eggs</spamm></foo>')
    
     
  • Richard Neumann

    Richard Neumann - 2016-10-28

    Thanks, this is exactly what I needed:

    from xml.dom import Node
    from pyxb.utils.domutils import BindingDOMSupport
    from pyxb.binding.basis import NonElementContent
    
    def any_contents(dom):
        """Yields stringified contents of xs:any DOMs"""
        bds = BindingDOMSupport()
    
        for element in dom.orderedContent():
            if isinstance(element, NonElementContent):
                yield element.value
            elif element.elementDeclaration is None:
                if isinstance(element.value, Node):
                    yield bds.cloneIntoImplementation(element.value).toxml()
                else:
                    yield element.value.toDOM(bds).toxml()
            else:
                yield element.value.toXML()
    
     

Log in to post a comment.