Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在haskell中从xml检索异构元素_Xml_Haskell - Fatal编程技术网

在haskell中从xml检索异构元素

在haskell中从xml检索异构元素,xml,haskell,Xml,Haskell,我有一个大的.xml文件,我使用Text.xml.Light在Haskell中加载和解析它。文件中的元素表示不同的对象。有点像这样: <matchhistory> <game starttime="2/10/13 18:00" endtime="2/11/13 18:40"> <participant> <name>John Doe</name> <color>green</colo

我有一个大的.xml文件,我使用
Text.xml.Light
在Haskell中加载和解析它。文件中的元素表示不同的对象。有点像这样:

<matchhistory>
  <game starttime="2/10/13 18:00" endtime="2/11/13 18:40">
    <participant>
      <name>John Doe</name>
      <color>green</color>
    </participant>
    <participant>
      <name>Jane Doe</name>
      <color>blue</color>
    </participant>
    <winner color="blue">
  </game>
  <game starttime="2/11/13 17:00" endtime="2/11/13 17:30">
    <participant>
      <name>Jane Doe</name>
      <color>green</color>
    </participant>
    <participant>
      <name>John Doe</name>
      <color>blue</color>
    </participant>
    <winner color="green">
  </game>
  ...
</matchhistory>

我将如何执行此转换,分别遍历整个文件(26K行)以提取每种对象类型似乎不是很优雅?是否有一种很好的方法(可能是通过模式匹配来调用不同的构造函数)可以在一次扫描中完成此操作?

是的,这将是构造此代码的一种很好的方法。使用您的数据定义,我能够非常轻松地找出如何将示例XML文档转换为数据结构。这里的技巧是构建增量解析器

首先,我们需要一些导入和数据定义的重述:

导入数据时间(UTCTime)
导入Data.Time.Format(parseTime)
导入System.Locale(defaultTimeLocale)
导入数据。可能(mapMaybe)
导入Text.XML.Light
导入控件。应用程序((),())
数据参与者=参与者
{name::String
,颜色::字符串
}推导(等式,显示)
数据游戏
{starttime::UTCTime
,endtime::UTCTime
,参加者::[参加者]
,winner::String
}推导(等式,显示)
数据匹配历史=匹配历史
{游戏::[游戏]
}推导(等式,显示)
我们可以使用
Text.XML.Light
中的
parseXML
函数将字符串转换为
[Content]
。接下来,我们可以使用
onlylems
提取所有顶级元素。对于解析,我们希望每个解析都能正常地失败,所以现在我们只使用
Maybe
monad。我们可以为每种数据类型创建存根:

parseParticipant :: Element -> Maybe Participant
parseParticipant = undefined

parseGame :: Element -> Maybe Game
parseGame = undefined

parseMatchHistory :: Element -> Maybe MatchHistory
parseMatchHistory = undefined
这让我们可以编写一个文档解析器:

parseDocument :: String -> [MatchHistory]
parseDocument = mapMaybe parseMatchHistory . onlyElems . parseXML
现在,对于每个解析的实现:

parseParticipant pElem = Participant
    <$> (strContent <$> findChild (blank_name { qName = "name"  }) pElem)
    <*> (strContent <$> findChild (blank_name { qName = "color" }) pElem)
最后,我们需要实现
parseMatchHistory
。我把这个留给你做练习,但应该很容易

一旦你有了一个解析过的文档,你可以做如下的事情

averageTimePlayed :: MatchHistory -> DiffTime
averageTimePlayed = average . map calcDiff . games
    where
        average xs = sum xs / fromIntegral (length xs)
        calcDiff g = endtime g `diffUTCTime` starttime g

虽然通过镜头的魔力,你可能会把它缩短。

我喜欢
mapaybay
parseXYZ
一起玩的方式。它导致了一个真正清晰简洁的实现。你对我问题的回答也是如此@j、 狗听了很高兴。你们当然可以在这个更干净的地方减少一点重复,我想象的更像
parseGame gElem = do
    starttimeStr <- findAttrBy (("starttime" ==) . qName) gElem
    endtimeStr <- findAttrBy (("endtime" ==) . qName) gElem
    winnerElem <- findChild (blank_name { qName = "winner" }) gElem
    let pElems = filterChildrenName (("participant" ==) . qName) gElem
    ...
parseTimeField :: String -> Maybe UTCTime
parseTimeField = parseTime defaultTimeLocale "%-m/%-d/%-y %R"

parseGame gElem = do
    starttimeStr <- findAttrBy (("starttime" ==) . qName) gElem
    endtimeStr <- findAttrBy (("endtime" ==) . qName) gElem
    winnerElem <- findChild (blank_name { qName = "winner" }) gElem
    let pElems = filterChildrenName (("participant" ==) . qName) gElem
    Game <$> parseTimeField starttimeStr
         <*> parseTimeField endtimeStr
         <*> pure (mapMaybe parseParticipant pElems)
         <*> findAttrBy (("color" ==) . qName) winnerElem
averageTimePlayed :: MatchHistory -> DiffTime
averageTimePlayed = average . map calcDiff . games
    where
        average xs = sum xs / fromIntegral (length xs)
        calcDiff g = endtime g `diffUTCTime` starttime g