我对元素树完全不熟悉,我一直在尝试更改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元素文本值(可能为空)
答案 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>'