LINUX.ORG.RU

Получить strpos() тэга в исходном xml

 , ,


0

1

Нужно распарсить xml, выдрать оттуда нужные тэги и запомнить смещения этих тэгов от начала исходного xml.

xml выглядит как-то так (docx, pptx, odt и т.д.):

<w:r>
  <w:rPr>
    <w:sz w:val="36"/>
    <w:szCs w:val="36"/>
  </w:rPr>
  <w:t>w</w:t> <!-- :( -->
</w:r>

Нужно получить offset w.

Самоочевидный такой вариант:

from lxml import etree
text = open('/devel/tmp/doc2/word/document.xml', 'r').read()
root = etree.XML(text)

start = 0
for e in root.iter("*"):
    if e.text:
        offset = text.index(e.text, start)
        l = len(e.text)
        print 'Text "%s" at offset %s and len=%s' % (e.text, offset, l)
        start = offset + l

Но если в e.text будет «w», «a» и т.д., то будет найден индекс не тэга, а чего попало.

Используй парсер, основанный на таком подходе, например, pugixml. Напиши обертку для питона, если надо.

annulen ★★★★★
()
Ответ на: комментарий от baverman

Зачем? Замену что ли делать? Чем не устраивает манипулирование домом?

Да, замену. Не устраивает то, что замене будет подвергаться все кроме текста в тегах, т.е. в примере выше заменено будет

<!--начиная отсюда-->
<w:r>
  <w:rPr>
    <w:sz w:val="36"/>
    <w:szCs w:val="36"/>
  </w:rPr>
  <w:t>
<!--до сюда-->
    w
<!--и снова отсюда и до следующего w:t, или тэга с текстом-->
   </w:t>
</w:r>
После замены нужно будет восстанавливать исходный формат, сделав все как было; XML может быть любой, поэтому писать по отдельному парсеру для каждого как-то не хочется.

division_hell
() автор топика
Ответ на: комментарий от division_hell

Ты хочешь очень странных вещей. Повторюсь, почему просто не удалить ненужные узлы и вместо них вставить требуемый?

поэтому писать по отдельному парсеру для каждого как-то не хочется.

На всякий случай спрошу, слышал про XPath?

// Если мусье все же так желает секаса, то вот: http://stackoverflow.com/questions/3187964/is-there-a-fast-xml-parser-in-pyth...

baverman ★★★
()
Ответ на: комментарий от baverman

Я проще напишу что нужно получить. Предположим, есть два текстовых блока:

<!--part0-->
<w:r>
  <w:rPr>
    <w:sz w:val="36"/>
    <w:szCs w:val="36"/>
  </w:rPr>
  <w:t>
   <!--/part0-->
    w
    <!--part1-->
   </w:t>
</w:r>
<w:r>
  <w:rPr>
    <w:sz w:val="36"/>
    <w:szCs w:val="36"/>
  </w:rPr>
  <w:t>
     <!--/part1-->
    qqqq
    <!--part2-->
   </w:t>
</w:r>

В итоге для удобства редактирования исходный xml примет вид:

<p0/>w<p1/>qqqq<p2/>....
Далее я знаю, что p0 =
<w:r>
  <w:rPr>
    <w:sz w:val="36"/>
    <w:szCs w:val="36"/>
  </w:rPr>
  <w:t>
И в конечном юзерском тексте меняю p0, p1 и т.д. на то, что было в оригинале. И вообще не забочусь о формате оригинального xml.

Естественно, никто не мешает внутрь w:t с текстом добавить элемент <p0> - `<w:t>text_here</w:t>` поменять на `<w:t><p0/>text_here</w:t>`. Но исходные индексы для замен побьются, либо придется вычислять смещение, либо повторно проходить конечный файл и убирать оттуда левые для исходного формата <pХ>.

Плюс такого подхода в том, что я смогу с тем же успехом обрабатывать и не xml форматы, т.к. метод основан на смещении. Если делать как-то иначе, то придется писать разные парсеры.

XPath юзал, конечно, но я не очень понимаю, как мне этот тут поможет?

division_hell
() автор топика
Ответ на: комментарий от division_hell

Ты как-то через жопу к гландам полез. Запомни просто какой элемент дома соответсвует каждому из редактируемых кусков и когда нужно будет сохранить исходный документ, заменяй текст в них.

Kalashnikov ★★★
()
Ответ на: комментарий от division_hell

Я так ничего и не понял.

В итоге для удобства редактирования исходный xml

o_O.

baverman ★★★
()
Ответ на: комментарий от annulen

Изкоробочность, как правило, перевешивает всё остальное.

baverman ★★★
()

Короче, пожалуй @Kalashnikov прав, лучше обойтись без индексов а для плейнтекста написать отдельный парсер. Хотя все равно не понятно, почему бы не передать pos начала сегмента...

from xml.etree import cElementTree # <-- я не нашел тут nsmap, поэтому etree
from lxml import etree
import zipfile, re, hashlib
file_path = '/devel/tmp/long_sample.docx'

zf = zipfile.ZipFile(file_path)
tree = etree.parse(zf.open('word/document.xml'))
nsmap = tree.getroot().nsmap
zf.close()

eos_chars = '.!?'

i = 0
dst_text = []
for e in tree.iter():
    # неймспейсы. как бы без вот этого вот
    tag_prefix = nsmap.get(e.prefix, '')

    if e.text and e.text.strip():
        # если кодировка файла utf8, почему возвращается str вместо unicode?
        text = e.text.encode('utf8')

        dst_text.append('<t%s/>' % i)
        dst_text.append(text)
        i += 1

        if any(c in text for c in eos_chars): 
            dst_text.append('\n')

    if e.tag == '{%s}br' % tag_prefix:
        dst_text.append('\n')

res = ''.join(dst_text)
print res, '\n'
division_hell
() автор топика
Ответ на: комментарий от division_hell

# если кодировка файла utf8, почему возвращается str вместо unicode?

e.text.encode('utf8')

/0

baverman ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.