Я читаю данные из словаря Python и пытаюсь добавить больше элементов книги в дерево ниже. Ниже приведен только пример, мне нужно скопировать элемент с его потомками, но заменить содержимое, в этом случае мне нужно скопировать элемент книги, но заменить заголовок и автора.

  <store>
    <bookstore>
        <book>
            <title lang="en">IT book</title>
            <author>Some IT Guy</author>
        </book>
    </bookstore>
  </store>

Я использую этот код:

root = et.parse('Template.xml').getroot()
bookstore = root.find('bookstore')
book = root.find('bookstore').find('book')

Затем я запускаю цикл по словарю и пытаюсь добавить новые элементы книги в книжный магазин:

for bk in bks:
    book.find('title').text = bk
    bookstore.append(book)

В результате элементы book добавляются в книжный магазин, однако все они содержат заголовок из последней итерации цикла. Я знаю, что я делаю что-то не так, но я не могу понять, что. Я старался:

book[0].append(book) and book[-1].append(book)

Но это не помогло.

1
Alex D. 13 Мар 2018 в 18:28

2 ответа

Лучший ответ

Вы меняете один и тот же объект.

Вам нужно реально скопировать объект с помощью copy.deepcopy

Примере:

import xml.etree.ElementTree as et
import copy

root = et.parse('Template.xml').getroot()
bookstore = root.find('bookstore')
book = root.find('bookstore').find('book')

bks = ["book_title_1", "book_title_2", "book_title_3"]
for bk in bks:
   new_book = copy.deepcopy(book)
   new_book.find('title').text = bk
   bookstore.append(new_book)

print et.tostring(root)
3
Chertkov Pavel 13 Мар 2018 в 16:29

Полагаю, вместо books.append(book) вы имеете в виду bookstore.append(book).

В основном здесь у вас есть структура:

- store
  - bookstore
    - book
      - book infos

С book = root.find('bookstore').find('book') вы фактически получаете ссылку на (единственный), который у вас уже есть, и в цикле вы продолжаете обновлять его заголовок и повторно добавлять его в магазин (так что в основном вы только перезаписываете заголовок). Что вам нужно делать, так это создавать каждый раз новый { {X1}} (или клонируйте его, как предложил Чертков Павел, но не забудьте перезаписать все поля, иначе вы можете унаследовать не того автора) и добавить его в книжный магазин:

for bk in bks:
    new_book = et.Element('book')

    # create and append title
    new_title = et.Element('title', attib={'lang':'eng'})
    new_title.text = bk
    new_book.append(new_title)

    # add also author and any other info
    # ...

    # append to the bookstore
    bookstore.append(new_book)

print et.tostring(root)
2
Cavaz 13 Мар 2018 в 16:48