mkay, so short of bugs, I think I've finished the jscript. I should be able to implement within mIRC in the next day or two

Code
(function (trim, esc) {
    var xml = new ActiveXObject("Msxml2.DOMDocument.6.0");
    xml.async = false;

    // Helper Function: returns the subjects cast type
    function getType(subject) {
        return Object.prototype.toString.call(subject).match(/^\[object (\S+)\]$/)[1].toLowerCase();
    }

    // Helper Function: formats text to be valid YAML
    function yamlTextEscape(text) {

        // Empty string
        if (text === '') {
            return '""';
        }

        // String needs to be quoted:
        //   Starts with: ! & * - ? # | > @ ` " '
        //   Contains: { } [ ] ( ) , : \ / tab carriage-return line-feed
        //   Ends with space
        //   is: void null true false
        if (/(?:^[!&*-?#|>@`"' ])|[{}\[\]\(\),:\\\/\t\r\n]|(?: $)|(?:^(?:void|null|true|false)$)/g.test(text)) {
            return '"' + text.replace(
                /[\\"\u0000-\u001F\u2028\u2029]/g,
                function (chr) {
                    return {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'}[chr] || '\\u' + (chr.charCodeAt(0) + 0x10000).toString(16).substr(1);
                }
            ) + '"';
        }

        // String can be left as-is
        return text;
    }

    // Formats input into valid YAML
    yaml = function (data, indent) {

        // undefined: do nothing
        if (data === undefined) {
            return;
        }

        var type = getType(data),
            key,
            value,
            hasChild,
            prefix,
            result = [];

        // Null, Boolean, Number: convert to string
        if (data === null || data === !!data || (type === 'number' && isFinite(data))) {
            return '' + data;
        }

        // String: escape text
        if (type === 'string') {
            return yamlTextEscape(data);
        }

        // Array
        if (type === 'array') {

            // Generate prefix indent
            prefix = Array(indent + 1).join(' ') + '-';

            // Loop over each item in array
            for (key = 0; key < data.length; key += 1) {

                // Invalid
                if (data[key] === undefined) {
                    continue;
                }

                // Get item and item type
                value = data[key];
                type = getType(value);

                // String
                if (type === 'string') {
                    result.push(prefix + ' ' + yamlTextEscape(value));

                // Null, Boolean, Number: convert to string
                } else if (value === null || value === !!value || (type === 'number' && isFinite(value))) {
                    result.push(prefix + ' ' + value);

                // Array
                } else if (type === 'array') {
                    value = yaml(value, indent + 2);

                    // value is empty array
                    if (value === '[]') {
                        result.push(prefix + ' []');

                    // Value is populated collection
                    } else {
                        result.push(prefix, value);
                    }

                // Collection
                } else if (type === 'object') {
                    value = yaml(value, indent + 2);

                    // value is empty collection
                    if (value === '{}') {
                        result.push(prefix + ' {}');

                    // Value is populated collection
                    } else {
                        result.push(prefix, value);
                    }

                // Unkown type
                } else {
                    continue;
                }

                // Subject array has atleast one valid child
                hasChild = true;
            }

            if (hasChild) {
                return result.join('\n');
            }

            // no valid items in the array
            return '[]';
        }

        // Collection
        if (type === 'object') {

            // Loop over each item in the collection
            for (key in data) {

                // Invalid item
                if (!Object.prototype.hasOwnProperty.call(data, key) || data[key] === undefined) {
                    continue;
                }

                // Get item and item type
                value = data[key];
                type = getType(value);

                // Prepare indent prefix
                prefix = Array(indent + 1).join(' ') + yamlTextEscape(key) + ':';

                // String
                if (type === 'string') {
                    result.push(prefix + ' ' + yamlTextEscape(value));

                // Null, Boolean, Number: convert to string
                } else if (value === null || value === !!value || (type === 'number' && isFinite(value))) {
                    result.push(prefix + ' ' + value);

                // Array
                } else if (type === 'array') {
                    value = yaml(value, indent + 2);

                    // value is empty array
                    if (value === '[]') {
                        result.push(prefix + ' []');

                    // Value is populated collection
                    } else {
                        result.push(prefix, value);
                    }

                // Collection
                } else if (type === 'object') {
                    value = yaml(value, indent + 2);

                    // value is empty collection
                    if (value === '{}') {
                        result.push(prefix + ' {}');

                    // Value is populated collection
                    } else {
                        result.push(prefix, value);
                    }

                // Unkown type
                } else {
                    continue;
                }

                // Subject collection has atleast one valid child
                hasChild = true;
            }

            // Collection has valid items
            if (hasChild) {
                return result.join('\n');
            }

            // empty collection
            return '{}';
        }
    }

    function xmlWalk(node, parent) {

        var text = (node.text === undefined || node.text === null || node.text === '') ? true : node.text,
            result,
            index,
            attr,
            attributes = {};

        // No attributes or children
        if (node.attributes.length === 0 && node.childNodes.length === 0) {
            result = text;

        } else {

            // prep result object
            result = {
                '@value': text
            };

            // Add attributes to result object
            for (
                index = 0;
                index < node.attributes.length;
                index += 1
            ) {
                attr = node.attributes[index];
                result['@@' + attr.nodeName] = attr.text === undefined ? true : attr.text;
            }

            // Add children to result object
            for (
                index = 0;
                index < node.childNodes.length;
                index += 1
            ) {
                child = node.childNodes[index];
                if (child.nodeType === 1) {
                    xmlWalk(child, result);
                }
            }
        }

        // Parent has entry for node
        if (Object.prototype.hasOwnProperty.call(parent, node.nodeName)) {

            // Entry for node is array
            if (getType(parent[node.nodeName]) === 'array') {
                parent[node.nodeName].push(result);

            // Entry for node is not an array
            } else {
                parent[node.nodeName] = [parent[node.nodeName], result];
            }

        // Parent does not have entry for node
        } else {
            parent[node.nodeName] = result;
        }

        return parent;
    }

    // Exposed Function: converts xml into valid yaml
    xml2yaml = function (data) {
        try {
            var loaded = xml.loadXML(data);
        } catch (e) {
            throw new Error('INVALID_XML');
        }
        if (!loaded || xml.documentElement == null) {
            throw new Error('INVALID_XML');
        }
        return yaml(xmlWalk(xml.documentElement, {}), 0);
    };

    // Exposed Function: converts json into valid yaml
    json2yaml = function (data) {
        data = String(data).replace(/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, function(chr) {
            return '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
        });
        if (!/^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
            throw new Error("INVALID_JSON");
        }
        try {
            data = eval('(' + data + ')');
        } catch (e) {
            throw new Error("INVALID_JSON");
        }
        return yaml(data, 0);
    };
}());


/* Uncomment for testing - run with cscript file.js from cmd.exe
WScript.echo(json2yaml('{"key": "value"}'));

WScript.echo(xml2yaml('<node />'));
*/



The format I've gone with:
Code
<root>
    <child1 />
    <child2>text</child2>
    <child3 attr="attr_value" />
    <child4 attr="attr_value">text</child4>
</root>

becomes

root
  child1: true
  child2: text
  child3:
    "@@attr": attr_value
    "@value": true
  child4:
    "@@attr": attr_value
    "@value": text

Last edited by FroggieDaFrog; 11/08/19 08:11 AM.

I am SReject
My Stuff