27

これまで見てきたすべての例では、Haskell XML ツールキット HXT を使用runXしてパーサーを実行していました。runXIO モナド内で実行されます。この XML パーサーを IO 以外で使用する方法はありますか? 私には純粋な操作のように思えますが、なぜ私が IO の中にいることを余儀なくされているのか理解できません。

4

2 に答える 2

27

xreadと一緒にHXT を使用して、 の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似ていますが、予想される入力と出力に合わせていくつかのマイナーな変更が加えられています。主な違いは、ここでは and の代わりに and を使用してxreadいるrunLAことreadStringですrunX

同様に怠け者のようなものを読み取れるといいのですがByteString、私の知る限り、これは現在 HXT では不可能です。


他のいくつかのこと:なしでこの方法で文字列を解析できIOますが、可能な場合はいつでも使用する方がおそらく良いでしょうrunX: パーサーの構成、エラー メッセージなどをより詳細に制御できます。

また、例のコードを簡単で拡張しやすいものにしようとしましたが、必要に応じて、 と のコンビネータをControl.Arrow使用Control.Arrow.ArrowListすると、矢印をより簡潔に操作できます。以下は、classesたとえばの同等の定義です。

classes = (getChildren >>> hasName "div" >>> pairs) >. M.fromList
  where pairs = getAttrValue "class" &&& deep getText
于 2010-10-10T19:11:53.197 に答える
1

Travis Brown の回答は非常に役に立ちました。ここに独自のソリューションを追加したいだけです。これはもう少し一般的だと思います(同じ関数を使用し、問題固有の問題を無視するだけです)。

私は以前に解凍していました:

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

これを行うと、パーサーなどの構成を制御しにくくなるという彼の意見に完全に同意します。これは残念なことです。

于 2014-10-21T09:22:55.520 に答える