【问题标题】:xpath to select from child element to end of parent从子元素选择到父元素末尾的xpath
【发布时间】:2013-03-20 22:19:46
【问题描述】:

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

【问题讨论】:

  • 使用以下兄弟轴,例如"pgBreak/following-sibling::*"
  • @tdelaney 我最初尝试过,但没有达到预期的效果。

标签: python xml xpath lxml


【解决方案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>

【讨论】:

  • 谢谢,我会在晚饭后试一试。我花了一整天后问了这个问题,许多失败的开始。我怀疑在给它一些真实数据后这会中断,但我只是想看看其他人会如何解决这个问题。这肯定令人沮丧。希望我在创建此 DTD 时能产生一些影响。
  • 所以当我给它更多数据时它确实会失败。但它似乎确实处理了我的样本数据。感谢您尝试回答,昨天一整天让我很困惑。
猜你喜欢
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2018-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多