オブジェクトをJSONテキスト形式に変換する

スキーマの処理を、考えていたら、細かなツールみたいなのが必要だと思い、作り始めた。
しかし、当然のごとく、頭の回転がにぶい。半日も費やしてしまった。^^;
連想配列と配列の判定の仕方がイマイチ。
(new Array (n)).join(' ') で n + 1 に早く気がつけ!>俺

<!DOCTYPE html>
<title></title>
<body>
  <div>
    <textarea id="ta1" rows="30" cols="56">
{
  "@prefix" : {
    "xsd" : "http://www.w3.org/2001/XMLSchema#"
  },
  "name1" : {
    "type" : "xsd:string"
  },
  "name2" : {
    "type" : "xsd:date"
  },
  "name3" : {
    "type" : "xsd:string",
    "pattern" : "/^\s*(?:abc|def)\s*$/i"
  },
  "name4" : {
    "length" : 2,
    "choice" : [
      {
        "type" : "xsd:int",
        "minInclusive" : 10,
        "maxInclusive" : 20
      },
      {
        "type" : "xsd:int",
        "minInclusive" : 21,
        "maxInclusive" : 30
      },
      {
        "type" : "xsd:int",
        "minInclusive" : 31,
        "maxInclusive" : 40
      }
    ]
  }
}
</textarea>
<textarea id="ta2" rows="30" cols="56"></textarea>
  </div>



<script>

var toStringFromJSON = function ( obj, index) {
  var p, key, af,
      ary  = [ ],
      spc  = (new Array ((index = index || 0) + 1)).join (' '),
      spc2 = spc + '  ';
  
  for (key in obj) {
    if ('undefined' === typeof af && '0' === key)
      af = true;
//    af = af || '0' === key; // いまいち
 
    if (obj.hasOwnProperty (key)) {
      switch (typeof (p = obj[ key ])) {
        case 'string':
          p = '"'+ p.replace (/(["'])/g, '\\$1') + '"';
          break;

        case 'boolean':
        case 'number':
          p = p.toString ();
          break;
          
        case 'object':
          p = arguments.callee (p, index + 2);
          break;

        default:
      }

      af ?
        ary.push (spc2 + p):
        ary.push (spc2 + '"' + key + '" : ' + p);
    }
  }
  
  return af ?
    '[\n' + ary.join (',\n') + '\n' + spc + ']':
    '{\n' + ary.join (',\n') + '\n' + spc + '}';
};

//_________________________

document.getElementById('ta2').value =
  toStringFromJSON (
    eval ('(' + document.getElementById ('ta1').value +')'));


</script>