如何在Hxt程序上正确收集命令行选项?

时间:2012-03-15 12:17:45

标签: haskell command-line xml-parsing hxt

我已经达到了论文的第3部分。 Haskell XML工具箱的食谱,以及M. Ohlendorf的处理RDF文档的示例

这是我写的程序,

import Text.XML.HXT.Core
import System.Exit
import System.Environment
import Data.Maybe

main = do
  args       <- getArgs
  (al, src)  <- cmdLineOpts args
  [rc]       <- runX (processDocument al src)
  exitWith ( if rc >= c_err
             then ExitFailure (-1)
             else ExitSuccess
           )

cmdLineOpts :: [String] -> IO (Attributes, String)
cmdLineOpts []  = return ([("","")], "")
cmdLineOpts xss = return (zip [""] xss :: Attributes, last xss)

processDocument :: Attributes -> String -> IOSArrow b Int
processDocument al src =
    readDocument al src -- lecture du document en appliquant les attributes                                                                                            
    >>>
    removeAllWhiteSpace >>> propagateNamespaces
    >>>
    writeDocument al (fromMaybe "" (lookup a_output_file al))
    >>>
    getErrStatus

但我仍然会遇到以下错误

hxtuto.hs:28:17:
    Couldn't match expected type `XIOSysState -> XIOSysState'
           against inferred type `(String, String)'
      Expected type: SysConfigList
      Inferred type: Attributes
    In the first argument of `readDocument', namely `al'
    In the first argument of `(>>>)', namely `readDocument al src'
Failed, modules loaded: none.

似乎我cmdLineOpts的实现并不合适。

这是什么问题?我该如何解决?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

由于readDocument和writeDocument的第一个参数是[SysConfig],您可能希望使用像GetOpt这样的包来处理从命令行读取文本并将其转换为所需对象的内务处理。我从论文的第50页获取了“可用选项”列表,并使用当前的相应SysConfigs(来自Text.XML.HXT.Arrow.XmlState.SystemConfig)创建了一个Options类型。除了为特定应用程序定制的部件外,其余部分(例如cmdLineOpts)直接取自GetOpt文档。

import System.Console.GetOpt
import System.Environment
import System.Exit 
import Text.XML.HXT.Core

data Options = Options {
    withvalidate :: SysConfig
  , withchecknamespaces :: SysConfig
  , withcanonicalize :: SysConfig
  , withremovews :: SysConfig
  , withtrace :: SysConfig
  , output_file :: String } 

defaultOptions = Options { withvalidate = (withValidate no)
                         , withchecknamespaces = (withCheckNamespaces no)
                         , withcanonicalize = (withCanonicalize no)
                         , withremovews = (withRemoveWS no)
                         , withtrace = (withTrace 0)
                         , output_file = "" } 

options :: [OptDescr (Options -> Options)]
options =
 [ Option ['V'] ["withValidate"] 
   (ReqArg (\v opts -> opts { withvalidate = withValidate (v == "yes") } ) "") 
   "perform DTD validation"
 , Option ['n'] ["withCheckNamespaces"] 
   (ReqArg (\n opts -> opts { withchecknamespaces = withCheckNamespaces (n == "yes") } ) "")
   "check namespaces"
 , Option ['c'] ["withCanonicalize"] 
   (ReqArg (\c opts -> opts { withcanonicalize = withCanonicalize (c == "yes") } ) "")
   "canonicalize document"
 , Option ['w'] ["withRemoveWS"] 
   (ReqArg (\w opts -> opts { withremovews = withRemoveWS (w == "yes") } ) "")
   "remove whitespace used for document indentation"
 , Option ['t'] ["withTrace"] 
   (ReqArg (\t opts -> opts { withtrace = withTrace (read t) } ) "")
   "set trace level" 
 , Option ['o'] ["outputFile"] 
   (ReqArg (\o opts -> opts { output_file = o } ) "") 
   "output file" ]

cmdLineOpts :: [String] -> IO (Options, [String])
cmdLineOpts argv =
    case getOpt Permute options argv of
      (o, n, []) -> return (foldl (flip id) defaultOptions o, n)
      (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options))
    where header = "Using: [OPTION ...]"

main :: IO ()
main = do (opts, (src:_)) <- cmdLineOpts =<< getArgs 
          [rc] <- runX $ processDocument opts src
          exitWith $ if rc >= c_err then ExitFailure (-1) else ExitSuccess

processDocument :: Options -> String -> IOSArrow b Int
processDocument (Options val ns can ws tr out) src =
    readDocument [val, ns, can, ws, tr] src >>> 
    removeAllWhiteSpace >>> propagateNamespaces >>>
    writeDocument [val, ns, can, ws, tr] out >>>
    getErrStatus