代码之家  ›  专栏  ›  技术社区  ›  Xeberdee

元素树分析

  •  0
  • Xeberdee  · 技术社区  · 7 年前

    我对元素树一无所知,我一直在尝试更改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>
    

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

    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元素文本值(可能为空)

    1 回复  |  直到 7 年前
        1
  •  1
  •   Bill Bell    7 年前

    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>'