質問
Haskell XML Toolkit、HXTを使用してこれまで見たすべての例は使用しています runX
パーサーを実行します。 runX
IO Monad内で走ります。 IO以外でこのXMLパーサーを使用する方法はありますか?私にとっては純粋な手術のようです。なぜ私がIOの中にいることを余儀なくされているのか理解していません。
解決
HXTを使用できます xread
一緒に runLA
外側のXML文字列を解析します IO
.
xread
次のタイプがあります。
xread :: ArrowXml a => a String XmlTree
これは、タイプのあらゆる矢印で作曲できることを意味します (ArrowXml a) => a XmlTree Whatever
を取得する a String Whatever
.
runLA
のようなものです runX
, 、しかし、タイプのもののために LA
:
runLA :: LA a b -> a -> [b]
LA
のインスタンスです ArrowXml
.
これをすべてまとめるために、次のバージョンの 私の答え 以前の質問にHXTを使用して、整形式のXMLを含む文字列を解析するために IO
関与:
{-# 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 >>> 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) >>> unlistA
where lookupValues cs m = map (flip M.lookup m) cs
xml = "<div><div class='c1'>a</div><div class='c2'>b</div>\
\<div class='c3'>123</div><div class='c4'>234</div></div>"
values :: [(String, Maybe String)]
values = runLA (xread >>> getValues ["c1", "c2", "c3", "c4"]) xml
main = print values
classes
と getValues
以前のバージョンに似ており、予想される入力と出力に合わせていくつかの小さな変更があります。主な違いは、ここで使用していることです xread
と runLA
それ以外の readString
と runX
.
怠zyのようなものを読むことができるのはいいことです ByteString
同様の方法では、私が知っている限り、これは現在HXTでは不可能です。
他のいくつかのこと:あなた できる この方法で文字列を解析します IO
, 、しかし、おそらく使用する方が良いでしょう runX
できる限り:パーサーの構成、エラーメッセージなどをより強く制御できます。
また:例のコードを簡単で簡単に拡張しようとしましたが、コンビネーターは Control.Arrow
と Control.Arrow.ArrowList
必要に応じて、より簡潔に矢印で作業できるようにします。以下は同等の定義です classes
, 、 例えば:
classes = (getChildren >>> hasName "div" >>> pairs) >. M.fromList
where pairs = getAttrValue "class" &&& deep getText
他のヒント
トラビス・ブラウンの答えはとても役に立ちました。ここに独自のソリューションを追加したいだけです。これはもう少し一般的だと思います(同じ機能を使用して、問題固有の問題を無視するだけです)。
私は以前に抑えていませんでした:
upIO :: XmlPickler a => String -> IO [a]
upIO str = runX $ readString [] str >>> arrL (maybeToList . unpickleDoc xpickle)
私はこれに変更することができました:
upPure :: XmlPickler a => String -> [a]
upPure str = runLA (xreadDoc >>> arrL (maybeToList . unpickleDoc xpickle)) str
私は彼に完全に同意します。これを行うと、パーサーなどの構成を制御できなくなりますが、残念です。