2009-03-17 5 views
7

Si tengo un documento XML como esto:En Haskell, ¿cómo se extraen las cadenas de un documento XML?

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

y algunas definiciones de tipo de datos/Haskell como este:

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

y quería escribir una función Haskell con la siguiente firma:

getLocalizedStrings :: String -> [LocalizedString] 

donde el primer parámetro era el texto XML, y el valor devuelto era:

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

¿cómo haré esto?

Si HaXml es la mejor herramienta, ¿cómo usaría HaXml para lograr el objetivo anterior?

¡Gracias!

Respuesta

5

Nunca me he molestado en descubrir cómo extraer bits de documentos XML usando HaXML; HXT ha satisfecho todas mis necesidades.

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

lo que probablemente como un poco más de comprobación de errores (es decir, no sólo con pereza usar atTag como yo, en realidad es verificar que <root> raíz, <elem> es descendiente directo, etc.), pero esto funciona bien en tu ejemplo.


Ahora, si necesita una introducción a Arrow s, por desgracia, no conozco ninguna buena. Yo mismo aprendí el camino "arrojado al océano para aprender a nadar".

Algo que puede ser útil a tener en cuenta es que la sintaxis proc/-< es simplemente azúcar para las operaciones básicas de flecha (arr, >>>, etc.), al igual que do/<- es simplemente azúcar para las operaciones básicas monad (return, >>=, etc.). Los siguientes son equivalentes:

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

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

Muchas gracias por una respuesta muy informativo! –

+0

Hay un tutorial de HXT en http://www.haskell.org/haskellwiki/HXT, pero es implacablemente sin puntos, por lo que no es fácil entender cómo se relaciona esto con la notación de flecha (como en el ejemplo anterior) . –

2

Fwiw, HXT parece un exceso donde un TagSoup sencilla hará :)

1

Aquí está mi segundo intento (después de recibir un buen aporte de otros) con TagSoup:

El primer intento mostró un método ingenuo (y defectuoso) para recortar el espacio en blanco de una cuerda.

+0

TagSoup acepta felizmente entradas mal formadas, que en realidad te pueden gustar :) Desafortunadamente, esta solución es más difícil de leer. Minor nit: Hubiera esperado algo más como 'trimWhiteSpace = dropWhile isSpace. marcha atrás . dropWhile isSpace. reverse'; el suyo es más como 'removeAllWhiteSpace'. – ephemient

+0

Gracias efusivo. Debería haber tenido algunos mejores datos de muestra. :) Tendré que asegurarme de que isSpace se deshace de las nuevas líneas porque tengo algunas novedades incorporadas en mi XML. –

+0

Inténtalo por ti mismo: escribe 'Data.Char.isSpace '\ n'' en GHCi. Sí, las nuevas líneas son, y siempre han sido, espacios en blanco. Mi nit no se trataba de eso, más en la línea de tu 'trimWhiteSpace" a b c "==" abc "' que no es intuitivo para mí. O tal vez soy extraño. – ephemient

3

Usa uno de los paquetes XML.

Los más populares son, en orden,

  1. haxml
  2. hxt
  3. xml-luz
  4. hexpat
Cuestiones relacionadas