Ich habe einen einfachen XML-Parser in Haskell geschrieben. Die Funktion convertXML empfängt den Inhalt einer XML-Datei und gibt eine Liste extrahierter Werte zurück, die weiterverarbeitet werden.Erweiterung der reinen Funktion um IO-Code möglich?
Ein Attribut des XML-Tags enthält auch eine URL eines Produktbilds und ich möchte die Funktion erweitern, um es auch herunterzuladen, wenn das Tag gefunden wird. Ich muss komplett neu schreiben convertXML Funktion zu einer unreinen Version
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
Jede Idee, wie in der getImgName Funktion oder tun einen IO-Code einfügen?
UPDATE II Endgültige Version der convertXML-Funktion. Hybride rein/unreine aber saubere Art vorgeschlagen von Carl. Der zweite Parameter des zurückgegebenen Paars ist eine E/A-Aktion, die das Herunterladen und Speichern von Bildern auf Festplatte ausführt und die Liste lokaler Pfade, in denen Bilder gespeichert sind, umschließt.
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
Das klingt nach einer netten Idee, um "Wert" des IO-Aktionstyps als zweites Argument zurückzugeben. Irgendwelche Hinweise, wie man meine -> ([String], [String]) Version auf -> ([String], IO [String]) aktualisiert? –
Nun, ich glaube nicht, dass "String" der richtige Typ für ein Bild ist. Angenommen, Sie möchten die Bytes, die von der URL zurückgegeben werden, möchten Sie 'ByteString' für die Darstellung verwenden, nicht String. String ist für Zeichendaten und enthält Unicode-Codepunkte. ByteString ist für die effiziente Behandlung von Bytefolgen, wie es ein Bild in binärer Form sein könnte. Bei einer Funktion wie 'fetch :: String -> IO ByteString', die eine URL akzeptiert, können Sie eine Liste von URLs in eine IO-Aktion konvertieren, um sie mit' mapM fetch urls' zu holen. – Carl
Danke Carl. Ich beabsichtigte Zugriff auf IO [String] wird die Liste der URLs von Bildern zurückgeben und auf die Festplatte herunterladen wird als "Nebeneffekt" aufgerufen. –