Извлечение узлов Python, содержащих тег, с использованием ElementTree

Мне нужно извлечь из XML несколько узлов, если один из них содержит ключевое слово. Наконец я добрался до точки, где я буду печатать ключевые слова, если они будут найдены. Теперь самое сложное (по крайней мере, для меня ;-)). Я объясню это ниже более подробно. XML:

<?xml version="1.0"?>
<ItemSearchResponse xmlns="http://url">
  <Items>
    <Item>
      <ItemAttributes>
        <ListPrice>
          <Amount>2260</Amount>
        </ListPrice>
      </ItemAttributes>
      <Offers>
        <Offer>
          <OfferListing>
            <Price>
              <Amount>1853</Amount>
            </Price>
          </OfferListing>
        </Offer>
      </Offers>
      <Offers>
        <Offer>
          <OfferListing>
            <Price>
              <Amount>1853</Amount>
            </Price>
          </OfferListing>
        </Offer>
      </Offers>
      <Offers>
        <Offer>
          <OfferListing>
            <Price>
              <Amount>1200</Amount>
            </Price>
          </OfferListing>
        </Offer>
      </Offers>
    </Item>
  </Items>
</ItemSearchResponse>

Мой сценарий выводит значение суммы, если оно найдено, и == 1853. Что мне действительно нужно, так это: когда найдено 1853 - сценарий должен извлечь все <Offers> в новый файл. Я запустил скрипт и застрял. Я действительно понятия не имею, как вернуться из <Amount> и скопировать всю группу <Offers>.

Скрипт 1:

import xml.etree.ElementTree as ET
import sys

name = str.strip(sys.argv[1])
filename = str.strip(sys.argv[2])

fp = open("sample.xml","r")
element = ET.parse(fp)

for elem in element.iter():
    if elem.tag == '{http://url}Price':
        output = {}
        for elem1 in list(elem):
            if elem1.tag == '{http://url}Amount':
                if elem1.text == name:
                    output['Amount'] = elem1.text
                    print output

И мой вывод:

python sample1.py '1853' x
{'Amount': '1853'}
{'Amount': '1853'}

«Х» здесь не имеет значения.

Как вернуться из <Amount> и скопировать всю группу <Offers> в новый файл или просто распечатать. Это нужно сделать с помощью ElementTree.


person jakkolwiek    schedule 05.09.2013    source источник
comment
только ElementTree? потому что этот пакет pythonhosted.org/pyquery забавен для такого мышления, это jquery-подобная система   -  person Philippe T.    schedule 05.09.2013
comment
Я ограничен здесь стандартом :/   -  person jakkolwiek    schedule 05.09.2013


Ответы (1)


Что насчет этого:

import xml.etree.ElementTree as ET
import sys

name = str.strip(sys.argv[1])
filename = str.strip(sys.argv[2])

fp = open("sample.xml","r")
tree = ET.parse(fp)
root = tree.getroot()

for offers in root.findall('.//{http://url}Offers'):
    value_found = False
    for amount in offers.findall('.//{http://url}Amount'):
        if amount.text == name:
            value_found = True
            break
    if value_found:
        print ET.tostring(offers)

Отпечатки

<url:Offers xmlns:url="http://url">
    <url:Offer>
      <url:OfferListing>
        <url:Price>
          <url:Amount>1853</url:Amount>
        </url:Price>
      </url:OfferListing>
    </url:Offer>
  </url:Offers>

<url:Offers xmlns:url="http://url">
    <url:Offer>
      <url:OfferListing>
        <url:Price>
          <url:Amount>1853</url:Amount>
        </url:Price>
      </url:OfferListing>
    </url:Offer>
  </url:Offers>

Чтобы записать в файлы, вы можете сделать что-то вроде: (заимствовано из этот ответ)

for i, offers in enumerate(root.findall('.//{http://url}Offers'), start=1):
    value_found = False
    for amount in offers.findall('.//{http://url}Amount'):
        if amount.text == name:
            value_found = True
            break
    if value_found:
        tree = ET.ElementTree(offers)
        tree.write("offers%d.xml" % i,
           xml_declaration=True, encoding='utf-8',
           method="xml", default_namespace='http://url')

который пишет файлы типа:

<?xml version='1.0' encoding='utf-8'?>
<Offers xmlns="http://url">
    <Offer>
      <OfferListing>
        <Price>
          <Amount>1853</Amount>
        </Price>
      </OfferListing>
    </Offer>
  </Offers>
person paul trmbrth    schedule 05.09.2013
comment
Это не так. Я ищу предложения с 1853 в сумме. Если найдено, мне нужно извлечь все «Предложения» с дочерними узлами в новый файл. Таким образом, когда задано 1853, необходимо выделить две группы: ‹Предложения›‹Предложение›‹Список предложений›‹Цена›‹Сумма›1853‹/Сумма›‹/Цена›‹/Список предложений›‹/Предложение›‹/Предложения›‹Предложения ›‹Предложение›‹Список предложений›‹Цена›‹Сумма›1853‹/Сумма›‹/Цена›‹/Список предложений›‹/Предложение›‹/Предложения›. Я также думал о xml.dom, но я не уверен, правильно ли я думаю здесь - person jakkolwiek; 05.09.2013
comment
Виноват. Я убрал 2-й брейк и позвонил ET.tostring(offers) - person paul trmbrth; 05.09.2013
comment
Ага, это просто идеально! Я вижу, что мне все еще нужно узнать об перечислениях, чтобы полностью понять это, но - большое спасибо! Это большая помощь! - person jakkolwiek; 05.09.2013
comment
@jakkolwiek, enumerate() просто очень удобный помощник для подсчета в циклах. Моим самым большим открытием в последнее время был параметр start ;) - person paul trmbrth; 05.09.2013
comment
На самом деле я до сих пор не понимаю одного ... Скажем, в моем исходном xml есть около 300 тегов ‹Amount› со значением = 1853. Все это хорошо печатается в терминале, но в файле написан только последний тег. Я также пытался передать строки в файл, но все еще не могу понять это правильно. И еще - в терминале все нормально, а в файле остается только одна последняя запись. - person jakkolwiek; 05.09.2013
comment
Можете ли вы опубликовать более полный XML с упомянутым вами случаем? - person paul trmbrth; 05.09.2013
comment
Это все тот же случай, даже с использованием кода, который вы разместили. В терминале все отлично, а в файл пишется только последний найденный тег и никак не могу понять почему. Особенно, когда он напечатан правильно. Итак... XML на самом деле такой же, только с несколькими группами ‹Offer› с различными ‹Amounts. В XML может быть вроде 5 Amounts = 1853 и 6 других. Скрипт выводит на экран правильно, нашел 5 с 1853, но в файле остается только последний. - person jakkolwiek; 05.09.2013