我有一个场景。
所需的输入和输出均为 JSON。
// Input
{
"OldObject": {
"Time": 1351160457922,
"Name": "OName",
"quantity": 100,
"price": 10
}
}
// Output
{
"NewObject": {
"Time": 1351160457922,
"Title": "OName",
"quantity": 100
}
}
我需要一些转换代码或者最好是 xslt 类型语言来将 json 从一种格式转换为另一种格式。该变压器还需要快速,因为转换将即时完成。
编辑
我没有收到的 INPUT 对象的定义,它可能在运行时发生变化。但如果需要,我可以使用 OUTPUT 对象的类。
我尝试以 json -> xml -> xslt -> xml -> json 的方式执行此操作,但此时每秒大约接收 1000 个对象,此过程可能会产生开销。
我也不能使用 JavaScript,因为 myApp 是简单的基于 Windows 的 java 应用程序,并且使用 JavaScript 可能会导致开销。
尝试JOLT。它是一个用 Java 编写的 JSON 到 JSON 转换库。它是在一个将大量 JSON 从 ElasticSearch“后端”转换为前端 API 的项目上创建的。
对于您在问题中列出的 JSON 转换,Jolt“shift”规范将是:
// Jolt "shift" spec
{
"OldObject": {
"Time": "NewObject.Time",
"Name": "NewObject.Title", // if the input has "OldObject.Name", copy it's value
// to "NewObject.Title
"quantity": "NewObject.quantity"
}
}
您可以使用 JSON patch 来完成此转换。
使用 jsonpatch-js 的示例:
var transformations = [
{ move: '/OldObject', to: '/NewObject' },
{ remove: '/NewObject/price' },
{ move: '/NewObject/Name', to: '/NewObject/Title' }
];
var oldObject = { "OldObject": { "Time": 1351160457922, "Name": "OName", "quantity": 100, "price": 10 } };
jsonpatch.apply(oldObject, transformations);
我没有测试所提供的,但应该像那样工作。
JSON 补丁有 Java 实现:
您可以使用 ZORBA 和 JsonIQ http://www.jsoniq.org/ 然而,它是一个本机库,它带有一个包装器,因此您可以在 java 中使用它。
你可以尝试jmom一个小的java库
String jsonstring = "...";
JsonValue json = JsonParser.parse(jsonstring);
Jmom jmom = Jmom.instance()
.copy("/OldObject", "/NewObject", true)
.remove("/NewObject/price")
.copy("/NewObject/Name", "/NewObject/Title", true);
jmom.apply(json);
jsonstring = json.toCompactString();
您可以尝试 Java 库 Silencio,它允许您将 JSON 文件的每个节点转换为新值。您可以决定应该转换哪些节点以及如何转换。
另一个选择是使用 Logz.io Sawmill 库。您定义一个管道并执行它。以你为例:
{
steps: [
{
rename {
config {
from: "OldObject"
to: "NewObject"
}
}
}
{
removeField {
config {
path: "NewObject.price"
}
}
}
{
rename {
config {
from: "NewObject.Name"
to: "NewObject.Title"
}
}
}
]
}
Javascript JSON 转换器: https://raw.githubusercontent.com/udhayasoftware/codebase/master/standalone/javascript/TransformJSON.js
我们可以将 JSON 数组转换为 JSON 对象,反之亦然。唯一的事情是我们在定义 xPath 时需要小心。
//Transforming JSON array to JSON object:
var inputObj = [{Name:"Senyora"},{Name:"Clinton"}]
sourceXpath = "[].Name";
targetXpath = "Marriage.Couples[].NewName";
// Output = {Marriage:{Couples:[{NewName:"Senyora"},{NewName:"Clinton"}]}}
//Transforming JSON object to JSON array:
var inputObj = {Marriage:{Couples:[{NewName:"Senyora"},{NewName:"Clinton"}]}}
sourceXpath = "Marriage.Couples[].NewName";
targetXpath = "[].Name";
// Output = [{Name:"Senyora"},{Name:"Clinton"}]
/*
Author: Udhayamoorthy
Email: [email protected]"
*/
//Code start
function prepareGroup(inputObj, flatted, sourceXpath) {
sourceXpath = sourceXpath.replace(/\[]/g, ".[0-9]*");
var reg = new RegExp(sourceXpath, "g")
var strVal = JSON.stringify(flatted).match(reg);
var groupVal = {};
if (strVal != null)
strVal.forEach(function (data) {
if (flatted[data] != undefined) {
groupVal[data] = flatted[data];
} else {
data = data.replace(/"/g, "");
groupVal[data] = getValue(inputObj, data);
}
})
return groupVal;
}
function processGrouped(obj, targetXpath) {
var flatOutput = {};
var keys = Object.keys(obj);
targetXpath = targetXpath.replace(/\[]./g, "[0-9]");
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var changed = key.match(/(^[0-9]*\.|\W[0-9]*\.)/g);
if (changed) {
changed = JSON.stringify(changed).replace(/\"\./g, "\"");
}
var arrapos = '';
try {
arrapos = JSON.parse(changed);
}
catch (e) {
arrapos = changed;
}
var temp = targetXpath;
if (arrapos != null) {
arrapos.forEach(function (pos) {
pos = "." + pos;
temp = temp.replace("[0-9]", pos)
})
}
//tinkering - started
if (temp.charAt(0) == ".") {
temp = temp.substring(1, temp.length);
}
//tinkering - end
flatOutput[temp] = obj[key];
}
return unflatten(flatOutput);
}
function merge(a, b) {
for (var key in b)
if (b.hasOwnProperty(key)) {
var src = a[key];
var dest = b[key];
if (typeof src === 'object' && typeof dest === 'object') {
merge(src, dest);
} else {
a[key] = b[key];
}
}
return a;
};
function getValue(localObj, xpath) {
//var localObj = JSON.parse(JSON.stringify(obj));
var xpathArr = xpath.split('.');
xpathArr.forEach(function (path) {
localObj = localObj[path];
})
return localObj;
}
function unflatten(target, opts) {
var opts = opts || {}
, delimiter = opts.delimiter || '.'
, result = {}
if (Object.prototype.toString.call(target) !== '[object Object]') {
return target
}
function getkey(key) {
var parsedKey = parseInt(key)
return (isNaN(parsedKey) ? key : parsedKey)
};
Object.keys(target).forEach(function (key) {
var split = key.split(delimiter)
, firstNibble
, secondNibble
, recipient = result
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
while (secondNibble !== undefined) {
if (recipient[firstNibble] === undefined) {
recipient[firstNibble] = ((typeof secondNibble === 'number') ? [] : {})
}
recipient = recipient[firstNibble]
if (split.length > 0) {
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
}
}
// unflatten again for 'messy objects'
recipient[firstNibble] = unflatten(target[key])
});
//Array Check
var keys = Object.keys(result);
if (keys.length > 0 && keys[0] === "0") {
var output = [];
keys.forEach(function (key) {
output.push(result[key])
});
return output;
}
return result
};
function flatten(target, opts) {
var output = {}
, opts = opts || {}
, delimiter = opts.delimiter || '.'
function getkey(key, prev) {
return prev ? prev + delimiter + key : key
};
function step(object, prev) {
Object.keys(object).forEach(function (key) {
var isarray = opts.safe && Array.isArray(object[key])
, type = Object.prototype.toString.call(object[key])
, isobject = (type === "[object Object]" || type === "[object Array]")
if (!isarray && isobject) {
return step(object[key]
, getkey(key, prev)
)
}
output[getkey(key, prev)] = object[key]
});
if (Object.keys(object) == "") {
if (object instanceof Array) {
output[prev] = [];
} else {
output[prev] = {};
}
}
};
step(target)
return output
};
function isChildAttribute(map, flatted, mapArray) {
var parent = map.sourceXpath;
for (var j = 0; j < mapArray.length; j++) {
var child = mapArray[j].sourceXpath;
if (child.indexOf(parent) != -1 && parent.length < child.length) {
if (child.indexOf(parent + ".") != -1 || child.indexOf(parent + "[]") != -1) {
var temp = child;
temp = temp.replace(/\[]/g, ".0");
if (flatted[temp] != undefined) {
return false;
}
}
}
}
return true;
}
function transformJSON(inputObj, mapArray) {
var flatted = flatten(inputObj);
var finalout = {};
if (mapArray.length > 0 && (mapArray[0].targetXpath).charAt(0) == "[")
finalout = [];
mapArray.forEach(function (map) {
if (isChildAttribute(map, flatted, mapArray)) {
var grouped = prepareGroup(inputObj, flatted, map.sourceXpath);
var output = processGrouped(grouped, map.targetXpath);
finalout = merge(finalout, output); // merge two json objects
}
});
return finalout;
}
//Code end
//How to use (See below) ??
var inputObj = {
a: {
b: [
{
Name: "Tommy",
Location: [
{Place: "Sydney"},
{Place: "Washington"}
],
Info: {age: 23}
},
{
Name: "Sara",
Location: [
{Place: "New York"},
{Place: "New Jercy"}
],
Info: {age: 34}
},
{
Name: "John",
Location: [
{Place: "Chicago"},
{Place: "Detroit"}
],
Info: {age: 78}
}
],
d: {
e: {
f: {
g: {
h: "I Love India"
}
}
}
}
}
};
var mapArray = []; // collect source and target xpath s
var obj = {};
obj.sourceXpath = "a.b[].Name"; // Name is string
obj.targetXpath = "x[].NewName"; // expecting NewName as string
mapArray.push(obj);
//obj = {};
//obj.sourceXpath = "a.b[].Location"; // Location is an array
//obj.targetXpath = "x[].NewName"; // INVALID MAPPING - NewName already mapped
//mapArray.push(obj);
obj = {};
obj.sourceXpath = "a.b[].Location"; // Location is an array
obj.targetXpath = "x[].NewLocation"; // Location data copied to NewLocation array(Place will be present in array elements)
mapArray.push(obj);
obj = {};
obj.sourceXpath = "a.b[].Location[].Place"; // Location is an array
obj.targetXpath = "x[].NewLocation[].NewPlace"; // NewPlace will be created parallel to existing Place.
mapArray.push(obj);
obj = {};
obj.sourceXpath = "a.d.e.f.g.h"; // Transforming attributes at different level
obj.targetXpath = "T.H";
mapArray.push(obj);
var finalout = transformJSON(inputObj, mapArray);
console.log("See line#204 for more about how to use?");
console.log("Transformed JSON = " + JSON.stringify(finalout));
注意: JSON 无法在不同维度的数组之间进行转换。 sourceXpath 中“[]”的计数应等于 targetXpath 中“[]”的计数,反之亦然。
另一个选择是Josson。 转换语句很短:
map(NewObject: OldObject.map(Time,Title:Name,quantity))
使用JSONata:
{
"NewObject": {
"Time": OldObject.Time,
"Title": OldObject.Name,
"quantity": OldObject.quantity
}
}
请参阅如何在 Java 中使用 JSONata? 了解在 Java 中使用 JSONata 的方法。