Estoy tratando de obtener datos de una página web que sirve un archivo XML periódicamente con cotizaciones bursátiles (sample data). La estructura del XML es muy simple, y es algo como esto:Parse XML en Haskell
<?xml version="1.0"?>
<Contents>
<StockQuote Symbol="PETR3" Date="21-12-2010" Time="13:20" Price="23.02" />
</Contents>
(que es más que eso, pero esto basta como ejemplo).
me gustaría analizar a una estructura de datos:
data Quote = Quote { symbol :: String,
date :: Data.Time.Calendar.Day,
time :: Data.Time.LocalTime.TimeOfDay,
price :: Float}
entiendo más o menos cómo funciona (en el nivel del libro Real World Haskell) Parsec, y he intentado un poco la Text.XML
biblioteca, pero todo lo que pude desarrollar fue un código que funcionó, pero es demasiado grande para una tarea tan simple y parece un truco medio cocido y no lo mejor que se podía hacer.
No sé mucho sobre analizadores sintácticos y XML (sé básicamente lo que leo en el libro de RWH, nunca usé analizadores sintácticos antes) (solo hago programación estadística y numérica, no soy científico informático) . ¿Hay una biblioteca de análisis XML donde podría simplemente decir cuál es el modelo y extraer la información de inmediato, sin tener que analizar cada elemento a mano y sin tener que analizar la cadena pura?
Estoy pensando en algo como:
myParser = do cont <- openXMLElem "Contents"
quote <- openXMLElem "StockQuote"
symb <- getXMLElemField "Symbol"
date <- getXMLElemField "Date"
(...)
closequote <- closeXMLElem "StockQuote"
closecont <- closeXMLElem "Contents"
return (symb, date)
results = parse myParser "" myXMLString
donde no tendría que lidiar con la cadena pura y crear los combinadores yo (soy muy malo en ello).
EDITAR: Probablemente necesite leer un poco (lo suficiente para hacer esto correctamente) sobre analizadores en general (no solo Parsec) y el mínimo sobre XML. ¿Ustedes recomiendan algo?
La cadena real que tengo que analizar es la siguiente:
stringTest = "<?xml version=\"1.0\"?>\r\n<ComportamentoPapeis><Papel Codigo=\"PETR3\"
Nome=\"PETROBRAS ON\" Ibovespa=\"#\" Data=\"05/01/201100:00:00\"
Abertura=\"29,80\" Minimo=\"30,31\" Maximo=\"30,67\" Medio=\"30,36\"
Ultimo=\"30,45\" Oscilacao=\"1,89\" Minino=\"29,71\"/></ComportamentoPapeis>\r\n"
Edit2:
He intentado lo siguiente (readFloat, readQuoteTime, etc ... son sólo funciones para leer cosas de cuerdas).
bvspaParser :: (ArrowXml a) => a XmlTree Quote
bvspaParser = hasName "ComportamentoPapeis" /> hasName "Papel" >>> proc x -> do
(hour,date) <- readQuoteTime ^<< getAttrValue "Data" -< x
quoteCode <- getAttrValue "Codigo" -< x
openPrice <- readFloat ^<< getAttrValue "Abertura" -< x
minim <- readFloat ^<< getAttrValue "Minimo" -< x
maxim <- readFloat ^<< getAttrValue "Maximo" -< x
ultimo <- readFloat ^<< getAttrValue "Ultimo" -< x
returnA -< Quote quoteCode (LocalTime date hour) openPrice minim maxim ultimo
docParser :: String -> IO [Quote]
docParser str = runX $ readString [] str >>> (parseXmlDocument False) >>> bvspaParser
Cuando llamo en ghci:
*Main> docParser stringTest >>= print
[]
¿Es algo malo?
Si usted está interesado en los combinadores de analizadores sintácticos, el tutorial de S. Doaitse Swierstra, http://www.cs.uu.nl/research/techreps/repo/CS-2008/2008- 044.pdf, es una introducción bastante buena. Utiliza el estilo aplicativo, pero no asume conocimiento de Aplicativo (o teoría del analizador sintáctico). Creo que la mayoría de las bibliotecas de combinador de analizadores en Hackage (Polyparse, Attoparsec, UU-parsinglib) son mejores opciones que Parsec. –