元素树解析
Element tree parsing
我对元素树完全陌生,我一直在尝试更改 xml 文件中的一些文本。我一直在阅读一些示例,但我似乎找不到与我要编辑的示例具有相同类型 xml 结构的示例。
我试图访问的特定元素是许多 AvClass 元素之一,看起来像这样..
<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>
id="MMpr" 是唯一的并且包含一个 ListElem - ATS_MM_PROJECT_DIRECTORY_NAME - 它有一个字符串 'Projects//Post//Grading'.
编辑:对不起,我忘了 post 代码示例:
我想将此字符串更改为 'Projects//NEW//STRING//ETC' 之类的内容,但我正在努力实现它。谁能指出我正确的方向?
自动取款机。我使用了很多 for 循环和比较运算符,但我确信有一种优雅的方法可以做到这一点。
tree = ET.parse(this_file) # create tree from file
root = tree.getroot() # set the root
for x in root.iter('AvClass'): # iterates thru ALL classes
for prop in x: # get 1st level properties of class
# Interplay Paths
for chi1 in prop: # child of prop
for chi2 in chi1: # child of child
if 'ATS_MM_PROJECT_DIRECTORY_NAME' in str(chi2.text):
print(chi2.text)
#chi2.text = 'Projects//NEW//STRING//ETC'
我想更改列表中的下一个 AvProp 元素文本值(可能为空)
旧的 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 时您不能假设顺序。换句话说,兄弟姐妹可以以任何顺序传递给程序。
如果这次我对您的理解正确的话,这似乎可以完成工作。
这一次,在确定了已知元素后,我得到了它的 parent,然后在它的 children 中查找具有所需 name
属性的元素。如果 children 的 none 满足此要求,则 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 文件,我 'commented out' 元素和 re-executed 代码。这一次尝试执行 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>'
我对元素树完全陌生,我一直在尝试更改 xml 文件中的一些文本。我一直在阅读一些示例,但我似乎找不到与我要编辑的示例具有相同类型 xml 结构的示例。
我试图访问的特定元素是许多 AvClass 元素之一,看起来像这样..
<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>
id="MMpr" 是唯一的并且包含一个 ListElem - ATS_MM_PROJECT_DIRECTORY_NAME - 它有一个字符串 'Projects//Post//Grading'.
编辑:对不起,我忘了 post 代码示例:
我想将此字符串更改为 'Projects//NEW//STRING//ETC' 之类的内容,但我正在努力实现它。谁能指出我正确的方向?
自动取款机。我使用了很多 for 循环和比较运算符,但我确信有一种优雅的方法可以做到这一点。
tree = ET.parse(this_file) # create tree from file
root = tree.getroot() # set the root
for x in root.iter('AvClass'): # iterates thru ALL classes
for prop in x: # get 1st level properties of class
# Interplay Paths
for chi1 in prop: # child of prop
for chi2 in chi1: # child of child
if 'ATS_MM_PROJECT_DIRECTORY_NAME' in str(chi2.text):
print(chi2.text)
#chi2.text = 'Projects//NEW//STRING//ETC'
我想更改列表中的下一个 AvProp 元素文本值(可能为空)
旧的 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 时您不能假设顺序。换句话说,兄弟姐妹可以以任何顺序传递给程序。
如果这次我对您的理解正确的话,这似乎可以完成工作。
这一次,在确定了已知元素后,我得到了它的 parent,然后在它的 children 中查找具有所需 name
属性的元素。如果 children 的 none 满足此要求,则 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 文件,我 'commented out' 元素和 re-executed 代码。这一次尝试执行 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>'