使用Python解析复杂的XML文件

时间:2015-04-20 09:08:01

标签: python xml parsing xml-parsing

我试图用Python解析一个非常丑陋的XML文件。我设法很好地进入它,但在npdoc元素它失败了。我做错了什么?

XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<npexchange xmlns="http://www.example.com/npexchange/3.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.5">
<article id="123" refType="Article">
<articleparts>
    <articlepart id="1234" refType="ArticlePart">
        <data>
            <npdoc xmlns="http://www.example.com/npdoc/2.1" version="2.1" xml:lang="sv_SE">
                <body>
                    <p>Lorem ipsum some random text here.</p>
                    <p>
                        <b>Yes this is HTML markup, and I would like to keep that.</b>
                    </p>
                </body>
                <headline>
                    <p>I am a headline</p>
                </headline>
                <leadin>
                    <p>I am some other text</p>
                </leadin>
            </npdoc>
        </data>
    </articlepart>
</articleparts>
</article>
</npexchange>

这是我到目前为止的python代码:

from xml.etree.ElementTree import ElementTree

def parse(self):
    tree = ElementTree(file=filename)

    for item in tree.iter("article"):
        articleParts = item.find("articleparts")
        for articlepart in articleParts.iter("articlepart"):
            data = articlepart.find("data")
            npdoc = data.find("npdoc")

            id = item.get("id")
            headline = npdoc.find("headline").text
            leadIn = npdoc.find("leadin").text
            body = npdoc.find("body").text


    return articles

我发现了id,但是我无法访问npdoc元素中的字段。 npdoc变量设置为None。

更新: 通过在.find()调用中使用命名空间来管理将元素转换为变量。我如何获得价值?由于它是HTML,因此无法使用.text属性正确显示。

2 个答案:

答案 0 :(得分:2)

nsmap = {'npdoc': 'http://www.example.com/npdoc/2.1'}
data = articlepart.find("npdoc:data", namespaces=nsmap)

...会找到您的data元素。不需要丑陋,不可靠的弦乐变换。 (Re:&#34;不可靠&#34; - 考虑这会对包含文字箭头括号的CDATA部分做什么)。

答案 1 :(得分:1)

这是我在Python 3.4中提出的。它当然不是防弹的,但它可能会给你一些想法。

import xml.etree.ElementTree as ET
tree = ET.parse(r'C:\Users\Gord\Desktop\nasty.xml')
npexchange = tree.getroot()
for article in npexchange:
    for articleparts in article:
        for articlepart in articleparts:
            id = articlepart.attrib['id']
            print("ArticlePart - id: {0}".format(id))
            for data in articlepart:
                for npdoc in data:
                    for child in npdoc:
                        tag = child.tag[child.tag.find('}')+1:]
                        print("    {0}:".format(tag))  ## e.g., "body:"
                        contents = ET.tostring(child).decode('utf-8')
                        contents = contents.replace('<ns0:', '<')
                        contents = contents.replace('</ns0:', '</')
                        contents = contents.replace(' xmlns:ns0="http://www.example.com/npdoc/2.1">', '>')
                        contents = contents.replace('<' + tag + '>\n', '')
                        contents = contents.replace('</' + tag + '>', '')
                        contents = contents.strip()
                        print("        {0}".format(contents))

控制台输出

ArticlePart - id: 1234
    body:
        <p>Lorem ipsum some random text here.</p>
                            <p>
                                <b>Yes this is HTML markup, and I would like to keep that.</b>
                            </p>
    headline:
        <p>I am a headline</p>
    leadin:
        <p>I am some other text</p>

<强>更新

使用

进行了一些改进
  • 命名空间地图(由Charles建议),
  • register_namespace带有空前缀以删除一些名称空间前缀“noise”和
  • 使用.findall()而不是盲目地遍历子节点,无论其标记如何:
import xml.etree.ElementTree as ET
npdoc_uri = 'http://www.example.com/npdoc/2.1'
nsmap = {
    'npexchange': 'http://www.example.com/npexchange/3.5',
    'npdoc': npdoc_uri
    }
ET.register_namespace("", npdoc_uri)
tree = ET.parse(r'/home/gord/Desktop/nasty.xml')
npexchange = tree.getroot()
for article in npexchange.findall('npexchange:article', nsmap):
    for articleparts in article.findall('npexchange:articleparts', nsmap):
        for articlepart in articleparts.findall('npexchange:articlepart', nsmap):
            id = articlepart.attrib['id']
            print("ArticlePart - id: {0}".format(id))
            for data in articlepart.findall('npexchange:data', nsmap):
                for npdoc in data.findall('npdoc:npdoc', nsmap):
                    for child in npdoc.getchildren():
                        tag = child.tag[child.tag.find('}')+1:]
                        print("    {0}:".format(tag))  ## e.g., "body:"
                        contents = ET.tostring(child).decode('utf-8')
                        # remove HTML block tags, e.g. <body ...> and </body>
                        contents = contents.replace('<' + tag + ' xmlns="' + npdoc_uri + '">\n', '')
                        contents = contents.replace('</' + tag + '>', '')
                        contents = contents.strip()
                        print("        {0}".format(contents))