我有XML数据,如下所示:
<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>
我希望能够提取:
(3)是目前最重要的要求; etree提供(1)罚款。
我无法直接看到任何方法(3),但希望迭代文档树中的元素会返回许多可以重新组合的小字符串,从而提供(2)和(3)。但是,请求根节点的.text仅返回根节点和第一个元素之间的文本,例如, “的首都 ”。
使用SAX执行(1)可能涉及实施已经多次写入的批次,例如, minidom和etree。使用lxml不是此代码所涉及的包的选项。有人可以帮忙吗?
答案 0 :(得分:4)
iterparse()
功能在xml.etree
中可用:
import xml.etree.cElementTree as etree
for event, elem in etree.iterparse(file, events=('start', 'end')):
if event == 'start':
print(elem.tag) # use only tag name and attributes here
elif event == 'end':
# elem children elements, elem.text, elem.tail are available
if elem.text is not None and elem.tail is not None:
print(repr(elem.tail))
另一种选择是覆盖start()
的{{1}},data()
,end()
方法:
etree.TreeBuilder()
from xml.etree.ElementTree import XMLParser, TreeBuilder
class MyTreeBuilder(TreeBuilder):
def start(self, tag, attrs):
print("<%s>" % tag)
return TreeBuilder.start(self, tag, attrs)
def data(self, data):
print(repr(data))
TreeBuilder.data(self, data)
def end(self, tag):
return TreeBuilder.end(self, tag)
text = """<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>"""
# ElementTree.fromstring()
parser = XMLParser(target=MyTreeBuilder())
parser.feed(text)
root = parser.close() # return an ordinary Element
答案 1 :(得分:1)
您需要查看.tail
属性以及.text
:.text
会在开始标记后直接为您提供文字,.tail
会直接为您提供文字结束标记。这将为您提供“许多小字符串”。
提示:您可以使用etree.iterwalk(elem)
(与etree.iterparse()
完全相同,但在现有树上)来迭代开始和结束标记。这个想法:
for event, elem in etree.iterwalk(xml_elem, events=('start', 'end')):
if event == 'start':
# it's a start tag
print 'starting element', elem.tag
print elem.text
elif event == 'end':
# it's an end tag
print 'ending element', elem.tag
if elem is not xml_elem:
# dont' want the text trailing xml_elem
print elem.tail
我猜你可以自己完成剩下的工作吗?
警告:.text
和.tail
可以是None
,因此如果您想连接,则必须加以防范(例如,使用(elem.text or '')
)
如果您熟悉sax(或者现有的sax代码可以满足您的需求),lxml可以让您produce sax events from an element or tree:
lxml.sax.saxify(elem, handler)
从元素中提取所有文本时要查找的其他一些事项:.itertext()
方法,xpath表达式.//text()
(lxml允许您从xpath表达式返回“智能字符串”:它们允许您检查他们属于哪个元素等...)。
答案 2 :(得分:0)
(2),请参阅此片段
from xml.sax.handler import ContentHandler
import xml.sax
import sys
class textHandler(ContentHandler):
def characters(self, ch):
sys.stdout.write(ch.encode("Latin-1"))
parser = xml.sax.make_parser()
handler = textHandler()
parser.setContentHandler(handler)
parser.parse("test.xml")
或示例1-1:本书中的bookhandler.py http://oreilly.com/catalog/pythonxml/chapter/ch01.html
(3)比较棘手,请参考这个帖子,它是Java,但是在Python SAX api中应该有类似的东西How do I get the correct starting/ending locations of a xml tag with SAX?
答案 3 :(得分:0)
(3)可以使用XMLParser.CurrentByteIndex完成,如下所示:
import xml.etree.ElementTree as ET
class MyTreeBuilder(ET.TreeBuilder):
def start(self, tag, attrs):
print(parser.parser.CurrentByteIndex)
ET.TreeBuilder.start(self, tag, attrs)
builder = MyTreeBuilder()
parser = ET.XMLParser(target=builder)
builder.parser = parser
tree = ET.parse('test.xml', parser=parser)
另请参阅this answer了解SAX替代方案。但请注意,字节索引与字符索引不同,并且可能没有一种在Python中将字节转换为字符索引的有效方法。 (另见here。)
获得字符偏移而不是字节偏移的一种(难以置信的丑陋)解决方法是将字节重新编码为字符。假设实际编码是utf8:
import xml.etree.ElementTree as ET
class MyTreeBuilder(ET.TreeBuilder):
def start(self, tag, attrs):
print(parser.parser.CurrentByteIndex)
ET.TreeBuilder.start(self, tag, attrs)
builder = MyTreeBuilder()
parser = ET.XMLParser(target=builder)
builder.parser = parser
with open('test.xml', 'rb') as f:
parser.feed(f.read().decode('latin1').encode('utf8'))