Python API XML 解析 - 命名空间

Python API XML parsing - Namespaces

我正在使用 Python 解析通过 API 从我的 Tableau 服务器返回的一些 XML。涉及命名空间,我想我可能对它们的工作原理缺乏一些基本的了解。这是我的 XML 的样子:

<tsResponse version-and-namespace-settings>
  <parent type="Project" id="1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e" />
  <permissions>
    <workbook id="1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d" name="Finance">
      <owner id="9f9e9d9c-8b8a-8f8e-7d7c-7b7a6f6d6e6d"/>
    </workbook>
    <granteeCapabilities>
      <group id="1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d"/>
      <capabilities>
        <capability name="Read" mode="Allow"/>
        <capability name="Filter" mode="Allow"/>
        <capability name="ViewUnderlyingData" mode="Allow"/>
        <capability name="ExportImage" mode="Allow"/>
        <capability name="ExportData" mode="Allow"/>
        <capability name="AddComment" mode="Allow"/>
        <capability name="ViewComments" mode="Allow"/>
        <capability name="ShareView" mode="Allow"/>
      </capabilities>
    </granteeCapabilities>
  </permissions>
</tsResponse>

这是我 运行 的代码,已简化到出现问题的位置。我的目标是初步识别给定工作簿 ID 下的每个组 ID,然后找到该组下的每个功能。

xmlns = {'t': 'http://tableau.com/api'}
test_response1 = []
test_response2 = []

url = "tableau.my.org/api/2.4/sites/siteid/workbooks/workbookid/permissions?pageSize=1000".format()
server_response_WB2 = requests.get(url, headers={'x-tableau-auth': auth_token})
test_response1.append(server_response_WB2.text)
server_response_WB2 = ET.fromstring(_encode_for_display(server_response_WB2.text))
permissions = server_response_WB2.findall('.//t:permissions', namespaces=xmlns)

for permission in permissions:
    capabilities = permission.findall('granteeCapabilities')
    test_response2.append(capabilities)

print test_response1
print test_response2

test_response1 包含如下列表:

[[<Element '{http://tableau.com/api}permissions' at 0x3c07d70>], 
[<Element '{http://tableau.com/api}permissions' at 0x3bb8dd0>]]

test_response2 但是,returns 一个空列表列表:

[[], [], []]

在上面的代码中,我正在寻找 'granteeCapabilities' 作为标记。我也试过使用命名空间将其作为路径查找,如下所示:

capabilities = permission.findall('.//t:permissions/granteeCapabilities', namespaces=xmlns)

这returns相同的结果。空列表的列表。为什么我能在权限下找到数据,但在较低级别却找不到?

如果问题可能与 XML 命名空间有关,那么您真的不应该在问题中省略 XML 的命名空间部分,因为它是诊断问题和解决问题的基础编写工作解决方案。

我怀疑命名空间 http://tableau.com/api 在 XML 中被声明为默认命名空间(没有前缀的那个),在这种情况下,所有没有前缀的后代元素都隐式地从祖先继承相同的命名空间.这可以解释为什么 granteeCapabilities 对你不起作用,你也应该尝试在此处添加前缀 t :

capabilities = permission.findall('t:granteeCapabilities', namespaces=xmlns)

如果不需要permissions元素的任何信息,可以直接获取granteeCapabilities:

capabilities = root.findall('.//t:granteeCapabilities', namespaces=xmlns)

这是一个简短但完整的示例,演示了解决方案:

raw = '''<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="w3.org/2001/XMLSchema-instance" xsi:schemaLocation="tableau/com/api tableau.com/api/ts-api-2.4.xsd">
  <parent type="Project" id="1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e" />
  <permissions>
    <granteeCapabilities>
      <group id="1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d"/>
      <capabilities>
        ....
      </capabilities>
    </granteeCapabilities>
  </permissions>
</tsResponse>'''

from xml.etree import ElementTree as ET
root = ET.fromstring(raw)
xmlns = {'t': 'http://tableau.com/api'}
permissions = root.findall('.//t:permissions', namespaces=xmlns)
for permission in permissions:
    capabilities = permission.findall('t:granteeCapabilities', namespaces=xmlns)
    print capabilities

eval.in demo

输出:

[<Element '{http://tableau.com/api}granteeCapabilities' at 0x402f430c>]