使用命名空间的Python ElementTree find()

时间:2019-04-30 12:55:31

标签: python xpath elementtree

我正在尝试使用Python的ElementTree来解析和修改xml文件。 XML命名空间带来了混乱。我可以使用findall和finditer来获取所有服务器名称。但是,我无法使xpath查询工作来查找特定的服务器。取而代之的是,查找只是带回父元素。

我需要做的是通过“名称”或“机器”元素找到正确的服务器,然后修改“参数”。

<? xml version=’1.0’ encoding=’UTF-8’?>
<domain xmlns=”http://xmlns.oracle.com.weblogic/domain”>
  <server>
    <name>Server1-rma</name>
    <machine>server1</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server2-rma</name>
    <machine>server2</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server3-rma</name>
    <machine>server3</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
</domain>

我尝试了查询的各种迭代。但是,我是XPath的新手,一定做错了事:

失败: root + “ns0:server/[ns0:machine=’server2’]

失败: root + “ns0:server/ns0:[machine=’server2’]

失败: root + “ns0:server/[ns0:machine=ns0:’server2’]

示例代码:

import xml.etree.ElementTree as ET
namespace = {‘ns0’: ‘ http://xmlns.oracle.com.weblogic/domain’}

tree = ET.parse(‘config.xml’)
root = tree.getroot()
for item in root.find((root + “ns0:server/[ns0:machine=’server2’]), namespace)
    print(item.tag)


output:
{http://xmlns.oracle.com.weblogic/domain}server

我希望能够匹配“ machine”元素并拉出父元素,以便访问正确的“ arguments”元素。

我是xpath和elementtree的初学者,所以我很肯定自己只是在做一些错误的事情。我只是不确定。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

像亚历杭德罗(Alejandro)在评论ElementTree has limited support for XPath中提到的那样。对于您要执行的操作来说,这并不重要。如果需要全面的XPath 1.0支持,请consider lxml

但是,它也有其他一些怪癖。其中之一就是它将自己的名称空间前缀添加到默认名称空间。要保留默认名称空间,您必须向register_namespace()注册它。

Alejandro还正确地选择了用于选择服务器的正确XPath:

ET.parse()

但是,当您使用getroot()构建树或使用ns0:domain获取根时,上下文已经为./ns0:server[ns0:machine='server2'] ,因此该上下文中的XPath实际上是:

arguments

由于您要更新服务器的./ns0:server[ns0:machine='server2']/ns0:server-start/ns0:arguments ,因此我们也可以将其添加到XPath:

wl

See here有关XPath位置路径的更多信息。

这是一个完整的例子。 (我使用的是前缀ns0而不是<?xml version='1.0' encoding='UTF-8'?> <domain xmlns="http://xmlns.oracle.com.weblogic/domain"> <server> <name>Server1-rma</name> <machine>server1</machine> <server-start> <arguments> -Xms4g</arguments> </server-start> </server> <server> <name>Server2-rma</name> <machine>server2</machine> <server-start> <arguments> -Xms4g</arguments> </server-start> </server> <server> <name>Server3-rma</name> <machine>server3</machine> <server-start> <arguments> -Xms4g</arguments> </server-start> </server> </domain> ,只是为了表明前缀在rules for namespace前缀之后并没有关系。)

XML输入(test.xml;固定引号和XML声明,因此为well-formed

import xml.etree.ElementTree as ET

tree = ET.parse("test.xml")

ns = {"wl": "http://xmlns.oracle.com.weblogic/domain"}

ET.register_namespace("", ns["wl"])

try:
    tree.find("./wl:server[wl:machine='server2']/wl:server-start/wl:arguments", namespaces=ns).text = "BAM!!!"
except AttributeError:
    print("Unable to find the correct server element.")

tree.write("output.xml", xml_declaration=True, encoding="UTF-8")

Python

<?xml version='1.0' encoding='UTF-8'?>
<domain xmlns="http://xmlns.oracle.com.weblogic/domain">
  <server>
    <name>Server1-rma</name>
    <machine>server1</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server2-rma</name>
    <machine>server2</machine>
    <server-start>
      <arguments>BAM!!!</arguments>
    </server-start>
  </server>
  <server>
    <name>Server3-rma</name>
    <machine>server3</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
</domain>

XML输出(output.xml)

Failure/Error: response = Facebook.oauth_for_app(provider).exchange_access_token_info(token)

     Koala::Facebook::OAuthTokenRequestError:
       type: OAuthException, code: 190, message: Invalid OAuth access token. [HTTP 400]