将字符串转换为对象层次结构
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>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
【讨论】:
我喜欢你的 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>
【讨论】:
以上是关于将字符串转换为对象层次结构的主要内容,如果未能解决你的问题,请参考以下文章