XPath选择从子元素到父元素的结束
我正在尝试使用lxml这个库,但最终这是一个关于正确使用xpath的问题。
我想从<pgBreak>
这个元素开始选择,一直到它的父元素的结束,这里指的是<p>
。
输入的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:
<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>
1 个回答
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>