使用Python';s xml.etree以查找元素开始和结束字符偏移量
我有如下XML数据:使用Python';s xml.etree以查找元素开始和结束字符偏移量,python,xml,sax,elementtree,Python,Xml,Sax,Elementtree,我有如下XML数据: <xml> The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>. </xml> 南非的首都是比勒陀利亚。 我希望能够提取: 当前在etree中提供的XML元素 文档的完整纯文本,位于开始标记和结束标记之间 每个起始元素在纯文本中的位置,作为字符偏移量 (3) 是目前最重要的要求,;etree提供
<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>
南非的首都是比勒陀利亚。
我希望能够提取:
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
(3) 更为棘手的是,请参考此线程,它是Java,但Python SAX api中应该有类似的东西,您需要查看
.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或“”)
)
如果您熟悉sax(或拥有满足您需要的现有sax代码),lxml允许您:
从一个元素中提取所有文本时,还需要寻找其他一些东西:.itertext()
方法、xpath表达式//text()
(lxml允许您从xpath表达式返回“智能字符串”:它们允许您检查它们属于哪个元素等 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))
另一个选项是重写etree.TreeBuilder()的start()
、data()
、end()
方法:
从xml.etree.ElementTree导入XMLParser,TreeBuilder
类MyTreeBuilder(TreeBuilder):
def启动(自身、标签、属性):
打印(“%s>”%tag)
return TreeBuilder.start(self、tag、attrs)
def数据(自身、数据):
打印(报告(数据))
TreeBuilder.data(self,data)
def端(自身,标签):
return TreeBuilder.end(self,tag)
text=”“”
南非的首都是比勒陀利亚。
"""
#ElementTree.fromstring()
parser=XMLParser(target=MyTreeBuilder())
parser.feed(文本)
root=parser.close()#返回一个普通元素
输出
“\n的资本”
“南非”
“是”
“比勒陀利亚”
“.\n”
(3)可以通过以下方式完成:
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)
有关SAX替代方案,请参见。但是请注意,字节索引与字符索引不同,在Python中可能没有有效的方法将字节索引转换为字符索引。(另见。)
获取字符偏移量而不是字节偏移量的一个(公认的丑陋)解决方法是将字节重新编码为字符。假设实际编码为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'))
谢谢(2) (3)使用SAX肯定更容易。上一次遇到这个问题时,我同时使用了SAX和minidom,但是将这两种方法的结果对齐是一个不值得解决的问题。如果我能很容易地做到(1),我会转向SAX。你知道有什么方法吗?谢谢!这看起来很完美——尽管我只能在lxml中找到iterwalk,而不能找到与Python捆绑在一起的ElementTree。我找错地方了吗?你是对的,它只在lxml中。对不起,我太习惯使用lxml了,我以为你也是。(试一试,太棒了)。但是您应该能够使用方法elem自己制作一些东西。text
可能在event==“start”
@Leon Derczynski处不可用:iterparse()
在所有使用xml.etree的Python版本上都可用。Sebastian:iterparse()
是,但iterwalk()
仅在lxml中。这非常有用。非常感谢。
<xml>
'\nThe captial of '
<place>
'South Africa'
' is '
<place>
'Pretoria'
'.\n'
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)
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'))