首页 文章

通过'ElementTree'在Python中使用命名空间解析XML

提问于
浏览
124

我有以下XML,我想用Python的 ElementTree 解析:

<rdf:RDF xml:base="http://dbpedia.org/ontology/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns="http://dbpedia.org/ontology/">

    <owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
        <rdfs:label xml:lang="en">basketball league</rdfs:label>
        <rdfs:comment xml:lang="en">
          a group of sports teams that compete against each other
          in Basketball
        </rdfs:comment>
    </owl:Class>

</rdf:RDF>

我想找到所有 owl:Class 标签,然后提取其中所有 rdfs:label 实例的值 . 我使用以下代码:

tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')

由于命名空间,我收到以下错误 .

SyntaxError: prefix 'owl' not found in prefix map

我尝试在http://effbot.org/zone/element-namespaces.htm阅读该文档,但由于上述XML具有多个嵌套命名空间,因此我仍然无法正常工作 .

请告诉我如何更改代码以查找所有 owl:Class 标签 .

6 回答

  • 178

    ElementTree对名称空间并不太聪明 . 您需要为 .find()findall()iterfind() 方法提供显式命名空间字典 . 这没有很好地记录:

    namespaces = {'owl': 'http://www.w3.org/2002/07/owl#'} # add more as needed
    
    root.findall('owl:Class', namespaces)
    

    只在您传入的 namespaces 参数中查找前缀 . 这意味着您可以使用任何您喜欢的命名空间前缀; API拆分 owl: 部分,在 namespaces 字典中查找相应的命名空间URL,然后更改搜索以查找XPath表达式 {http://www.w3.org/2002/07/owl}Class . 当然,您也可以使用相同的语法:

    root.findall('{http://www.w3.org/2002/07/owl#}Class')
    

    如果你可以切换到lxml library东西更好;该库支持相同的ElementTree API,但在元素的 .nsmap 属性中为您收集名称空间 .

  • 0

    以下是如何使用lxml执行此操作,而无需对命名空间进行硬编码或扫描文本(如Martijn Pieters所提到的):

    from lxml import etree
    tree = etree.parse("filename")
    root = tree.getroot()
    root.findall('owl:Class', root.nsmap)
    
  • 5

    Note :这是一个对Python的ElementTree标准库有用的答案,不使用硬编码命名空间 .

    要从XML数据中提取名称空间的前缀和URI,您可以使用 ElementTree.iterparse 函数,仅解析名称空间启动事件(start-ns):

    >>> from io import StringIO
    >>> from xml.etree import ElementTree
    >>> my_schema = u'''<rdf:RDF xml:base="http://dbpedia.org/ontology/"
    ...     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    ...     xmlns:owl="http://www.w3.org/2002/07/owl#"
    ...     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    ...     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    ...     xmlns="http://dbpedia.org/ontology/">
    ... 
    ...     <owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
    ...         <rdfs:label xml:lang="en">basketball league</rdfs:label>
    ...         <rdfs:comment xml:lang="en">
    ...           a group of sports teams that compete against each other
    ...           in Basketball
    ...         </rdfs:comment>
    ...     </owl:Class>
    ... 
    ... </rdf:RDF>'''
    >>> my_namespaces = dict([
    ...     node for _, node in ElementTree.iterparse(
    ...         StringIO(my_schema), events=['start-ns']
    ...     )
    ... ])
    >>> from pprint import pprint
    >>> pprint(my_namespaces)
    {'': 'http://dbpedia.org/ontology/',
     'owl': 'http://www.w3.org/2002/07/owl#',
     'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
     'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
     'xsd': 'http://www.w3.org/2001/XMLSchema#'}
    

    然后字典可以作为参数传递给搜索函数:

    root.findall('owl:Class', my_namespaces)
    
  • 17

    我一直在使用类似的代码,并发现它总是值得阅读文档...像往常一样!

    findall()只会找到 direct children of the current tag 的元素 . 所以,不是全部 .

    尝试使用以下代码来处理代码时可能是值得的,特别是如果您正在处理大而复杂的xml文件,以便还包括该子子元素(等) . 如果你知道自己的xml元素在哪里,那么我想它会没事的!只是觉得这值得记住 .

    root.iter()
    

    ref:https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall() finds only elements with a tag which are direct children of the current element. Element.find() finds the first child with a particular tag, and Element.text accesses the element’s text content. Element.get() accesses the element’s attributes:"

  • 46

    我知道我迟了几年,但我刚刚创建了一个包,用于处理将字典转换为带有命名空间的有效XML . 该软件包托管在PyPi @ https://pypi.python.org/pypi/xmler上 .

    使用此包,您可以使用如下所示的字典:

    myDict = {
        "RootTag": {                        # The root tag. Will not necessarily be root. (see #customRoot)
            "@ns": "soapenv",           # The namespace for the RootTag. The RootTag will appear as <soapenv:RootTag ...>
            "@attrs": {                     # @attrs takes a dictionary. each key-value pair will become an attribute
                { "xmlns:soapenv": "http://schemas.xmlsoap.org/soap/envelope/" }
            },
            "childTag": {
                "@attrs": {
                    "someAttribute": "colors are nice"
                },
                "grandchild": "This is a text tag"
            }
        }
    }
    

    并获得如下所示的XML输出:

    <soapenv:RootTag xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <childTag someAttribute="colors are nice">
            <grandchild>This is a text tag</grandchild>
        </childTag>
    </soapenv:RootTag>
    

    希望这对未来的人们有用

  • 1

    以命名空间格式获取命名空间,例如 {myNameSpace} ,您可以执行以下操作:

    root = tree.getroot()
    ns = re.match(r'{.*}', root.tag).group(0)
    

    这样,您可以稍后在代码中使用它来查找节点,例如使用字符串插值(Python 3) .

    link = root.find(f'{ns}link')
    

相关问题