2013-05-28 32 views
8

Tôi có một tập tin pom mà có định nghĩa sau đây:Reading Maven Pom xml bằng Python

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

Và tôi đang tìm kiếm để xây dựng một từ điển ra khỏi name & value yếu tố dưới property dưới các yếu tố mappings. Vì vậy, những gì tôi đang cố gắng tìm hiểu làm thế nào để có được tất cả các yếu tố có thể mappings (Incase của nhiều cấu hình xây dựng) để tôi có thể nhận được tất cả các yếu tố property và đọc từ Supported XPath syntax sau đây sẽ in ra tất cả các văn bản có thể/các yếu tố giá trị:

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) 

Không trả lại giá trị nào. Tôi đã cố gắng chỉ cần in ra tất cả các mappings yếu tố và nhận được:

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

Và khi tôi in ra tất cả mọi thứ từ root tôi nhận được:

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

Mà làm cho tôi cố gắng in:

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

Nhưng điều đó cũng không hiệu quả.

Mọi đề xuất sẽ tuyệt vời.

Cảm ơn,

+0

tôi thấy ý chính này mà làm việc cho tôi và làm cho nó một chút ít tiết: https://gist.github.com/kennedyj/1895332 – borism

Trả lời

4

Ok, phát hiện ra rằng khi tôi loại bỏ những thứ maven từ các yếu tố project nên nó chỉ <project> tôi có thể làm điều này:

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) 

nào sẽ cho kết quả:

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

Tuy nhiên, nếu tôi để lại nội dung của Maven ở trên cùng, tôi có thể thực hiện việc này:

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) 

mà kết quả trong:

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

Tuy nhiên, tôi rất muốn để có thể tìm ra cách để tránh phải giải thích cho những thứ maven vì nó khóa tôi vào một định dạng này.

EDIT:

Ok, tôi quản lý để có được một cái gì đó một chút dài dòng hơn:

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 
1

tôi sửa đổi một pom.xml với trăn. Có vẻ như etree không được ghi lại rất tốt. Phải mất một thời gian để mang lại cho tất cả mọi thứ để làm việc nhưng nó có vẻ làm việc ngay bây giờ.


Như bạn có thể thấy trong đoạn mã sau, Maven sử dụng namespace http://maven.apache.org/POM/4.0.0. Thuộc tính xmlns trong nút gốc xác định không gian tên mặc định.Thuộc tính xmlns:xsi cũng xác định một không gian tên, nhưng nó chỉ được sử dụng cho 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"> 

Để sử dụng thẻ như profile trong các phương pháp như find, bạn phải xác định không gian tên là tốt. Ví dụ: bạn có thể viết thông tin sau để tìm tất cả 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)) 

Điều nhập khác là // tại đây. Sử dụng tệp xml của bạn aboive, */ sẽ có cùng kết quả cho ví dụ này. Nhưng nó sẽ không hoạt động cho các thẻ khác như mappings. Vì * chỉ đại diện cho một cấp, */child có thể được mở rộng thành parent/tag hoặc xyz/tag nhưng không thể hiển thị với xyz/parent/tag.


Tôi nghĩ đây là những vấn đề chính trong mã của bạn ở trên. Bạn phải sử dụng // được insted của */ để cho phép bất kỳ phần tử con nào thay vì chỉ trẻ em trực tiếp. Và bạn phải chỉ định không gian tên. Sử dụng này, bạn sẽ có thể làm điều gì đó như thế này để tìm tất cả các ánh xạ:

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 

Nhưng xác định không gian tên như trên không phải là rất tốt đẹp. Bạn có thể xác định một bản đồ không gian tên và cung cấp cho nó như là đối số thứ hai để 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 
Các vấn đề liên quan