2016-08-26 2 views
2

Wahrscheinlich ist es eine Anfängerfrage. Ich habe ein JSON-Datenformat, das polymorphe Datensätze enthält, und ich muss es analysieren. Dies sind Eckpunkte oder Kanten eines GraphenAnalyse von JSON polymorphen Datensätzen mit Elm

{ 
    "records": [{ 
     "id": 0, 
     "object": { 
      "id": "vertex1" 
     } 
    }, { 
     "id": 1, 
     "object": { 
      "id": "vertex2" 
     } 

    }, { 
     "id": 2, 
     "object": { 
      "from": "vertex1", 
      "to": "vertex2" 
     } 
    }] 
} 

Wie Sie sehen können sie alle id, aber Ecken und Kanten haben verschiedene Satzstrukturen.

Ich habe versucht, etwas auf dem Parsen solche Strukturen zu finden, aber das einzige, was ich war Handling records with shared substructure in Elm gefunden, aber ich kann die Antwort auf Elm 0,17 (eine einfache Umbenennung von data zu type nicht helfen)

Im Allgemeinen nicht übersetzen es gibt 2 Herausforderungen:

  1. eine polymorphe Datensatz
  2. decode JSON dynamisch in einen Scheitelpunkt oder einen Rand definieren
Dies ist

, wie weit ich bekam:

type alias RecordBase = 
    { id : Int 
    } 

type Records = List (Record RecordBase) 

type Record o = 
    VertexRecord o 
    | EdgeRecord o 

type alias VertexRecord o = 
    { o | object : { 
     id : Int 
    } 
    } 

type alias EdgeRecord o = 
    { o | object : { 
     from : Int 
     , to : Int 
    } 
    } 

aber der Compiler beschwert sich mit

mehrere Top-Level-Namenswerte VertexRecord macht die Dinge zweideutig.

Offenbar definiert union bereits die VertexRecord und EdgeRecord Typen.

Ich weiß wirklich nicht, wie ich von hier fortfahren soll. Alle Vorschläge sind herzlich willkommen.

Antwort

1

Da Sie das Label id an mehreren Stellen und von mehreren Typen haben, denke ich, es macht die Dinge ein wenig sauberer Typ Aliase und Feldnamen, die den Zweck jeder ID angeben.

bearbeitet 2016.12.15: Aktualisiert Ulme-0,18

type alias RecordID = Int 

type alias VertexID = String 

type alias VertexContents = 
    { vertexID : VertexID } 

type alias EdgeContents = 
    { from : VertexID 
    , to : VertexID 
    } 

Ihr Record Typ muss nicht tatsächlich die Feldnamen von object überall aufzunehmen. Sie können einfach einen Union-Typ verwenden. Hier ist ein Beispiel. Sie können dies auf verschiedene Arten gestalten. Der wichtige Teil, den Sie verstehen müssen, ist, beide Datentypen als einen einzigen Datensatztyp zu verwenden.

type Record 
    = Vertex RecordID VertexContents 
    | Edge RecordID EdgeContents 

Sie könnten eine Funktion definieren, die die recordID entweder ein Scheitelpunkt oder Kante so wie angegeben zurückgibt:

getRecordID : Record -> RecordID 
getRecordID r = 
    case r of 
    Vertex recordID _ -> recordID 
    Edge recordID _ -> recordID 

Nun, auf Decodierung.Mit Json.Decode.andThen, können Sie den gemeinsamen Datensatz-ID-Feld dekodieren kann, dann die JSON übergeben an einen anderen Decoder aus dem Rest des Inhalts zu erhalten:

recordDecoder : Json.Decoder Record 
recordDecoder = 
    Json.field "id" Json.int 
    |> Json.andThen \recordID -> 
     Json.oneOf [ vertexDecoder recordID, edgeDecoder recordID ] 

vertexDecoder : RecordID -> Json.Decoder Record 
vertexDecoder recordID = 
    Json.object2 Vertex 
    (Json.succeed recordID) 
    (Json.object1 VertexContents (Json.at ["object", "id"] Json.string)) 

edgeDecoder : RecordID -> Json.Decoder Record 
edgeDecoder recordID = 
    Json.object2 Edge 
    (Json.succeed recordID) 
    (Json.object2 EdgeContents 
     (Json.at ["object", "from"] Json.string) 
     (Json.at ["object", "to"] Json.string)) 

recordListDecoder : Json.Decoder (List Record) 
recordListDecoder = 
    Json.field "records" Json.list recordDecoder 

setzen sie alle zusammen, können Sie Ihr Beispiel so dekodieren kann:

import Html exposing (text) 
import Json.Decode as Json 

main = 
    text <| toString <| Json.decodeString recordListDecoder testData 

testData = 
    """ 
{ 
    "records": [{ 
     "id": 0, 
     "object": { 
      "id": "vertex1" 
     } 
    }, { 
     "id": 1, 
     "object": { 
      "id": "vertex2" 
     } 

    }, { 
     "id": 2, 
     "object": { 
      "from": "vertex1", 
      "to": "vertex2" 
     } 
    }] 
} 
""" 
+0

Wow! Es klappt! @ chad-gilbert du hast mir sehr geholfen! Ich würde es alleine nicht finden können. Danke vielmals! –