【问题标题】:Reading Maven Pom xml in Python在 Python 中读取 Maven Pom xml
【发布时间】:2013-05-24 01:19:01
【问题描述】:

我有一个 pom 文件,其中定义了以下内容:

<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>org.welsh</groupId>
<artifactId>my-site</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<profiles>
    <profile>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.welsh.utils</groupId>
                    <artifactId>site-tool</artifactId>
                    <version>1.0</version>
                    <executions>
                        <execution>
                            <configuration>
                                <mappings>
                                    <property>
                                        <name>homepage</name>
                                        <value>/content/homepage</value>
                                    </property>
                                    <property>
                                        <name>assets</name>
                                        <value>/content/assets</value>
                                    </property>
                                </mappings>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
</project>

我希望在propertymappings 元素下的namevalue 元素上构建一个字典。

所以我想弄清楚如何获取所有可能的mappings 元素(如果有多个构建配置文件),这样我就可以获取它下面的所有property 元素,并阅读有关Supported XPath syntax 的内容,以下应该打印排除所有可能的文本/值元素:

import xml.etree.ElementTree as xml

pomFile = xml.parse('pom.xml')
root = pomFile.getroot()

for mapping in root.findall('*/mappings'):
    for prop in mapping.findall('.//property'):
        logging.info(prop.find('name').text + " => " + prop.find('value').text)

什么都不返回。我试着打印出所有 mappings 元素并得到:

>>> print root.findall('*/mappings')
[]

当我打印出 root 的所有内容时,我得到:

>>> print root.findall('*')
[<Element '{http://maven.apache.org/POM/4.0.0}modelVersion' at 0x10b38bd50>, <Element '{http://maven.apache.org/POM/4.0.0}groupId' at 0x10b38bd90>, <Element '{http://maven.apache.org/POM/4.0.0}artifactId' at 0x10b38bf10>, <Element '{http://maven.apache.org/POM/4.0.0}version' at 0x10b3900d0>, <Element '{http://maven.apache.org/POM/4.0.0}packaging' at 0x10b390110>, <Element '{http://maven.apache.org/POM/4.0.0}name' at 0x10b390150>, <Element '{http://maven.apache.org/POM/4.0.0}properties' at 0x10b390190>, <Element '{http://maven.apache.org/POM/4.0.0}build' at 0x10b390310>, <Element '{http://maven.apache.org/POM/4.0.0}profiles' at 0x10b390390>]

这让我尝试打印:

>>> print root.findall('*/{http://maven.apache.org/POM/4.0.0}mappings')
[]

但这也不行。

任何建议都会很棒。

谢谢,

【问题讨论】:

标签: python xml python-2.7 xml-parsing


【解决方案1】:

题中代码的主要问题是

  • 它没有指定命名空间,并且
  • 它使用*/ 而不是//,后者仅匹配直接子代。

正如您在 XML 文件顶部看到的那样,Maven 使用命名空间 http://maven.apache.org/POM/4.0.0。根节点中的属性xmlns 定义了默认命名空间。属性xmlns:xsi 定义了一个仅用于xsi:schemaLocation 的命名空间。

<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">

要在find 之类的方法中指定profile 之类的标签,您还必须指定命名空间。例如,您可以编写以下代码来查找所有 profile-tags。

import xml.etree as xml

pom = xml.parse('pom.xml')
for profile in pom.findall('//{http://maven.apache.org/POM/4.0.0}profile'):
    print(repr(profile))

另请注意,我使用的是//。对于上面的特定 xml 文件,使用 */ 会产生相同的结果。但是,它适用于 mappings 等其他标签。由于* 只代表一个级别,所以*/child 可以扩展为parent/tagxyz/tag,但不能扩展为xyz/parent/tag


现在,您应该能够想出类似的方法来查找所有映射:

pom = xml.parse('pom.xml')
map = {}
for mapping in pom.findall('//{http://maven.apache.org/POM/4.0.0}mappings'
                           '/{http://maven.apache.org/POM/4.0.0}property'):
    name  = mapping.find('{http://maven.apache.org/POM/4.0.0}name').text
    value = mapping.find('{http://maven.apache.org/POM/4.0.0}value').text
    map[name] = value

像这样指定命名空间非常冗长。为了便于阅读,您可以定义命名空间映射并将其作为第二个参数传递给findfindall

# ...
nsmap = {'m': 'http://maven.apache.org/POM/4.0.0'}
for mapping in pom.findall('//m:mappings/m:property', nsmap):
    name  = mapping.find('m:name', nsmap).text
    value = mapping.find('m:value', nsmap).text
    map[name] = value

【讨论】:

    【解决方案2】:

    好的,发现当我从 project 元素中删除 maven 内容时,它只是 &lt;project&gt; 我可以这样做:

    for mapping in root.findall('*//mappings'):
        logging.info(mapping)
        for prop in mapping.findall('./property'):
            logging.info(prop.find('name').text + " => " + prop.find('value').text)
    

    这会导致:

    INFO:root:<Element 'mappings' at 0x10d72d350>
    INFO:root:homepage => /content/homepage
    INFO:root:assets => /content/assets
    

    但是,如果我将 Maven 内容留在顶部,我可以这样做:

    for mapping in root.findall('*//{http://maven.apache.org/POM/4.0.0}mappings'):
        logging.info(mapping)
        for prop in mapping.findall('./{http://maven.apache.org/POM/4.0.0}property'):
            logging.info(prop.find('{http://maven.apache.org/POM/4.0.0}name').text + " => " + prop.find('{http://maven.apache.org/POM/4.0.0}value').text)
    

    结果:

    INFO:root:<Element '{http://maven.apache.org/POM/4.0.0}mappings' at 0x10aa7f310>
    INFO:root:homepage => /content/homepage
    INFO:root:assets => /content/assets
    

    但是,我希望能够弄清楚如何避免考虑 maven 的东西,因为它将我锁定在这种格式中。

    编辑:

    好的,我设法得到了一些更详细的东西:

    import xml.etree.ElementTree as xml
    
    def getMappingsNode(node, nodeName):
        if node.findall('*'):
            for n in node.findall('*'):
                if nodeName in n.tag:
                    return n
            else:
                return getMappingsNode(n, nodeName)
    
    def getMappings(rootNode):
        mappingsNode = getMappingsNode(rootNode, 'mappings')
        mapping = {}
    
        for prop in mappingsNode.findall('*'):
            key = ''
            val = ''
    
            for child in prop.findall('*'):
                if 'name' in child.tag:
                    key = child.text
    
                if 'value' in child.tag:
                    val = child.text
    
            if val and key:
                mapping[key] = val
    
        return mapping
    
    pomFile = xml.parse('pom.xml')
    root = pomFile.getroot()
    
    mappings = getMappings(root)
    print mappings
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-31
      • 2013-01-21
      • 2017-10-28
      • 2019-08-07
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多