diff options
author | jeschli <jeschli@gmail.com> | 2019-03-21 20:09:09 +0100 |
---|---|---|
committer | jeschli <jeschli@gmail.com> | 2019-03-21 20:09:09 +0100 |
commit | 34bec52f303b0db7af47ae06605ef2bbbcc6b303 (patch) | |
tree | 12b029aee9f63dc2b0b70c280450c240f4183f28 /lib/xml.nix | |
parent | a670535cb361a1019034d078c7dc13bc058b5081 (diff) | |
parent | db8d53cefd8f3fae0b48d5a7d175833c8ea408fe (diff) |
Merge branch 'master' of prism.r:stockholm into new-master
Diffstat (limited to 'lib/xml.nix')
-rw-r--r-- | lib/xml.nix | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/xml.nix b/lib/xml.nix new file mode 100644 index 0000000..1605244 --- /dev/null +++ b/lib/xml.nix @@ -0,0 +1,88 @@ +{ lib }: +with lib; +with builtins; +rec { + + # Use `term` to construct XML. + # + # Examples: + # + # (term "bool" null null) + # (term "cool" null []) + # (term "fool" { hurr = "durr"; } null) + # (term "hool" null [ + # (term "tool" null null) + # ]) + # + # See `render` for how these get transformed into actuall XML documents. + # + term = name: attrs: content: { + inherit name attrs content; + }; + + empty = term null null null; + + # Ref http://www.w3.org/TR/xml/#syntax + # + # Example: + # + # (quote "<cheez!>") #===> <cheez!> + # + quote = let + sub = { + "&" = "&"; + "<" = "<"; + ">" = ">"; + "'" = "'"; + "\"" = """; + }; + in + stringAsChars (c: sub.${c} or c); + + # Turn an XML element to an XML document string. + doc = t: + "<?xml version='1.0' encoding='UTF-8'?>${render t}"; + + # Render an XML element to a string. + # + # Rendering `empty` yields the empty string. + # + # Examples: + # + # (term "bool" null null) #===> <bool/> + # (term "cool" null []) #===> <cool></cool> + # (term "fool" { hurr = "durr"; } null) #===> <fool hurr="durr"/> + # (term "hool" null [ + # (term "tool" null null) + # ]) #===> <hool><tool/></hool> + # + render = let + render-attrs = attrs: + getAttr (typeOf attrs) { + null = ""; + set = concatStrings (mapAttrsToList (n: v: " ${n}=\"${v}\"") attrs); + }; + + render-content = content: + getAttr (typeOf content) { + bool = toJSON content; + int = toJSON content; + list = concatMapStrings render content; + string = quote content; + }; + in + { name, attrs, content }: + # XXX we're currently encoding too much information with `null`.. + if name == null + then + if content == null + then "" + else content + else let + attrs' = render-attrs attrs; + content' = render-content content; + in + if content == null + then "<${name}${attrs'}/>" + else "<${name}${attrs'}>${content'}</${name}>"; +} |