XML APIサーバーで使いたい
バックエンドの開発用サーバーを皆に黙って、こっそりYesodで作ろうかと思ってたら、メンテナーがいなくなることが判明し、全員に却下されることとなったが、いつかやってやろうと思っている。
でXML
YesodでXMLを出力する、TemplateHaskellを使うと結構簡単
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Handler.Home where
import Import
import Text.XML
import Text.Hamlet.XML
import qualified Data.Map as M
import qualified Text.XML.Stream.Render as R
getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
provideRep $ return $ repXml $ renderText rs (getXml 10)
getXml :: Int -> Document
getXml n = Document p elm []
where
p = Prologue [] Nothing []
elm = Element "root" M.empty [xml|
<params>
<param>#{pack $ show n}
<param>yyy
|]
rs :: R.RenderSettings
rs = def
Handler部分だけですが、TypedContentとrepXmlでcontent-type/xmlに変えて、Document型を返す関数をrenderText関数へ食わせるだけ。
THとか使わない版
ベタに書くとこんな感じか、オレオレデータをXMLに無理やり変換してるだけ、あまり綺麗じゃないので許してね
{-# LANGUAGE OverloadedStrings #-}
import Text.XML
import qualified Data.Text as T
import qualified Data.Text.Internal as T
import qualified Data.Text.Lazy as L
import qualified Data.Text.Internal.Lazy as L
import qualified Data.Map as M
data Foo = Foo {
identFoo :: Int
, namefoo :: T.Text
, argList :: [Argument]
} deriving(Show)
data Argument = Argument {
nameArg :: T.Text
, dataArg :: Maybe T.Text
} deriving(Show)
data Other = Other {
identOther :: Int
, nameOther :: T.Text
} deriving(Show)
main :: IO ()
main = putStrLn $ T.unpack $ L.toStrict $
renderText (def :: RenderSettings) $ createDoc $ (foos createFoo) ++ (others createOther)
createDoc :: [Node] -> Document
createDoc nodes = Document prlg elem []
where
prlg = Prologue [] Nothing []
elem = Element (Name "root" Nothing Nothing) M.empty nodes
foos :: [Foo] -> [Node]
foos = map (fooNodes)
others :: [Other] -> [Node]
others = map (otherNodes)
node :: Int -> T.Text -> M.Map Name T.Text
node i name = M.fromList [
(Name "id" Nothing Nothing, (T.pack $ show i))
, (Name "name" Nothing Nothing, name)
]
fooNodes :: Foo -> Node
fooNodes f@(Foo i name arg) = NodeElement elem
where
elem = Element n
(node i name)
nodes
n = Name "foo" Nothing Nothing
nodes = map (\(Argument an dt) ->
NodeElement
(Element (Name "argument" Nothing Nothing)
(M.fromList [(Name "name" Nothing Nothing, an)])
(nodeCont dt))
) arg
otherNodes :: Other -> Node
otherNodes o@(Other i name) = NodeElement elem
where
elem = Element n
(node i name)
[]
n = Name "other" Nothing Nothing
nodeCont :: Maybe T.Text -> [Node]
nodeCont (Just val) = [NodeContent val]
nodeCont _ = []
createFoo :: [Foo]
createFoo = [Foo 1 "test" createArgument, Foo 2 "test2" createArguments]
createArgument :: [Argument]
createArgument = [Argument "a" (Just "empty 吉田")]
createArguments :: [Argument]
createArguments = [Argument "b" (Just "エンペラー 吉田"), Argument "c" Nothing]
createOther :: [Other]
createOther = [Other 2 "someother"]
{-
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo id="1" name="test">
<argument name="a">empty 吉田</argument>
</foo>
<foo id="2" name="test2">
<argument name="b">エンペラー 吉田</argument>
<argument name="c"/>
</foo>
<other id="2" name="someother"/>
</root>
-}
とりあえず、吉田さんのとこに上げときます
https://github.com/calimakvo/resp-xml