我正在尝试使用python解析maven项目定义来提取版本。
项目定义如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>1.6.0-SNAPSHOT</version>
...
</project>
我可以使用以下方法提取版本:
root = ET.fromstring(xml)
version = root.find('./p:version', { 'p': 'http://maven.apache.org/POM/4.0.0' })
print(version.text)
prints: 1.6.0-SNAPSHOT
但是,使用的命名空间可能会更改,我不想依赖于此。有没有办法提取在我后续的xpath表达式中使用的命名空间?
我尝试了以下内容,看看xmlns本身是否暴露,但没有运气:
root = ET.fromstring(xml)
for k in root.attrib:
print('%s => %s' % (k, root.attrib[k]))
prints: {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
答案 0 :(得分:2)
不幸的是,ElementTree
命名空间支持相当不完整。
您需要使用xml.etree.ElementTree
模块中的内部方法来获取命名空间映射:
_, namespaces = ET._namespaces(root, 'utf8')
namespaces
现在是一个dict,URI为键,前缀为值。
您可以改用lxml
。该库实现了相同的ElementTree API,但却大大增强了该API。
例如,每个节点都包含.nsmap
属性,该属性将前缀映射到URI,包括密钥None
下的默认命名空间。
答案 1 :(得分:2)
但是,使用的命名空间可能会改变,我不想依赖它。
您是说名称空间uri可能会更改,还是前缀可能会更改?如果它只是前缀,那么这不是问题,因为重要的是XPath中的前缀与您提供给XPath求值程序的前缀相匹配。在任何一种情况下,自动检测命名空间可能都是一个糟糕的调用。假设有人决定开始生成这样的XML:
<proj:project xmlns:proj="http://maven.apache.org/POM/4.0.0"
xmlns:other="http://maven.apache.org/POM/5.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">
仍然完全代表与您的示例相同的命名空间中的XML,但您不知道proj
前缀是您正在寻找的命名空间前缀。
我认为Apache不太可能突然改变其官方XML格式之一的命名空间,但如果你真的担心它,应该总是选择使用local-name()来命名空间 - 无法找到一个你正在寻找的节点:
version = root.find('./*[local-name() = "version"]')
另外,我不熟悉elementTree库,但你可以尝试这个尝试获取有关XML文档命名空间的信息,只是为了看看你是否可以:
namespaces = root.findall('//namespace::*')