I'm looking for a way to generate XML like in the example below, but the existing XML libraries don't provide adequate documentation for me to understand how to use them to generate XML. I can find plenty of XML-generating libraries, but none with a simple example which says: here's how to generate this XML.
The Blaze and Lucid libraries are great for generating HTML, for example. Let's say you want to make this HTML:
<emph class="foo">bar</emph>
Using Lucid, you would write:
emph_ [class_ "foo"] "bar"
So what's a good way to do this with XML? I've been looking through the API documentation for, for instance, HaXml. But I can't find many tutorials about using those packages.
I did see that Yesod's Hamlet quasi-quoter is a very succinct way of generating XML. But I don't like the idea of quasi-quoting up a new schema, since it doesn't seem as maintable, and seems like learning a new language. So I'm hoping to find something more modular, and composable, like Blaze and Lucid.
Edit: To explain further, the problem is not a lack of Haskell XML libraries, or knowing which one to use. It's knowing how to use one (any of them) to generate XML. For instance, I know I can generate the HTML code <html>foo</html>
using Lucid's html_ "foo". But how can I do that for XML?
Here's a pseudo-Haskell example of what I'm trying to do:
Objective: generate the following XML:
<foo attribute="something">
<bar>
<foobar>
<barfoo>
something here
</barfoo>
</foobar>
</bar>
</foo>
Pseudo-Haskell:
foo_ [attribute_ "bar"] $ bar_ $ foobar_ $ barfoo_ "something here"
At the start of the Yesod Book documentation on xml-hamlet, they show how to generate XML using the Text.XML
API from xml-conduit
. So, literally, the "way you use (any of them) to generate XML" is:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import qualified Data.Text.Lazy.IO as Text
import qualified Data.Map as Map
import Text.XML
myFoo = Element "foo" [("attribute", "something")]
[ NodeElement $ Element "bar" []
[ NodeElement $ Element "foobar" []
[ NodeElement $ Element "barfoo" []
[ NodeContent "something here" ]]]]
main = Text.putStrLn $ renderText def $ Document (Prologue [] Nothing []) myFoo []
giving:
> main
<?xml version="1.0" encoding="UTF-8"?><foo attribute="something">
<bar><foobar><barfoo>something here</barfoo></foobar></bar></foo>
The main issue is syntax, but it's really not that difficult to write your own lucid-like DSL using plain Haskell functions. If you want a completely flexible syntax that's schema agnostic, you could write:
-- helpers
attr_ = (,)
element_ nam attrs bdy = NodeElement $ Element nam (Map.fromList attrs) bdy
text_ = NodeContent
-- elements
foo_ = element_ "foo"
bar_ = element_ "bar"
foobar_ = element_ "foobar"
barfoo_ = element_ "barfoo_"
-- attributes
attribute_ = attr_ "attribute"
-- used to unwrap a top level Node to an Element
unNode (NodeElement x) = x
myFoo = unNode $
foo_ [attribute_ "something"] $
[ bar_ []
[ foobar_ []
[ barfoo_ []
[ text_ "something here" ]]]]
main = Text.putStrLn $ renderText def $ Document (Prologue [] Nothing []) myFoo []
Usually the syntax can be simplified by considering your (informal) schema. If barfoos have no attributes and can only contain a block of text, then you write:
barfoo_ txt = element_ "barfoo" [] [text_ txt]
and use it as barfoo_ "something here"
instead.
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加