5

我正在解析一个 XML 文件,HXT并试图将一些节点提取分解为模块化部分(我一直使用它作为我的指南)。不幸的是,一旦我进行了第一级解析,我就无法弄清楚如何应用一些选择器。

 import Text.XML.HXT.Core

 let node tag = multi (hasName tag)
 xml <- readFile "test.xml"
 let doc = readString [withValidate yes, withParseHTML no, withWarnings no] xml
 books <- runX $ doc >>> node "book"

我看到书有一个类型[XmlTree]

 :t books
 books :: [XmlTree]

现在我想获取第一个元素,books然后在子树中提取一些值。

 let b = head(books)
 runX $ b >>> node "cost"

Couldn't match type ‘Data.Tree.NTree.TypeDefs.NTree’
               with ‘IOSLA (XIOState ()) XmlTree’
Expected type: IOSLA (XIOState ()) XmlTree XNode
  Actual type: XmlTree
In the first argument of ‘(>>>)’, namely ‘b’
In the second argument of ‘($)’, namely ‘b >>> node "cost"’

一旦我有了一个,我就找不到选择器,XmlTree并且我展示了上面不正确的用法来说明我想要什么。我知道我可以这样做:

 runX $ doc >>> node "book" >>> node "cost" /> getText
 ["55.9","95.0"]

但我不仅对cost里面的更多元素感兴趣book。XML 文件非常深,所以我不想嵌套所有内容,<+>并且很多评估者更喜欢提取我想要的块,然后在单独的函数中提取子元素。

示例(虚构)XML 文件:

 <?xml version="1.0" encoding="UTF-8"?><start xmlns="http://www.example.com/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <books> 
         <book>
             <author>
                 <name>
                     <first>Joe</first>
                     <last>Smith</last>
                 </name>
                 <city>New York City</city>
             </author>
             <released>1990-11-15</released>
             <isbn>1234567890</isbn>
             <publisher>X Publisher</publisher>
             <cost>55.9</cost>
         </book>
         <book>
             <author>
                 <name>
                     <first>Jane</first>
                     <last>Jones</last>
                 </name>
                 <city>San Francisco</city>
             </author>
             <released>1999-01-19</released>
             <isbn>0987654321</isbn>
             <publisher>Y Publisher</publisher>
             <cost>95.0</cost>
         </book>
     </books>
  </start> 

有人可以帮我理解,如何提取 的子元素book?理想情况下,>>>node可以定义自己的函数,例如getCost,getName等,每个函数都将大致具有签名XmlTree -> [String]

4

1 回答 1

3

doc不是你想的那样。它有类型IOStateArrow s b XmlTree。你真的应该再读一遍你的指南,所有你想知道的都在“避免 IO”的标题下结束。

箭头基本上是函数。SomeArrow a b可以被认为是类型的通用/专用函数a -> b>>>范围内的其他运算符用于箭头组合,类似于函数组合。你books有类型[XmlTree],所以它不是箭头,不能用箭头组成。满足您的需求的是runLA,它将箭头转换node "tag"为正常功能:

module Main where

import           Text.XML.HXT.Core

main = do
  html <- readFile "test.xml"
  let doc = readString [withValidate yes, withParseHTML no, withWarnings no] html
  books <- runX $ doc >>> node "book"
  -- runLA (node "cost" /> getText) :: XmlTree -> [String]
  let costs = books >>= runLA (node "cost" /> getText)
  print costs

node tag = multi (hasName tag)
于 2016-01-25T12:26:57.003 回答