【问题标题】:Accessing XMLNS attribute with Python Elementree?使用 Python Elementtree 访问 XMLNS 属性?
【发布时间】:2010-12-29 13:16:29
【问题描述】:

如何通过 ElementTree 访问 NS 属性?

以下内容:

<data xmlns="http://www.foo.net/a" xmlns:a="http://www.foo.net/a" book="1" category="ABS" date="2009-12-22">

当我尝试 root.get('xmlns') 时,我返回无,类别和日期都很好,感谢任何帮助..

【问题讨论】:

  • 我无法回答您的问题 - 但在与这个缺点作斗争了几天后,我准备声称它无法与当前的 ElementTree API 一起使用。在我的应用程序中,我需要检测根元素上是否已经存在 xmlns:xlink 属性,如果没有,则添加它。无法测试 xmlns 属性是否已经存在,更重要的是,如果您尝试,ElementTree 很乐意添加它两次。由于同一元素中的零个或两个相同的 xmlns 属性会在大多数 XML 使用者中导致错误,这使得 ElementTree 非常难以使用。

标签: python xml elementtree


【解决方案1】:

试试这个:

import xml.etree.ElementTree as ET
import re
import sys

with open(sys.argv[1]) as f:
    root = ET.fromstring(f.read())
    xmlns = ''
    m = re.search('{.*}', root.tag)
    if m:
        xmlns = m.group(0)
    print(root.find(xmlns + 'the_tag_you_want').text)

【讨论】:

    【解决方案2】:

    我认为element.tag 是您正在寻找的。请注意,您的示例缺少尾部斜杠,因此它不平衡并且不会解析。我在示例中添加了一个。

    >>> from xml.etree import ElementTree as ET
    >>> data = '''<data xmlns="http://www.foo.net/a"
    ...                 xmlns:a="http://www.foo.net/a"
    ...                 book="1" category="ABS" date="2009-12-22"/>'''
    >>> element = ET.fromstring(data)
    >>> element
    <Element {http://www.foo.net/a}data at 1013b74d0>
    >>> element.tag
    '{http://www.foo.net/a}data'
    >>> element.attrib
    {'category': 'ABS', 'date': '2009-12-22', 'book': '1'}
    

    如果您只想知道 xmlns URI,可以使用如下函数将其拆分:

    def tag_uri_and_name(elem):
        if elem.tag[0] == "{":
            uri, ignore, tag = elem.tag[1:].partition("}")
        else:
            uri = None
            tag = elem.tag
        return uri, tag
    

    有关 ElementTree 中的命名空间和限定名称的更多信息,请参阅 effbot's examples

    【讨论】:

    • 为什么库中没有这样的功能?似乎每个带有命名空间的 xml 文件都需要它。我错过了吗?
    • @clutch 我想知道同样的事情。有人知道原因吗?
    • @rednaw,我不相信拆分更好。分区保证返回正好三个元素的元组,分裂可以返回任意数量的元素。在实践中,除了一个右花括号外,其他任何东西在语法上都是无效的,但仍然如此。我认为分区更好。
    【解决方案3】:

    查看 effbot 命名空间文档/示例;特别是parse_map 函数。它向您展示了如何为每个元素添加一个 *ns_map* 属性,其中包含适用于该特定元素的前缀/URI 映射。

    但是,这会将 ns_map 属性添加到所有元素。根据我的需要,我发现我想要一个所有命名空间的全局映射,用于使元素查找更容易而不是硬编码。

    这是我想出的:

    import elementtree.ElementTree as ET
    
    def parse_and_get_ns(file):
        events = "start", "start-ns"
        root = None
        ns = {}
        for event, elem in ET.iterparse(file, events):
            if event == "start-ns":
                if elem[0] in ns and ns[elem[0]] != elem[1]:
                    # NOTE: It is perfectly valid to have the same prefix refer
                    #     to different URI namespaces in different parts of the
                    #     document. This exception serves as a reminder that this
                    #     solution is not robust.    Use at your own peril.
                    raise KeyError("Duplicate prefix with different URI found.")
                ns[elem[0]] = "{%s}" % elem[1]
            elif event == "start":
                if root is None:
                    root = elem
        return ET.ElementTree(root), ns
    

    有了这个,你可以解析一个 xml 文件并获得一个带有命名空间映射的字典。所以,如果你有一个像下面这样的 xml 文件(“my.xml”):

    <?xml version="1.0" encoding="UTF-8" ?>
    <rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"\
    >
    <feed>
      <item>
        <title>Foo</title>
        <dc:creator>Joe McGroin</dc:creator>
        <description>etc...</description>
      </item>
    </feed>
    </rss>
    

    您将能够使用 xml 命名空间并获取诸如 dc:creator 等元素的信息:

    >>> tree, ns = parse_and_get_ns("my.xml")
    >>> ns
    {u'content': '{http://purl.org/rss/1.0/modules/content/}',
    u'dc': '{http://purl.org/dc/elements/1.1/}'}
    >>> item = tree.find("/feed/item")
    >>> item.findtext(ns['dc']+"creator")
    'Joe McGroin'
    

    【讨论】:

    • 你在stackoverflow.com/questions/13018024/…回复了我的帖子
    • 我在您的代码中发现了一个小错误。我通过在 for 循环内将 ns[elem[0]] 设置为 elem[1] 来修复它,因为 ET 命名空间字典不需要大括号。
    • 我在 Python 中进行 XML 解析,最初认为类似这个函数的东西会被内置。但事实并非如此。我的搜索把我带到了这里,这个功能非常完美,让您不必手动打开 XML 文件并手动获取命名空间信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 2011-06-02
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    相关资源
    最近更新 更多