141 lines
3.7 KiB
Text
141 lines
3.7 KiB
Text
|
{-|
|
||
|
Render an `XML` value as `Text`
|
||
|
|
||
|
For indentation and schema validation, see the `xmllint` utility
|
||
|
bundled with libxml2.
|
||
|
|
||
|
```
|
||
|
let XML = ./package.dhall
|
||
|
|
||
|
in XML.render
|
||
|
( XML.element
|
||
|
{ name = "foo"
|
||
|
, attributes = [ XML.attribute "a" "x", XML.attribute "b" (Natural/show 2) ]
|
||
|
, content = [ XML.leaf { name = "bar", attributes = XML.emptyAttributes } ]
|
||
|
}
|
||
|
)
|
||
|
= "<foo a=\"x\" b=\"2\"><bar/></foo>"
|
||
|
```
|
||
|
|
||
|
-}
|
||
|
let XML =
|
||
|
missing
|
||
|
sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9
|
||
|
? ./Type.dhall
|
||
|
|
||
|
let Text/concatMap =
|
||
|
missing
|
||
|
sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f
|
||
|
? ../Text/concatMap.dhall
|
||
|
|
||
|
let Text/concat =
|
||
|
missing
|
||
|
sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0
|
||
|
? ../Text/concat.dhall
|
||
|
|
||
|
let element =
|
||
|
missing
|
||
|
sha256:79266d604e147caf37e985581523b684f7bac66de0c93dd828841df3dfc445f9
|
||
|
? ./element.dhall
|
||
|
|
||
|
let text =
|
||
|
missing
|
||
|
sha256:a59670560a08bfc815893dee1f3eae21a5252400f8a619d1cd7bdd9f48eea2ab
|
||
|
? ./text.dhall
|
||
|
|
||
|
let emptyAttributes =
|
||
|
missing
|
||
|
sha256:11b86e2d3f3c75d47a1d580213d2a03fd2c36d64f3e9b6381de0ba23472f64d5
|
||
|
? ./emptyAttributes.dhall
|
||
|
|
||
|
let Attr = { mapKey : Text, mapValue : Text }
|
||
|
|
||
|
let esc = λ(x : Text) → λ(y : Text) → Text/replace x "&${y};"
|
||
|
|
||
|
let `escape&` = esc "&" "amp"
|
||
|
|
||
|
let `escape<` = esc "<" "lt"
|
||
|
|
||
|
let `escape>` = esc ">" "gt"
|
||
|
|
||
|
let `escape'` = esc "'" "apos"
|
||
|
|
||
|
let `escape"` = esc "\"" "quot"
|
||
|
|
||
|
let escapeCommon = λ(text : Text) → `escape<` (`escape&` text)
|
||
|
|
||
|
let escapeAttr = λ(text : Text) → `escape"` (`escape'` (escapeCommon text))
|
||
|
|
||
|
let escapeText = λ(text : Text) → `escape>` (escapeCommon text)
|
||
|
|
||
|
let renderAttr = λ(x : Attr) → " ${x.mapKey}=\"${escapeAttr x.mapValue}\""
|
||
|
|
||
|
let render
|
||
|
: XML → Text
|
||
|
= λ(x : XML) →
|
||
|
x
|
||
|
Text
|
||
|
{ text = escapeText
|
||
|
, rawText = λ(t : Text) → t
|
||
|
, element =
|
||
|
λ ( elem
|
||
|
: { attributes : List { mapKey : Text, mapValue : Text }
|
||
|
, content : List Text
|
||
|
, name : Text
|
||
|
}
|
||
|
) →
|
||
|
let attribs = Text/concatMap Attr renderAttr elem.attributes
|
||
|
|
||
|
in "<${elem.name}${attribs}"
|
||
|
++ ( if Natural/isZero (List/length Text elem.content)
|
||
|
then "/>"
|
||
|
else ">${Text/concat elem.content}</${elem.name}>"
|
||
|
)
|
||
|
}
|
||
|
|
||
|
let simple =
|
||
|
λ(name : Text) →
|
||
|
λ(content : List XML) →
|
||
|
element { name, attributes = emptyAttributes, content }
|
||
|
|
||
|
let example0 =
|
||
|
assert
|
||
|
: render
|
||
|
( simple
|
||
|
"note"
|
||
|
[ simple "to" [ text "Tove" ]
|
||
|
, simple "from" [ text "Jani" ]
|
||
|
, simple "heading" [ text "Reminder" ]
|
||
|
, simple "body" [ text "Don't forget me this weekend!" ]
|
||
|
]
|
||
|
)
|
||
|
≡ Text/replace
|
||
|
"\n"
|
||
|
""
|
||
|
''
|
||
|
<note>
|
||
|
<to>Tove</to>
|
||
|
<from>Jani</from>
|
||
|
<heading>Reminder</heading>
|
||
|
<body>Don't forget me this weekend!</body>
|
||
|
</note>
|
||
|
''
|
||
|
|
||
|
let example1 =
|
||
|
assert
|
||
|
: render
|
||
|
( element
|
||
|
{ name = "escape"
|
||
|
, attributes = toMap { attribute = "<>'\"&" }
|
||
|
, content = [ text "<>'\"&" ]
|
||
|
}
|
||
|
)
|
||
|
≡ Text/replace
|
||
|
"\n"
|
||
|
""
|
||
|
''
|
||
|
<escape attribute="<>'"&"><>'"&</escape>
|
||
|
''
|
||
|
|
||
|
in render
|