2010-02-11 8 views
1

Cela peut être une question de débutant :) mais cela m'énerve depuis que je suis nouveau à XML. Je le fichier XML suivant:obtenir des attributs de nœuds xml spécifiques

<assetsMain> 
    <assetParent type='character' shortName='char'> 
    <asset> 
     pub 
    </asset> 
    <asset> 
     car 
    </asset> 
    </assetParent> 
    <assetParent type='par' shortName='pr'> 
    <asset> 
     camera 
    </asset> 
    <asset> 
     rig 
    </asset> 
    </assetParent> 
</assetsMain> 

Est-il possible de récupérer tous les nœuds <assetParent> et tous leurs attributs et textes enfants? Par exemple, pour avoir le résultat comme suit:

[ [['character','char'],['pub','car']] 
    [['par','pr'],['camera','rig']] 
] 

Soit dit en passant, j'utiliser DOM et Python 2.6

Merci à l'avance.

+0

je ne voudrais pas vous battre à ce sujet. XML ne correspond pas bien aux types de données de programmation courants. Le traitement peut être une douleur complète. Et XPATH, une méthode utile et puissante pour accéder aux données XML peut être difficile à maîtriser. J'ai eu du mal à trouver des exemples utiles. – MattH

Répondre

3

Une réponse utilisant lxml.etree. XPath serait probablement réutilisable dans une autre bibliothèque capable:

>>> from lxml import etree 
>>> data = """<assetsMain> 
... <assetParent type='character' shortName='char'> 
... <asset>pub</asset> 
... <asset>car</asset> 
... </assetParent> 
... <assetParent type='par' shortName='pr'> 
... <asset>camera</asset> 
... <asset>rig</asset> 
... </assetParent> 
... </assetsMain> 
... """ 
>>> doc = etree.XML(data) 
>>> for aP in doc.xpath('//assetParent'): 
... parent = aP.attrib['type'] 
... for a in aP.xpath('./asset/text()'): 
...  print parent, a.strip() 
... 
character pub 
character car 
par camera 
par rig 
0

Ce code donne la sortie que vous voulez:

from xml.dom.minidom import parseString 

document = """\ 
<assetsMain> 
    <assetParent type='character' shortName='char'> 
    <asset> 
     pub 
    </asset> 
    <asset> 
     car 
    </asset> 
    </assetParent> 
    <assetParent type='par' shortName='pr'> 
    <asset> 
     camera 
    </asset> 
    <asset> 
     rig 
    </asset> 
    </assetParent> 
</assetsMain> 
""" 

def getNestedList(): 
    dom = parseString(document) 
    li = [] 
    for assetParent in dom.childNodes[0].getElementsByTagName("assetParent"): 
     # read type and shortName 
     a = [assetParent.getAttribute("type"), assetParent.getAttribute("shortName")] 
     # read content of asset nodes 
     b = [asset.childNodes[0].data.strip() for asset in assetParent.getElementsByTagName("asset")] 
     # put the lists together in a list and add them to the list (!) 
     li.append([a,b]) 
    return li 

if __name__=="__main__": 
    print getNestedList() 

Notez que nous pouvons sélectionner les nœuds enfants que nous voulons lire avec getElementsByTagName. Les attributs sont lus avec getAttribute sur un nœud. Le contenu du texte à l'intérieur d'un nœud est lu à travers la propriété data (le texte lui-même est également un nœud enfant). Si vous lisez texte à l'intérieur d'un nœud, vous pouvez vérifier afin qu'il soit vraiment texte:

if node.nodeType == node.TEXT_NODE: 

Notez également qu'il n'y a pas de vérification ou d'une erreur de manipulation ici. Les noeuds manquant de noeuds enfant lèveront un IndexError.

Bien que, une liste imbriquée de trois niveaux me donne envie de vous suggérer d'utiliser des dictionnaires à la place.

Sortie:

[[[u'character', u'char'], [u'pub', u'car']], [[u'par', u'pr'], [u'camera', u'rig']]] 
Questions connexes