跳轉到內容

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
華夏公益教科書