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
也没有找到这种情况下的解决方案(全部内容,包括内标签).
这是适合我和你的样本的东西:
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
避免重复尾部.
您可能需要处理其他节点类型(如果存在).
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)