2016-05-05 8 views
2

Es scheint bytestring ist kein serializable Beispiel in aeson die Vernünftigste diese Karten unter aeson github tracker zu tun sein könnte nach: ticket1, ticket2.Senden/Empfangen von Binärdaten in Aeson

Also, was ist eine gute Möglichkeit, binäre Objekte in aeson dann serialisieren/deserialisieren dann? Dies scheint MDN zu empfehlen, um binäre Objekte zu serialisieren: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data.

aktualisieren

am JSONsource code Sehen, ich sehe Word8 eine gültige Instanz. Also, wäre es am besten, das Bytearray als Vector von Word8 aus Javascript (Uint8Array) zu senden?

+0

Im Allgemeinen ist binary nicht mit JSON kompatibel (dh Ihre Binärdaten könnten Ihren JSON durch Hinzufügen von abgrenzenden Zeichen wie '' ',' '' '' '' '') beschädigen. Sie sollten einen Algorithmus in Betracht ziehen B. [base64] (https://hackage.haskell.org/package/base64-bytestring), um zuerst Ihre Binärdatei in ein ASCII-Format zu konvertieren, wenn Sie diese Daten über ein Nur-Text-Format (z. B. JSON) übertragen möchten. – RageD

+0

@RageD, wenn es ein einfaches Beispiel gibt, wie man das mit Aeson macht, wird das sehr hilfreich sein.Sie könnten es als eine Antwort verwenden. Ich schätze, man könnte es über den Draht als 'Text' und in' senden Aeson-Dekodierer, wandle zuerst 'Text' in' ByteString' mit 'encodeUTF8' um und dann' decide' in 'base64', um originale Binärdaten zurück zu bekommen. Nicht sicher, ob ich das richtig verstanden habe. – Sal

Antwort

2

Da Sie für ein Beispiel auf Base64-kodiert Ihre Daten gefragt über JSON zu schicken, habe ich ein grobes Beispiel peitschte:

{-# LANGUAGE OverloadedStrings #-} 
module Main(main) where 
import qualified Control.Applicative as App 
import qualified Data.Aeson as A 
import Data.Aeson.Types 
import Data.ByteString 
import qualified Data.ByteString.Lazy as LB 
import Data.ByteString.Base64 
import Data.Maybe (fromMaybe) 
import Data.Text 
import Data.Text.Encoding 

data MyObject = MyObject { objectName :: Text, objectData :: ByteString } deriving (Eq) 

instance FromJSON ByteString where 
    parseJSON (String t) = pure $ (either (const "") id . decode . encodeUtf8) t 
    parseJSON _ = App.empty 

instance ToJSON ByteString where 
    toJSON = String . decodeUtf8 . encode 

instance FromJSON MyObject where 
    parseJSON (Object v) = MyObject <$> v .: "name" <*> v .: "data" 
    parseJSON _ = App.empty 

instance ToJSON MyObject where 
    toJSON obj = object [ "name" .= objectName obj, "data" .= objectData obj ] 

exampleObject :: MyObject 
exampleObject = MyObject "example" "\x01\x02\x03\x04\x05" 

exampleJson :: LB.ByteString 
exampleJson = "{\"data\":\"AQIDBAU=\",\"name\":\"example\"}" 

main :: IO() 
main = do 
    print $ A.encode exampleObject 
    print $ exampleObject == fromMaybe (MyObject "fail" "") (A.decode exampleJson) 

Welche sollte die folgende Ausgabe erzeugen:

"{\"data\":\"AQIDBAU=\",\"name\":\"example\"}" 
True 

Um ein wenig expliziter zu sein, passiert die wahre Magie in unseren Definitionen von ToJSON und FromJSON für ByteString:

instance FromJSON ByteString where 
    parseJSON (String t) = pure $ (either (const "") id . decode . encodeUtf8) t 
    parseJSON _ = App.empty 

instance ToJSON ByteString where 
    toJSON = String . decodeUtf8 . encode 

Kurz gesagt, dies bietet Aeson-Richtung, wie wir wollen, dass es jede Instanz des (strengen) ByteString Typs serialisiert. Jetzt wird jede gefundene Instanz von ByteString automatisch codiert und dekodiert, wie wir angegeben haben (beachten Sie, wie MyObject wie eine "typische" Aeson-Definition aussieht). Natürlich, wenn Sie nur insbesondereByteString s codieren möchten, könnten Sie die instance Definitionen verzichten und es direkt dort in den Code für MyObject Serialisierung tun.

Die ToJSON ruft einfach die encode aus der Base64-Bibliothek auf dem Eingang und wandelt die resultierenden ByteString (aus dem encode Aufruf) zu einem Text Objekt, das die Eingabe des String Konstruktor (eine Art von Aeson Value, die zurückgegeben werden müssen, von dieser Funktion).

Die FromJSON sieht etwas gruseliger aus, aber - im Prinzip - ist ziemlich ähnlich. Wir nehmen die Aeson Value vom Typ String (für alles andere geben wir empty zurück) und wir konvertieren den Wert, der im String Objekt enthalten ist, in ByteString. Wir geben dann diese ByteString an die base64 decode-Methode, die eine Either produziert (je nachdem, ob es die ByteString erfolgreich dekodieren konnte oder nicht). Wir geben einfach eine leere Zeichenfolge zurück, falls dies fehlgeschlagen ist, andernfalls geben wir den decodierten Wert für das Objekt an.

Die Hauptfunktion dient als einfache Plausibilitätsprüfung. Ich kodiere zuerst exampleObject (enthält einen 5-Byte-Binärstring) und drucke seinen Wert. In der folgenden Zeile nehmen wir diese Ausgabe und haben sie exampleJson genannt. Wir dekodieren exampleJson und vergleichen es mit dem Speicher, den wir im Speicher erstellt hatten.Diese Werte sind - wie erwartet - einander gleich, sodass Sie sehen können, dass das Codieren und Decodieren ordnungsgemäß funktioniert.

+0

Vielen Dank. Sehr hilfreich! – Sal

+0

In der Tat ein sehr hilfreicher Beitrag –