2013-03-20 5 views
0

Я пытаюсь сделать это с помощью lxml, но в крайнем случае это вопрос о правильном пути xpath. Я хотел бы, чтобы выбрать из <pgBreak> элемента до конца своего родителя, в этом случае <p>xpath для выбора из дочернего элемента в конец родителя

XML В:

<root> 
    <pgBreak pgId="1"/> 
     <p> 
     some text to fill out a para 
      <pgBreak pgId="2"/> 
      some more text 
      <quote> A quoted block </quote> 
      remainder of para 
     </p> 
    </root> 

XML OUT:

<root> 
    <pgBreak pgId="1"/> 
     <p> 
     some text to fill out a para 
     </p> 
      <pgBreak pgId="2"/> 
     <p> 
      some more text 
      <quote> A quoted block </quote> 
      remainder of para 
     </p> 
    </root> 
+0

Используйте следующую-двойников ось, что-то вроде ' "pgBreak/следующий-собрата :: *"' – tdelaney

+0

@tdelaney я попробовал, что изначально, и это не не достичь ожидаемых результатов. – matchew

ответ

1

Что вы попытка сделать не тривиальна: вы не только должны соответствовать элементам «pgBreak» и всем последующим братьям и сестрам, тогда вы хотите переместить их за пределы родительской области и обернуть братьев и сестер в элементе «p». Забавные вещи.

Следующий код должен дать вам представление о том, как его достичь (ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: пример только, требуется очистка, крайние случаи, вероятно, не обрабатываются). Код намеренно раскоментирован, поэтому вам нужно это выяснить :)

Я немного изменил входной XML, чтобы лучше иллюстрировать функциональность.

import lxml.etree 

text = """ 
<root> 
    <pgBreak pgId="1"/> 
    <p> 
    some text to fill out a para 
    <pgBreak pgId="2"/> 
    some more text 
    <quote> A quoted block </quote> 
    remainder of para 
    <pgBreak pgId="3"/> 
    <p> 
     blurb 
    </p> 
    </p> 
</root> 
""" 

root = lxml.etree.fromstring(text) 
for pgbreak in root.xpath('//pgBreak'): 
    inner = pgbreak.getparent() 
    if inner == root: 
     continue 
    outer = inner.getparent() 
    pgbreak_index = inner.index(pgbreak) 
    inner_index = outer.index(inner) + 1 
    siblings = inner[pgbreak_index+1:] 
    inner.remove(pgbreak) 
    outer.insert(inner_index,pgbreak) 
    if siblings[0].tag != 'p': 
     p = lxml.etree.Element('p') 
     p.text = pgbreak.tail 
     pgbreak.tail = None 
     for node in siblings: 
      p.append(node) 
     outer.insert(inner_index+1,p) 
    else: 
     for node in siblings: 
      inner_index += 1 
      outer.insert(inner_index,node) 

Выход:

<root> 
    <pgBreak pgId="1"/> 
    <p> 
    some text to fill out a para 
    </p> 
    <pgBreak pgId="2"/> 
    <p> 
    some more text 
    <quote> A quoted block </quote> 
    remainder of para 
    </p> 
    <pgBreak pgId="3"/> 
    <p> 
    blurb 
    </p> 
</root> 
+0

спасибо, я дам этот снимок после обеда. Я задал этот вопрос, проведя целый день, и многие неудачные попытки. Я подозреваю, что это сломается после передачи некоторых реальных данных, но я просто хотел посмотреть, как кто-то другой приблизится к этой проблеме. Это, конечно, разочаровывает. Хотел бы я иметь некоторое влияние, когда этот DTD был создан. – matchew

+0

Так что это не удается, когда я даю ему несколько данных. Но он, похоже, обрабатывает мои данные образца. Спасибо за попытку ответа, вчера он держал меня в основном в тупике. – matchew

Смежные вопросы