将字符串转换为对象层次结构

Posted

技术标签:

【中文标题】将字符串转换为对象层次结构【英文标题】:Convert string to object hierarchy 【发布时间】:2015-09-28 05:03:49 【问题描述】:

我从 API 返回了以下字符串,我想使用 javascript 将其转换为对象层次结构。

收到的字符串是:

"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"

我想将其转换为 javascript 对象,例如:


    paymentInfoList: 
        PaymentInfo: [
             receiver: 
                 amount: 12.0
             
        ]
    

我可以编写自己的解析器,但想知道那里是否已经有一些代码。

更新

根据@JasonCust 的回答,这里有一个解析器来解析来自 PayPal Adaptive Payments Pay 方法的完整响应: https://github.com/danielflippance/paypal-ap-parser

【问题讨论】:

这是标准格式吗?它对我来说看起来很ad hoc,所以我怀疑是否有人已经编写了代码来处理它。 如果你使用 JSON 有一个内置的解析器。然而,这看起来像是一种自定义格式,因此您将需要编写一个自定义解析器。我会验证您使用的 API 没有返回 JSON 的选项,因为这样做很简单。顺便说一句,从您的文字中甚至很难辨别出实际的模式。如果 paymentInfo 有 2 个成员,那会是什么样子呢? 这是一种来自 PayPal Adaptive Payments 的格式。 该表达式似乎是某种 Java 表达式语言 (EL) 生成的。不确定是否可以用 Javascript 解决 @DanielFlippance 如果paymentInfo(0)paymentInfo(3),那么预期的输出是什么? 【参考方案1】:

我不知道处理该格式的现有解析器。也许在 Paypal 的开发者网站上有一些东西?如果您自己滚动,您可以使用递归函数来执行此操作,如下例所示。我还没有彻底测试过,但它是一个很容易做到的 POC。

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 = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var pair = input.split(':').map(function (str)  return str.replace(/"/g, ''); );
var newObj = setObjVal(, 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 = _.set(, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);

var input = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var pair = input.split(':').map(function (str)  return str.replace(/"/g, ''); );

var newObj = _.set(, pair[0].replace(/\(/g, '[').replace(/\)/g, ']'), pair[1]);

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

【讨论】:

我喜欢你的 lodash 解决方案。 @Jordan 我也这样做,但偶尔通过挖掘和滚动自己的解决方案来解决难题很有趣。 :-P【参考方案2】:

由于我无法抗拒一个小谜题,这里有一个干净的递归解决方案,适用于您提供的输入(向下滚动并查看小操场的 sn-p):

function objectFromExpression(expression, value) 
  if (!expression) 
    return value;
  

  var obj = ;
  var matchKeyIdxRest = /^(\w+)(?:\((\d+)\))?(?:\.(.+))?$/;
  var matches = expression.match(matchKeyIdxRest);

  if (!matches) 
    throw new Error('Oops! There\'s a problem with the expression at "' + expression + '"');
  

  var key = matches[1];
  var idx = matches[2];
  var rest = matches[3];
  var next = objectFromExpression(rest, value);

  if (idx) 
    var arr = [];
    arr[ parseInt(idx) ] = next;
    obj[key] = arr;
   else 
    obj[key] = next;
  

  return obj;


function keyValueExpressionToKeyValue(str) 
  var matchKeyVal = /^"([^"]+)":"([^"]+)"$/;
  var matches = str.match(matchKeyVal);

  if (!matches) 
    throw new Error('Oops! Couldn\'t extract key and value from input!');
  

  return matches.slice(1);


var input = '"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"';
var keyAndValue = keyValueExpressionToKeyValue(input);
var key = keyAndValue[0];   // => paymentInfoList.paymentInfo(0).receiver.amount
var value = keyAndValue[1]; // => 12.00

objectFromExpression(key, value);
// =>  paymentInfoList:
//       paymentInfo:
//        [  receiver:
//             amount: "12.00" 
//          
//        ]
//      
//    

function objectFromExpression(expression, value) 
  if (!expression) 
    return value;
  

  var obj = ;
  var matchKeyIdxRest = /^(\w+)(?:\((\d+)\))?(?:\.(.+))?$/;
  var matches = expression.match(matchKeyIdxRest);

  if (!matches) 
    throw new Error('Oops! There\'s a problem with the expression at "' + expression + '"');
  

  var key = matches[1];
  var idx = matches[2];
  var rest = matches[3];
  var next = objectFromExpression(rest, value);

  if (idx) 
    var arr = [];
    arr[ parseInt(idx) ] = next;
    obj[key] = arr;
   else 
    obj[key] = next;
  

  return obj;


function keyValueExpressionToKeyValue(str) 
  var matchKeyVal = /^"([^"]+)":"([^"]+)"$/;
  var matches = str.match(matchKeyVal);

  if (!matches) 
    throw new Error('Oops! Couldn\'t extract key and value from input!');
  

  return matches.slice(1);


var inputEl = document.getElementById('input');

function onKeyUp() 
  var outputEl = document.getElementById('output');
  var input = inputEl.value.trim();

  try 
    var keyAndValue = keyValueExpressionToKeyValue(input);
    var key = keyAndValue[0];
    var value = keyAndValue[1];

    var output = objectFromExpression(key, value);
    outputEl.value = JSON.stringify(output, null, 2);
   catch (ex) 
    outputEl.value = ex.toString();
  


inputEl.addEventListener('keyup', onKeyUp);
inputEl.dispatchEvent(new Event('keyup'));
label, textarea, input  display: block; 
label  font-family: sans-serif; 
input, textarea  font-family: monospace; width: 100%; margin-bottom: 1em; 
textarea  height: 15em; 
<label for="input">Input (type to see changes)</label>
<input id="input" value='"paymentInfoList.paymentInfo(0).receiver.amount":"12.00"'/>
<label for="output">Output</label>
<textarea id="output">Click the "Parse!" button!</textarea>

【讨论】:

以上是关于将字符串转换为对象层次结构的主要内容,如果未能解决你的问题,请参考以下文章

如何将整数转换为字符串[重复]

将数据框转换为rec数组(将对象转换为字符串)

Delphi:如何将表结构转换为对象

如何将数组转换成JSON-CSDN论坛

如何将 BigQuery Struct Schema 字符串转换为 Javascript 对象?

在python中将对象数据类型转换为字符串问题