JSON.stringify bez cudzysłowu na właściwościach?

100

Używam usługi, która używa nieprawidłowego formatu JSON (bez podwójnych cudzysłowów wokół właściwości). Więc muszę wysłać

{ name: "John Smith" } zamiast { "name": "John Smith" }

Nie można zmienić tego formatu, ponieważ to nie jest moja usługa.

Czy ktoś wie o routingu stringify do formatowania obiektu JavaScript, jak powyżej?

blady
źródło

Odpowiedzi:

119

To proste rozwiązanie wyrażenia regularnego działa w większości przypadków w celu usunięcia cudzysłowu nazw właściwości JSON:

const object = { name: 'John Smith' };
const json = JSON.stringify(object);  // {"name":"John Smith"}
console.log(json);
const unquoted = json.replace(/"([^"]+)":/g, '$1:');
console.log(unquoted);  // {name:"John Smith"}

Ekstremalna sprawa:

var json = '{ "name": "J\\":ohn Smith" }'
json.replace(/\\"/g,"\uFFFF");  // U+ FFFF
json = json.replace(/"([^"]+)":/g, '$1:').replace(/\uFFFF/g, '\\\"');
// '{ name: "J\":ohn Smith" }'

Specjalne podziękowania dla Roba W. za naprawienie tego.

Ograniczenia

W normalnych przypadkach powyższe wyrażenie regularne będzie działać, ale matematycznie niemożliwe jest opisanie formatu JSON wyrażeniem regularnym w taki sposób, aby działał w każdym pojedynczym przypadku (policzenie tej samej liczby nawiasów klamrowych jest niemożliwe w przypadku wyrażenia regularnego). Dlatego mam utwórz nową funkcję, aby usunąć cudzysłowy, formalnie analizując ciąg JSON za pomocą funkcji natywnej i ponownie go zerializuj:

function stringify(obj_from_json) {
    if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
        // not an object, stringify using native function
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    let props = Object
        .keys(obj_from_json)
        .map(key => `${key}:${stringify(obj_from_json[key])}`)
        .join(",");
    return `{${props}}`;
}

Przykład: https://jsfiddle.net/DerekL/mssybp3k/

Derek 朕 會 功夫
źródło
3
-1 też nie byłem mną, ale musisz uważnie przeczytać pytanie. OP musi zakodować obiekt do (zepsutego) json, a nie analizować / oceniać go.
Salman A
7
@Derek Ta metoda nie jest niezawodna . Na przykład weźmy następujące dane wejściowe: {"foo":"e\":bar"}(prawidłowy JSON) staje się {foo:e:bar"}(...)!
Rob W,
1
@Derek /\\\"/można uprościć do /\\"/. Nie zapomnij dodać flagi globalnej /\\"/g, w przeciwnym razie zepsuje się na łańcuchach z wieloma \". Jeśli chodzi o znak losowy, nigdy nie używaj literału U + FFFF, na wypadek gdyby edytor się dławi, ale sekwencji ucieczki. Wyrażenie regularne do przywracania to /\uFFFF/g.
Rob W,
2
@Derek 朕 會 功夫 Twoje wyrażenie regularne /\"([^(\")"]+)\":/gmożna uprościć do /"([^"]+)":/g, patrz regex101.com/r/qnz0ld/2
tanguy_k
1
@endriu W takim przypadku po prostu dodaj dodatkowe sprawdzenie wartości null.
Derek 朕 會 功夫
18

Wygląda na to, że jest to prosta metoda Object toString, której szukasz.

W Node.js jest to rozwiązane poprzez użycie obiektu util i wywołanie util.inspect (yourObject). To da ci wszystko, czego chcesz. kliknij ten link, aby uzyskać więcej opcji, w tym głębokość zastosowania metody. http://nodejs.org/api/util.html#util_util_inspect_object_options

Więc to, czego szukasz, to w zasadzie inspektor obiektów, a nie konwerter JSON. Format JSON określa, że ​​wszystkie właściwości muszą być ujęte w podwójne cudzysłowy. W związku z tym nie będzie konwerterów JSON do robienia tego, co chcesz, ponieważ po prostu nie jest to format JSON.Specs tutaj: https://developer.mozilla.org/en-US/docs/Using_native_JSON

W zależności od języka twojego serwera potrzebujesz sprzeciwu do łańcucha lub inspekcji.

fino
źródło
1
Dziękuję bardzo! To jest dokładnie to, czego szukałem. Używam json do wysyłania danych przez serwer WS do mojej gry i wierzę lub nie, brak konieczności zajmowania się dodatkowymi cudzysłowami wokół nazw właściwości oszczędza ogromną ilość danych! Dla wyjaśnienia, .toSource()działa dobrze również w nodejs, ale nie działa z obiektami w tablicach. utilSprawdzać prace dla tablic i obiektów w tablicach, które jest wspaniałe, uwielbiam go.
NiCk Newman
3
util.inspect()po prostu zadziałało wspaniale podczas pisania obiektu do zapytania Neo4j, aby ustawić wiele parametrów jednocześnie.
agm1984,
1
Z linku nodejs:> Metoda util.inspect () zwraca ciąg znaków reprezentujący obiekt przeznaczony do debugowania. Dane wyjściowe funkcji util.inspect mogą ulec zmianie w dowolnym momencie i nie należy na nich programowo polegać.
Peter Roehlen
5

Możesz spojrzeć na kod źródłowy parsera utworzony przez tego, który zdefiniował format JSON . Poszukaj wywołań funkcji: otaczają one wartość cudzysłowami. Klucze są cytowane w wierszach 326 i 338 .json2.js quote

Nie dołączaj biblioteki po modyfikacji. Zamiast tego weź tylko odpowiednią ( stringify) część lub przynajmniej zamień na JSONcoś innego, np. FAKEJSON.

Na przykład obiekt, FAKEJSONktóry definiuje tylko stringify: http://jsfiddle.net/PYudw/

Rob W
źródło
Dlaczego potrzebujesz dodatkowej biblioteki, skoro możesz to zrobić w czystym JavaScript?
Derek 朕 會 功夫
To jest dobry pomysł. Rozwidliłbym repozytorium, usunąłbym cudzysłowy i zmieniłbym nazwę obiektu JSON na coś żartobliwego, jak FAILJSON, aby było jasne, że nie pracujesz z rzeczywistym obiektem JSON lub faktycznym JSON.
RichardTowers
@Derek Biblioteki nie należy uwzględniać w całości. Weź tylko JSON.stringifyudział i usuń cytaty. Ponieważ biblioteka jest tworzona przez osobę, która zdefiniowała JSON , możemy być prawie pewni, że wynikiem jest bardzo poprawny JSON.
Rob W,
Wygląda na to, że to najlepsze podejście.
Derek 朕 會 功夫
Tak, zgadzam się z Derekiem. Chociaż jego zamiennik działa dobrze, czuję się pewniej z kodem crawforda, bez szacunku dla dereka lol. .toSource()działa dobrze, ale nie obejmuje, jeśli twój obiekt jest w tablicy, co jest bummer (i jestem w węźle, więc kompatybilność przeglądarki nie jest problemem: P), więc użyję tej metody dzięki @RobW również, wydaje się, że link jsfiddle utknąć na stronie ładowania :(
NiCk Newman
4

Spróbuj użyć servive'a z JSONP, myślę, że oferują go przy używaniu tego formatu.

W przeciwnym razie prześlij im szczegółowy raport o błędzie zawierający dobrą argumentację, dlaczego powinien być zgodny ze standardem. Żadne inne rozwiązanie niż wyeliminowanie problemu źródłowego nie jest prawdziwym rozwiązaniem.

Szybką naprawą może być przepuszczenie ciągu przez wyrażenie regularne przed jego przetworzeniem:

var obj = JSON.parse(str.replace(/(\{|,)\s*(.+?)\s*:/g, '$1 "$2":'));

Lub spróbuj dostosować istniejący parser JSON javascript (taki jak ten ), jeśli chcesz uzyskać bardziej składniową analizę.

Bergi
źródło
3

Znalazłem dobry pakiet NPM, który wystarczy do tego:

https://www.npmjs.com/package/stringify-object

const stringify = require('stringify-object')

let prettyOutput = stringify(json);

Działa całkiem dobrze.

user1543276
źródło
1
Ta biblioteka nie jest rekurencyjna.
corysimmons
2

Twoja odziedziczona składnia powinna być łatwo zjadana przez YAML, który jest nadzbiorem JSON.

Wypróbuj parser JavaScript YAML i program dumper: http://nodeca.github.com/js-yaml/

user1649339
źródło
2

@Derek 朕 會 功夫 Dzięki za udostępnienie tej metody, chciałbym udostępnić mój kod, który obsługuje również tworzenie ciągów znaków w tablicy obiektów.

export const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
    // In case of an array we'll stringify all objects.
    if (Array.isArray(obj_from_json)) {
        return `[${
                    obj_from_json
                        .map(obj => `${stringifyObjectWithNoQuotesOnKeys(obj)}`)
                        .join(",")
                }]` ;
    }
    // not an object, stringify using native function
    if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null){
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    return `{${
            Object
                .keys(obj_from_json)
                .map(key => `${key}:${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`)
                .join(",")
            }}`;
};
Adel Bachene
źródło
1
Powinieneś także użyć JSON.stringifyna przykład Date. Zwróć także, 'null'jeśli obj_from_jsonjest null.
Far Dmitry
1
Właśnie poprawiłem punkty podniesione przez @FarDmitry, zmieniając drugi warunek, aby wyglądał tak:if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
Brunno Vodola Martins
2

Posługiwać się JSON5.stringify

JSON5 jest rozszerzeniem JSON, który pozwala ES5 składni, w tym notowanych kluczy własności. Implementacja referencyjna JSON5 ( json5pakiet npm ) udostępnia JSON5obiekt, który ma te same metody z tymi samymi argumentami i semantyką co wbudowany JSONobiekt.

Jest wysoce prawdopodobne, że usługa, z której korzystasz, korzysta z tej biblioteki.

Inigo
źródło