Haskell HXT для извлечения списка значений - PullRequest
5 голосов
/ 09 октября 2010

Я пытаюсь разобраться в HXT с XPath и стрелками одновременно, и я полностью застрял в том, как решить эту проблему. У меня есть следующий HTML:

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

, который я извлек в HXT XmlTree. Что я хотел бы сделать, это определить функцию (я думаю?):

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

Который, если использовать getValues ["c1", "c2", "c3", "c4"], получит меня:

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

Помогите пожалуйста?

Ответы [ 2 ]

2 голосов
/ 09 октября 2010

Вот один из подходов (мои типы немного более общие, и я не использую 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"])

Я бы, вероятно, запустил стрелку, чтобы получить карту, а затем выполнил бы поиск, но этот способ также работает.


Чтобы ответить на ваш вопрос о listA: divs >>> divs >>> pairs - это стрелка списка с типом a XmlTree (String, String) - т.е., это недетерминированное вычисление, которое принимает дерево XML и возвращает пары строк.

arr M.fromList имеет тип a [(String, String)] (M.Map String String). Это означает, что мы не можем просто составить его с divs >>> divs >>> pairs, так как типы не совпадают.

listA решает эту проблему: она сворачивается divs >>> divs >>> pairs в детерминированную версию с типом a XmlTree [(String, String)], что именно то, что нам нужно.

0 голосов
/ 04 ноября 2012

Вот способ сделать это, используя BeautifulSoup :

-- 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 - это файл HTML.

...