基于GSON实现SignalK JSON对象的拆分与扁平化处理
用GSON实现SignalK JSON的扁平化与拆分
我来帮你搞定用GSON处理SignalK JSON的扁平化与拆分问题,结合你给的示例,给你两种实用的实现方式:
一、方式1:完全扁平化整个JSON对象
这种方式会把所有嵌套的字段展开成顶层键(比如navigation.position.latitude直接作为键名),适合需要统一结构存储或处理的场景。
实现代码
import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.util.HashMap; import java.util.Map; public class SignalKFlattener { private static final Gson gson = new Gson(); // 递归遍历JsonObject,生成扁平键值对 public static Map<String, Object> flattenJson(JsonObject jsonObject) { Map<String, Object> flatMap = new HashMap<>(); flattenJson("", jsonObject, flatMap); return flatMap; } private static void flattenJson(String prefix, JsonElement element, Map<String, Object> flatMap) { if (element.isJsonObject()) { JsonObject obj = element.getAsJsonObject(); obj.entrySet().forEach(entry -> { String newPrefix = prefix.isEmpty() ? entry.getKey() : prefix + "." + entry.getKey(); flattenJson(newPrefix, entry.getValue(), flatMap); }); } else if (element.isJsonPrimitive()) { // 根据原始类型存储,避免都转成字符串 if (element.getAsJsonPrimitive().isNumber()) { flatMap.put(prefix, element.getAsNumber()); } else if (element.getAsJsonPrimitive().isBoolean()) { flatMap.put(prefix, element.getAsBoolean()); } else { flatMap.put(prefix, element.getAsString()); } } // 如需处理数组,可在此补充JsonArray的遍历逻辑 } public static void main(String[] args) { // 你的原始SignalK JSON字符串 String signalKJson = "{ \"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\": { \"value\": 10.5 } } }"; // 解析+扁平化+输出 JsonObject jsonObject = gson.fromJson(signalKJson, JsonObject.class); Map<String, Object> flatMap = flattenJson(jsonObject); System.out.println(gson.toJson(flatMap)); } }
输出结果
{ "mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031", "name": "Mona", "navigation.position.timestamp": "1991-09-03T03:5:36.000Z", "navigation.position.latitude": 51.763691, "navigation.position.longitude": 9.501367, "navigation.position.altitude": 0.0, "navigation.position.source": "N0183-01", "navigation.courseOverGroundTrue.value": 23.0, "navigation.speedOverGround.value": 2.010289, "environment.depth.value": 10.5 }
二、方式2:拆分为独立的规范测量项
如果需要把每个独立的测量模块(位置、航向、航速、水深)拆成单独的JSON对象,每个对象包含船只为标识、测量类型、数值等元数据,这种方式更适合按业务维度处理数据。
1. 定义规范的测量项实体类
import com.google.gson.annotations.SerializedName; public class MeasurementItem { @SerializedName("mmsi") private String mmsi; @SerializedName("vessel_name") private String vesselName; @SerializedName("measurement_type") private String measurementType; @SerializedName("timestamp") private String timestamp; @SerializedName("source") private String source; @SerializedName("value") private Double value; // 位置专属字段 @SerializedName("latitude") private Double latitude; @SerializedName("longitude") private Double longitude; @SerializedName("altitude") private Double altitude; // 自动生成getter、setter和构造函数即可 }
2. 转换实现代码
import com.google.gson.Gson; import com.google.gson.JsonObject; import java.util.ArrayList; import java.util.List; public class SignalKSplitter { private static final Gson gson = new Gson(); public static List<MeasurementItem> splitIntoItems(String signalKJson) { List<MeasurementItem> items = new ArrayList<>(); JsonObject root = gson.fromJson(signalKJson, JsonObject.class); String mmsi = root.get("mmsi").getAsString(); String vesselName = root.get("name").getAsString(); // 处理位置信息 JsonObject position = root.getAsJsonObject("navigation").getAsJsonObject("position"); MeasurementItem positionItem = new MeasurementItem(); positionItem.setMmsi(mmsi); positionItem.setVesselName(vesselName); positionItem.setMeasurementType("position"); positionItem.setTimestamp(position.get("timestamp").getAsString()); positionItem.setSource(position.get("source").getAsString()); positionItem.setLatitude(position.get("latitude").getAsDouble()); positionItem.setLongitude(position.get("longitude").getAsDouble()); positionItem.setAltitude(position.get("altitude").getAsDouble()); items.add(positionItem); // 处理航向 JsonObject cog = root.getAsJsonObject("navigation").getAsJsonObject("courseOverGroundTrue"); MeasurementItem cogItem = new MeasurementItem(); cogItem.setMmsi(mmsi); cogItem.setVesselName(vesselName); cogItem.setMeasurementType("course_over_ground_true"); cogItem.setValue(cog.get("value").getAsDouble()); items.add(cogItem); // 处理航速 JsonObject sog = root.getAsJsonObject("navigation").getAsJsonObject("speedOverGround"); MeasurementItem sogItem = new MeasurementItem(); sogItem.setMmsi(mmsi); sogItem.setVesselName(vesselName); sogItem.setMeasurementType("speed_over_ground"); sogItem.setValue(sog.get("value").getAsDouble()); items.add(sogItem); // 处理水深 JsonObject depth = root.getAsJsonObject("environment").getAsJsonObject("depth"); MeasurementItem depthItem = new MeasurementItem(); depthItem.setMmsi(mmsi); depthItem.setVesselName(vesselName); depthItem.setMeasurementType("depth"); depthItem.setValue(depth.get("value").getAsDouble()); items.add(depthItem); return items; } public static void main(String[] args) { String signalKJson = "{ \"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\": { \"value\": 10.5 } } }"; List<MeasurementItem> items = splitIntoItems(signalKJson); System.out.println(gson.toJson(items)); } }
输出结果
[ { "mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031", "vessel_name": "Mona", "measurement_type": "position", "timestamp": "1991-09-03T03:5:36.000Z", "source": "N0183-01", "latitude": 51.763691, "longitude": 9.501367, "altitude": 0.0 }, { "mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031", "vessel_name": "Mona", "measurement_type": "course_over_ground_true", "value": 23.0 }, { "mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031", "vessel_name": "Mona", "measurement_type": "speed_over_ground", "value": 2.010289 }, { "mmsi": "urn:mrn:signalk:uuid:5377770-4ee4-4a4b-3230-888037332031", "vessel_name": "Mona", "measurement_type": "depth", "value": 10.5 } ]
小提示
- 如果你的SignalK JSON包含数组结构,可以在递归方法里补充
JsonArray的遍历逻辑。 - 若需要处理大量数据,建议用GSON的
TypeAdapter替代手动解析,性能会更优。 - 实体类的字段可根据业务规范自由调整,比如增减元数据字段、修改字段命名。
内容的提问来源于stack exchange,提问作者fredimx40
相关产品推荐
相关产品推荐

