Python XML удаляет некоторые элементы и их дочерние элементы, но сохраняет определенные элементы и их дочерние элементы

У меня очень большой XML-файл, и я пытаюсь создать новый XML-файл, в котором содержится небольшая часть содержимого этого файла большего размера. Я хочу указать атрибут (в моем случае, itemID) и присвоить ему несколько конкретных значений, а затем он удалит все элементы, кроме тех, которые имеют эти itemID и их дочерние элементы.

Мой большой XML-файл выглядит примерно так:

<?xml version='1.0' encoding='UTF-8'?>
<api version="2">
  <currentTime>2013-02-27 17:00:18</currentTime>
  <result>
    <rowset name="assets" key="itemID" columns="itemID,locationID,typeID,quantity,flag,singleton">
      <row itemID="1008551770576" locationID="31000559" typeID="17187" quantity="1" flag="0" singleton="1" rawQuantity="-1" />
      <row itemID="1008700753886" locationID="31000559" typeID="17187" quantity="1" flag="0" singleton="1" rawQuantity="-1" />
      <row itemID="1008700756994" locationID="31000559" typeID="17184" quantity="1" flag="0" singleton="1" rawQuantity="-1" />
      <row itemID="1008701224901" locationID="31000559" typeID="17186" quantity="1" flag="0" singleton="1" rawQuantity="-1" />
      <row itemID="1004072840841" locationID="31002238" typeID="17621" quantity="1" flag="0" singleton="1" rawQuantity="-1">
        <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
          <row itemID="150571923" typeID="25863" quantity="2" flag="119" singleton="0" />
          <row itemID="188435728" typeID="3388" quantity="1" flag="119" singleton="0" />
          <row itemID="210122947" typeID="3419" quantity="4" flag="119" singleton="0" />
        </rowset>
      </row>
      <row itemID="1005279202146" locationID="31002238" typeID="17621" quantity="1" flag="0" singleton="1" rawQuantity="-1">
        <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
          <row itemID="1004239962001" typeID="16275" quantity="49596" flag="4" singleton="0" />
          <row itemID="1005364142068" typeID="4246" quantity="156929" flag="4" singleton="0" />
          <row itemID="1005624252854" typeID="4247" quantity="93313" flag="4" singleton="0" />
        </rowset>
      </row>
      <row itemID="1004388226389" typeID="648" quantity="1" flag="0" singleton="1" rawQuantity="-1">
        <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
          <row itemID="1004388228218" typeID="31119" quantity="1" flag="92" singleton="1" rawQuantity="-1" />
          <row itemID="1004388701243" typeID="31119" quantity="1" flag="94" singleton="1" rawQuantity="-1" />
          <row itemID="1004388701485" typeID="31119" quantity="1" flag="93" singleton="1" rawQuantity="-1" />
          <row itemID="1009147502645" typeID="51" quantity="1" flag="5" singleton="1" rawQuantity="-1" />
        </rowset>
      </row>
    </rowset>
  </result>
  <cachedUntil>2013-02-27 23:00:18</cachedUntil>
</api>

Этот файл имеет около девяноста тысяч строк и составляет около 9 мегабайт.

Обратите внимание, что существуют itemID, и некоторые типы элементов могут (но не всегда) иметь больше элементов внутри себя, и эти дочерние элементы также имеют свои собственные itemID. Я пытаюсь получить несколько конкретных itemID и их детей и опустить все остальные.

Я использовал код изэтот ответ и это сближает меня. Он идеален, за исключением того, что он исключает потомков из itemID, который я использовал.

Мой код выглядит так:

import lxml.etree as le

##Take this big .xml file and pull out just the parts we want then write those to a new .xml file##
with open(filename,'r') as f:
    doc=le.parse(f)
    for elem in doc.xpath('//*[attribute::itemID]'):
        if elem.attrib['itemID']=='1004072840841':
            elem.attrib.pop('itemID')
        else:
            parent=elem.getparent()
            parent.remove(elem)
    print(le.tostring(doc))

Вот как выглядит полученная распечатка:

<api version="2">
  <currentTime>2013-03-01 21:46:52</currentTime>
  <result>
    <rowset name="assets" key="itemID" columns="itemID,locationID,typeID,quantity,flag,singleton">
      <row locationID="31002238" typeID="17621" quantity="1" flag="0" singleton="1" rawQuantity="-1">
        <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
          </rowset>
      </row>
      </rowset>
  </result>
  <cachedUntil>2013-03-02 03:46:53</cachedUntil>
</api>

Я хочу, чтобы это выглядело так:

<api version="2">
  <currentTime>2013-03-01 21:46:52</currentTime>
  <result>
    <rowset name="assets" key="itemID" columns="itemID,locationID,typeID,quantity,flag,singleton">
      <row locationID="31002238" typeID="17621" quantity="1" flag="0" singleton="1" rawQuantity="-1">
        <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
          <row itemID="150571923" typeID="25863" quantity="2" flag="119" singleton="0" />
          <row itemID="188435728" typeID="3388" quantity="1" flag="119" singleton="0" />
          <row itemID="210122947" typeID="3419" quantity="4" flag="119" singleton="0" />
        </rowset>
      </row>
      </rowset>
  </result>
  <cachedUntil>2013-03-02 03:46:53</cachedUntil>
</api>

Я недостаточно хорошо понимаю код, чтобы увидеть, что мне нужно изменить, чтобы включить в него потомки элемента itemID, который он мне ищет. Кроме того, в идеале я мог бы добавить несколько идентификаторов элементов, и это исключило бы все, кроме этих элементов и их дочерних элементов. Это означает, что нужно будет сохранитьitemID=[number] Атрибут строки (чтобы я мог использовать xPath для ссылки на конкретный itemID и его дочерние элементы, когда я использую этот XML-файл.)

Итак, мой главный вопрос о том, как включить дочерние элементы itemID, которые я ищу, в свой получившийся .xml. Мой дополнительный вопрос о том, как сделать это для более чем одного itemID одновременно (чтобы результирующий файл .xml убрал все, кроме этих itemID и их потомков).

ОБНОВЛЕНИЕ: Гадкий РЕШЕНИЕ

Я понял, чтоelem.attrib.pop('itemID') часть была частью, которая убрала itemID, и так как я хотел бы иметь несколько itemID и их детей, мне нужно было это сохранить, поэтому я убрал эту часть. Я пытался найти способ пропустить потомков строки с помощью itemID, который я искал, и что я придумал, чтобы пометить каждого атрибутом, который я мог бы затем найти обратно, и удалить все, что не иметь этот атрибут. Мне не нужен атрибут flag для того, что я делаю, поэтому я продолжил и использовал его для этой цели (поскольку попытки ввести новый атрибут встречались с ключевой ошибкой, когда я пытался выполнить итерации по ним.) Просто пометка детей было недостаточно, я должен был также пометить детей.

Вот мое уродливое решение:

with open(filename,'r') as f:
    doc=le.parse(f)
    for elem in doc.xpath('//*[attribute::itemID]'):
        if elem.attrib['itemID']=='1004072840841' or elem.attrib['itemID']=='1005279202146': # this or statement lets me get a resulting .xml file that has two itemIDs and their children
            elem.attrib['flag']='Keep'
            for child in elem.iterchildren():
                child.attrib['flag']='Keep'
                for c in child.iterchildren():
                    c.attrib['flag']='Keep'
        else:
            pass
    for e in doc.xpath('//*[attribute::flag]'):
        if e.attrib['flag']!='Keep':
            parent=e.getparent()
            parent.remove(e)
        else:
            pass
    print(le.tostring(doc))
    ##This part writes the pruned down .xml to a file##
    with open('test.xml', 'w') as t:
        for line in le.tostring(doc):
            t.write(line)
    t.close

Это уродливое решение включает в себя много итераций по данным и, я подозреваю, далеко не самый эффективный способ сделать это, но оно работает.

Ответы на вопрос(1)

Ваш ответ на вопрос