2010-10-09 6 views
5

Sto provando a capire come funziona HXT con XPath e frecce allo stesso tempo e sono completamente bloccato su come pensare a questo problema. Ho il seguente codice HTML:Haskell HXT per estrarre un elenco di valori

<div> 
<div class="c1">a</div> 
<div class="c2">b</div> 
<div class="c3">123</div> 
<div class="c4">234</div> 
</div> 

che ho estratto in un XmlTree HXT. Quello che mi piacerebbe fare è definire una funzione (credo?):

getValues :: [String] -> IOSArrow Xmltree [(String, String)] 

Il che, se utilizzato come getValues ["c1", "c2", "c3", "c4"], otterrà me:

[("c1", "a"), ("c2", "b"), ("c3", "123"), ("c4", "234")] 

Aiuto per favore?

risposta

2

Ecco uno approccio (i miei tipi sono un po 'più generale e non sto usando XPath):

{-# LANGUAGE Arrows #-} 
module Main where 

import qualified Data.Map as M 
import Text.XML.HXT.Arrow 

classes :: (ArrowXml a) => a XmlTree (M.Map String String) 
classes = listA (divs >>> divs >>> pairs) >>> arr M.fromList 
    where 
    divs = getChildren >>> hasName "div" 
    pairs = proc div -> do 
     cls <- getAttrValue "class" -< div 
     val <- deep getText   -< div 
     returnA -< (cls, val) 

getValues :: (ArrowXml a) => [String] -> a XmlTree [(String, Maybe String)] 
getValues cs = classes >>> arr (zip cs . lookupValues cs) 
    where lookupValues cs m = map (flip M.lookup m) cs 

main = do 
    let xml = "<div><div class='c1'>a</div><div class='c2'>b</div>\ 
      \<div class='c3'>123</div><div class='c4'>234</div></div>" 

    print =<< runX (readString [] xml >>> getValues ["c1", "c2", "c3", "c4"]) 

avrei probabilmente eseguito una freccia per ottenere la mappa e poi fare le ricerche, ma in questo modo funziona pure.


per rispondere alla tua domanda sul listA: divs >>> divs >>> pairs è una freccia lista con il tipo a XmlTree (String, String) -i.e., si tratta di un calcolo non deterministico che prende un albero XML e restituisce coppie di stringhe.

arr M.fromList ha tipo a [(String, String)] (M.Map String String). Ciò significa che non possiamo semplicemente comporlo con divs >>> divs >>> pairs, poiché i tipi non corrispondono.

listA risolve questo problema: collassadivs >>> divs >>> pairs in una versione deterministica di tipo a XmlTree [(String, String)], che è esattamente quello che ci serve.

+0

Cosa fa l'elencoA? – Muchin

0

Ecco un modo per farlo utilizzando HandsomeSoup:

-- For the join function. 
import Data.String.Utils 
import Text.HandsomeSoup 
import Text.XML.HXT.Core 

-- Of each element, get class attribute and text. 
getItem = (this ! "class" &&& (this /> getText)) 
getItems selectors = css (join "," selectors) >>> getItem 

main = do 
    let selectors = [".c1", ".c2", ".c3", ".c4"] 
    items <- runX (readDocument [] "data.html" >>> getItems selectors) 
    print items 

data.html è il file HTML.