{nixpkgs, ...}: { toXMLGeneric = let toXMLRecursive = toXmlRecursive' "\n" 0; indent = depth: ( if (depth <= 0) then "" else (" " + (indent (depth - 1))) ); toXmlRecursive' = str: depth: xml: let parseTag = str: depth: xml: (builtins.concatStringsSep "" [ str "${indent depth}<${xml.tag}${ if !(builtins.hasAttr "content" xml) || (((builtins.isString xml.content) && xml.content == "") || ((builtins.isList xml.content) && ((builtins.length xml.content) == 0))) then "" else ">" }" ( if (builtins.hasAttr "attrib" xml) then (" " + builtins.concatStringsSep " " (nixpkgs.lib.attrsets.mapAttrsToList (name: value: "${name}=\"${nixpkgs.lib.strings.escapeXML value}\"") xml.attrib)) else "" ) ( if !(builtins.hasAttr "content" xml) || (((builtins.isString xml.content) && xml.content == "") || ((builtins.isList xml.content) && ((builtins.length xml.content) == 0))) then " />" else ((toXmlRecursive' "\n" (depth + 1) xml.content) + "") ) ]); in if (builtins.isAttrs xml) then "${parseTag str depth xml}\n${indent (depth - 1)}" else if (builtins.isList xml) then "\n${(builtins.concatStringsSep "" (builtins.map (x: (toXmlRecursive' "" depth x)) xml))}${indent (depth - 1)}" else if ((builtins.isInt xml) || (builtins.isNull xml) || (builtins.isFloat xml)) then (builtins.toString xml) else if (builtins.isString xml) then xml else if (builtins.isBool xml) then if xml then "true" else "false" else throw "Cannot convert a ${builtins.typeOf xml} to XML. ${toString (builtins.trace xml xml)}"; in toXMLRecursive; }