Greetings I want to take part of a word remove it and then append something new. Here is my xml

<Symbols>

                        <Item>
                                <Symbol>UPS2008</Symbol>
                                <Order>usg_05Y</Order>
                        </Item>

</Symbols>

My python code should remove the 2008 in UPS and change it to 2009 (basically write to file with elementtree), except I do not know what is up with my code. Any help would be appreciated and yes I read the effbot site but I must be doing something wierd. Thank you.

import urllib
import sys, string, os, datetime
import xml.etree.ElementTree as ET

root=ET.parse("thefile").getroot()
iter=root.getiterator('Item')
print iter
for n in iter :
        symbol=n.findtext('Symbol')
        print symbol
        if 'USP' in symbol:
            nodes=symbol[3:7]
            
          n.remove(nodes)
            n.append('2009')
            print "done"

Thanks

Dani AI

Generated

Nice catch by and on why your original code was failing. If you want to stay within ElementTree, you almost never need to remove and recreate the <Symbol> element just to tweak its text. remove()/append() operate on child elements, not on the string inside them, so the simplest and safest fix is to mutate .text in place and write the tree back out.

import xml.etree.ElementTree as ET

tree = ET.parse("thefile")
root = tree.getroot()

for sym in root.findall(".//Item/Symbol"):
    t = sym.text or ""
    # Only touch values like UPS#### at the end
    if t.startswith("UPS") and len(t) >= 7 and t[-4:].isdigit():
        sym.text = t[:-4] + "2009"   # or str(int(t[-4:]) + 1) to roll the year

tree.write("out.xml", encoding="utf-8", xml_declaration=True)

A few tips for readers coming across this later:

  • If you are on modern Python, prefer root.iter("Item") or findall() instead of getiterator(), which is deprecated.
  • If you want stricter matching (e.g., only change a trailing 4-digit year when the prefix is exactly UPS), use a small regex before assigning .text, or check t == "UPS2008" if it is truly unique.
  • For very large XML files, consider ET.iterparse(..., events=("end",)) and update each <Symbol> as it is parsed to keep memory usage low.

Recommended Answers

All 3 Replies

Firstly, it is 'UPS' and not 'USP'

Secondly, wouldn't this be simpler if 'UPS2008' is a rather unique string:

xml = """<Symbols>

<Item>
<Symbol>UPS2008</Symbol>
<Order>usg_05Y</Order>
</Item>

</Symbols>"""

new_xml = xml.replace('UPS2008', 'UPS2009')

print new_xml

"""
my output:
<Symbols>

<Item>
<Symbol>UPS2009</Symbol>
<Order>usg_05Y</Order>
</Item>
"""

Hi msaenz,

Lardmeister is correct in that your check for the symbol token "UPS" is flubbed. His approach works fine if you want to treat the whole XML file as a string. However, if you want to do this using the Python xml module, please see my modifications to your code below:

import sys, xml.etree.ElementTree as ET

# Create the root of the ElementTree from file
root = ET.parse("thefile").getroot()

# Get an iterator for the root node
iterator = root.getiterator("Item")

# Loop using the iterator
# (Please use clear variable names!)
for item in iterator:

    # To find a sub-element with a text tag, use find()
    old_symbol = item.find("Symbol")

    # This is how you get its text field
    text = old_symbol.text

    # Is 'UPS' in our text field?
    if 'UPS' in text:

        # If so, remove the sub-element
        # remove() takes out nodes, not text
        item.remove(old_symbol)

        # Add a new sub-element to the item
        new_symbol = ET.SubElement(item, "Symbol")

        # Set its text field to the appropriate thing
        new_symbol.text = text[0:3]+"2009"

# Now get the full tree from the root
tree = ET.ElementTree(root)

# And write to file!
tree.write("out.xml")

You can learn more at . This link takes you to the page which discusses searching for sub-elements and adding/removing them. It's not the main page - maybe you missed it?

Hope this helps!

Hi msaenz,

Lardmeister is correct in that your check for the symbol token "UPS" is flubbed. His approach works fine if you want to treat the whole XML file as a string. However, if you want to do this using the Python xml module, please see my modifications to your code below:

import sys, xml.etree.ElementTree as ET

# Create the root of the ElementTree from file
root = ET.parse("thefile").getroot()

# Get an iterator for the root node
iterator = root.getiterator("Item")

# Loop using the iterator
# (Please use clear variable names!)
for item in iterator:

    # To find a sub-element with a text tag, use find()
    old_symbol = item.find("Symbol")

    # This is how you get its text field
    text = old_symbol.text

    # Is 'UPS' in our text field?
    if 'UPS' in text:

        # If so, remove the sub-element
        # remove() takes out nodes, not text
        item.remove(old_symbol)

        # Add a new sub-element to the item
        new_symbol = ET.SubElement(item, "Symbol")

        # Set its text field to the appropriate thing
        new_symbol.text = text[0:3]+"2009"

# Now get the full tree from the root
tree = ET.ElementTree(root)

# And write to file!
tree.write("out.xml")

You can learn more at . This link takes you to the page which discusses searching for sub-elements and adding/removing them. It's not the main page - maybe you missed it?

Hope this helps!

thank you both very much for your help. I did not want to treat the whole xml file as a string but attempt to use the module. I guessI just needed it broken down to me a bit more than the effbot site did for me. Thank you once again, with this example above it will help me understand how the module works and what effbot is talking about.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.