2009-03-17 11 views
7

Se ho un documento XML come questo:In Haskell come si estrae le stringhe da un documento XML?

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

e alcuni Haskell definizioni tipo/dati come questo:

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

e ho voluto scrivere una funzione Haskell con la seguente firma:

dove il primo parametro era il testo XML e il valore restituito era:

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

come farei questo?

Se HaXml è lo strumento migliore, come utilizzerei HaXml per raggiungere l'obiettivo di cui sopra?

Grazie!

risposta

5

Non mi sono mai preso la briga di capire come estrarre i bit dai documenti XML usando HaXML; HXT ha soddisfatto tutti i miei bisogni.

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

si sarebbe probabilmente come un po 'più di controllo degli errori (vale a dire non solo pigramente utilizzare atTag come me, in realtà verificare che <root> è radice, <elem> è discendente diretta, ecc), ma questo funziona bene sul tuo esempio.


Ora, se avete bisogno di un'introduzione al Arrow s, purtroppo non so di qualsiasi buona. Io stesso l'ho imparato come "gettato nell'oceano per imparare a nuotare".

Qualcosa che può essere utile tenere a mente è che la sintassi proc/-< è semplicemente zucchero per le operazioni di base freccia (arr, >>>, ecc), proprio come do/<- è semplicemente lo zucchero per le operazioni di base monade (return, >>=, ecc.). I seguenti sono equivalenti:

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

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

ringrazio molto per una risposta molto istruttivo! –

+0

C'è un tutorial HXT su http://www.haskell.org/haskellwiki/HXT, ma è implacabilmente senza punti, quindi capire come questo si riferisca alla notazione delle frecce (come nell'esempio sopra) non è facile . –

2

FWIW, HXT sembra eccessivo dove un semplice TagSoup farà :)

1

Ecco il mio secondo tentativo (dopo aver ricevuto qualche buon input da altri) con TagSoup:

Il primo tentativo ha mostrato un metodo ingenuo (e difettoso) per il ritaglio di spazi bianchi da una stringa.

+0

TagSoup accetta felicemente input non corretti - che potreste effettivamente piacere :) - sfortunatamente IMO questa soluzione è più difficile da leggere. Minore nit: mi sarei aspettato qualcosa di più come 'trimWhiteSpace = dropWhile isSpace. invertire. dropWhile isSpace. reverse'; il tuo è più come 'removeAllWhiteSpace'. – ephemient

+0

Grazie effimero. Avrei dovuto avere dati di esempio migliori. :) Dovrò assicurarmi che isSpace si sbarazzi delle newline perché avevo alcune newline incorporate nel mio XML. –

+0

Prova solo tu stesso: digita 'Data.Char.isSpace '\ n'' in GHCi. Sì, i newline sono, e sono sempre stati, spazi bianchi. La mia nit non era su questo, più sulla falsariga del tuo 'trimWhiteSpace" a b c "==" abc "' che non è intuitivo per me. O forse sono strano. – ephemient

3

Utilizzare uno dei pacchetti XML.

I più popolari sono, in ordine,

  1. haxml
  2. HXT
  3. xml-luce
  4. hexpat
Problemi correlati