Je travaille avec xml.etree pour analyser quelques énormes fichiers XML que je dois importer dans une base de données avec Python, mais pour une raison quelconque, je ne peux pas comprendre comment extraire une balise spécifique en fonction d'un attribut d'un autre étiquette

Par exemple, dans ce morceau de XML inclus ci-dessous, j'ai besoin d'extraire le texte des balises qui se trouvent sous les balises NicamWarningCS et de les mettre toutes les deux dans une seule liste. Des suggestions sur la façon d'y parvenir?

<Main xmlns:mpeg7="urn:mpeg:mpeg7:schema:2001" xmlns="urn:tva:metadata:2004">
  <ProgramDescription>
    <ProgramInformationTable>
      <ProgramInformation programId="123456">
        <BasicDescription>
           <Genre href="urn:tva:metadata:cs:2004:2.4">
             <Name xml:lang="NL"><![CDATA[Film]]></Name>
           </Genre>
           <Genre href="urn:po:metadata:cs:GenreCS:2009:4" type="other">
             <Name xml:lang="NL"><![CDATA[Film]]></Name>
           </Genre>
           <Genre href="urn:po:metadata:cs:NicamWarningCS:2007:t">
             <Name xml:lang="NL"><![CDATA[Grof taalgebruik]]></Name>
           </Genre>
           <Genre href="urn:po:metadata:cs:NicamWarningCS:2007:g">
             <Name xml:lang="NL"><![CDATA[Geweld]]></Name>
           </Genre>
           <Genre href="urn:po:metadata:cs:GenreCS:2009:23" type="other">
             <Name xml:lang="NL"><![CDATA[Biography/Drama/History]]></Name>
           </Genre>
         </BasicDescription>
       </ProgramInformation>
     </ProgramInformationTable>
   </ProgramDescription>
 </Main>
1
ih16 11 avril 2018 à 19:15

3 réponses

Meilleure réponse

Voici une procédure détaillée de ce que je ferais:

import xml.etree.ElementTree as ET

# 1. Parse your xml file
tree = ET.parse('your.xml')

# 2. Get the root
root = tree.getroot()

# 3. Set the tag and attribute you are looking for
ns = 'urn:tva:metadata:2004'
matchTag = 'NicamWarningCS'

# 4. retrieve all Genres
genres = root.find('{%s}ProgramDescription' % ns) \
    .find('{%s}ProgramInformationTable' % ns) \
    .find('{%s}ProgramInformation' % ns) \
    .find('{%s}BasicDescription' % ns) \
    .findall('{%s}Genre' % ns)

# 5. filter them in order to get just the Names of the ones that match your matchTag : 'NicamWarningCS'
filteredGenreNames = [genre.find('{%s}Name' % ns) for genre in genres if matchTag in genre.get('href')]

# 6. extract the text of the tags
data = [t.text for t in filteredGenreNames]

print(data)
# ['Grof taalgebruik', 'Geweld']
2
IvanJijon 12 avril 2018 à 09:50

Je n'ai pas pu obtenir rapidement la réponse d'Erik, mais cela m'a laissé entrevoir une solution différente qui a réussi à résoudre mon problème.

En créant un dict avec tous les genres, j'ai pu filtrer tous les avertissements Nicam et les ajouter à une liste que je pourrais ensuite utiliser pour remplir mes instructions SQL:

genreitemdict = dict()
for genreitem in program.iter("{urn:tva:metadata:2004}Genre"):
    for child in genreitem:
        genreitemdict[genreitem.attrib['href']] = child.text
        NicamWarningCS = [v for k, v in genreitemdict.items() if 'NicamWarningCS' in k]
print NicamWarningCS

Ce n'est peut-être pas la meilleure solution, mais pour l'instant, cela suffira.

0
ih16 11 avril 2018 à 23:14

Obtenez simplement tous les Genre éléments et filtrez ceux qui ont un attribut href qui vous intéresse:

ns = 'urn:tva:metadata:2004'
all_genres = fromstring(xml) \
    .find('{%s}ProgramDescription' % ns) \
    .find('{%s}ProgramInformationTable' % ns) \
    .find('{%s}ProgramInformation' % ns) \
    .find('{%s}BasicDescription' % ns) \
    .findall('{%s}Genre' % ns)
some_genres = [g for g in all_genres if 'NicamWarningCS' in g.get('href')]
1
Erik Cederstrand 11 avril 2018 à 19:06