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文件,我“注释”了该元素并重新执行了代码。这次尝试执行
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>'