Как вставить родительский узел в XML через Python? - PullRequest
0 голосов
/ 14 апреля 2020

У меня есть файл XML с такой структурой, и я хочу вставлять тег «newline» каждый раз, когда в координатах есть определенное расстояние (например, здесь, в файле они все разные) при условии:

 <?xml version="1.0" encoding="utf-8"?>
<pages>
    <page id="1" bbox="0.000,0.000,462.047,680.315" rotate="0">
        <textbox id="0" bbox="179.739,592.028,261.007,604.510">
            <textline bbox="179.739,592.028,261.007,604.510">
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">C</text>
                <text font="NUMPTY+ImprintMTnum-it"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.333">A</text>
                <text font="NUMPTY+ImprintMTnum-it"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.333">P</text>
                <text font="NUMPTY+ImprintMTnum-it"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.333">I</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">T</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">O</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">L</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">O</text>
                <text></text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
                <text font="NUMPTY+ImprintMTnum"  bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
                <text></text>
            </textline>
        </textbox>
    </page>
</pages>

Однако, мой код не работает как дерево, которое я напечатал, я не нахожу никаких следов новой строки. Следует обернуть текстовый тег до следующего, например:

<newline><text></text></newline><newline><text></text></newline>

et c.

Код:

import xml.etree.ElementTree as ET
import lxml.etree as etree
tree = ET.parse("fe2.xml")
root = tree.getroot()
node = ET.Element('newline')


for child in root.iter():
    if child.tag == 'text':
        #print(child.tag, child.attrib.items())
        for name, value in child.attrib.items():
                if name == 'bbox':
                        value = tuple(value.split(","))
                        x1 = float(value[0])
                        x2 = float(value[2])
                        distance = x2 - x1
                        if distance > 10:
                                root.insert(3, node)
                                xml_str = ET.tostring(root, encoding='unicode')
                                print(xml_str)

Как я могу сделать эту работу?

1 Ответ

1 голос
/ 14 апреля 2020

Для выполнения вашей задачи проще использовать l xml вместо ElementTree . Поэтому я использовал следующий импорт:

import lxml.etree as etree
from lxml.builder import E

Второй импорт обеспечивает фабрику новых элементов.

Чтобы упростить идентификацию элементов, я немного изменил значения чисел c в исходном файле. (дробные части после 191. ).

Чтобы получить красивую печать с новыми строками, я читаю исходный файл следующим образом:

parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse('input.xml', parser)
root = tree.getroot()

Чтобы обернуть последовательность "хороших" элементов в одном символе новой строки , действуйте следующим образом:

  1. Определите функцию для удаления элемента из родителя по его индексу и вернуть этот элемент:

    def removeByIdx(parent, idx):
        currElem = parent[idx]   # The indicated element
        parent.remove(currElem)  # Remove it from the parent
        return currElem          # Return the index and element
    
  2. Определить функцию для переноса дочерних элементов строки (родитель) с заданными индексами в newline element:

    def wrap(line, idxList):
        if len(idxList) == 0:
            return    # No elements to wrap
        # Take the first element from the original location
        idx = idxList.pop(0)     # Index of the first element
        elem = removeByIdx(line, idx) # The indicated element
        # Create "newline" element with "elem" inside
        nElem = E.newline(elem)
        line.insert(idx, nElem)  # Put it in place of "elem"
        while len(idxList) > 0:  # Process the rest of index list
            # Value not used, but must be removed
            idxList.pop(0) 
            # Remove the current element from the original location
            currElem = removeByIdx(line, idx + 1)
            nElem.append(currElem)  # Append it to "newline"
    
  3. После прочтения исходного XML дерева выполните:

    for line in root.iter('textline'):
        idxList = []
        for elem in line:
            bbox = elem.attrib.get('bbox')
            if bbox is not None:
                tbl = bbox.split(',')
                distance = float(tbl[2]) - float(tbl[0])
            else:
                distance = 100  # "Too big" value
            if distance < 10:
                par = elem.getparent()
                idx = par.index(elem)
                idxList.append(idx)
            else:  # "Wrong" element, wrap elements "gathered" so far
                wrap(line, idxList)
                idxList = []
        # Process "good" elements without any "bad" after them, if any
        wrap(line, idxList)
    

Тогда я распечатал дерево результатов:

print(etree.tostring(root, encoding='unicode', pretty_print=True))

получив:

<pages>
  <page id="1" bbox="0.000,0.000,462.047,680.315" rotate="0">
    <textbox id="0" bbox="179.739,592.028,261.007,604.510">
      <textline bbox="179.739,592.028,261.007,604.510">
        <newline>
          <text font="NUMPTY+ImprintMTnum" bbox="191.740,592.218,199.339,603.578" ncolour="0" size="12.482">C</text>
          <text font="NUMPTY+ImprintMTnum-it" bbox="191.741,592.218,199.339,603.578" ncolour="0" size="12.333">A</text>
          <text font="NUMPTY+ImprintMTnum-it" bbox="191.742,592.218,199.339,603.578" ncolour="0" size="12.333">P</text>
          <text font="NUMPTY+ImprintMTnum-it" bbox="191.743,592.218,199.339,603.578" ncolour="0" size="12.333">I</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.744,592.218,199.339,603.578" ncolour="0" size="12.482">T</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.745,592.218,199.339,603.578" ncolour="0" size="12.482">O</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.746,592.218,199.339,603.578" ncolour="0" size="12.482">L</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.747,592.218,199.339,603.578" ncolour="0" size="12.482">O</text>
        </newline>
        <text/>
        <newline>
          <text font="NUMPTY+ImprintMTnum" bbox="191.748,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.749,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
          <text font="NUMPTY+ImprintMTnum" bbox="191.750,592.218,199.339,603.578" ncolour="0" size="12.482">I</text>
        </newline>
        <text/>
      </textline>
    </textbox>
  </page>
</pages>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...