【问题标题】:xmlns namespace breaking lxmlxmlns 命名空间破坏 lxml
【发布时间】:2013-08-05 21:12:24
【问题描述】:

我正在尝试打开一个 xml 文件,并从某些标签中获取值。我已经做了很多,但是这个特殊的 xml 给了我一些问题。这是xml文件的一部分:

<?xml version='1.0' encoding='UTF-8'?>
<package xmlns="http://apple.com/itunes/importer" version="film4.7">
  <provider>filmgroup</provider>
  <language>en-GB</language>
  <actor name="John Smith" display="Doe John"</actor>
</package>

这是我的python代码示例:

metadata = '/Users/mylaptop/Desktop/Python/metadata.xml'
from lxml import etree
parser = etree.XMLParser(remove_blank_text=True)
open(metadata)
tree = etree.parse(metadata, parser)
root = tree.getroot()
for element in root.iter(tag='provider'):
    providerValue = tree.find('//provider')
    providerValue = providerValue.text
    print providerValue
tree.write('/Users/mylaptop/Desktop/Python/metadataDone.xml', pretty_print = True, xml_declaration = True, encoding = 'UTF-8')

当我运行它时,它找不到提供者标签或其值。如果我删除xmlns="http://apple.com/itunes/importer",那么一切都会按预期工作。 我的问题是如何删除这个命名空间,因为我对此完全不感兴趣,所以我可以使用 lxml 获取我需要的标签值?

【问题讨论】:

    标签: python namespaces lxml xml-namespaces


    【解决方案1】:

    provider 标记位于 http://apple.com/itunes/importer 命名空间中,因此您需要使用完全限定名称

    {http://apple.com/itunes/importer}provider
    

    或使用具有the namespaces parameter 的lxml 方法之一,例如root.xpath。然后你可以用命名空间前缀来指定它(例如ns:provider):

    from lxml import etree
    parser = etree.XMLParser(remove_blank_text=True)
    tree = etree.parse(metadata, parser)
    root = tree.getroot()
    namespaces = {'ns':'http://apple.com/itunes/importer'}
    items = iter(root.xpath('//ns:provider/text()|//ns:actor/@name',
                           namespaces=namespaces))
    for provider, actor in zip(*[items]*2):
        print(provider, actor)
    

    产量

    ('filmgroup', 'John Smith')
    

    请注意,上面使用的 XPath 假定 &lt;provider&gt;&lt;actor&gt; 元素总是交替出现。如果这不是真的,那么当然有办法处理它,但是代码变得有点冗长:

    for package in root.xpath('//ns:package', namespaces=namespaces):
        for provider in package.xpath('ns:provider', namespaces=namespaces):
            providerValue = provider.text
            print providerValue
        for actor in package.xpath('ns:actor', namespaces=namespaces):
            print actor.attrib['name']
    

    【讨论】:

    • ubuntu,如何找到标签的属性,我已经修改了我原来的例子,所以我正在寻找actor name=的值
    • 如果您有element,您可以使用element.attrib['name'] 访问属性值。但是,如果您要从 XML 文件中抓取 provideractor 元素,则可以使用 |(或)语法设置一个 XPath 来同时执行这两项操作。我已经编辑了帖子以说明我的意思。
    • 最后一个问题,如果我的 xml 中有多个“标题”标签怎么办,我该如何提供我需要的确切标题的绝对 xpath?
    • XPath tutorial开始。它将向您展示指定 XPath 的所有基本方法。
    • 我将如何完全删除命名空间,所以没有 xmlns=.... ??
    【解决方案2】:

    我的建议是不要忽略命名空间,而是将其考虑在内。我为我在 django-quickbooks 库上的工作编写了一些相关函数(稍作修改后复制)。使用这些功能,您应该能够做到这一点:

    providers = getels(root, 'provider', ns='http://apple.com/itunes/importer')
    

    以下是这些功能:

    def get_tag_with_ns(tag_name, ns):
        return '{%s}%s' % (ns, tag_name)
    
    def getel(elt, tag_name, ns=None):
        """ Gets the first tag that matches the specified tag_name taking into
        account the QB namespace.
    
        :param ns: The namespace to use if not using the default one for
        django-quickbooks.
        :type  ns: string
        """
    
        res = elt.find(get_tag_with_ns(tag_name, ns=ns))
        if res is None:
            raise TagNotFound('Could not find tag by name "%s"' % tag_name)
        return res
    
    def getels(elt, *path, **kwargs):
        """ Gets the first set of elements found at the specified path.
    
        Example:
            >>> xml = (
            "<root>" +
                "<item>" +
                    "<id>1</id>" +
                "</item>" +
                "<item>" +
                    "<id>2</id>"* +
                "</item>" +
            "</root>")
            >>> el = etree.fromstring(xml)
            >>> getels(el, 'root', 'item', ns='correct/namespace')
            [<Element item>, <Element item>]
        """
    
        ns = kwargs['ns']
    
        i=-1
        for i in range(len(path)-1):
            elt = getel(elt, path[i], ns=ns)
        tag_name = path[i+1]
        return elt.findall(get_tag_with_ns(tag_name, ns=ns))
    

    【讨论】:

      猜你喜欢
      • 2011-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-06
      相关资源
      最近更新 更多