元素树解析

时间:2017-06-29 11:20:42

标签: python xml elementtree

我对元素树完全不熟悉,我一直在尝试更改xml文件中的某些文本。我一直在阅读一些例子,但我似乎找不到具有与我想要编辑的xml结构相同的xml结构的示例。

我尝试访问的特定元素是许多AvClass元素之一,看起来像这样..

initialString

id =“MMpr”是唯一的,包含一个ListElem - ATS_MM_PROJECT_DIRECTORY_NAME - 其中包含一个字符串'Projects // Post // Grading'。

编辑:抱歉,我忘记发布代码示例:

我想将此字符串更改为“Projects // NEW // STRING // ETC”,我正在努力解决这个问题。任何人都可以指出我正确的方向吗?

ATM。我正在使用很多for循环和比较运算符,但我确信有一种优雅的方法可以做到。

<AvClass id="MMpr">
  <AvProp id="ASET" name="name" type="string">Untitled</AvProp>
  <AvProp id="ASET" name="kind" type="string">Interplay Folder</AvProp>
  <AvProp id="ASET" name="attributes" type="int16">17</AvProp>
  <AvProp id="ASET" name="type" type="int16">32</AvProp>
  <AvProp id="ASET" name="attrList" type="reference">
    <AvClass id="ATTR">
      <AvProp id="ATTR" name="__OMFI:ATTR:NumItems" type="int32">3</AvProp>
      <List id="OMFI:ATTR:AttrRefs">
        <ListElem>
          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">2</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_PROJECT_DIRECTORY_NAME</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:StringAttribute" type="string">Projects//Post//Grading</AvProp>
        </ListElem>
        <ListElem>
          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_APPEND_PROJECT</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">1</AvProp>
        </ListElem>
        <ListElem>
          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_VERIFY_DIRECTORY</AvProp>
          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">0</AvProp>
        </ListElem>
        <ListElem/>
      </List>
    </AvClass>
  </AvProp>
</AvClass>

我想更改列表中的下一个AvProp元素文本值(可能为空)

1 个答案:

答案 0 :(得分:1)

Ye olde xpath。

由于您知道目标字符串,因此可以使用它识别AvProp元素。在这段代码中,完成后我验证我可以看到文本,然后我将新文本分配给元素。最后,我展示了xml的完整新版本。

>>> from lxml import etree
>>> tree = etree.parse('this_file.xml')
>>> avprop = tree.xpath('.//AvProp[text()="ATS_MM_PROJECT_DIRECTORY_NAME"]')[0]
>>> avprop.text
'ATS_MM_PROJECT_DIRECTORY_NAME'
>>> avprop.text = 'SOMETHING REALLY NOTICEABLE'
>>> etree.tostring(tree)
b'<AvClass id="MMpr">\n  <AvProp id="ASET" name="name" type="string">Untitled</AvProp>\n  <AvProp id="ASET" name="kind" type="string">Interplay Folder</AvProp>\n  <AvProp id="ASET" name="attributes" type="int16">17</AvProp>\n  <AvProp id="ASET" name="type" type="int16">32</AvProp>\n  <AvProp id="ASET" name="attrList" type="reference">\n    <AvClass id="ATTR">\n      <AvProp id="ATTR" name="__OMFI:ATTR:NumItems" type="int32">3</AvProp>\n      <List id="OMFI:ATTR:AttrRefs">\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">2</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">SOMETHING REALLY NOTICEABLE</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:StringAttribute" type="string">Projects//Post//Grading</AvProp>\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_APPEND_PROJECT</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">1</AvProp>\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_VERIFY_DIRECTORY</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">0</AvProp>\n        </ListElem>\n        <ListElem/>\n      </List>\n    </AvClass>\n  </AvProp>\n</AvClass>'

编辑:虽然输入文件显示兄弟姐妹在特定顺序中彼此跟随,但在处理xml时你不能假设顺序。换句话说,兄弟姐妹可能会以任何顺序传递给一个程序。

如果我这次正确理解你,这似乎可以胜任。

这一次,在确定了已知元素后,我得到了它的父元素,然后在其子元素中查找具有所需name属性的元素。如果没有孩子满足此要求,那么elements将是一个空列表。否则,只有列表中的第一个项目是要更改其内容的项目。

>>> from lxml import etree
>>> tree = etree.parse('this_file.xml')
>>> elements = tree.xpath('.//AvProp[text()="ATS_MM_PROJECT_DIRECTORY_NAME"]/../*[@name="OMFI:ATTB:StringAttribute"]')
>>> elements[0].text
'Projects//Post//Grading'
>>> if elements:
...     elements[0].text = '*** SOMETING I CAN SEE EASILY ***'
...     
>>> etree.tostring(tree)
b'<AvClass id="MMpr">\n  <AvProp id="ASET" name="name" type="string">Untitled</AvProp>\n  <AvProp id="ASET" name="kind" type="string">Interplay Folder</AvProp>\n  <AvProp id="ASET" name="attributes" type="int16">17</AvProp>\n  <AvProp id="ASET" name="type" type="int16">32</AvProp>\n  <AvProp id="ASET" name="attrList" type="reference">\n    <AvClass id="ATTR">\n      <AvProp id="ATTR" name="__OMFI:ATTR:NumItems" type="int32">3</AvProp>\n      <List id="OMFI:ATTR:AttrRefs">\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">2</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_PROJECT_DIRECTORY_NAME</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:StringAttribute" type="string">*** SOMETING I CAN SEE EASILY ***</AvProp>\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_APPEND_PROJECT</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">1</AvProp>\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_VERIFY_DIRECTORY</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">0</AvProp>\n        </ListElem>\n        <ListElem/>\n      </List>\n    </AvClass>\n  </AvProp>\n</AvClass>'

然后,为了验证代码是否能够处理缺少该元素的xml文件,我已经注释掉了&#39;元素并重新执行代码。这次尝试执行elements[0].text(在生产代码中你不会做的事情)失败,正如预期的那样,xml保持不变。

>>> tree = etree.parse('this_file.xml')
>>> elements = tree.xpath('.//AvProp[text()="ATS_MM_PROJECT_DIRECTORY_NAME"]/../*[@name="OMFI:ATTB:StringAttribute"]')
>>> elements[0].text
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
IndexError: list index out of range
>>> if elements:
...     elements[0].text = '*** SOMETING I CAN SEE EASILY ***'
... 
>>> etree.tostring(tree)
b'<AvClass id="MMpr">\n  <AvProp id="ASET" name="name" type="string">Untitled</AvProp>\n  <AvProp id="ASET" name="kind" type="string">Interplay Folder</AvProp>\n  <AvProp id="ASET" name="attributes" type="int16">17</AvProp>\n  <AvProp id="ASET" name="type" type="int16">32</AvProp>\n  <AvProp id="ASET" name="attrList" type="reference">\n    <AvClass id="ATTR">\n      <AvProp id="ATTR" name="__OMFI:ATTR:NumItems" type="int32">3</AvProp>\n      <List id="OMFI:ATTR:AttrRefs">\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">2</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_PROJECT_DIRECTORY_NAME</AvProp>\n          <!-- AvProp id="ATTR" name="OMFI:ATTB:StringAttribute" type="string">Projects//Post//Grading</AvProp -->\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_APPEND_PROJECT</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">1</AvProp>\n        </ListElem>\n        <ListElem>\n          <AvProp id="ATTR" name="OMFI:ATTB:Kind" type="int32">1</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:Name" type="string">ATS_MM_VERIFY_DIRECTORY</AvProp>\n          <AvProp id="ATTR" name="OMFI:ATTB:IntAttribute" type="int32">0</AvProp>\n        </ListElem>\n        <ListElem/>\n      </List>\n    </AvClass>\n  </AvProp>\n</AvClass>'