xml - 为什么 parsecs "choice"组合器似乎停留在第一选择上?

标签 xml parsec haskell

在查看 Real World Haskell 中的 CSV 示例代码后,我尝试构建一个小型 XML 解析器。但是关闭标签会出现“意外的“/””错误。你能告诉我为什么我的“closeTag”解析器不起作用(或者可能从未被调用过)吗?谢谢!

import Text.ParserCombinators.Parsec

xmlFile = manyTill line eof
line = manyTill tag eol
eol = char '\n'

word = many1 (noneOf "></")

tag = choice [openTag, closeTag, nullTag, word]

nullTag = between (char '<') (string "/>") word
closeTag = between (string "</") (char '>') word
openTag = between (char '<') (char '>')  tagContent
attrval = between (char '"') (char '"') word

atts = do {
        (char ' ')
        ; sepBy attr (char ' ')
}

attr = do {
                word
                ; char '='
                ; attrval
        }

tagContent = do {
                w <- word
                ; option []  atts
                ; return w
        }

parseXML :: String -> Either ParseError [[String]]
parseXML input = parse xmlFile "(unknown)" input

main =
    do c <- getContents
       case parse xmlFile "(stdin)" c of
            Left e -> do putStrLn "Error parsing input:"
                         print e
            Right r -> mapM_ print r

最佳答案

Parsec 的策略本质上是 LL(1),这意味着无论何时消耗任何输入,它都会“提交”到当前分支。你的openTag解析器使用 <及其 char '<' ,这意味着如果它看到 >而不是 / ,整个解析失败而不是尝试新的选择。如果openTag没有消耗任何输入并失败,将尝试另一种选择。 Parsec 这样做是为了提高效率(替代方案是指数时间!)和合理的错误消息。

您有两个选择。在合理的情况下,首选的选择是考虑语法,以便在不消耗输入的情况下做出所有选择,例如:

tag = word <|> (char '<' >> tagbody)
    where
    tagbody = do
        content <- tagcontent
        choice [ string "/>", char '>' ]

模数错误和风格(此刻我的大脑有点炸了:-P)。

另一种方法是使用 try 来本地更改 parsec 的语义(以上述错误消息和效率为代价——但通常不会太糟糕,因为它是本地的)。组合器,它允许解析器使用输入并仍然“温和地”失败,因此可以尝试另一种选择:

nulltag = try $ between (char '<') (string "/>") word
-- etc.

有时使用 try 比上面的因式分解更简洁、更容易,后者会掩盖语言的“深层结构”。这是一种风格上的权衡。

关于xml - 为什么 parsecs "choice"组合器似乎停留在第一选择上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5697922/

相关文章:

haskell - 是否有用于编写词法分析器的 haskell EDSL?

haskell - 将 [Int] 转换为 [Word8]

python 2.7 : type object "ElementTree" has no attribute "register_namespace"

xml - 通过 Delphi XML 数据绑定(bind)向导使用 XML 枚举

haskell - 连接解析结果

haskell - 应用式秒差距的问题

haskell - 埃拉托斯特尼筛无限列表

haskell - GHCi 错误 - "Not in scope: ` isUpper'"

xml - 使用vbscript读取xml文件

java - 使用子元素的 JAXB 注释