2015-08-08 49 views
3

我想用xml-conduit解析GPX文件。到目前为止,我有以下几点:如何使用Haskell的xml-conduit解析GPX文件?

{-# LANGUAGE OverloadedStrings #-} 

import Control.Applicative 
import Data.Text   as T 
import Text.XML 
import Text.XML.Cursor 

data Trkpt = Trkpt { 
    trkptLat :: Text, 
    trkptLon :: Text, 
    trkptEle :: Text, 
    trkptTime :: Text 
    } deriving (Show) 

trkptsFromFile path = 
    gpxTrkpts . fromDocument <$> Text.XML.readFile def path 

gpxTrkpts = 
    child >=> element "{http://www.topografix.com/GPX/1/0}trk" >=> 
    child >=> element "{http://www.topografix.com/GPX/1/0}trkseg" >=> 
    child >=> element "{http://www.topografix.com/GPX/1/0}trkpt" >=> 
    child >=> \e -> do 
    let ele = T.concat $ element "{http://www.topografix.com/GPX/1/0}ele" e >>= descendant >>= content 
    let time = T.concat $ element "{http://www.topografix.com/GPX/1/0}time" e >>= descendant >>= content 
    let lat = T.concat $ attribute "lat" e 
    let lon = T.concat $ attribute "lon" e 
    return $ Trkpt lat lon ele time 

样本GPX文件是here

虽然原始的GPX文件数据都是有效的,但我得到了奇怪的结果,其中解析的文本大部分是空的,有一些零星的实际值。当有实际值时,它只在记录的其中一个字段中。

我很确定我没有正确使用xml-conduit API。我究竟做错了什么?

回答

2

两个问题。首先,名称空间中存在拼写错误;它应该是http://www.topografix.com/GPX/1/1。其次,你最后的Kleisli箭头(\e -> do -- etc.)正在对trkpt元素的子元素进行操作,而不是在trkpt本身。这里是一个gpxTrkpts它应该做你想做的:

gpxTrkpts = 
    child >=> element "{http://www.topografix.com/GPX/1/1}trk" >=> 
    child >=> element "{http://www.topografix.com/GPX/1/1}trkseg" >=> 
    child >=> element "{http://www.topografix.com/GPX/1/1}trkpt" >=> 
    \e -> do 
    let cs = child e 
     ele = T.concat $ cs >>= element "{http://www.topografix.com/GPX/1/1}ele" >>= descendant >>= content 
     time = T.concat $ cs >>= element "{http://www.topografix.com/GPX/1/1}time" >>= descendant >>= content 
     lat = T.concat $ attribute "lat" e 
     lon = T.concat $ attribute "lon" e 
    return $ Trkpt lat lon ele time 
+0

就是这样。谢谢 :) – Ana

2

@duplode指出了问题。这里有更多评论。

  1. 如何使用gpx-conduit package

  2. 下面是一些代码,它可以帮助调试解析问题:

代码:

{-# LANGUAGE OverloadedStrings #-} 
module Lib2 where 

import qualified Data.Text   as T 
import Data.Text (Text) 
import Text.XML 
import Text.XML.Cursor 
import qualified Filesystem.Path.CurrentOS as Path 
import Control.Monad 

showNode (NodeElement e)  = "NodeEement " ++ T.unpack (nameLocalName $ elementName e) 
showNode (NodeInstruction _) = "NodeInstruction ..." 
showNode (NodeContent t)  = "NodeContent " ++ show t 
showNode (NodeComment _)  = "NodeComment" 

testParser parser = do 
    content <- Text.XML.readFile def (Path.decodeString "sample.xml") 
    let nodes = map node $ parser (fromDocument content) 
    forM_ nodes $ \n -> putStrLn (showNode n) 

使用它在这样ghci中:

ghci> :set -XOverloadedStrings 
ghci> :l Lib2 
Lib2> testParser child 
NodeContent "\n " 
NodeEement metadata 
NodeContent "\n " 
NodeEement trk 
NodeContent "\n " 
NodeEement extensions 
NodeContent "\n" 

Lib2> testParser $ child >=> element "trk" 
Lib2> testParser $ child >=> laxElement "trk" 
NodeEement trk 

Lib2> testParser $ child >=> laxElement "trk" >=> child >=> laxElement "trkseg" 
NodeElement trkseg 
Lib2> testParser $ child >=> laxElement "trk" >=> child >=> laxElement "trkseg" >=> child >=> laxElement "trkpt" 
NodeEement trkpt 
NodeEement trkpt 
NodeEement trkpt 
NodeEement trkpt 
Lib2>