2012-05-12 26 views
9

Mam kilka obiektów, które parsuję z json za pomocą natywnych implementacji przeglądarki. Niektóre właściwości obiektów to liczby. W tej chwili liczby są parsowane z json jako stringi, a ja używam parseInt, aby rzucić ciąg do int, którego potrzebuję.javascript JSON parsuje właściwość obiektu bezpośrednio do int

Problem polega na tym, że mam 23 obiektów Robię to ze i ogólnie około 80 właściwości, które mam do analizowania wskazówki tak:

if (TheObject && TheObject.TheProperty) { 
    TheObject.TheProperty = parseInt(TheObject.TheProperty, 10); 
} 

Istnieje wiele linii kodu, które wyglądają bardzo podobnie . Czy istnieje sposób użycia prototypów lub czegoś, aby zmienić sposób działania funkcji JSON.parse, aby za każdym razem, gdy analizator uruchamia się, sprawdza, czy właściwość łańcucha znaków faktycznie jest int, a jeśli tak, czy rzutuje ją bezpośrednio jako taką?

Dzięki.

+0

Jak zrobiłbyś to automagicznie, jeśli 'parseInt ('1a', 10);' zwraca '1'? Ale w każdym razie, nawet jeśli właściwość wygląda jak liczba - nie oznacza to, że jest numeryczna – zerkms

+0

W przypadkach, w których uruchamiam funkcję parseInt, wiem, że jest to liczba. W przypadku, gdy właściwość może być liczbą, ale może również być liczbą 1a, należy użyć funkcji IsNumeric jquery. – frenchie

+0

Jeśli ** numeryczny ciąg znaków ** jest liczbą zgodną ze źródłem, możesz dokonać konwersji, w przeciwnym razie nie. –

Odpowiedz

8

JSON może obsługiwać numery następująco:

{ 
    "TheObject":{ 
     "TheProperty":5 
    } 
} 

Jeśli nieruchomość została doublequoted to jest to ciąg indziej jest to numeryczny, logiczna (true i false wartości), null lub po prostu coś, co powoduje Błąd analizy.

Zobacz http://json.org/

+0

ok, dziękuję, rzeczywiście działa bez parsowania; Właśnie usunąłem cały kod parsujący i działało dla większości właściwości. Dla tych, które nie działały, aktualizuję serializator serwera, aby zająć się problemem podwójnego cytowania. Dzięki. – frenchie

+0

Używaj parsera internetowego, takiego jak ten [ten] (http://json.parser.online.fr/), jeśli nie jesteś pewien swojego JSON-a lub tylko eksperymentów. – kbec

2

nie sądzę, będzie można zmodyfikować parser, ale zamiast wielu podobnych linii kodu, należy szereg właściwości i dostęp do nich z notacją [] w pętli do parseInt() im. Oczywiście, jeśli masz dostęp do kodu generującego JSON, łatwiej jest go zmienić na wyjściowe ints odpowiednio niecytowane.

// Array of properties you want to parse out 
var parseUs = ['prop1','prop2','prop3','prop4']; 

// Array of objects you need to parse them in 
var objs = [obj1, obj2, obj3]; 

// Iterate over the objects 
for (var i=0; i<objs.length; i++) { 

    // And over the properties array 
    for (var j=0; j<parseUs.length; j++) { 
    // Parse out the int value if the object has the property 
    if (objs[i].hasOwnProperty(parseUs[j]) { 
     objs[i][parseUs[j]] = parseInt(parseUs[j], 10); 
    } 
    } 
} 

Uwaga: To nie zadziała, jeżeli obiekty dzielić nazwy właściwości, które nie są int wartości w każdym z nich. W takim przypadku musisz zmodyfikować to, aby użyć tablicy właściwości dla każdego obiektu.

+0

* "Nie sądzę, że będziesz w stanie zmodyfikować analizator składni ..." * Nie ma potrzeby, do tego służą funkcje rewitalizatora. –

+0

Nie można zmodyfikować analizatora składni. To po prostu kod natywny do parsera wbudowanego w przeglądarkę. Możesz napisać własną, ale po co to wszystko? – kbec

1

@kbec daje poprawną odpowiedź. Jeśli nie masz kontroli nad źródła danych, a następnie można użyć mniej więcej tak:

function intify(obj, fields) { 
    if (typeof(obj) == "undefined") return; 
    var numFields = fields.length; 
    for (var i = 0; i < numFields; i++) { 
    var field = fields[i]; 
    if (typeof(obj[field]) != "undefined") { 
     obj[field] = parseInt(obj[field], 10); 
    } 
    } 
    return obj; 
} 

intify(obj, ['foo', 'bar']); 
intify(obj.baz, ['boo']); 
+0

Jeśli ręcznie przekonwertujesz na int, możesz użyć zamiast niego 'parseInt (obj [pole], 10);' this: 'parseInt (obj [pole], 10) || 0'. Dzięki temu masz pewność, że twoja własność jest liczbą, nawet jeśli ma wartość NaN (a nie numer), masz tylko "0". – kbec

+1

@kbec: Kwestia opinii i szczególnego przypadku użycia.Generalnie jednak wolałbym otrzymać 'NaN' niż' 0' dla czegoś, co nie jest liczbą, ale powinno być. Zamiatanie go pod dywanik jako "0" może prowadzić do bolesnych sesji debugowania. – Amadan

+2

@kbec: To prawda, ale potem ukrywasz, że to, co miało być numerem, nie było. –

9

JSON.parse przyjmuje drugi argument w postaci funkcji, które można wykonać niektóre przetwarzania post.

JSON.parse('{"p": "5"}', function(k, v) { 
    return (typeof v === "object" || isNaN(v)) ? v : parseInt(v, 10); 
}); 

I nie chcesz, aby przetworzyć wszystkie ciągi znaków numerycznych, a następnie utworzyć tabelę przeglądową właściwości Ty chcesz.

var props = {"p":1, "some_prop":1, "another_prop":1}; 

JSON.parse('{"p": "5"}', function(k, v) { 
    return props.hasOwnProperty(k) ? parseInt(v, 10) : v; 
}); 
+0

Problem polega na tym, że niektóre rzeczy mogą przejść test "isNaN", a nadal nie są liczbami: '{" name ":" Johnny Wonten "," login ":" 1.10 ", description:" One-Ten, geddit!?! 11! " } ' – Amadan

+0

@Amadan: To tylko przykład testu. OP może zamiast tego przetestować na podstawie tabeli właściwości. Chociaż nie wiem dokładnie, co masz na myśli. Który element w twoim przykładzie minie, a który nie powinien. –

+0

W tym przykładzie 'login' powinien być ciągiem; to zbieg okoliczności, że wygląda jak liczba. – Amadan

2

Jeśli źródło danych nie może być stałe (numery powinny być przekazywane w postaci liczb, a nie jako ciągi znaków), you can pass JSON.parse a "reviver" function, który otrzyma każdy element jak to jest przetwarzane.To daje możliwość przekształcenia go:

// Create this once 
var propsToConvert = { 
    TheProperty: 1, 
    TheOtherProperty: 1, 
    YetAnotherProperty: 1, 
    // ...and so on... 
}; 

// Use it each time you parse 
var obj = JSON.parse(str, function(key, value) { 
    if (propsToConvert.hasOwnProperty(key)) { 
     return parseInt(value, 10); 
    } 
    return value; 
}); 

Live example | source

lub jeśli nazwy właściwości nie są wystarczająco wyjątkowy (TheProperty nie zawsze potrzeba przenoszenia, tylko gdy jest to własność TheObject), można to zrobić za pomocą czeku dwupoziomowego:

// Define the object names and their property names (once) 
var propsToConvert = { 
    TheObject: { 
     TheProperty: 1, 
     TheOtherProperty: 1, 
     YetAnotherProperty: 1, 
     // ...and so on... 
    }, 
    AnotherObject: { 
     // Other properties... 
    } 
}; 

// Use it each time you parse 
var obj = JSON.parse(str, function(key, value) { 
    var name, props; 

    if (typeof value === "object") { 
     props = propsToConvert[key]; 
     if (props) { 
      for (name in props) { 
       value[name] = parseInt(value[name], 10); 
      } 
     } 
    } 
}); 

(Revivers nazywane są wewnątrz-out, więc właściwości będą na obiekcie do czasu można zobaczyć obiekt na klucz;. dlatego aktualizować je na miejscu)

masz pomysł, tam dużo ty a do funkcji reviver.


Notatka: parseInt, którego użyłem powyżej, jest dość wyrozumiały   — ewentualnie bardziej wyrozumiały niż chcesz. Na przykład:

var a = parseInt('1a', 10); // 1, instead of NaN 

Jeśli jesteś w porządku ze strunami jak "0x10" leczony jako hex, a następnie:

var a = Number(str); 

... co daje NaN dla nieprawidłowych ciągów liczbowych (Number("1a") jest NaN) . Ponieważ JSON nie ma mieć liczb szesnastkowych, jeśli jesteś pewien, że uszkodzone źródło danych nie zakoduje ich jako heksadecymalnych, jesteś złoty.

W przeciwnym razie, jeśli potrzebujesz dziesiętnego, ale chcesz być ścisły, będziesz musiał zrobić wyraże regularne na ciągu, aby upewnić się, że pasuje do wzorca dla prawidłowej liczby dziesiętnej (co jest dość skomplikowane, jeśli chcesz obsługuje wszystkie rzeczy obsługiwane przez literały numeryczne JavaScript).

+0

"Problem polega na tym, że mam 23 obiekty, z którymi to robię i ogólnie około 80 właściwości". Domyślam się, że nie chodzi o to, jak przekonwertować właściwości, chodzi o zrobienie tego na 80 różnych 'TheProperty's. W tym świetle nie ma znaczenia, czy dokonuje tego funkcja reviver, czy przetwarzanie postprocesowe na parsowanym obiekcie. – Amadan

+0

@Amadan: Dobra uwaga, aktualizacja. –

+0

Użycie '.hasOwnProperty' będzie bezpieczniejsze niż' in', zważywszy na niewielką szansę, że istnieje pewna własność na sparsowanym JSON-ie, który współużytkuje nazwę z właściwością na 'Object.prototype'. Właśnie zdałem sobie sprawę, że Mozilla ma niestandardową właściwość ["oglądaj"] (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch). –

Powiązane problemy