2013-05-28 9 views
8

Mam plik pom że ma następującą definicją:Reading Maven Pom XML w Pythonie

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

i szukam zbudować słownika wyłączyć name & value elementów pod property pod elementem mappings.

Więc co usiłuję dowiedzieć się, jak uzyskać wszystkie możliwe mappings elementy (Incase wielu profili Build), więc można uzyskać wszystkie elementy property pod nim i od czytania o Supported XPath syntax następujące powinien wypisać wszystkie możliwe tekst/elementy wartości:

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) 

Który niczego nie zwraca. Próbowałem po prostu drukowania wszystkie mappings elementy, a otrzymasz:

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

I kiedy wydrukować wszystko od root uzyskać:

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

co sprawiło mi spróbować druku:

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

Ale to też nie działa.

Wszelkie sugestie byłyby świetne.

Dzięki,

+0

Znalazłem to sens, który pracuje dla mnie i sprawia, że ​​nieco mniej gadatliwy: https://gist.github.com/kennedyj/1895332 – borism

Odpowiedz

4

Ok, okazało się, że kiedy usunąć maven rzeczy od elementu project więc jej tylko <project> mogę to zrobić:

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) 

Które spowodowałoby:

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

Jeśli jednak zostawię rzeczy Mavena na górze, mogę to zrobić:

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) 

co skutkuje:

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

Jednak chciałbym, aby móc dowiedzieć się, jak uniknąć konieczności uwzględnienia rzeczy maven ponieważ blokuje mnie w tym jednym formacie.

EDIT:

Ok, udało mi się dostać coś nieco bardziej opisowy:

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

I zmodyfikowana pom.xml z pytona. Wydaje się, że nie jest dobrze udokumentowany. Minęło trochę czasu, zanim wszystko zaczęło działać, ale teraz wydaje się działać.


Jak widać w poniższym fragmencie, Maven używa nazw http://maven.apache.org/POM/4.0.0. Atrybut xmlns w węźle głównym definiuje domyślny obszar nazw.Atrybut xmlns:xsi definiuje również przestrzeń nazw, ale jest używana tylko dla 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"> 

Aby używać znaczników takich jak profile metod jak find, trzeba podać nazw, jak również. Na przykład możesz napisać poniższe, aby znaleźć wszystkie -tagi.

Inną ważną rzeczą jest // tutaj. Jeśli użyjesz pliku xml, */ będzie miał taki sam wynik dla tego przykładu. Ale byłoby nie pracować dla innych tagów, takich jak mappings. Ponieważ * reprezentuje tylko jeden poziom, */child może zostać rozszerzony do parent/tag lub xyz/tag, ale nie do xyz/parent/tag.


To są główne problemy w powyższym kodzie. Musisz użyć // insted z */, aby zezwolić na dowolne podelementy zamiast bezpośrednich tylko dla dzieci. I musisz określić przestrzeń nazw. Korzystanie z tym, należy być w stanie zrobić coś takiego, aby znaleźć wszystkie mapowania:

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 

Ale wyszczególnieniem nazw jak powyżej nie jest bardzo miłe. Można zdefiniować mapę przestrzeni nazw i dać go jako drugi argument do find i 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 
Powiązane problemy