Reprezentowanie wartości null w JSON

422

Jaka jest preferowana metoda zwracania wartości zerowych w JSON? Czy istnieje inna preferencja dla prymitywów?

Na przykład, jeśli mój obiekt na serwerze ma liczbę całkowitą o nazwie „myCount” bez wartości, najbardziej poprawnym JSON dla tej wartości byłoby:

{}

lub

{
    "myCount": null
}

lub

{
    "myCount": 0
}

To samo pytanie dla ciągów - jeśli mam ciąg zerowy „myString” na serwerze, to najlepszy JSON:

{}

lub

{
    "myString": null
}

lub

{
    "myString": ""
}

lub (Panie, pomóż mi)

{
    "myString": "null"
}

Podoba mi się konwencja reprezentowania kolekcji w JSON jako pusta kolekcja http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

Pusta tablica byłaby reprezentowana:

{
    "myArray": []
}

Podsumowanie edycji

Argument „osobistych preferencji” wydaje się realistyczny, ale w skrócie, jako społeczność będziemy konsumować coraz większą liczbę różnych usług / źródeł. Konwencje dotyczące struktury JSON pomogłyby znormalizować zużycie i ponowne wykorzystanie tych usług. Jeśli chodzi o ustanowienie standardu, proponuję przyjęcie większości konwencji Jacksona z kilkoma wyjątkami:

  • Przedmioty są lepsze od prymitywów.
  • Puste kolekcje są preferowane niż puste.
  • Obiekty bez wartości są reprezentowane jako null.
  • Prymitywy zwracają swoją wartość.

Jeśli zwracasz obiekt JSON z przeważnie wartościami zerowymi, możesz mieć kandydata do refaktoryzacji do wielu usług.

{

    "value1": null,

    "value2": null,

    "text1": null,

    "text2": "hello",

    "intValue": 0, //use primitive only if you are absolutely sure the answer is 0

    "myList": [],

    "myEmptyList": null, //NOT BEST PRACTICE - return [] instead

    "boolean1": null, //use primitive only if you are absolutely sure the answer is true/false

    "littleboolean": false

}

Powyższy JSON został wygenerowany z następującej klasy Java.

package jackson;

import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonApp {

    public static class Data {

        public Integer value1;

        public Integer value2;

        public String text1;

        public String text2 = "hello";

        public int intValue;

        public List<Object> myList = new ArrayList<Object>();

        public List<Object> myEmptyList;

        public Boolean boolean1;

        public boolean littleboolean;

    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(new Data()));
    }
}

Zależność od Maven:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.3.0</version>
</dependency>
pherris
źródło
5
Nie ma najlepszego sposobu. Wybierz to, co najłatwiej zużyć dla klienta w konkretnym przypadku użycia. W duchu zwracania pustych kolekcji zamiast null, zastanów się, czy lepiej jest dla twojego klienta z pustym ciągiem lub null- ciąg zawierający słowo „null” jest nie do odróżnienia od prawidłowej wartości, nie rób tego.
Philipp Reichart
3
0 lub pusty ciąg może równie dobrze mieć inne znaczenie niż null, co może mieć inne znaczenie niż brak atrybutu. Jeśli chcesz reprezentować null, użyj null. To jest najbardziej jednoznaczne.
John Sheehan
W Objective-C istnieje zdefiniowana NSNullklasa, która ma instancję singleton. Odwołanie do tego wystąpienia jest równoważne odwołaniu JSON null. Domyślam się, że inny język mógłby zrobić to samo. Oczywiście należałoby sprawdzić klasę otrzymanego obiektu przed rzutem na przypuszczalną klasę - być „zerowym świadomym”, jak to było.
Hot Licks
2
Zauważ, że posiadanie listy „zerowej” nie jest najlepszą praktyką w Javie: jeśli lista ma być pusta, zainicjuj ją na pustej liście. Jeśli wymagane jest pozostanie puste (np. Ponieważ zostanie on zastąpiony hurtowo nową listą, a nie zmodyfikowany w celu dodania wartości), zainicjuj go na pustej liście (tj Collections.emptyList().). Pozwala to uniknąć błędów zerowych odniesień, które w innym przypadku mogą być uciążliwe.
Periata Breatta
@HotLicks - jest to możliwe tylko dlatego, że Objective-C jest dynamicznie wpisywany. Na przykład w Javie nie można mieć (użytecznej) Nullklasy, ponieważ można przypisać jej wartości tylko do obiektów własnego typu lub typu Object.
Periata Breatta

Odpowiedzi:

378

Oceńmy parsowanie każdego z nich:

http://jsfiddle.net/brandonscript/Y2dGv/

var json1 = '{}';
var json2 = '{"myCount": null}';
var json3 = '{"myCount": 0}';
var json4 = '{"myString": ""}';
var json5 = '{"myString": "null"}';
var json6 = '{"myArray": []}';

console.log(JSON.parse(json1)); // {}
console.log(JSON.parse(json2)); // {myCount: null}
console.log(JSON.parse(json3)); // {myCount: 0}
console.log(JSON.parse(json4)); // {myString: ""}
console.log(JSON.parse(json5)); // {myString: "null"}
console.log(JSON.parse(json6)); // {myArray: []}

Tl; dr tutaj:

Fragment w zmiennej json2 to sposób, w jaki specyfikacja JSON wskazuje, że nullpowinien być reprezentowany. Ale jak zawsze zależy to od tego, co robisz - czasami „właściwy” sposób, aby to zrobić, nie zawsze działa w twojej sytuacji. Wykorzystaj swój osąd i podejmij świadomą decyzję.


JSON1 {}

Zwraca pusty obiekt. Nie ma tam żadnych danych, a tylko powie ci, że każdy klucz, którego szukasz (czy to myCountcoś innego) jest typu undefined.


JSON2 {"myCount": null}

W tym przypadku myCountjest faktycznie zdefiniowany, chociaż jego wartość to null. To nie jest to samo co „nie undefinedi nie null”, a jeśli testujesz dla jednego lub drugiego warunku, może się to udać, podczas gdy JSON1 zawiedzie.

Jest to ostateczny sposób reprezentacji nullzgodnie ze specyfikacją JSON .


JSON3 {"myCount": 0}

W tym przypadku myCount wynosi 0. To nie to samo co nulli to nie to samo co false. Jeśli twoje zdanie warunkowe ocenia myCount > 0, to warto je mieć. Ponadto, jeśli wykonujesz obliczenia na podstawie wartości tutaj, 0 może być przydatne. Jeśli jednak próbujesz przetestować null, w rzeczywistości to nie zadziała.


JSON4 {"myString": ""}

W takim przypadku otrzymujesz pusty ciąg. Ponownie, podobnie jak w JSON2, jest zdefiniowane, ale jest puste. Możesz przetestować, if (obj.myString == "")ale nie możesz przetestować nulllub undefined.


JSON5 {"myString": "null"}

To prawdopodobnie wpędzi cię w kłopoty, ponieważ ustawiasz wartość ciągu na null; w tym przypadku obj.myString == "null"jednak tak nie jest == null.


JSON6 {"myArray": []}

To powie ci, że twoja tablica myArrayistnieje, ale jest pusta. Jest to przydatne, jeśli próbujesz wykonać policzenie lub ocenę myArray. Powiedzmy na przykład, że chcesz ocenić liczbę zdjęć opublikowanych przez użytkownika - możesz to zrobić myArray.lengthi zwróci 0: zdefiniowane, ale nie opublikowano żadnych zdjęć.

brandonscript
źródło
1
Wielkie dzięki, bardzo pomocne. Tylko mały węzeł boczny; kiedy Play Json (scala) serializuje Opcja [Ciąg] = Brak wyniku to JSON1np.{}
Neil
207

nullnie jest zero. Nie jest to wartość sama w sobie : jest to wartość poza domeną zmiennej wskazująca na brakujące lub nieznane dane.

Jest tylko jeden sposób reprezentacji nullw JSON. Zgodnie ze specyfikacjami ( RFC 4627 i json.org ):

2.1 Wartości

Wartość JSON MUSI być obiektem, tablicą, liczbą lub łańcuchem, lub jednym z nich
następujące trzy dosłowne nazwy:

  false null true

wprowadź opis zdjęcia tutaj

Nicholas Carey
źródło
8
Szkoda, że ​​zerowy musi być w ogóle obecny. 4 znaki za nic. Byłoby miło po prostu całkowicie wyłączyć tę wartość. json = '{"myValue":}';
Richard A Quadling
119
@Richard A Quadling - Jestem zwolennikiem Hal Abelsona „Programy muszą być napisane, aby ludzie mogli je czytać, a tylko przypadkowo, aby maszyny mogły je uruchomić”. Wolę słowo „null”, potwierdzające zamiar programisty, a nie tylko kwestię przypadkowego pominięcia.
Scott Smith
13
@Dave May: „Wartości JSON nie są programami” - Chodzi mi o jednoznaczne zasygnalizowanie zamiaru. Tak, kosztuje dodatkowe cztery znaki, a dla niektórych aplikacji różnica może być znacząca. W wielu przypadkach jednak, korzyści z podejmowania błędy wyglądać źle znacznie przewyższają korzyści z optymalizacji drobnych.
Scott Smith
11
@Dave Ponadto, według json.org, JSON „jest łatwy do czytania i pisania dla ludzi”.
Sophivorus
14
Zauważ też, że jeśli masz problemy z 4 znakami ASCII, JSON nie jest najlepszym podejściem, spójrz na Binary JSON lub lepiej na czysty format binarny.
PhoneixS
26

Jest tylko jeden sposób reprezentacji null; to jest z null.

console.log(null === null);   // true
console.log(null === true);   // false
console.log(null === false);  // false
console.log(null === 'null'); // false
console.log(null === "null"); // false
console.log(null === "");     // false
console.log(null === []);     // false
console.log(null === 0);      // false

To jest do powiedzenia; jeśli którykolwiek z klientów korzystających z reprezentacji JSON korzysta z ===operatora; to może być dla nich problem.

bez wartości

Jeśli chcesz przekazać, że masz obiekt, którego atrybut myCountnie ma wartości:

{ "myCount": null }

brak atrybutu / brak atrybutu

Co jeśli chcesz przekazać, że masz obiekt bez atrybutów:

{}

Kod klienta będzie próbował uzyskać dostęp myCounti uzyskać undefined; nie ma go.

pusta kolekcja

Co jeśli chcesz przekazać, że masz obiekt z atrybutem, myCountktóry jest pustą listą:

{ "myCount": [] }
dnozay
źródło
+1 dobre przykłady z porównaniami, ale pomocne byłoby rozróżnienie między javascript a json, co oznacza, że ​​reprezentacja wartości null w javascript nie musiała odpowiadać jsonowi (chociaż tak jest).
Mladen B.,
15

Chciałbym użyć, nullaby pokazać, że nie ma wartości dla tego konkretnego klucza. Na przykład użyj nulldo przedstawienia, że ​​„liczba urządzeń w twoim domu łączy się z Internetem” jest nieznana.

Z drugiej strony użyj, {}jeśli ten konkretny klucz nie ma zastosowania. Na przykład nie powinieneś pokazywać liczby, nawet jeśli nullna pytanie „liczba samochodów z aktywnym połączeniem internetowym” jest zadawane osobie, która nie jest właścicielem żadnego samochodu.

Unikałbym domyślnej wartości, chyba że ma to sens. Chociaż możesz zdecydować się na użycie, nullaby nie przedstawiać żadnej wartości, na pewno nigdy tego nie używaj "null".

marcoseu
źródło
7

Wybrałbym „default” dla typu danych zmiennej ( nulldla łańcuchów / obiektów, 0dla liczb), ale rzeczywiście sprawdzam, jakiego kodu oczekuje obiekt. Nie zapominaj, że czasami istnieje różnica między null/ default a „not present”.

Sprawdź wzorzec obiektu zerowego - czasem lepiej jest przekazać jakiś obiekt specjalny zamiast null(tj. []Tablicę zamiast nulltablic lub ""łańcuchów).

Aleksiej Lewenkow
źródło
2

Jest to osobisty i sytuacyjny wybór. Ważną rzeczą do zapamiętania jest to, że pusty ciąg i liczba zero są koncepcyjnie różne null.

W przypadku countpewnie zawsze potrzebujesz poprawnego numeru (chyba żecount jest nieznany lub niezdefiniowany), ale w przypadku ciągów, kto wie? Pusty ciąg może oznaczać coś w twojej aplikacji. A może nie. Ty decydujesz.

Wayne
źródło
1

Zgodnie ze specyfikacją JSON najbardziej zewnętrzny pojemnik nie musi być słownikiem (lub „obiektem”), jak sugeruje większość powyższych komentarzy. Może to być także lista lub sama wartość (tj. Ciąg, liczba, wartość logiczna lub null). Jeśli chcesz reprezentować wartość zerową w JSON, cały ciąg JSON (z wyłączeniem cudzysłowów zawierających ciąg JSON) jest po prostu null. Bez nawiasów klamrowych, bez nawiasów, bez cudzysłowów. Możesz podać słownik zawierający klucz o wartości null ( {"key1":null}) lub listę o wartości null ( [null]), ale same nie są to wartości null - są to właściwe słowniki i listy. Podobnie, pusty słownik ( {}) lub pusta lista ( []) są w porządku, ale też nie są zerowe.

W Pythonie:

>>> print json.loads('{"key1":null}')
{u'key1': None}
>>> print json.loads('[null]')
[None]
>>> print json.loads('[]')
[]
>>> print json.loads('{}')
{}
>>> print json.loads('null')
None
iggie
źródło
Zauważ, że to gramatyka formularza McKeeman na prawym pasku bocznym połączonej strony specyfikacji JSON potwierdza poprawność stwierdzenia, które się nie zgadza, nullstanowi prawidłowy JSON. Główny tekst i ilustracje są niejednoznaczne i jeśli coś wydaje się sugerować, że tylko obiekty i tablice są prawidłowe u podstawy.
yoyoyoyosef