我有一个包含一些数据的 XML 文件。该文件具有列和数据本身的描述。我可以读取列名称,但无法读取数据,因为我不明白如何将此行名称赋予将返回数据的函数。
XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<Header>
<Project code="SOME PROJECT" label="PROJECT LABEL"></Project>
<Datatable name="LOG" label="Visits"></Datatable>
<Columns>
<column name="study" label="Study" ordinal="1" type="TEXT"></column>
<column name="site" label="Site" ordinal="2" type="INTEGER"></column>
<column name="number" label="Subject" ordinal="3" type="INTEGER"></column>
<column name="visit" label="Visit number" ordinal="4" type="CHARACTER VARYING(20)">
</column>
<column name="vdate" label="Visit date (dd/mm/yyyy)." ordinal="5" type="CHARACTER VARYING(10)"></column>
</Columns>
</Header>
<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>1</visit>
<vdate>28/12/2010</vdate>
</row>
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>2</visit>
<vdate>03/03/2011</vdate>
</row>
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>3</visit>
<vdate>09/06/2011</vdate>
</row>
</table>
</Document>
示例代码:
{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Core
import Data.Tree.NTree.TypeDefs
parseXML :: String -> IOStateArrow s b XmlTree
parseXML file = readDocument [ withValidate yes
, withRemoveWS yes
] file
atTag :: ArrowXml a => String -> a (NTree XNode) XmlTree
atTag tag = deep (isElem >>> hasName tag)
text :: ArrowXml cat => cat (NTree XNode) String
text = getChildren >>> getText
getRowsData :: ArrowXml cat => cat (NTree XNode) [String]
getRowsData = atTag "table" >>>
proc l -> do
row <- atTag "row" -< l
study <- text <<< atTag "study" -< row
site <- text <<< atTag "site" -< row
returnA -< [study,site]
readTable :: ArrowXml t => t (NTree XNode) [[String]]
readTable =
proc l -> do
rows <- listA getRowsData -< l
returnA -< rows
main :: IO ()
main = do
res <- runX ( parseXML "log.xml" >>> readTable )
print res
我的问题在于
getRowsData
。在示例代码中,我隐式给出了列名称,但我希望它从列表中读取,应用于箭头函数并返回行。
import Control.Arrow
我相信您正在寻找的是一种在同一输入上组合多个箭头以列出其输出的方法:
list :: Arrow a => [a b c] -> a b [c]
list [] = returnA >>^ const []
list (a:as) = (a &&& list as) >>^ uncurry (:)
(a &&& list as)
返回一对头部和尾部,然后我们后应用>>^
纯函数uncurry (:) :: (x,[x]) -> [x]
来重新组合它们。
我们来测试一下。以下是 IO 箭头的一些玩法。单子是一个箭头,但你必须将它包装到它的 Kleisli 类别中。
runKleisli
再次打开它,以便您可以运行它,但输入时间太长,因此我使用了中缀版本 >$>
来为其提供输入:
ask :: Kleisli IO String String
ask = Kleisli $ \xs -> putStrLn xs >> getLine
(>$>) = runKleisli
所以现在互动更容易了:
*Main> ask >$> "Hello?"
Hello?
Hello!
"Hello!"
和
list
工作正常:
*Main> list [ask,ask] >$> "say something!"
say something!
OK
say something!
What do you want me to say?
["OK","What do you want me to say?"]
但是您想将字符串列表转换为生成字符串列表的箭头。
appList :: Arrow a => (s -> a b c) -> [s] -> a b [c]
appList f xs = list (map f xs)
我们可以使用询问测试的变体来测试:
askRespond xs = Kleisli $ \thx -> do
putStrLn xs
ans <- getLine
putStrLn thx
return ans
所以我们可以看到
appList
正在按照你想要的方式工作,通过在每个字符串中制作一个箭头,然后运行每个字符串,再次将答案组合成一个字符串:
*Main> appList askRespond ["What's your name?","What's your favourite colour?","Would you like some cheese?"] >$> "Thanks."
What's your name?
Andrew
Thanks.
What's your favourite colour?
Green
Thanks.
Would you like some cheese?
Yes - could I have gruyere?
Thanks.
["Andrew","Green","Yes - could I have gruyere?"]
现在让我们将其应用于您的问题。
首先让我们制作一个简写,用字符串制作箭头:
textAtTag xs = text <<< atTag xs
那就用
appList
:
getRowsData = atTag "table"
>>> atTag "row"
>>> appList textAtTag ["study","site"]
我还没有测试过最后一个 - 请检查!