私は単純なXMLパーサーをHaskellに書いた。 関数convertXMLは、XMLファイルの内容を受け取り、さらに処理される抽出値のリストを返します。IOコードで純関数を拡張することは可能ですか?
XMLタグの1つの属性にも商品画像のURLが含まれています。タグが見つかった場合は、そのタグをダウンロードする機能も拡張したいと考えています。
convertXML :: (Text.XML.Light.Lexer.XmlSource s) => s -> [String]
convertXML xml = productToCSV products
where
productToCSV [] = []
productToCSV (x:xs) = (getFields x) ++ (productToCSV
(elChildren x)) ++ (productToCSV xs)
getFields elm = case (qName . elName) elm of
"product" -> [attrField "uid", attrField "code"]
"name" -> [trim $ strContent elm]
"annotation" -> [trim $ strContent elm]
"text" -> [trim $ strContent elm]
"category" -> [attrField "uid", attrField "name"]
"manufacturer" -> [attrField "uid",
attrField "name"]
"file" -> [getImgName]
_ -> []
where
attrField fldName = trim . fromJust $
findAttr (unqual fldName) elm
getImgName = if (map toUpper $ attrField "type") == "FULL"
then
-- here I need some IO code
-- to download an image
-- fetchFile :: String -> IO String
attrField "file"
else []
products = findElements (unqual "product") productsTree
productsTree = fromJust $ findElement (unqual "products") xmlTree
xmlTree = fromJust $ parseXMLDoc xml
にIOコードを挿入する方法任意のアイデアはgetImgName機能または私は完全に不純なバージョンにconvertXML機能を書き換えなければならないのですか?
UPDATE II convertXML関数の最終バージョンです。ハイブリッド純粋な/不純なしかしクリーンな方法は、カールによって示唆された。返されるペアの2番目のパラメータは、ダウンロードしてディスクに保存するイメージを実行し、イメージが格納されているローカルパスのリストをラップするIOアクションです。
convertXML :: (Text.XML.Light.Lexer.XmlSource s) => s -> ([String], IO [String])
convertXML xml = productToCSV products (return [])
where
productToCSV :: [Element] -> IO String -> ([String], IO [String])
productToCSV [] _ = ([], return [])
productToCSV (x:xs) (ys) = storeFields (getFields x)
(storeFields (productToCSV (elChildren x) (return []))
(productToCSV xs ys))
getFields elm = case (qName . elName) elm of
"product" -> ([attrField "uid", attrField "code"], return [])
"name" -> ([trim $ strContent elm], return [])
"annotation" -> ([trim $ strContent elm], return [])
"text" -> ([trim $ strContent elm], return [])
"category" -> ([attrField "uid", attrField "name"], return [])
"manufacturer" -> ([attrField "uid",
attrField "name"], return [])
"file" -> getImg
_ -> ([], return [])
where
attrField fldName = trim . fromJust $
findAttr (unqual fldName) elm
getImg = if (map toUpper $ attrField "type") == "FULL"
then
([attrField "file"], fetchFile url >>=
saveFile localPath >>
return [localPath])
else ([], return [])
where
fName = attrField "file"
localPath = imagesDir ++ "/" ++ fName
url = attrField "folderUrl" ++ "/" ++ fName
storeFields (x1s, y1s) (x2s, y2s) = (x1s ++ x2s, liftM2 (++) y1s y2s)
products = findElements (unqual "product") productsTree
productsTree = fromJust $ findElement (unqual "products") xmlTree
xmlTree = fromJust $ parseXMLDoc xml
IOアクションタイプの "値"を第2引数として返すのはいい考えです。どのように私の - >([String]、[String])バージョンを - >([String]、IO [String])に更新するかのヒント? –
さて、私は、 'String'はイメージの正しいタイプではないと思います。 URLによって返されるバイトが必要であると仮定すると、文字列ではなく、表現に 'ByteString'を使いたいとします。文字列は文字データ用で、Unicodeコードポイントが含まれます。 ByteStringは、バイナリ形式のイメージである可能性があるため、一連のバイトを効率的に処理するためのものです。 URLを取る 'fetch :: String - > IO ByteString'のような関数を与えられた場合、URLのリストをIOアクションに変換して' mapM fetch urls'でそれらをフェッチすることができます。 – Carl
Carlさんに感謝します。私はIO [String]へのアクセスを意図していましたが、イメージのURLのリストを返し、それらをディスクにダウンロードすることは "副作用"として呼び出されます。 –