1

I am trying to use python to edit .plist files, which are in XML format. In this example, I want to modify the IP address.

<dict>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/ExD2017/render/bin/renderqueue</string>
        <string>-h</string>
        <string>127.0.0.1</string>
    </array>
</dict>

In this case, I can get the value by using root[1][2].text, but this will break if the argument order in the XML changes. So I need to find it by specifying the tag following the tag named string whose value is -h. How can I find the index of the string whose value is -h? It should be a nested number like root[x][x].

Tomalak
  • 332,285
  • 67
  • 532
  • 628
Elliott B
  • 980
  • 9
  • 32
  • You want to look at XPath (https://docs.python.org/3.6/library/xml.etree.elementtree.html#xpath-support). In 99% of all cases trying to use numeric indexes with XML trees is the wrong thing to do. This is one of those cases. – Tomalak Mar 28 '18 at 08:09
  • Thanks. Do you know how to do this with XPath? According to the online XPath tester, this code should work, but it gives a syntax error in my script. `root.findall("./dict/array/string[.='-h']")` – Elliott B Mar 28 '18 at 08:44
  • Hm, the XPath implementation of elementtree is very lackluster. `./dict/array[string='-h']` ("finding an element by the text value of one of its children") would work, `./dict/array/string[.='-h']` ("finding an element by its own text value") is not supported. Also [see here](https://stackoverflow.com/q/10836205/18771). Do you have lxml installed by any chance, things would be much more straight-forward there: `tree.xpath("./dict/array/string[preceding-sibling::string[1]='-h']")` would get you precisely the right element. – Tomalak Mar 28 '18 at 10:18

1 Answers1

1

Since you have to iterate through all children anyway, to find -h, you can you can simply iterate to the next child:

h_found = False
for child in array_element:
    if child.text == '-h':
        h_found = True
    elif h_found:
        child.text = new_ip
        break
Daniel
  • 42,087
  • 4
  • 55
  • 81