2009-11-29 3 views
0

Mon fichier XML ressemble à ceci:Python: Extrait HTML à partir d'un fichier XML

<strings> 
     <string>Bla <b>One &amp; Two</b> Foo</string> 
</strings> 

Je veux extraire le contenu de chaque chaîne < > tout en maintenant les balises internes. C'est-à-dire, je voudrais voir la chaîne de Python suivante: u "Bla <b> Un & Deux </b > Foo". Alternativement, je suppose que je pourrais régler sur vous "Bla <b> One & Deux </b > Foo", puis essayez de remplacer les entités moi-même. J'utilise actuellement lxml, qui me permet d'itérer sur les balises imbriquées, de rater le texte qui ne se trouve pas dans une balise, ou encore sur tout le contenu textuel (itertext), en perdant les informations d'étiquette. Il me manque probablement quelque chose.

Si possible, je préfère conserver lxml, bien que je puisse passer à une autre bibliothèque si nécessaire.

Répondre

3

Il peut y avoir une meilleure façon de gérer conditionnellement des objets retournés par la fonction xpath(), mais je suis pas suffisamment au courant avec lxml pour savoir ce que c'est, donc j'ai dû écrire une fonction pour retourner la valeur de texte d'un nœud. Mais cela dit, cela montre une approche générale au problème:

>>> from lxml import etree 
>>> from StringIO import StringIO 
>>> def node_text(n): 
     try: 
      return etree.tostring(n, method='html', with_tail=False) 
     except TypeError: 
      return str(n) 

>>> f = StringIO('<strings><string>This is <b>not</b> how I plan to escape.</string></strings>') 
>>> x = etree.parse(f) 
>>> ''.join(node_text(n) for n in x.xpath('/strings/string/node()')) 
'This is <b>not</b> how I plan to escape.' 
+0

Il s'avère qu'au lieu d'utiliser node(), on pourrait aussi child.iterdescendants(), mais merci de me pointer dans la bonne direction. – miracle2k

2

essayer etree.tostring

outer = etree.tostring(string_elem, method='html') 
inner = re.match("^[^>]+>(.*)<[^<]+$", outer).groups(1)[0] 
+0

Je sais à propos de tostring réellement, mais cela inclut l'étiquette de chaîne elle-même. – miracle2k

+0

ne serait pas si difficile à couper manuellement, une simple regex fonctionnerait – cobbal

+0

+ 1 pour trouver l'un des rares cas où l'utilisation d'une expression régulière pour traiter XML n'est pas une terrible, terrible idée. –

0

Quelle que soit la langue, modèle XSLT relativement simple ferait l'affaire. Quelque chose comme la définition de modèles pour les étiquettes que vous souhaitez conserver, la conversion en texte d'autres.

Vous pouvez bien sûr utiliser une fonction récursive avec une implémentation DOM conforme (minidom peut-être?) Et traiter les balises à la main.

(pseudocode)

def Function(tag): 
    if tag.NodeType = "#text": return tag.innerText 
    text="" 
    if tag.ElementName in allowedTags: 
     text="<%s>"%tag.ElementName 
    text += [Function(subtag) for subtag in tag.childs] 
    if tag.ElementName in allowedTags: 
     text+="</%s>"%tag.ElementName 
    return text 
-1

Ne pas utiliser l'analyseur, mais simplement de la pure manipulation de chaîne

mystring=""" 
<strings> 
     <string>Bla <b>One &amp; Two</b> Foo</string> 
</strings> 
""" 
for s in mystring.split("</string>"): 
    if "<string>" in s: 
     i = s.index("<string>") 
     print s[i+len("<string>"):].replace("&amp;","") 
+0

Cette liste de choses incorrectes avec cette approche n'est pas courte: entre autres, elle échoue s'il y a un élément '' vide, ou si un élément '' contient des attributs, ou des espaces dans sa balise d'ouverture ou de fermeture, ou si du texte Le noeud contient des entités de caractères ou CDATA. –

+0

vous en assumez trop !! Et c'est une mauvaise habitude. – ghostdog74

Questions connexes