簡體   English   中英

在 java 中展平 3 級嵌套 JSON 字符串

[英]Flattening a 3 level nested JSON string in java

要求是為輸入 JSON object 創建一個通用展平實用程序到展平的 JSON ZA8Z6FDE6331BD4B666AC

樣品 JSON 如下所示

{
  "Source": "source-1",
  "Rows": [
    {
      "Keys": {
        "device-id": "BC04-EBH-N3K-01",
        "interface-name": "TenGigE0/0/0/39",
        "node-name": "0/0/CPU0"
      },
      "Timestamp": 1567621527656,
      "inner": {
        "donm": {
          "id": "0062",
          "mol": {
            "rem": 30,
            "len": 11,
            "org": {
              "ldp": [
                {
                  "t": 486,
                  "o": 322
                },
                {
                  "t": 487,
                  "o": 32,
                  "twss": 1,
                  "tlv": "00:01"
                }
              ]
            },
            "chlen": 14,
            "poe": 5,
            "combs": 10,
            "chaype": 4,
            "rek": 0,
            "rem-um": 67
          },
          "detail": {
            "enas": "B,R",
            "systes": "B,R",
            "timng": 91,
            "syn": "C",
            "met-type": 0,
            "neses": {
              "lldEDIT": [
                {
                  "ium": 830,
                  "m": 1,
                  "ass": {
                    "ape": "ipv4",
                    "ipvs": "94"
                  }
                }
              ]
            },
            "pess": "0008",
            "por]d": 0,
            "pon": "BCtive",
            "sysme": "BC1"
          },
          "reme": "Bu1",
          "hean": 0,
          "porl": "Et1"
        }
      }
    }

  ],
  "Tey": {
    "epath": "Cgetail",
    "sustr": "MX",
    "coime": 1567621527653,
    "msp": 1567621527653,
    "come": 1567621527660,
    "nor": "BC5",
    "cid": 14789654
  }
}

我一直在嘗試將其展平為 3 個級別,並提出了以下實用程序。 但是,當我必須處理 Arrays 和 String、long、Timestamp 等類型的值時,事情變得復雜起來。此外,我無法理解如何維護嵌套鍵的唯一性。

public static Map<String,Object> flattenJson(JsonNode input){
        Map<String,Object> finalMap = new HashMap<>();

        ObjectMapper datamapper = new ObjectMapper();
        Map<String,Object> topLevelJsonMap = datamapper.convertValue(input,Map.class);
        Set<String> topLevelKeys = topLevelJsonMap.keySet();

        for(String topLevelKey : topLevelKeys){

            System.out.println("Key :::: "+topLevelKey);

            Object topLevelData = topLevelJsonMap.get(topLevelKey);
            System.out.println("value :::: "+topLevelData.toString());

            if(topLevelData instanceof ArrayNode){
                ArrayNode arrayOfData = (ArrayNode) topLevelData;
                for(JsonNode dataNode : arrayOfData){
                    flattenJson(input);
                }
            } else if(topLevelData instanceof JsonNode){
                Map<String,Object> innerLevelJsonMap = datamapper.convertValue(topLevelData,Map.class);
                Set<String> innerLevelKeys = innerLevelJsonMap.keySet();
                for(String innerLevelKey : innerLevelKeys){
                    System.out.println("inner key :::: "+innerLevelKey);
                    flattenJson((JsonNode) innerLevelJsonMap.get(innerLevelKey));
                }
            }else {
               finalMap.put(topLevelKey,topLevelData);
            }
        }
        return finalMap;
    }

任何幫助是極大的贊賞。

試試這個代碼:

public static void flattenJson(JsonNode node, String parent, Map<String, ValueNode> map) {
    if (node instanceof ValueNode) {
        map.put(parent, (ValueNode)node);
    } else {
        String prefix = parent == null ? "" : parent + ".";
        if (node instanceof ArrayNode) {
            ArrayNode arrayNode = (ArrayNode)node;
            for(int i = 0; i < arrayNode.size(); i++) {
                flattenJson(arrayNode.get(i), prefix + i, map);
            }
        } else if (node instanceof ObjectNode) {
            ObjectNode objectNode = (ObjectNode) node;
            for (Iterator<Map.Entry<String, JsonNode>> it = objectNode.fields(); it.hasNext(); ) {
                Map.Entry<String, JsonNode> field = it.next();
                flattenJson(field.getValue(), prefix + field.getKey(), map);
            }
        } else {
            throw new RuntimeException("unknown json node");
        }
    }
}

public static Map<String, ValueNode> flattenJson(JsonNode input) {
    Map<String, ValueNode> map = new LinkedHashMap<>();
    flattenJson(input, null, map);
    return map;
}

然后你可以打電話

    ObjectMapper om = new ObjectMapper();
    JsonNode jsonNode = om.readTree(json);
    Map<String, ValueNode> m = flattenJson(jsonNode);
    for (Map.Entry<String, ValueNode> kv : m.entrySet()) {
        System.out.println(kv.getKey() + "=" + kv.getValue().asText());
    }

Output:

Source=source-1
Rows.0.Keys.device-id=BC04-EBH-N3K-01
Rows.0.Keys.interface-name=TenGigE0/0/0/39
Rows.0.Keys.node-name=0/0/CPU0
Rows.0.Timestamp=1567621527656
Rows.0.inner.donm.id=0062
Rows.0.inner.donm.mol.rem=30
Rows.0.inner.donm.mol.len=11
Rows.0.inner.donm.mol.org.ldp.0.t=486
Rows.0.inner.donm.mol.org.ldp.0.o=322
Rows.0.inner.donm.mol.org.ldp.1.t=487
Rows.0.inner.donm.mol.org.ldp.1.o=32
Rows.0.inner.donm.mol.org.ldp.1.twss=1
Rows.0.inner.donm.mol.org.ldp.1.tlv=00:01
Rows.0.inner.donm.mol.chlen=14
Rows.0.inner.donm.mol.poe=5
Rows.0.inner.donm.mol.combs=10
Rows.0.inner.donm.mol.chaype=4
Rows.0.inner.donm.mol.rek=0
Rows.0.inner.donm.mol.rem-um=67
Rows.0.inner.donm.detail.enas=B,R
Rows.0.inner.donm.detail.systes=B,R
Rows.0.inner.donm.detail.timng=91
Rows.0.inner.donm.detail.syn=C
Rows.0.inner.donm.detail.met-type=0
Rows.0.inner.donm.detail.neses.lldEDIT.0.ium=830
Rows.0.inner.donm.detail.neses.lldEDIT.0.m=1
Rows.0.inner.donm.detail.neses.lldEDIT.0.ass.ape=ipv4
Rows.0.inner.donm.detail.neses.lldEDIT.0.ass.ipvs=94
Rows.0.inner.donm.detail.pess=0008
Rows.0.inner.donm.detail.por]d=0
Rows.0.inner.donm.detail.pon=BCtive
Rows.0.inner.donm.detail.sysme=BC1
Rows.0.inner.donm.reme=Bu1
Rows.0.inner.donm.hean=0
Rows.0.inner.donm.porl=Et1
Tey.epath=Cgetail
Tey.sustr=MX
Tey.coime=1567621527653
Tey.msp=1567621527653
Tey.come=1567621527660
Tey.nor=BC5
Tey.cid=14789654

為避免與鍵名沖突,您可以使用JSON 指針規范來創建它們。 Jackson庫也支持它,因此您以后可以使用它們來遍歷JsonNode節點。

簡單的實現可能如下所示:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

public class JsonApp {

  public static void main(String[] args) throws Exception {
    File jsonFile = new File("./test.json");

    ObjectMapper mapper = new ObjectMapper();
    JsonNode root = mapper.readTree(jsonFile);
    Map<String, JsonNode> map = new JsonFlattener(root).flatten();

    System.out.println("Use key-value pairs:");
    map.forEach(
        (k, v) -> {
          System.out.println(k + " => " + v);
        });

    System.out.println();
    System.out.println("Use pointers:");
    map.forEach(
        (k, v) -> {
          System.out.println(k + " => " + root.at(k));
        });
  }
}

class JsonFlattener {

  private final Map<String, JsonNode> json = new LinkedHashMap<>(64);
  private final JsonNode root;

  JsonFlattener(JsonNode node) {
    this.root = Objects.requireNonNull(node);
  }

  public Map<String, JsonNode> flatten() {
    process(root, "");
    return json;
  }

  private void process(JsonNode node, String prefix) {
    if (node.isObject()) {
      ObjectNode object = (ObjectNode) node;
      object
          .fields()
          .forEachRemaining(
              entry -> {
                  process(entry.getValue(), prefix + "/" + entry.getKey());
              });
    } else if (node.isArray()) {
      ArrayNode array = (ArrayNode) node;
      AtomicInteger counter = new AtomicInteger();
      array
          .elements()
          .forEachRemaining(
              item -> {
                process(item, prefix + "/" + counter.getAndIncrement());
              });
    } else {
      json.put(prefix, node);
    }
  }
}

上面的代碼打印:

Use key-value pairs:
/Source => "source-1"
/Rows/0/Keys/device-id => "BC04-EBH-N3K-01"
/Rows/0/Keys/interface-name => "TenGigE0/0/0/39"
/Rows/0/Keys/node-name => "0/0/CPU0"
/Rows/0/Timestamp => 1567621527656
/Rows/0/inner/donm/id => "0062"
/Rows/0/inner/donm/mol/rem => 30
/Rows/0/inner/donm/mol/len => 11
/Rows/0/inner/donm/mol/org/ldp/0/t => 486
/Rows/0/inner/donm/mol/org/ldp/0/o => 322
/Rows/0/inner/donm/mol/org/ldp/1/t => 487
/Rows/0/inner/donm/mol/org/ldp/1/o => 32
/Rows/0/inner/donm/mol/org/ldp/1/twss => 1
/Rows/0/inner/donm/mol/org/ldp/1/tlv => "00:01"
/Rows/0/inner/donm/mol/chlen => 14
/Rows/0/inner/donm/mol/poe => 5
/Rows/0/inner/donm/mol/combs => 10
/Rows/0/inner/donm/mol/chaype => 4
/Rows/0/inner/donm/mol/rek => 0
/Rows/0/inner/donm/mol/rem-um => 67
/Rows/0/inner/donm/detail/enas => "B,R"
/Rows/0/inner/donm/detail/systes => "B,R"
/Rows/0/inner/donm/detail/timng => 91
/Rows/0/inner/donm/detail/syn => "C"
/Rows/0/inner/donm/detail/met-type => 0
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ium => 830
/Rows/0/inner/donm/detail/neses/lldEDIT/0/m => 1
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ass/ape => "ipv4"
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ass/ipvs => "94"
/Rows/0/inner/donm/detail/pess => "0008"
/Rows/0/inner/donm/detail/por]d => 0
/Rows/0/inner/donm/detail/pon => "BCtive"
/Rows/0/inner/donm/detail/sysme => "BC1"
/Rows/0/inner/donm/reme => "Bu1"
/Rows/0/inner/donm/hean => 0
/Rows/0/inner/donm/porl => "Et1"
/Tey/epath => "Cgetail"
/Tey/sustr => "MX"
/Tey/coime => 1567621527653
/Tey/msp => 1567621527653
/Tey/come => 1567621527660
/Tey/nor => "BC5"
/Tey/cid => 14789654

Use pointers:
/Source => "source-1"
/Rows/0/Keys/device-id => "BC04-EBH-N3K-01"
/Rows/0/Keys/interface-name => "TenGigE0/0/0/39"
/Rows/0/Keys/node-name => "0/0/CPU0"
/Rows/0/Timestamp => 1567621527656
/Rows/0/inner/donm/id => "0062"
/Rows/0/inner/donm/mol/rem => 30
/Rows/0/inner/donm/mol/len => 11
/Rows/0/inner/donm/mol/org/ldp/0/t => 486
/Rows/0/inner/donm/mol/org/ldp/0/o => 322
/Rows/0/inner/donm/mol/org/ldp/1/t => 487
/Rows/0/inner/donm/mol/org/ldp/1/o => 32
/Rows/0/inner/donm/mol/org/ldp/1/twss => 1
/Rows/0/inner/donm/mol/org/ldp/1/tlv => "00:01"
/Rows/0/inner/donm/mol/chlen => 14
/Rows/0/inner/donm/mol/poe => 5
/Rows/0/inner/donm/mol/combs => 10
/Rows/0/inner/donm/mol/chaype => 4
/Rows/0/inner/donm/mol/rek => 0
/Rows/0/inner/donm/mol/rem-um => 67
/Rows/0/inner/donm/detail/enas => "B,R"
/Rows/0/inner/donm/detail/systes => "B,R"
/Rows/0/inner/donm/detail/timng => 91
/Rows/0/inner/donm/detail/syn => "C"
/Rows/0/inner/donm/detail/met-type => 0
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ium => 830
/Rows/0/inner/donm/detail/neses/lldEDIT/0/m => 1
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ass/ape => "ipv4"
/Rows/0/inner/donm/detail/neses/lldEDIT/0/ass/ipvs => "94"
/Rows/0/inner/donm/detail/pess => "0008"
/Rows/0/inner/donm/detail/por]d => 0
/Rows/0/inner/donm/detail/pon => "BCtive"
/Rows/0/inner/donm/detail/sysme => "BC1"
/Rows/0/inner/donm/reme => "Bu1"
/Rows/0/inner/donm/hean => 0
/Rows/0/inner/donm/porl => "Et1"
/Tey/epath => "Cgetail"
/Tey/sustr => "MX"
/Tey/coime => 1567621527653
/Tey/msp => 1567621527653
/Tey/come => 1567621527660
/Tey/nor => "BC5"
/Tey/cid => 14789654

只需通過將每個級別的鍵附加到更高級別的鍵中來創建鍵的命名空間。 換句話說,您扁平化的 JSON 鍵將是:

{
 "L1key::L2key": "L2val",
 "L1key": "L1val",
 "L1key::L2key::L3key": "L3val"
}

這樣您就可以保證唯一性,而且您也可以從中創建原始的 json。 最后確保您的密鑰中不存在級別分隔符(此處為:: )。

高溫高壓

你可以看看json-flattener

順便說一句,我是這個庫的作者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM