簡體   English   中英

Python:ElementTree,獲取一個元素的命名空間字符串

[英]Python: ElementTree, get the namespace string of an Element

此 XML 文件名為example.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>14.0.0</modelVersion>
  <groupId>.com.foobar.flubber</groupId>
  <artifactId>uberportalconf</artifactId>
  <version>13-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>Environment for UberPortalConf</name>
  <description>This is the description</description>    
  <properties>
      <birduberportal.version>11</birduberportal.version>
      <promotiondevice.version>9</promotiondevice.version>
      <foobarportal.version>6</foobarportal.version>
      <eventuberdevice.version>2</eventuberdevice.version>
  </properties>
  <!-- A lot more here, but as it is irrelevant for the problem I have removed it -->
</project>

如果我加載 example.xml 並使用 ElementTree 解析它,我可以看到它的命名空間是http://maven.apache.org/POM/4.0.0

>>> from xml.etree import ElementTree
>>> tree = ElementTree.parse('example.xml')
>>> print tree.getroot()
<Element '{http://maven.apache.org/POM/4.0.0}project' at 0x26ee0f0>

我還沒有找到一種方法來調用只從Element獲取命名空間而不求助於解析Elementstr(an_element) 似乎必須有更好的方法。

命名空間應該在“實際”標簽之前的Element.tag

>>> root = tree.getroot()
>>> root.tag
'{http://maven.apache.org/POM/4.0.0}project'

要了解有關命名空間的更多信息,請查看ElementTree:使用命名空間和限定名稱

這是正則表達式的完美任務。

import re

def namespace(element):
    m = re.match(r'\{.*\}', element.tag)
    return m.group(0) if m else ''

我不確定這是否可以用xml.etree ,但這里是你如何用lxml.etree做到這lxml.etree

>>> from lxml import etree
>>> tree = etree.parse('example.xml')
>>> tree.xpath('namespace-uri(.)')
'http://maven.apache.org/POM/4.0.0'

不使用正則表達式:

>>> root
<Element '{http://www.google.com/schemas/sitemap/0.84}urlset' at 0x2f7cc10>

>>> root.tag.split('}')[0].strip('{')
'http://www.google.com/schemas/sitemap/0.84'

lxml.xtree庫的元素有一個名為nsmap的字典,它顯示了當前標記范圍內使用的所有命名空間。

>>> item = tree.getroot().iter().next()
>>> item.nsmap
{'md': 'urn:oasis:names:tc:SAML:2.0:metadata'}

簡短的回答是:

ElementTree._namspace_map[ElementTree._namspace_map.values().index('')]

但前提是你一直在打電話

ElementTree.register_namespace(prefix,uri)

響應在迭代結果時收到的每個事件==“start-ns”

ET.iterparse(...) 

你注冊了“start-ns”

回答“什么是默認命名空間?”的問題,有必要澄清兩點:

(1) XML 規范說默認命名空間不一定在整個樹中是全局的,而是可以在根下的任何元素重新聲明默認命名空間,並向下繼承,直到遇到另一個默認命名空間重新聲明。

(2) ElementTree 模塊可以(事實上)處理沒有根默認名稱空間的類 XML 文檔,如果它們在文檔中的任何地方都沒有名稱空間使用。 (* 可能有不那么嚴格的條件,例如,“if”而不一定是“iff”)。

可能也值得考慮“你想要它做什么?” 考慮到 XML 文件在語義上可以是等效的,但在語法上卻非常不同。 例如,以下三個文件在語義上是等價的,但 A.xml 有一個默認命名空間聲明,B.xml 有三個,而 C.xml 沒有。

A.xml:
<a xlmns="http://A" xlmns:nsB0="http://B0" xlmns:nsB1="http://B1">
     <nsB0:b/>
     <nsB1:b/>
</a>

B.xml:
<a xlmns="http://A">
     <b xlmns="http://B0"/>
     <b xlmns="http://B1"/>
</a>

C.xml:
<{http://A}a>
     <{http://B0}b/>
     <{http://B1}b/>
</a>

文件 C.xml 是呈現給 ElementTree 搜索功能的規范擴展句法表示。

如果您事先確定不會有命名空間沖突,則可以在解析時修改元素標簽,如下所述: Python ElementTree 模塊:如何在使用“查找”方法時忽略 XML 文件的命名空間以定位匹配元素, “找到所有”

我認為查看屬性會更容易:

>>> root.attrib
{'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation':
   'http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'}

結合上面的一些答案,我認為最短的代碼是

theroot = tree.getroot()
theroot.attrib[theroot.keys()[0]]

這是我在 ElementTree 3.9+ 上的解決方案,

def get_element_namespaces(filename, element):
    namespace = []
    for key, value in ET.iterparse(filename, events=['start', 'start-ns']):
        print(key, value)
        if key == 'start-ns':
            namespace.append(value)
        else:
            if ET.tostring(element) == ET.tostring(value):
                return namespace
            namespace = []
    return namespaces

這將返回一個 [prefix:URL] 元組數組,如下所示:

[('android', 'http://schemas.android.com/apk/res/android'), ('tools', 'http://schemas.android.com/tools')]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM