{ pkgs }: let inherit (pkgs) lib; inherit (lib) escapeShellArg filterAttrs hasPrefix attrNames ; inherit (lib.types) nullOr oneOf listOf attrsOf bool int float str path attrs ; in { attribute-prefix ? "@", content-name ? "#text", }: { type = let attrsType = let contentType = attrsOf valueType; attributesType = attrsOf (oneOf [ str path bool int float ]); addCheck = val: let attributes = filterAttrs (name: _: hasPrefix attribute-prefix name) val; contents = filterAttrs (name: _: !hasPrefix attribute-prefix name) val; in attributesType.check attributes && ( if contents ? ${content-name} then attrNames contents == [ content-name ] && str.check contents.${content-name} else contentType.check contents ); in attrs // { check = val: attrs.check val && addCheck val; description = "XML values"; }; valueType = nullOr (oneOf [ bool int float str path attrsType (listOf valueType) ]) // { description = "XML value"; }; in valueType; generate = name: value: pkgs.callPackage ( { runCommand, yq-go }: runCommand name { nativeBuildInputs = [ yq-go ]; value = builtins.toJSON value; passAsFile = [ "value" ]; preferLocalBuild = true; } '' yq \ --xml-attribute-prefix ${escapeShellArg attribute-prefix} \ --xml-content-name ${escapeShellArg content-name} \ --output-format xml \ "$valuePath" > "$out" '' ) { }; }