2016-01-25 84 views
4

我正在用HXT解析XML文件,我試圖將某些節點提取分解爲模塊化部分(我一直使用它作爲我的guide)。不幸的是,一旦我進行了第一級解析,我無法弄清楚如何應用一些選擇器。從子樹中提取值

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,所以我可以定義自己的功能,如getCostgetName等每一個大致會具有簽名XmlTree -> [String]

回答

3

doc是不是你認爲它是什麼東西。它有類型IOStateArrow s b XmlTree。你真的應該再次閱讀你的指南,你想知道的只是標題"Avoiding 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) 
+1

感謝@zakyggaps。我試圖在一次只操作一本'book',這似乎工作'[b] >> = runLA(node「cost」/> getText)' – Ecognium