//copyright Ryan Day 2010 <http://ryanday.org>, Joscha Feth 2013 <http://www.feth.com> [MIT Licensed]



var process_to_xml = function(node_data,options){

  var makeNode = function(name, content, attributes, level, hasSubNodes) {

    var indent = options.prettyPrint ? '\n' + new Array(level).join("\t") : '';

    var node = [indent, '<',name, (attributes || '')];
    if(content && content.length > 0) {
      node.push('>')
      node.push(content);
      hasSubNodes && node.push(indent);
      node.push('</');
      node.push(name);
      node.push('>');
    } else {
      node.push('/>');
    }
    return node.join('');
  };

  return (function fn(node_data,node_descriptor, level){
    var type = typeof node_data;
    if(node_data instanceof Array) {
      type = 'array';
    } else if(node_data instanceof Date) {
      type = 'date';
    }

    switch(type) {
    //if value is an array create child nodes from values
      case 'array':
        var ret = [];
        node_data.map(function(v){
            ret.push(fn(v,1, level+1));
            //entries that are values of an array are the only ones that can be special node descriptors
        });
        ret.push('\n');
        return ret.join('');
        break;

      case 'date':
        // cast dates to ISO 8601 date (soap likes it)
        return node_data.toJSON?node_data.toJSON():node_data+'';
        break;

      case 'object':
        if(node_descriptor == 1 && node_data.name){
          var content = []
          , attributes = []
          ;

          if(node_data.attrs) {
            if(typeof node_data.attrs != 'object') {
            // attrs is a string, etc. - just use it as an attribute
              attributes.push(' ');
              attributes.push(node_data.attrs);
            } else {
              for(var key in node_data.attrs){
                var value = node_data.attrs[key];
                attributes.push(' ');
                attributes.push(key);
                attributes.push('="')
                attributes.push(options.escape ? esc(value) : value);
                attributes.push('"');
              }
            }
          }

          //later attributes can be added here
          if(node_data.text || node_data.value) { 
            var c = (node_data.value || '')+(node_data.text || '');
            content.push(options.escape ? esc(c) : c);
          }

          if(node_data.children){
            content.push(fn(node_data.children,0,level+1));
          }

          return makeNode(node_data.name, content.join(''), attributes.join(''),level,!!node_data.children);

        } else {
          var nodes = [];
          for(var name in node_data){
            nodes.push(makeNode(name, fn(node_data[name],0,level+1),null,level+1));
          }
          nodes.length > 0 && nodes.push('\n');
          return nodes.join('');
        }
        break;

      case 'function':
        return node_data();
        break;

      default:
        return options.escape ? esc(node_data) : node_data;
    }

  }(node_data, 0, 0))
};


var xml_header = function(standalone) {
  var ret = ['<?xml version="1.0" encoding="utf-8"'];

  if(standalone) {
    ret.push(' standalone="true"');
  }
  
  ret.push('?>');

  return ret.join('');
};

module.exports = function(obj,options){

  if(typeof obj == 'string' || obj instanceof Buffer) {
    try{
      obj = JSON.parse(obj.toString());
    } catch(e){
      return false;
    }
  }

  var xmlheader = '';
  var docType = '';
  if(options) {
    if(typeof options == 'object') {
      // our config is an object

      if(options.xmlHeader) {
        // the user wants an xml header
        xmlheader = xml_header(!!options.xmlHeader.standalone);
      }

      if(typeof options.docType != 'undefined') {
        docType = '<!DOCTYPE '+options.docType+'>'
      }
    } else {
      // our config is a boolean value, so just add xml header
      xmlheader = xml_header();
    }
  }
  options = options || {}

  var ret = [
    xmlheader,
    (options.prettyPrint && docType ? '\n' : ''),
    docType,
    process_to_xml(obj,options)
  ];

  return ret.join('');
}

module.exports.json_to_xml= 
module.exports.obj_to_xml = module.exports;

module.exports.escape = esc;

function esc(str){
  if(!str.replace) {
    return str;
  } else {
    return str.replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
  }
}

module.exports.cdata = cdata;

function cdata(str){
  return "<!CDATA[["+str.replace(/]]>/g,'')+']]>';
};




@@ -3013,16 +3013,19 @@
 data) : 
+''+
 node_dat
@@ -4268,68 +4268,23 @@
 %7B%0A  
-if(!str.replace) %7B%0A    return str;%0A  %7D else %7B%0A    return str
+return (''+str)
 .rep
@@ -4299,26 +4299,24 @@
 g, '&amp;')%0A
-  
       .repla
@@ -4330,34 +4330,32 @@
 , '&lt;')%0A      
-  
 .replace(/%3E/g, '
@@ -4357,26 +4357,24 @@
 /g, '&gt;')%0A
-  
       .repla
@@ -4393,20 +4393,16 @@
 uot;');%0A
-  %7D%0A
 %7D%0A%0Amodul

fix for stringifying and escaping arbitrary objects.