【问题标题】:Parse a xml file with multiple root element in python在python中解析具有多个根元素的xml文件
【发布时间】:2017-08-03 05:13:38
【问题描述】:

我有一个 xml 文件,我需要从中获取一些标签以用于某些用途,其中包含如下数据:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
<?xml version="1.0"?>
<data>
    <country name="Liechtenstein1">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria1" direction="E"/>
        <neighbor name="Switzerland1" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia1" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

我需要解析这个,所以我使用了:

import xml.etree.ElementTree as ET
tree = ET.parse("myfile.xml")
root = tree.getroot()

此代码在第 2 行给出错误:xml.etree.ElementTree.ParseError: junk after document element:

我认为这是因为多个 xml 标签,你有什么想法,我应该如何解析这个?

【问题讨论】:

  • "我有一个 xml 文件..." 不,你没有。文件来自哪里?有没有可能解决那方面的问题? (解析它应该不会太难,但是如果有什么方法可以避免无效的 XML,那就更好了。)
  • 这不是一个有效的 XML 文件。但是可以在&lt;?xml version="1.0"?&gt;之前进行拆分,分别解析部分。
  • @smarx 你说的is there a possibility.. 是什么意思?我只给出了文件中的示例数据,它确实包含更多像这样的根元素......@KlausD。寻找更好的选择。
  • @ggupta 我的意思是您是否控制创建该文件的应用程序,您能否修复它以生成有效的 XML?
  • 然后将文件拆分到&lt;?xml ... 行并分别解析每个部分(现在是一个有效的 XML 文档)。

标签: python xml python-2.7 parsing


【解决方案1】:

我使用了一个简单的技巧来解析此类伪 XML(重要的是Wazuh rule files) - 只是暂时将其包装在一个假元素 &lt;whatever&gt;&lt;/whatever&gt; 中,从而在所有这些“根”上形成一个根。

在你的情况下,而不是像这样有一个无效的 XML:

<data> ... </data>
<data> ... </data>

就在将它传递给解析器之前,暂时将其重写为:

<whatever>
    <data> ... </data>
    <data> ... </data>
</whatever>

然后你像往常一样解析它并迭代&lt;data&gt;元素。

import xml.etree.ElementTree as etree
import pathlib

file = Path('rules/0020-syslog_rules.xml')
data = b'<rules>' + file.read_bytes() + b'</rules>'
etree.fromstring(data)
etree.findall('group')
... array of Elements ...

【讨论】:

    【解决方案2】:

    如果您需要,此代码会填写一种方法的详细信息。

    代码监视 'accumulated_xml,直到遇到另一个 xml 文档的开头或文件的结尾。当它有一个完整的 xml 文档时,它会调用display 来运行lxml 库来解析文档并报告一些内容。

    >>> from lxml import etree
    >>> def display(alist):
    ...     tree = etree.fromstring(''.join(alist))
    ...     for country in tree.xpath('.//country'):
    ...         print(country.attrib['name'], country.find('rank').text, country.find('year').text)
    ...         print([neighbour.attrib['name'] for neighbour in country.xpath('neighbor')])
    ... 
    >>> accumulated_xml = []
    >>> with open('temp.xml') as temp:
    ...     while True:
    ...         line = temp.readline()
    ...         if line:
    ...             if line.startswith('<?xml'):
    ...                 if accumulated_xml:
    ...                     display (accumulated_xml)
    ...                     accumulated_xml = []
    ...             else:
    ...                 accumulated_xml.append(line.strip())
    ...         else:
    ...             display (accumulated_xml)
    ...             break
    ... 
    Liechtenstein 1 2008
    ['Austria', 'Switzerland']
    Singapore 4 2011
    ['Malaysia']
    Panama 68 2011
    ['Costa Rica', 'Colombia']
    Liechtenstein1 1 2008
    ['Austria1', 'Switzerland1']
    Singapore 4 2011
    ['Malaysia1']
    Panama 68 2011
    ['Costa Rica', 'Colombia']
    

    【讨论】:

    • 谢谢,我只是用同样的方法,不知道没有这样的python库。
    • 每当我使用这种分割文件的方式时,我认为在 Python 中一定有更好的表达方式。
    【解决方案3】:

    问题:...任何想法,我应该如何解析这个?

    过滤整个文件并拆分为有效的&lt;?xml ...块。
    创建myfile_01, myfile_02 ... myfile_nn。

    n = 0
    out_fh = None
    with open('myfile.xml') as in_fh:
        while True:
            line = in_fh.readline()
            if not line: break
    
            if line.startswith('<?xml'):
                if out_fh:
                    out_fh.close()
                n += 1
                out_fh = open('myfile_{:02}'.format(n))
    
            out_fh.write(line)
    
        out_fh.close()
    

    如果您想将所有&lt;country&gt; 合为一个XML Tree:

    import re
    from xml.etree import ElementTree as ET
    
    with open('myfile.xml') as fh:
        root = ET.fromstring('<?xml version="1.0"?><data>{}</data>'.
                             format(''.join(re.findall('<country.*?</country>', fh.read(), re.S)))
                                    )
    

    用 Python 测试:3.4.2

    【讨论】:

    • 感谢您的建议,使用相同的方法。谢谢
    • 我只是在寻找解析文件的方法,而不是任何特定的标签,您之前的回答对我有帮助,感谢您修改它。
    猜你喜欢
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-10
    • 2015-08-26
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多