2009-03-17 5 views
7

Si j'ai un document XML comme ceci:Dans Haskell, comment extraire les chaînes d'un document XML?

<root> 
    <elem name="Greeting"> 
    Hello 
    </elem> 
    <elem name="Name"> 
    Name 
    </elem> 
</root> 

et quelques définitions de type/données Haskell comme ceci:

type Name = String 
type Value = String 
data LocalizedString = LS Name Value 

et je voulais écrire une fonction Haskell avec la signature suivante:

getLocalizedStrings :: String -> [LocalizedString] 

où le premier paramètre est le texte XML, et la valeur renvoyée est:

[LS "Greeting" "Hello", LS "Name" "Name"] 

Comment est-ce que je ferais ceci?

Si HaXml est le meilleur outil, comment utiliser HaXml pour atteindre l'objectif ci-dessus?

Merci!

Répondre

5

Je n'ai jamais vraiment pris la peine de comprendre comment extraire des bits de documents XML en utilisant HaXML; HXT a répondu à tous mes besoins.

{-# LANGUAGE Arrows #-} 
import Data.Maybe 
import Text.XML.HXT.Arrow 

type Name = String 
type Value = String 
data LocalizedString = LS Name Value 

getLocalizedStrings :: String -> Maybe [LocalizedString] 
getLocalizedStrings = (.) listToMaybe . runLA $ xread >>> getRoot 

atTag :: ArrowXml a => String -> a XmlTree XmlTree 
atTag tag = deep $ isElem >>> hasName tag 

getRoot :: ArrowXml a => a XmlTree [LocalizedString] 
getRoot = atTag "root" >>> listA getElem 

getElem :: ArrowXml a => a XmlTree LocalizedString 
getElem = atTag "elem" >>> proc x -> do 
    name <- getAttrValue "name" -< x 
    value <- getChildren >>> getText -< x 
    returnA -< LS name value 

Vous auriez probablement comme un peu plus de contrôle des erreurs (par exemple ne sont pas seulement paresseusement utiliser atTag comme moi, vérifiaient réellement que <root> est la racine, <elem> est descendant direct, etc.), mais cela fonctionne très bien sur votre exemple.


Maintenant, si vous avez besoin d'une introduction à Arrow s, malheureusement, je ne connais pas de bon. Je l'ai moi-même appris "jeté dans l'océan pour apprendre à nager".

Quelque chose qui peut être utile de garder à l'esprit est que la syntaxe proc/-< est simplement le sucre pour les opérations de flèche de base (arr, >>>, etc.), tout comme do/<- est simplement le sucre pour les opérations monade de base (return, >>=, etc.). Les suivantes sont équivalentes:

getAttrValue "name" &&& (getChildren >>> getText) >>^ uncurry LS 

proc x -> do 
    name <- getAttrValue "name" -< x 
    value <- getChildren >>> getText -< x 
    returnA -< LS name value 
+0

Merci beaucoup pour une réponse très instructif! –

+0

Il existe un tutoriel HXT sur http://www.haskell.org/haskellwiki/HXT, mais il est implacablement sans point, donc comprendre comment cela se rapporte à la flèche Do-notation (comme dans l'exemple ci-dessus) n'est pas facile . –

2

FWIW, HXT semble overkill où simple TagSoup fera :)

1

Voici ma seconde tentative (après avoir reçu une bonne entrée des autres) avec TagSoup:

La première tentative a montré une méthode naïve (et défectueuse) pour couper les espaces d'une chaîne.

+0

TagSoup accepte volontiers les entrées malformées - ce qui pourrait vous plaire :) - Malheureusement, cette solution est plus difficile à lire. Minor nit: Je m'attendais à quelque chose de plus comme 'trimWhiteSpace = dropWhile isSpace. sens inverse . dropWhile isSpace. inverser »; Le vôtre ressemble plus à 'removeAllWhiteSpace'. – ephemient

+0

Merci éphémient. J'aurais dû avoir de meilleurs exemples de données. :) Je vais devoir m'assurer qu'isSpace se débarrasse des nouvelles lignes parce que j'avais des nouvelles lignes intégrées à mon XML. –

+0

Essayez par vous-même: tapez 'Data.Char.isSpace '\ n'' dans GHCi. Oui, les nouvelles lignes sont, et ont toujours été, des espaces. Mon nit n'était pas à ce sujet, plus le long de votre 'trimWhiteSpace" un b c "==" abc "' qui est non intuitive pour moi. Ou peut-être que je suis étrange. – ephemient

3

Utilisez l'un des packages XML.

Les plus populaires sont, dans l'ordre,

  1. haxml
  2. HXT
  3. xml-light
  4. hexpat
Questions connexes