How to set ElementTree Element text field in the constructor
Asked Answered
C

4

21

How do I set the text field of of ElementTree Element from its constructor? Or, in the code below, why is the second print of root.text None?

import xml.etree.ElementTree as ET

root = ET.fromstring("<period units='months'>6</period>")
ET.dump(root)
print root.text

root=ET.Element('period', {'units': 'months'}, text='6')
ET.dump(root)
print root.text

root=ET.Element('period', {'units': 'months'})
root.text = '6'
ET.dump(root)
print root.text

Here the output:

<period units="months">6</period>
6
<period text="6" units="months" />
None
<period units="months">6</period>
6
Cratch answered 7/8, 2013 at 2:53 Comment(0)
C
15

The constructor doesn't support it:

class Element(object):
    tag = None
    attrib = None
    text = None
    tail = None

    def __init__(self, tag, attrib={}, **extra):
        attrib = attrib.copy()
        attrib.update(extra)
        self.tag = tag
        self.attrib = attrib
        self._children = []

If you pass text as a keyword argument to the constructor, you will add a text attribute to your element, which is what happened in your second example.

Clarke answered 7/8, 2013 at 2:57 Comment(1)
Thanks! (I should have read the code instead of the documentation!)Cratch
G
6

The constructor does not allow for it because they thought that it would be improper to have every foo=bar add an attribute except for the random two: text and tail

If you think this is a dumb reason to remove constructor comforts (as I do) then you can create your own element. I did. I have it as a subclass and added a parent parameter. This allows you to still use it with everything else!

Python 2.7:

import xml.etree.ElementTree as ET

# Note: for python 2.6, inherit from ET._Element
#       python 2.5 and earlier is untested
class TElement(ET.Element):
    def __init__(self, tag, text=None, tail=None, parent=None, attrib={}, **extra):
        super(TextElement, self).__init__(tag, attrib, **extra)

        if text:
            self.text = text
        if tail:
            self.tail = tail
        if not parent == None:   # Issues warning if just 'if parent:'
            parent.append(self)

Python 2.6:

#import xml.etree.ElementTree as ET

class TElement(ET._Element):
    def __init__(self, tag, text=None, tail=None, parent=None, attrib={}, **extra):
        ET._Element.__init__(self, tag, dict(attrib, **extra))

        if text:
            self.text = text
        if tail:
            self.tail = tail
        if not parent == None:
            parent.append(self)
Gherardi answered 14/5, 2014 at 16:13 Comment(0)
K
0

From API design perspective, extra and attrib are redundant, they should put text and tail instead inside extra

i.e., they should change the library code from:

class Element(object):
    tag = None
    attrib = None
    text = None
    tail = None

    def __init__(self, tag, attrib={}, **extra):
        attrib = attrib.copy()
        attrib.update(extra)
        self.tag = tag
        self.attrib = attrib
        self._children = []

into:

class Element(object):
    tag = None
    attrib = None
    text = None
    tail = None

    def __init__(self, tag, attrib={}, **extra):
        attrib = attrib.copy()
        self.tag = tag
        self.text = extra.get('text',None)
        self.tail = extra.get('tail',None)
        self.attrib = attrib
        self._children = []

Anyway, storing data structure using XML has already been deprecated because JSON is much more efficient and elegant. The only reason to use XML today is because of legacy reasons: too many existing libraries are still using it.

Kimbra answered 15/12, 2021 at 4:52 Comment(0)
W
0

With the lxml package you can do:

from lxml import etree

root = etree.Element('root')
etree.SubElement(root, 'periods', units='months').text = '6'

print(etree.tostring(root, pretty_print=True).decode())

Output:

<root>
  <periods units="months">6</periods>
</root>

It's not entirey in the constructor, but a one liner nevertheless.

Wellordered answered 27/1, 2023 at 14:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.