module Text.XRDS (
XRDS, XRD
, Service(..)
, isUsable
, hasType
, parseXRDS
) where
import Control.Arrow
import Control.Monad
import Data.List
import Data.Maybe
import Text.XML.Light
type XRDS = [XRD]
type XRD = [Service]
data Service = Service
{ serviceTypes :: [String]
, serviceMediaTypes :: [String]
, serviceURIs :: [String]
, serviceLocalIDs :: [String]
, servicePriority :: Maybe Int
, serviceExtra :: [Element]
} deriving Show
isUsable :: XRDS -> Bool
isUsable = not . null . concat
tag :: String -> Element -> Bool
tag n el = qName (elName el) == n
findAttr' :: (QName -> Bool) -> Element -> Maybe String
findAttr' p el = attrVal `fmap` find (p . attrKey) (elAttribs el)
readMaybe :: Read a => String -> Maybe a
readMaybe str = case reads str of
[(x,"")] -> Just x
_ -> Nothing
getText :: Element -> String
getText el = case elContent el of
[Text cd] -> cdData cd
_ -> []
hasType :: String -> Service -> Bool
hasType ty svc = ty `elem` serviceTypes svc
parseXRDS :: String -> Maybe XRDS
parseXRDS str = do
doc <- parseXMLDoc str
let xrds = filterChildren (tag "XRD") doc
return $ map parseXRD xrds
parseXRD :: Element -> XRD
parseXRD el =
let svcs = filterChildren (tag "Service") el
in mapMaybe parseService svcs
parseService :: Element -> Maybe Service
parseService el = do
let vals t x = first (map getText) $ partition (tag t) x
(tys,tr) = vals "Type" (elChildren el)
(mts,mr) = vals "MediaType" tr
(uris,ur) = vals "URI" mr
(lids,rest) = vals "LocalID" ur
priority = readMaybe =<< findAttr' (("priority" ==) . qName) el
guard $ not $ null tys
return $ Service { serviceTypes = tys
, serviceMediaTypes = mts
, serviceURIs = uris
, serviceLocalIDs = lids
, servicePriority = priority
, serviceExtra = rest
}