diff options
author | lassulus <lassulus@lassul.us> | 2019-02-16 17:38:03 +0100 |
---|---|---|
committer | lassulus <lassulus@lassul.us> | 2019-02-16 17:38:03 +0100 |
commit | 2db5d56cf2e252822f38900ef9436d7b118476a9 (patch) | |
tree | eacbc9a6e9d0a57df85df138d6d14d725af8072e /lib/xml.nix | |
parent | 5845742ae0770bae3c341d2d7eacb4ccc05245c9 (diff) | |
parent | 270ceb7676e867c9dff5f5faa765666b58aaa371 (diff) |
Merge remote-tracking branch 'ni/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}>"; +} |