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 | a045a7f054859efcb40baf8ded13bcb7fd706d01 (patch) | |
tree | df23b0d31db9fc0b0087f4d5d4c7b3dd7a88b44c /lib/xml.nix | |
parent | ed499a84a9fe067c80e5a4768482333863c1e9ad (diff) | |
parent | 550faa1f64434951cd3949bc96a25012349f0090 (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 000000000..16052445b --- /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}>"; +} |