如何在Python中获取两个xml标记之间的全部内容?

Bru*_*tus 13 python xml lxml xml-parsing

我尝试在一个开放的xml标签和它的结束对应物之间获取整个内容.

title以下情况下获取内容很简单,但如果使用混合内容并且我想保留内部标记,如何在标记之间获取整个内容

<?xml version="1.0" encoding="UTF-8"?>
<review>
  <title>Some testing stuff</title>
  <text sometimes="attribute">Some text with <extradata>data</extradata> in it.
  It spans <sometag>multiple lines: <tag>one</tag>, <tag>two</tag> 
  or more</sometag>.</text>
</review>
Run Code Online (Sandbox Code Playgroud)

我想要的是两个text标签之间的内容,包括任何标签:Some text with <extradata>data</extradata> in it. It spans <sometag>multiple lines: <tag>one</tag>, <tag>two</tag> or more</sometag>.

现在我使用正则表达式,但它有点混乱,我不喜欢这种方法.我倾向于基于XML解析器的解决方案.我看了看minidom,etree,lxml并且BeautifulSoup也没有找到这种情况下的解决方案(全部内容,包括内标签).

Mat*_*ttH 7

这是适合我和你的样本的东西:

from lxml import etree
doc = etree.XML(
"""<?xml version="1.0" encoding="UTF-8"?>
<review>
  <title>Some testing stuff</title>
  <text>Some text with <extradata>data</extradata> in it.</text>
</review>"""
)

def flatten(seq):
  r = []
  for item in seq:
    if isinstance(item,(str,unicode)):
      r.append(unicode(item))
    elif isinstance(item,(etree._Element,)):
      r.append(etree.tostring(item,with_tail=False))
  return u"".join(r)

print flatten(doc.xpath('/review/text/node()'))
Run Code Online (Sandbox Code Playgroud)

产量:

Some text with <extradata>data</extradata> in it.
Run Code Online (Sandbox Code Playgroud)

xpath选择<text>元素的所有子节点,如果它们是字符串/ unicode子类(<class 'lxml.etree._ElementStringResult'>)etree.tostring,则直接将它们呈现为unicode,如果它是a ,则调用它们Element,with_tail=False避免重复尾部.

您可能需要处理其他节点类型(如果存在).


Mar*_*cin 3

from lxml import etree
t = etree.XML(
"""<?xml version="1.0" encoding="UTF-8"?>
<review>
  <title>Some testing stuff</title>
  <text>Some text with <extradata>data</extradata> in it.</text>
</review>"""
)
(t.text + ''.join(map(etree.tostring, t))).strip()
Run Code Online (Sandbox Code Playgroud)

这里的技巧是它t是可迭代的,并且迭代时会产生所有子节点。因为 etree 避免了文本节点,所以您还需要恢复第一个子标签之前的文本,使用t.text.

In [50]: (t.text + ''.join(map(etree.tostring, t))).strip()
Out[50]: '<title>Some testing stuff</title>\n  <text>Some text with <extradata>data</extradata> in it.</text>'
Run Code Online (Sandbox Code Playgroud)

或者:

In [6]: e = t.xpath('//text')[0]

In [7]: (e.text + ''.join(map(etree.tostring, e))).strip()
Out[7]: 'Some text with <extradata>data</extradata> in it.'
Run Code Online (Sandbox Code Playgroud)