2016-11-27 19 views
7

Tôi vừa mới bắt đầu làm việc với Elm để tạo một số mẫu front-end bằng cách sử dụng API Rest tôi đang làm việc. Nói chung, API trả về cấu trúc dữ liệu "hợp lý" có thể được giải mã bởi vì các khóa và giá trị kiểu nổi tiếng, nhưng một số loại tài nguyên trả về mục nhập data chỉ có json thô không có cấu trúc được xác định trước.Elm giải mã cấu trúc json chưa biết

Mọi thứ tôi đã đọc cho đến nay dường như giả định bạn biết cấu trúc của dữ liệu bạn đang giải mã, trong khi ở các js đơn giản, nó tương đối dễ dàng lặp lại các khóa và phản ánh trên các loại. được xử lý trong thời gian chạy. Tôi không nhìn thấy một con đường rõ ràng đối với việc xử lý loại dữ liệu này trong Elm.

Ví dụ,

{ 
    "name":"foo", 
    "data": { 
    "bar": [{"baz":123}, "quux"] 
    }, 
    ... 
} 

Tôi muốn biết nếu nó hiện có thể phân tích giá trị của các mục nhập data với một cái gì đó giống như

function go(obj) 
    for key in keys(foo) 
     if foo[key] is an object 
      go(foo[k]) 
     else if foo[key] is an array 
      map(go, foo[k]) 
     ... 

Cụ thể:

  1. Hiện tại, có thể xử lý dữ liệu json không xác định, lồng nhau và không đồng nhất trong Elm?
  2. Nếu có, bạn có thể cho tôi khái niệm chính hoặc trực giác mức độ cao về cách (các) tác giả dự định dữ liệu như thế này được giải mã không?
+0

Tôi sợ nó không phải là “Elm- như "để nhận được một cấu trúc bạn không biết. Trong Elm, bạn luôn mong đợi một đối tượng chứa các thuộc tính nhất định, và Elm thậm chí thực hiện kiểm tra trong thời gian chạy cho dù tất cả các thuộc tính mà bạn mong đợi tồn tại trong đối tượng đó. –

Trả lời

6

Có, bạn có thể viết bộ giải mã mục đích chung. Trước tiên, bạn có thể định nghĩa một kiểu liên minh chứa tất cả các loại Json thể:

type JsVal 
    = JsString String 
    | JsInt Int 
    | JsFloat Float 
    | JsArray (List JsVal) 
    | JsObject (Dict String JsVal) 
    | JsNull 

Và bây giờ bạn có thể sử dụng Json.Decode.oneOf thử mọi khả năng.

import Json.Decode as D exposing (Decoder) 
import Dict exposing (Dict) 

jsValDecoder : Decoder JsVal 
jsValDecoder = 
    D.oneOf 
    [ D.string |> D.andThen (D.succeed << JsString) 
    , D.int |> D.andThen (D.succeed << JsInt) 
    , D.float |> D.andThen (D.succeed << JsFloat) 
    , D.list (D.lazy (\_ -> jsValDecoder)) |> D.andThen (D.succeed << JsArray) 
    , D.dict (D.lazy (\_ -> jsValDecoder)) |> D.andThen (D.succeed << JsObject) 
    , D.null JsNull 
    ] 

Json.Decode.lazy là cần thiết cho việc JsArrayJsObject nhà xây dựng vì chúng được định nghĩa đệ quy.

Cấu trúc này sẽ xử lý mọi thứ bạn ném vào nó và sẽ tùy thuộc vào phần còn lại của chương trình của bạn để quyết định nên làm gì với loại linh hoạt như vậy.

Sửa

Như @Tosh chỉ ra, bộ giải mã này có thể được làm sạch bằng cách sử dụng map thay vì một andThen theo sau là một succeed:

jsValDecoder : Decoder JsVal 
jsValDecoder = 
    D.oneOf 
    [ D.map JsString D.string 
    , D.map JsInt D.int 
    , D.map JsFloat D.float 
    , D.list (D.lazy (\_ -> jsValDecoder)) |> D.map JsArray 
    , D.dict (D.lazy (\_ -> jsValDecoder)) |> D.map JsObject 
    , D.null JsNull 
    ] 
+2

Chỉ muốn nhận xét rằng bạn có thể sử dụng biểu mẫu: ví dụ: 'D.map JsString D.string'. Ít hơn một chút để đọc cho tôi, ít nhất. – Tosh

+0

Cảm ơn, @Tosh! Điểm tốt, một ràng buộc đơn lẻ thành công của 'thành công 'là một mùi tốt mà một“ bản đồ ”đơn giản cũng nên hoạt động tốt. –

Các vấn đề liên quan