You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:24:44