使用 Node.js 反序列化奇怪的查询字符串

Deserialize strange querystring with Node.js

我有以下字符串并想将其反序列化为一个对象:

responseEnvelope.timestamp=2015-07-06T15%3A20%3A49.534-07%3A00
&responseEnvelope.ack=Failure&responseEnvelope.correlationId=a58a06c1000d8
&responseEnvelope.build=15743565&error(0).errorId=520003&error(0).domain=PLATFORM
&error(0).subdomain=Application&error(0).severity=Error&error(0).category=Application

(顺便说一句 - 这是使用经典 API 的 PayPal 自适应支付的响应) https://developer.paypal.com/webapps/developer/docs/classic/api/adaptive-payments/Pay_API_Operation/

使用 Node.js 我可以使用

将其转换为项目数组
var qs = require('querystring');
var response = the-response-from-paypal;
var paypalResponse = qs.parse(response.toString());
console.log(paypalResponse["responseEnvelope.ack"])
//Renders:  Failure

但我想将它转换成一个对象,可以像这样访问:

var ack = deserializedResponse.responseEnvelope.ack;
//etc

或JSON:

{
    responseEnvelope: {
        ack: "Failure",
        timestamp: blah,
        correlationId: "a58a06c1000d8",
        ...
    },
    error: [
        {
            errorId: 520003,
            domain: "Platform",
            ...
        }
    ]

}

是否有一些方便的工具可以做到这一点?

这是基于我对你的另一个 的回答。您只需要将递归函数包装在将为您构建整个对象的预处理中。

var newObj = input.split('&').reduce(function (o, str) {
  var pair = str.split('=');

  return setObjVal(o, pair[0].split('.'), pair[1]);
}, {});

function setObjVal(obj, paths, val) {
  var path;
  var arrayInfo;

  if (paths.length === 0) {
    return val;
  }

  obj = obj || {};
  path = paths.shift();
  arrayInfo = path.match(arrayRegExp);

  if (arrayInfo) {
    path = arrayInfo[1];

    if (!Array.isArray(obj[path])) {
      obj[path] = [];
    }

    obj[path][arrayInfo[2]] = setObjVal(obj[path][arrayInfo[2]], paths, val);
  }
  else {
    obj[path] = setObjVal(obj[path], paths, val);
  }

  return obj;
}

var arrayRegExp = /^(\w+)\((\d+)\)$/;

var input = 'responseEnvelope.timestamp=2015-07-06T15%3A20%3A49.534-07%3A00&responseEnvelope.ack=Failure&responseEnvelope.correlationId=a58a06c1000d8&responseEnvelope.build=15743565&error(0).errorId=520003&error(0).domain=PLATFORM&error(0).subdomain=Application&error(0).severity=Error&error(0).category=Application';

var newObj = input.split('&').reduce(function (o, str) {
  var pair = str.split('=');
  
  return setObjVal(o, pair[0].split('.'), pair[1]);
}, {});

function setObjVal(obj, paths, val) {
  var path;
  var arrayInfo;
  
  if (paths.length === 0) {
    return val;
  }

  obj = obj || {};
  path = paths.shift();
  arrayInfo = path.match(arrayRegExp);
  
  if (arrayInfo) {
    path = arrayInfo[1];
    
    if (!Array.isArray(obj[path])) {
      obj[path] = [];
    }
    
    obj[path][arrayInfo[2]] = setObjVal(obj[path][arrayInfo[2]], paths, val);
  }
  else {
    obj[path] = setObjVal(obj[path], paths, val);
  }
  
  return obj;
}

document.write('<pre>' + JSON.stringify(newObj, null, 4) + '</pre>');

或者 如果您想像其他答案一样使用 lodash,您可以使用 _.set():

var newObj = input.split('&').reduce(function (o, str) {
  var pair = str.split('=');

  return _.set(o, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);
}, {});

var input = 'responseEnvelope.timestamp=2015-07-06T15%3A20%3A49.534-07%3A00&responseEnvelope.ack=Failure&responseEnvelope.correlationId=a58a06c1000d8&responseEnvelope.build=15743565&error(0).errorId=520003&error(0).domain=PLATFORM&error(0).subdomain=Application&error(0).severity=Error&error(0).category=Application';

var newObj = input.split('&').reduce(function (o, str) {
  var pair = str.split('=');

  return _.set(o, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);
}, {});

document.write('<pre>' + JSON.stringify(newObj, null, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>