Добавление нового SubElement в существующий файл XML с помощью ElementTree - PullRequest
1 голос
/ 12 марта 2020

У меня есть две папки, в одной папке которых находятся тысячи изображений, а в другой папке - соответствующие файлы. xml. XML имена файлов и изображений совпадают (например, 2007. xml и 2007.jpg). Теперь я хотел бы добавить имя изображения (2007.jpg) в соответствующий файл (2007. xml). . xml Формат файла:

<?xml version='1.0' encoding='ASCII'?>
<annotation>
  <size>
    <width>1820</width>
    <height>940</height>
  </size>
  <object>
    <name>Car</name>
    <bndbox>
      <xmin>74.0</xmin>
      <ymin>509.0</ymin>
      <xmax>236.0</xmax>
      <ymax>609.0</ymax>
    </bndbox>
</annotation>  

Я хочу добавить новый SubElement

<?xml version='1.0' encoding='ASCII'?>
    <annotation>
      <filename>2007.jpg</filename>
      <size>
        <width>1820</width>
        <height>940</height>
      </size>
      <object>
        <name>Car</name>
        <bndbox>
          <xmin>74.0</xmin>
          <ymin>509.0</ymin>
          <xmax>236.0</xmax>
          <ymax>609.0</ymax>
        </bndbox>
    </annotation>  

Я пытаюсь следующим образом:

import xml.etree.ElementTree as ET
import os
doc = ET.parse('00390.xml')
root = doc.getroot()
s = '/image/00390.jpg'
filename = (os.path.basename(s))
userElement = ET.Element("annotation")
newSub = ET.SubElement(userElement, "filename")
newSub.set(filename, '')
root.insert(0, newSub)
tree = ET.ElementTree(root)
tree.write(open('3.xml', 'w'), encoding = 'UTF-8')

Вывод получен : <filename 00390.jpg=""/> Хотя вывод должен быть <filename>00390.jpg</filename> Я думаю, что проблема в использовании newSub.set (), который принимает 3 входных аргумента.

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Обновленный ответ для вашей новой проблемы

import xml.etree.ElementTree as ET
import os
doc = ET.parse('00390.xml')
root = doc.getroot()
s = '/image/00390.jpg'
filename = (os.path.basename(s))
userElement = ET.Element("annotation")
newSub = ET.SubElement(userElement, "filename")
newSub.set(filename, '')#<----- ***** 
root.insert(0, newSub)
tree = ET.ElementTree(root)
tree.write(open('3.xml', 'w'), encoding = 'UTF-8')

Выходные данные вернутся

<filename 00390.jpg=""/>

Вместо

<filename>00390.jpg</filename>

Это потому, что в (*) вы устанавливаете значение атрибута вместо текста в теге подэлемента XML.

Чтобы решить вашу проблему, замените newSub.set(filename, '') на

newSub.text = filename#Assigns text
root.insert(0,newSub)
#Returns this <filename>00390.jpg</filename>

См. Пример здесь

0 голосов
/ 12 марта 2020

Как уже упоминал @mzjn, попробуйте использовать метод Element.insert. Это позволяет вам указать индекс, куда именно вы хотите его вставить.

Например, чтобы вставить перед вторым элементом:

import xml.etree.ElementTree as ET

#your tree
root = ET.fromstring('''
<element>
    <att1></att1>
    <att3></att3>
</element>
 ''')

#Create a new element
new = ET.Element('att2')
root.insert(1, new)  # <-----------Insert operaton
print(ET.tostring(root))

#output
"""
<root>
    <att1/>
    <att2/>#newly inserted 
    <att3/>
</root>
"""

Редактировать:

Метод ElementTree.write по умолчанию использует кодировку us-ascii и, как таковой, ожидает открытия файла для записи в двоичном виде:

Выходными данными является либо строка (str) или двоичный (байты). Это контролируется аргументом кодирования. Если кодировка равна "unicode", выводом является строка; в противном случае это двоичный файл. Обратите внимание, что это может конфликтовать с типом file , если это открытый объект файла; убедитесь, что вы не пытаетесь записать строку в двоичный поток и наоборот.

Поэтому откройте файл для записи в двоичном режиме:

tree.write(open('person.xml', 'wb'))

или откройте файл для записи в текстовом режиме и укажите "unicode" как кодировку :

tree.write(open('person.xml', 'w'), encoding='unicode')
...