簡體   English   中英

如何將平面地圖轉換為復雜的 JSONObject?

[英]How to transform a flat map to complex JSONObject?

我想將平面鍵值映射轉換為復雜的 json 對象。

結構如下:

  • 地圖鍵當然代表 json 鍵。
  • 嵌套元素用點分隔
  • 列表元素由鍵末尾的數字表示。 末尾可能有多個數字。 不幸的是,這些鍵的順序相反。 意味着第一個“關鍵片段”映射到最后一個數字,最里面的關鍵片段映射到第一個數字。

下面的例子:

service.fee.1.1=a
service.fee.2.1=b
service.fee.3.1=c

這里的“服務”鍵總是映射到 index=1。 這意味着“服務”是一個數組,但在這種情況下只有一個元素。 第一個元素有鍵“fee”,里面有 3 個值。

因此,生成的json應該是:

{
    "service": [
        {
            "fee": ["a", "b", "c"]
        }
    ]
}

另一個例子:

service.fee.name.1.1=a
service.fee.age.2.1=b
service.fee.test.2.1=c

{
    "service": [
        {
            "fee": [
                {
                    "name": "a"
                },
                {
                    "age": "b",
                    "test": "c"
                }
            ]
        }
    ]
}

這就是我的開始,但我無法理解我可能必須使用遞歸來處理嵌套對象和列表:

JSONObject json = new JSONObject();

for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    if (endswithdigit(key)) {

    } else {
        if (key.contains("-")) {
            //complex object
            JSONObject subjson = new JSONObject();
            json.put(key, subjson);

            //TODO probably have to apply some kind of recursion here with subjson??
        } else {
            //plain value
            json.put(key, entry.getValue());
        }
    }
}

也許您可以建議如何使用嵌套列表和遞歸正確構建嵌套的JSONObject

如果您需要自己解決這個問題(即:庫無法處理它),那么我會將其分解,以便可以使用Composite Pattern連貫地解決它。

我將分兩部分來回答這個答案:首先,提出的創建層次結構的解決方案; 其次,如何利用 Composite 模式將您的內部層次結構轉換為您想要的 JSON。


第 1 部分:創建繼承權

一種方法是通過將元素划分為 bin 來迭代地創建對象(從包含每個元素的公共復合根對象開始)。 這將形成數據的復合結構。 流程將是:

  • 對於對象組合的 bin 中的每個元素:
    • 從元素左側剝離頂級標識符
    • 創建一個與之關聯的標識符。
    • 如果是鍵控:
      • 從右邊剝掉鑰匙
      • 為標識符創建一個復合數組(如果它不存在)。
      • 如果元素的=還剩下更多數據:
        • 為與該數組索引關聯的元素 bin 創建一個復合對象(如果它不存在)。
        • 將元素放入該對象的容器中。
      • 否則為索引的值創建一個葉節點。
    • 否則,如果元素的=后面還有其他數據:
      • 為與該數組索引關聯的元素 bin 創建一個復合對象(如果它不存在)。
      • 將元素放入該對象的容器中。
    • 否則,為標識符的值創建一個葉節點。
  • 對所有新垃圾箱重復此操作。

例如,假設我們正在使用給定的數據集:

x.y.z.1.1=A
x.y.z.3.1=B
x.y.w.1.1=C
x.u.1=D
a.b.1=E
a.c.1=F
e.1=G
e.2=H
i=I
m.j=J
m.k=K

然后流程如下:

ITERATION 0 (initialize):
root // x.y.z.1.1=A, x.y.z.3.1=B, x.y.w.1.1=C, x.u.1=D, a.b.1=E, a.c.1=F, e.1=G, e.2=H, i=I, m.j=J, m.k=K

ITERATION 1:
root :
  x[1] // y.z.1=A, y.z.3=B, y.w.1=C, u=D
  a[1] // b=E, c=F
  e[1] : "G"
  e[2] : "H"
  i : "I"
  m : // j=J, k=K

ITERATION 2:
root :
  x[1] : 
    y[1] // z=A, w=C
    y[3] // z=B
    u : "D"
  a[1] :
    b : "E"
    c : "F"
  e[1] : "G"
  e[2] : "H"
  i : "I"
  m : 
    j : "J"
    k : "K"

ITERATION 3:
root :
  x[1] :
    y[1] :
      z : "A"
      w : "C"
    y[3] :
      z : "B"
    u: "D"
  a[1] :
    b : "E"
    c : "F"
  e[1] : "G"
  e[2] : "H"
  i : "I"
  m : 
    j : "J"
    k : "K"

第 2 部分:復合模式

在這一點上,我們已經迭代地將我們的數據划分為一個分層的復合結構; 現在我們只需要將我們內部化的數據結構轉化為 JSON。 這是復合模式派上用場的地方; 您的每個對象都將實現以下接口:

// All objects in the composite tree must implement this.
public interface Jsonable {
    // The non-leaf objects will need to have their implementation of this
    // call it for each child object (and handle gaps).
    JsonObject toJsonObject(); 
}

如果遵循上述,我們可能會有這個接口的三個實現: ArrayCompositeObjectCompositeValueLeaf

在根元素上調用toJsonObject()將為您提供完整的JsonObject 上面示例的紋理表示如下(注意y數組中添加的間隙;這需要在數組組合的toJsonObject()調用中處理):

{
  "x" : [
    {
      "y" : [
        {
          "z" : "A",
          "w" : "C"
        },
        "",
        {
          "z" : "B"
        }
      ]
    }
  ],
  "a" : [
    {
      "b" : "D",
      "c" : "E"
    }
  ],
  "e" : [
    "F",
    "G"
  ]
  "i" : "I"
  "m" : {
    "j" : "J",
    "k" : "K"
  }
}

哪個,忽略白色間距,似乎是你正在尋找的。


請注意,這假設數據集不包含會導致無效 JSON 的元素。 IE:數據集不能包含以下內容:

i=I
i.1=I

正如它所說的那樣, i既是一個數組又是一個值。

請嘗試 Gson 庫並使用 new Gson().toJson(yourmap); 這會將您的地圖轉換為 JSON 格式。

也許您可以通過拆分數字開始處的鍵來解決它,並對子鍵使用 LIFO,對值和索引使用 FIFO。 可以通過解析鍵並檢測數字開始的位置來代替拆分它:

例如:

x.y.z.2.1 = val

這是拆分以顯示它是如何工作的,但它可以通過解析字符串來完成(:是分隔分隔符)。

x.y.z : 2.1 : val

然后將子項放入 LIFO(x 先進入,z 最后進入):

LIFO
head: z
      y
      x

以及用於值和索引的 FIFO(2 先進入,val 最后進入)

Fifo
top:2
    1
    val

然后你可以從 LIFO 中彈出,並將其與 FIFO 的彈出匹配。 第一個賦值是映射的值,然后賦值給最后一步的對象或數組。

z = val
y[1] = z
x[2] = y

暫無
暫無

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

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