Haskell/XML
外观
< Haskell
有几个用于 XML 工作的 Haskell 库,以及一些用于 HTML 的额外库。对于更多与 Web 相关的作品,你可能想参考 Haskell/Web 编程 章节。
- Haskell XML 工具箱 (hxt) 是一组用于解析 XML 的工具,旨在比其他工具采用更通用的方法。
- HaXml 是一组用于使用 Haskell 解析、过滤、转换和生成 XML 文档的实用程序。
- HXML 是一种非验证、惰性、空间效率高的解析器,可以用作 HaXml 的直接替换。
- xml-conduit 提供用于 XML 的解析和渲染功能。有关教程,请参见 [1]。
- HSXML 将 XML 文档表示为静态类型安全的 s 表达式。
- tagsoup 是一个用于解析非结构化 HTML 的库,即它不假设数据的有效性或良好格式。
在下文中,我们将使用 Haskell XML 工具箱作为我们的示例。你应该有一个工作正常的 GHC 安装,包括 GHCi,并且你应该根据 说明 下载并安装 HXT。
有了这些,我们就可以开始使用 HXT 了。让我们将 XML 解析器引入作用域,并解析一个简单的 XML 格式字符串
Prelude> :m + Text.XML.HXT.Parser.XmlParsec Prelude Text.XML.HXT.Parser.XmlParsec> xread "<foo>abc<bar/>def</foo>" [NTree (XTag (QN {namePrefix = "", localPart = "foo", namespaceUri = ""}) []) [NTree (XText "abc") [],NTree (XTag (QN {namePrefix = "", localPart = "bar", namespaceUri = ""}) []) [],NTree (XText "def") []]]
我们看到 HXT 将 XML 文档表示为树列表,其中节点可以构造为包含子树列表的 XTag,或包含字符串的 XText。使用 GHCi,我们可以更详细地探索这一点
Prelude> :m + Data.Tree.NTree.TypeDefs Prelude Text.XML.HXT.Parser.XmlParsec Text.XML.HXT.DOM> :i NTree data NTree a = NTree a (NTrees a) -- Defined in Data.Tree.NTree.TypeDefs Prelude Text.XML.HXT.Parser.XmlParsec Text.XML.HXT.DOM> :i NTrees type NTrees a = [NTree a] -- Defined in Data.Tree.NTree.TypeDefs
正如我们所见,NTree 是一种通用的树结构,其中节点在其列表中存储其子节点,并且更多浏览将告诉我们 XML 文档是基于 XNode 类型的树,定义为
data XNode = XText String | XCharRef Int | XEntityRef String | XCmt String | XCdata String | XPi QName XmlTrees | XTag QName XmlTrees | XDTD DTDElem Attributes | XAttr QName | XError Int String
回到我们的示例,我们注意到虽然 HXT 成功解析了我们的输入,但人们可能希望为人类消费提供更清晰的表示。幸运的是,DOM 模块提供了这一点。请注意,xread 返回一个树列表,而格式化函数作用于单个树。
Prelude Text.XML.HXT.Parser.XmlParsec> :m + Text.XML.HXT.DOM.FormatXmlTree Prelude Text.XML.HXT.Parser.XmlParsec Text.XML.HXT.DOM> putStrLn $ formatXmlTree $ head $ xread "<foo>abc<bar/>def</foo>" ---XTag "foo" | +---XText "abc" | +---XTag "bar" | +---XText "def"
这种表示使结构变得明显,并且很容易看到它与我们的输入字符串的关系。让我们继续用一些属性扩展我们的 XML 文档(当然要小心地转义引号)
Prelude Text.XML.HXT.Parser.XmlParsec> xread "<foo a1=\"my\" b2=\"oh\">abc<bar/>def</foo>" [NTree (XTag (QN {namePrefix = "", localPart = "foo", namespaceUri = ""}) [NTree (XAttr (QN {namePrefix = "", localPart = "a1", namespaceUri = ""})) [NTree (XText "my") []],NTree (XAttr (QN {namePrefix = "", localPart = "b2", namespaceUri = ""})) [NTree (XText "oh") []]]) [NTree (XText "abc") [],NTree (XTag (QN {namePrefix = "", localPart = "bar", namespaceUri = ""}) []) [],NTree (XText "def") []]]
请注意,属性作为具有 XAttr 内容类型的常规 NTree 节点存储,并且(当然)没有子节点。随意像上面那样对该表达式进行美化打印。
对于数据提取的简单示例,请考虑使用 XPath 的这个小示例
Prelude> :set prompt "> " > :m + Text.XML.HXT.Parser.XmlParsec Text.XML.HXT.XPath.XPathEval > let xml = "<foo><a>A</a><c>C</c></foo>" > let xmltree = head $ xread xml > let result = getXPath "//a" xmltree > result > [NTree (XTag (QN {namePrefix = "", localPart = "a", namespaceUri = ""}) []) [NTree (XText "A") []]] > :t result > result :: NTrees XNode