跳转到内容

Haskell/XML

来自维基教科书,开放世界中的开放书籍

有几个用于 XML 工作的 Haskell 库,以及一些用于 HTML 的额外库。对于更多与 Web 相关的作品,你可能想参考 Haskell/Web 编程 章节。

用于解析 XML 的库

[编辑 | 编辑源代码]
  • Haskell XML 工具箱 (hxt) 是一组用于解析 XML 的工具,旨在比其他工具采用更通用的方法。
  • HaXml 是一组用于使用 Haskell 解析、过滤、转换和生成 XML 文档的实用程序。
  • HXML 是一种非验证、惰性、空间效率高的解析器,可以用作 HaXml 的直接替换。
  • xml-conduit 提供用于 XML 的解析和渲染功能。有关教程,请参见 [1]

用于生成 XML 的库

[编辑 | 编辑源代码]
  • HSXML 将 XML 文档表示为静态类型安全的 s 表达式。

其他选项

[编辑 | 编辑源代码]
  • tagsoup 是一个用于解析非结构化 HTML 的库,即它不假设数据的有效性或良好格式。

熟悉 HXT

[编辑 | 编辑源代码]

在下文中,我们将使用 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
华夏公益教科书