使用 GSON 转换和展平 JSON
Posted
技术标签:
【中文标题】使用 GSON 转换和展平 JSON【英文标题】:Transform and flatten JSON using GSON 【发布时间】:2018-04-17 11:31:48 【问题描述】:我正在将 SignalK JSON 对象拆分为代表每个值的规范 JSON 项。
原始 JSON 如下所示:
"mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"name": "Mona",
"navigation":
"position":
"timestamp": "1991-09-03T03:5:36.000Z",
"latitude": 51.763691,
"longitude": 9.501367,
"altitude": 0.000000,
"source": "N0183-01"
,
"courseOverGroundTrue":
"value": 23.000000
,
"speedOverGround":
"value": 2.010289
,
"environment":
"depth":
"belowTransducer":
"value": 12.700000
,
"wind":
"angleApparent":
"value": 0.174533
,
"speedApparent":
"value": 0.000000
所需的转换后的 JSON 如下所示,其中 JSON 元素表示每个值,项目命名表示值的整个路径。
"items": [
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "EnvironmentWindSpeedApparent",
"isStep": false,
"name": "EnvironmentWindSpeedApparent",
"timestamps": 1523962903470,
"type": "numerical",
"values": 0.0
,
"key": "20180417-130143470EnvironmentWindSpeedApparent5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "EnvironmentWindAngleApparent",
"isStep": false,
"name": "EnvironmentWindAngleApparent",
"timestamps": 1523962903470,
"type": "numerical",
"values": 0.174533
,
"key": "20180417-130143470EnvironmentWindAngleApparent5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "EnvironmentDepthBelowTransducer",
"isStep": false,
"name": "EnvironmentDepthBelowTransducer",
"timestamps": 1523962903470,
"type": "numerical",
"values": 12.7
,
"key": "20180417-130143470EnvironmentDepthBelowTransducer5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "NavigationPositionLongitude",
"isStep": false,
"name": "NavigationPositionLongitude",
"timestamps": 1523962903470,
"type": "numerical",
"values": 9.501367
,
"key": "20180417-130143470NavigationPositionLongitude5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "NavigationPositionLatitude",
"isStep": false,
"name": "NavigationPositionLatitude",
"timestamps": 1523962903470,
"type": "numerical",
"values": 51.763691
,
"key": "20180417-130143470NavigationPositionLatitude5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "NavigationCourseOverGroundTrue",
"isStep": false,
"name": "NavigationCourseOverGroundTrue",
"timestamps": 1523962903470,
"type": "numerical",
"values": 23.0
,
"key": "20180417-130143470NavigationCourseOverGroundTrue5377770-4ee4-4a4b-3230-888037332031"
,
"columns":
"assetId": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031",
"description": "NavigationSpeedOverGround",
"isStep": false,
"name": "NavigationSpeedOverGround",
"timestamps": 1523962903470,
"type": "numerical",
"values": 2.010289
,
"key": "20180417-130143470NavigationSpeedOverGround5377770-4ee4-4a4b-3230-888037332031"
]
如何以灵活的方式进行这种转换,以适应更改原始 JSON 中可用的子节点? 我现在正在以一种简单的方式对其进行转换,但想知道是否可以使用 JsonReader、gson 或其他迭代原始 JSON 对象的方式来完成。
【问题讨论】:
【参考方案1】:我最终定义了表示转换后的 json 的对象结构,并编写了一个自定义序列化程序来进行转换。这可能是更有效的方法,但这种方法似乎工作正常。
public class SignalKDeserializer implements JsonDeserializer<TargetObject>
//written based on examples from http://www.javacreed.com/gson-deserialiser-example/
final TargetObject targetObject = new TargetObject ();
@Override
public TargetObject deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException
final JsonObject jsonObject = json.getAsJsonObject();
traverse (jsonObject,0,"", mmsi);
return targetObject;
private void traverse (JsonObject jsonObject, Integer level, String parentName, String mmsi)
Set<String> keys = jsonObject.keySet();
Iterator<?> keysIterator = keys.iterator ();
while( keysIterator.hasNext ())
String key = (String) keysIterator.next ();
String signalName = parentName+upperCaseFirst (key); //setting signalName to complete path of value
if (jsonObject.get (key) instanceof JsonObject)
traverse ((jsonObject.get (key)).getAsJsonObject (),level+1,upperCaseFirst (signalName),mmsi);
else if (jsonObject.get (key) instanceof JsonElement)
if (level>0)
try
final Double value = jsonObject.get(key).getAsDouble ();
calendar = Calendar.getInstance ();
Long timeStamp = calendar.getTimeInMillis ();
Item targetItem = new Item ();
targetItem.columns.setIsStep (false);
targetItem.columns.setAssetId (mmsi);
targetItem.columns.setTimestamps (calendar.getTimeInMillis ());
targetItem.columns.setType ("numerical");
targetItem.columns.setDescription (signalName);
targetItem.columns.setValues (value);
targetItem.columns.setName (signalName);
targetItem.setKey (signaldateformat.format (timeStamp) + mmsi);
targetObject.items.add (targetItem);
catch (NumberFormatException n)
// Expected, the value is non numerical and will not be transformed
我正在使用我的主类中的序列化程序,如下所示:
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TargetObject.class, new SignalKDeserializer ());
final Gson gson = gsonBuilder.create();
TargetObject targetObject = gson.fromJson (jsonSignalK,TargetObject.class);
String jsonOutString = gson.toJson (targetObject);
jsonOutString 包含我需要的转换后的 json。
【讨论】:
以上是关于使用 GSON 转换和展平 JSON的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Gson 和 Retrofit 将类似的 Json 对象转换为 Json 数组