XPath选择从子元素到父元素的结束

0 投票
1 回答
1045 浏览
提问于 2025-04-17 19:48

我正在尝试使用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>

撰写回答