2009-03-17 69 views
7

Nếu tôi có một tài liệu XML như thế này:Trong Haskell, làm thế nào để bạn trích xuất các chuỗi từ một tài liệu XML?

<root> 
    <elem name="Greeting"> 
    Hello 
    </elem> 
    <elem name="Name"> 
    Name 
    </elem> 
</root> 

và một số Haskell định nghĩa kiểu/dữ liệu như thế này:

type Name = String 
type Value = String 
data LocalizedString = LS Name Value 

và tôi muốn viết một hàm Haskell với chữ ký sau đây:

getLocalizedStrings :: String -> [LocalizedString] 

nơi tham số đầu tiên là văn bản XML và giá trị trả lại là:

[LS "Greeting" "Hello", LS "Name" "Name"] 

Tôi làm cách nào để thực hiện việc này?

Nếu HaXml là công cụ tốt nhất, tôi sẽ sử dụng HaXml như thế nào để đạt được mục tiêu trên?

Cảm ơn!

Trả lời

5

Tôi chưa bao giờ thực sự bực mình để tìm ra cách trích xuất các bit ra khỏi tài liệu XML bằng cách sử dụng HaXML; HXT đã đáp ứng tất cả nhu cầu của tôi.

{-# LANGUAGE Arrows #-} 
import Data.Maybe 
import Text.XML.HXT.Arrow 

type Name = String 
type Value = String 
data LocalizedString = LS Name Value 

getLocalizedStrings :: String -> Maybe [LocalizedString] 
getLocalizedStrings = (.) listToMaybe . runLA $ xread >>> getRoot 

atTag :: ArrowXml a => String -> a XmlTree XmlTree 
atTag tag = deep $ isElem >>> hasName tag 

getRoot :: ArrowXml a => a XmlTree [LocalizedString] 
getRoot = atTag "root" >>> listA getElem 

getElem :: ArrowXml a => a XmlTree LocalizedString 
getElem = atTag "elem" >>> proc x -> do 
    name <- getAttrValue "name" -< x 
    value <- getChildren >>> getText -< x 
    returnA -< LS name value 

Bạn muốn có lẽ giống như một chút nữa kiểm tra lỗi (tức là không chỉ lười biếng sử dụng atTag như tôi; thực sự xác minh rằng <root> là root, <elem> là hậu duệ trực tiếp, vv) nhưng điều này chỉ hoạt động tốt trên ví dụ của bạn.


Bây giờ, nếu bạn cần một giới thiệu về Arrow s, tiếc là tôi không biết về bất kỳ một tốt. Bản thân tôi đã học được nó là "ném xuống đại dương để học bơi".

Cái gì đó có thể hữu ích cần lưu ý là cú pháp proc/-< chỉ đơn giản là đường cho các hoạt động cơ bản mũi tên (arr, >>>, vv), giống như do/<- chỉ đơn giản là đường cho các hoạt động đơn nguyên cơ bản (return, >>=, v.v.). Sau đây là tương đương:

getAttrValue "name" &&& (getChildren >>> getText) >>^ uncurry LS 

proc x -> do 
    name <- getAttrValue "name" -< x 
    value <- getChildren >>> getText -< x 
    returnA -< LS name value 
+0

Cảm ơn bạn rất nhiều vì một câu trả lời rất nhiều thông tin! –

+0

Có một hướng dẫn HXT tại http://www.haskell.org/haskellwiki/HXT, nhưng nó không ngừng miễn phí, vì vậy việc hiểu cách điều này liên quan đến việc ghi chú mũi tên (như trong ví dụ trên) là không dễ dàng . –

2

FWIW, HXT có vẻ như quá mức cần thiết, nơi một TagSoup đơn giản sẽ làm :)

1

Dưới đây là thứ hai nỗ lực của tôi (sau khi nhận được một số đầu vào tốt từ người khác) với TagSoup:

Lần thử đầu tiên trình bày một phương pháp ngây thơ (và bị lỗi) để cắt bớt khoảng trống của chuỗi.

+0

TagSoup vui vẻ chấp nhận đầu vào không đúng định dạng - mà bạn có thể thực sự thích :) - tiếc là IMO giải pháp này khó đọc hơn. Nit nhỏ: Tôi đã mong đợi một cái gì đó giống như 'trimWhiteSpace = dropWhile isSpace. đảo ngược . dropWhile isSpace. đảo ngược'; của bạn giống như 'removeAllWhiteSpace'. – ephemient

+0

Cảm ơn ephemient. Tôi nên có một số dữ liệu mẫu tốt hơn. :) Tôi sẽ phải đảm bảo rằng không gian bị loại bỏ khỏi dòng mới vì tôi đã có một số dòng mới được nhúng trong XML của mình. –

+0

Chỉ cần thử cho chính mình: gõ 'Data.Char.isSpace '\ n'' vào GHCi. Có, dòng mới là, và luôn luôn có, khoảng trắng. My nit không phải là về điều đó, nhiều hơn dọc theo dòng của bạn 'trimWhiteSpace" một b c "==" abc "' đó là không trực quan với tôi. Hoặc có lẽ tôi là lạ. – ephemient

3

Sử dụng một trong các gói XML.

phổ biến nhất là, theo thứ tự,

  1. haxml
  2. hxt
  3. xml-ánh sáng
  4. hexpat
Các vấn đề liên quan