Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Python';s xml.etree以查找元素开始和结束字符偏移量_Python_Xml_Sax_Elementtree - Fatal编程技术网

使用Python';s xml.etree以查找元素开始和结束字符偏移量

使用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数据:

<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>

南非的首都是比勒陀利亚。
我希望能够提取:

  • 当前在etree中提供的XML元素
  • 文档的完整纯文本,位于开始标记和结束标记之间
  • 每个起始元素在纯文本中的位置,作为字符偏移量
  • (3) 是目前最重要的要求,;etree提供(1)罚款

    我看不到任何直接执行(3)的方法,但希望遍历文档树中的元素将返回许多可以重新组合的小字符串,从而提供(2)和(3)。但是,请求根节点的.text只返回根节点和第一个元素之间的文本,例如“的大写字母”

    使用SAX执行(1)可能需要实现很多已经编写过多次的内容,例如minidom和etree。使用lxml不是此代码要进入的包的选项。有人能帮忙吗?

    (2)使用SAX很容易,请看这个片段

    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'))