我有一个带有一些数据的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
。在示例代码中,我隐式地给出了列名,但是我希望它从列表中读取,应用于箭头函数并返回行。
答案 0 :(得分:2)
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箭头的一些内容。 monad是一个箭头,但你必须把它包装成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)
我们可以使用ask测试中的变体测试:
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"]
我没有测试过最后一个 - 请检查!