LXML + python: How to change every instance of an element

Viewed 60

How would I go about changing every element of Weather_ID in the following using LXML and Python?

As you can see, I'm basically trying to set each Weather_Id to a new value, in this case that value is 5.

My real world example could have dozens to hundreds of Weather_Ids.

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<ProjectDataSet>
<Fx>
    <Id>1</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>2</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
    <Fx>3<Id>3</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>4</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
</ProjectDataSet>

What I have tried so far:

from lxml import etree

text = """\
<ProjectDataSet>
<Fx>
    <Id>1</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>2</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
    <Fx>3<Id>3</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>4</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
</ProjectDataSet>
"""

root= etree.fromstring(text)


newWeatherId = 5

targets = root.xpath("//Fx[./Weather_Id]")
print(targets)
for target in targets:
    target.text = str(newWeatherId)

I either seem to not be modifying the list, not modifying the value of the Weather_Id tags, or generating various errors because I'm not addressing the text correctly.

2 Answers

You are close, you just have to set your xpath right. Also why not print root?

from lxml import etree

text = """
<ProjectDataSet>
<Fx>
    <Id>1</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>2</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    3
    <Id>3</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
<Fx>
    <Id>4</Id>
    <Weather_Id>2</Weather_Id>
    <Other></Other>
</Fx>
</ProjectDataSet>
"""

root= etree.fromstring(text)
newWeatherId = 5
targets = root.xpath("//Fx/Weather_Id")

for target in targets:
    target.text = str(newWeatherId)

print(etree.tostring(root))

This was the approach taken, in the end. Inefficient, but functional.

curWxID = 5

fxNumber = root.xpath('//Fx/Weather_Id')
            if fxNumber:
                length = len(fxNumber)
                for i in range(length):
                    fxNumber[i].text = str(curWxID)
Related