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

У меня есть XML, структурированный так:

 <?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="192.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>

Атрибут bbox в текстовом теге имеет четыре значения, и мне нужно иметь разность первого значения bbox элемента и его предыдущего , Другими словами, расстояние между первыми двумя bboxes составляет 1.

Пока мой код:

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"

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)

Но часть, которая интересует проблему, конкретно:

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])

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

1 Ответ

0 голосов
/ 15 апреля 2020

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

значение bbox текстового узла - значение bbox предыдущих текстовых узлов, не превышающее 10.

Вы можете попробовать с XSL и XPath. Сначала код XSL (обязательный шаг для сравнения значения bbox с XPath на следующем шаге):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="no" indent="yes"/>

<xsl:template match="@bbox">
  <xsl:attribute name="{name()}">
  <xsl:value-of select="substring(.,1,3)" />
  </xsl:attribute>
</xsl:template>

<xsl:template match="@font">
  <xsl:attribute name="{name()}">
  <xsl:text>NUMPTY+ImprintMTnum</xsl:text>
  </xsl:attribute>
</xsl:template>

<xsl:template match="*[not(node())]"/> 
<xsl:strip-space  elements="*"/>

 <xsl:template match="@*|node()">
  <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

Затем:

import lxml.etree as IP

xml = IP.parse(xml_filename)
xslt = IP .parse(xsl_filename)
transform = IP.XSLT(xslt)

Затем запрос с:

tree = IP.parse(transform)
for nodes in tree.xpath("//text[@bbox<preceding::text[1]/@bbox+11]"):
    print(nodes)

Замените //text[@bbox<preceding::text[1]/@bbox+11] на //text[@bbox>preceding::text[1]/@bbox] для проверки с вашими примерами данных (выберет текстовые узлы с большим значением bbox, чем предыдущее текстовое значение bbox).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...