2015-06-15 18 views
9

Nota prawna: Sprawdziłem pytanie here i nie odpowiada ono mojej.Eliksir - Zagnieżdżone parsowanie JSON do struktur

Próbuję wymyślić sposób zagnieżdżonego struct parsing JSON. Przykład:

{"name": "blah blah", "address": {"street": "smthing"}} 

chcę osiągnąć ten rezultat:

%User{name: "blah blah", address: %Address{street: "smthing"}} 

Bo wtedy byłoby łatwiej podłączyć walidację (używając Vex dla exapmle).

Wiem, że Trucizna obsługuje opcję "as struct", ale nie zapewnia zagnieżdżania. Powyższe będzie analizowany:

%User{name: "blah blah", address: %{"street" => "smthing"}}. 

wiem Mógłbym napisać implementację dekodera do modułu User ale myślę, że nie jest przeznaczony przypadek użycia i nie byłoby rodzajowy.

Kiedy zastanawiam się nad implementacją, nie mogłem znaleźć sposobu na stwierdzenie, czy atom jest modułem ... może muszę przejść z :code.is_loaded(module_name)?

W każdym razie, zanim spróbuję wdrożenia, chciałbym wiedzieć, czy jest coś, czego nie widzę.

Odpowiedz

9

Wierzę, że powyższe jest teraz możliwe dzięki zatruć:

defmodule User do 
    @derive [Poison.Encoder] 
    defstruct [:address] 
end 

defmodule Address do 
    @derive [Poison.Encoder] 
    defstruct [:street] 
end 

Poison.decode(response, as: %User{address: %Address{}}) 
+1

Działa to doskonale dla mnie z Poison 2.0. Dzięki @Maikon – q231950

5

Obecnie jedyną dostępną opcją jest dostarczenie własnej implementacji dla protokołu Poison.Decoder (zwróć uwagę na końcowy protokół r). Ma to dodatkową zaletę, że możesz mieć te konwersje w jednym miejscu i wystarczy napisać as: User, aby przekonwertować adres poprawnie. Na przykład:

defimpl Poison.Decoder, for: User do 
    def decode(task_list, options) do 
    Map.update! task_list, :address, fn address -> 
     Poison.Decode.decode(address, Keyword.merge(options, as: [Address])) 
    end 
    end 
end 

Uwaga że wewnętrzna wywołanie decode nie jest z Poison.Decoder, ale Poison.Decode bez spływu r w nazwie modułu. Nie dostaniesz błędu, jeśli użyjesz niewłaściwego, to po prostu nie zadziała, co może być kłopotliwe w debugowaniu.

W dłuższej perspektywie wydaje mi się, że w Truciźnie trzeba trochę pracy, aby ta cała zabawa była bardziej przyjemna. Może makro, które ułatwi pisanie implementacji Poison.Decoder dla niestandardowych struktur. Może również obsługa zagnieżdżonych opcji struktury, takich jak as: %User{address: Address}, które nie powinny być zbyt trudne do wdrożenia. Myślę też, że nazwy modułów Decode i Decoder są zbyt łatwe do zmylenia, a jedna z nich powinna zostać zmieniona. Jeśli będę miał czas, może zrobię te sugestie i ustanowię PR z Poison.

+0

Jeśli pójdę tamtędy może bardziej ogólne podejście jest wdrożenie rodzajowego dekoder że będę 'korzystania BaseDecoder' a następnie wewnątrz' def __using __ (_), wykonaj: etcetera, aby zdefiniować implementację protokołu. Ale wtedy musiałbym wiedzieć, czy atom jest prawidłowym modułem, który jest strukturą. – Olinasc

+0

Osobiście uważam, że to trochę za dużo magii, ale hej, czemu nie ;-) Z pewnością ta konfiguracja mogłaby być uproszczona, ale wolałbym bardziej jednoznaczne podejście. W tym celu otworzyłem zagadnienie Github, zobaczmy, co myśli oryginalny autor, a potem może spróbuję go zaimplementować. https://github.com/devinus/poison/issues/35 –