2013-05-28 15 views
8

Ho un file pom che ha il seguente definito:lettura Maven Pom XML in 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> 

e sto cercando di costruire un dizionario largo delle name & value elementi sotto property sotto l'elemento mappings.

Quindi quello che sto cercando di capire come ottenere tutti i possibili elementi mappings (Incase di più profili di compilazione) in modo da poter ottenere tutti gli elementi property sotto di essa e da leggere su Supported XPath syntax il seguente dovrebbe stampare tutto il testo possibili/elementi di valore:

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) 

Che non restituisce nulla. Ho provato solo la stampa di tutte le mappings elementi e ottenere:

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

E quando stampo il tutto da root ottengo:

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

che mi ha fatto provare a stampare:

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

Ma anche questo non funziona.

Qualsiasi suggerimento sarebbe ottimo.

Grazie,

+0

ho trovato questa sostanza che lavora per me e lo rende un po 'meno prolissa: https://gist.github.com/kennedyj/1895332 – borism

risposta

4

Ok, scoperto che quando rimuovo roba Maven dall'elemento project così il suo solo <project> posso fare questo:

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) 

che si tradurrebbe in:

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

Tuttavia, se lascio la roba di Maven in alto posso fare questo:

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) 

che si traduce in:

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

Tuttavia, mi piacerebbe essere in grado di capire come evitare di dover spiegare la roba Maven perché mi blocca in questo formato.

EDIT:

Ok, sono riuscito ad ottenere qualcosa di un po 'più dettagliato:

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

ho modificato un pom.xml con pitone. Sembra che etree non sia documentato molto bene. Ci è voluto un po 'per portare tutto a lavoro, ma sembra funzionare ora.


Come si può vedere nel seguente frammento, Maven utilizza lo spazio dei nomi http://maven.apache.org/POM/4.0.0. L'attributo xmlns nel nodo radice definisce lo spazio dei nomi predefinito.L'attributo xmlns:xsi definisce anche uno spazio dei nomi, ma viene utilizzato solo per 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"> 

Per utilizzare i tag come profile nei metodi come find, è necessario specificare lo spazio dei nomi pure. Ad esempio, è possibile scrivere quanto segue per trovare tutti i tag profile.

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

Un'altra cosa importante è // qui. Utilizzando il file xml aboive, */ avrebbe lo stesso risultato per questo esempio. Ma sarebbe non lavoro per altri tag come mappings. Poiché * rappresenta un solo livello, */child può essere esteso a parent/tag o xyz/tag ma non a xyz/parent/tag.


I cosa questo sono i problemi principali nel codice sopra. Devi utilizzare // di */ per consentire qualsiasi sottoelemento invece di solo bambini diretti. E devi specificare lo spazio dei nomi. Usando questo, si dovrebbe essere in grado di fare qualcosa di simile per trovare tutte le mappature:

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 

Ma specificando gli spazi dei nomi, come sopra non è molto bello. È possibile definire una mappa dello spazio dei nomi e dare come secondo argomento al find e findall:

# ... 
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 
Problemi correlati