2012-05-12 17 views
9

Ich habe einige Objekte, die ich von json mit nativen Browser-Implementierungen analysieren. Einige Eigenschaften der Objekte sind Zahlen. Im Moment werden die Zahlen von json als Strings analysiert und ich benutze parseInt, um die Zeichenkette auf den Int zu transformieren, den ich brauche.JavaScript JSON analysieren Objekteigenschaft direkt auf int

Das Problem ist, dass ich 23 Objekte habe ich dies mit und insgesamt etwa 80 Objekte, die ich ints wie diese bin Parsen:

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

Es gibt viele Codezeilen, die sehr ähnlich aussehen . Gibt es einen Weg, Prototypen oder etwas zu verwenden, um die Funktionsweise der JSON.parse-Funktion zu ändern, so dass bei jeder Ausführung des Parsers überprüft wird, ob eine String-Eigenschaft tatsächlich ein int ist, und wenn ja, direkt als solcher?

Danke.

+0

Wie würden Sie das automatisch machen, wenn 'parseInt ('1a', 10);' '' 'zurückgibt? Aber egal, auch wenn eine Eigenschaft wie eine Zahl aussieht - das heißt nicht, dass sie numerisch ist. – zerkms

+0

In den Fällen, in denen ich die parseInt-Funktion ausführe, weiß ich, dass es eine Zahl ist. Für den Fall, dass die Eigenschaft eine Zahl sein könnte, aber auch 1a, müssten Sie die IsNumeric-Funktion von jquery verwenden. – frenchie

+0

Wenn die ** numerische Zeichenkette ** die Nummer gemäß der Quelle ist, dann können Sie konvertieren, sonst nicht. –

Antwort

8

JSON können Zahlen wie folgt behandeln:

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

Wenn Ihre Immobilie doublequoted wurde, dann ist es ein String sonst ist es ein numerisches, boolean (true und false Werte), null oder nur etwas, das Parse-Fehler verursachen.

Siehe http://json.org/

+0

ok, danke, es funktioniert tatsächlich ohne Parsing; Ich habe nur den ganzen Parsing-Code entfernt und es funktionierte für die meisten Eigenschaften. Für die, die es nicht funktionierte, aktualisiere ich den Server-Serializer, um sich um das doppelte Angebotsproblem zu kümmern. Vielen Dank. – frenchie

+0

Verwenden Sie Online-Parser wie [dieser] (http://json.parser.online.fr/), wenn Sie sich nicht sicher sind, ob Sie JSON verwenden oder nur für Experimente. – kbec

2

Ich glaube nicht, Sie in der Lage sein werden, den Parser, zu modifizieren, sondern viele ähnlichen Zeilen Code von, eine Reihe von Eigenschaften verwenden und greifen Sie mit der [] Notation in einer Schleife zu parseInt() sie. Wenn Sie Zugriff auf den Code haben, der den JSON erzeugt, ist es natürlich einfacher, ihn so zu ändern, dass er nicht korrekt ausgegeben wird.

// 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); 
    } 
    } 
} 

Hinweis: Das wird nicht funktionieren, wenn die Objekte Eigenschaftsnamen teilen, die nicht Werte in allen von ihnen int. Wenn dies der Fall ist, müssten Sie dies ändern, um ein Array von Eigenschaften pro Objekt zu verwenden.

+0

* "Ich glaube nicht, dass Sie in der Lage sein werden, den Parser zu modifizieren ..." * Keine Notwendigkeit, dafür sind die Reviver-Funktionen gedacht. –

+0

Sie können den Parser nicht ändern. Es ist nur nativer Code für den eingebauten Parser. Sie können eine eigene schreiben, aber wofür ist das alles? – kbec

1

@kbec gibt die richtige Antwort. Wenn Sie keine Kontrolle über Ihre Datenquelle haben, dann können Sie so etwas wie folgt verwenden:

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

Wenn Sie manuell in int konvertieren, können Sie stattdessen 'parseInt (obj [field], 10) verwenden;' this one: 'parseInt (obj [field], 10) || 0'. Damit bist du dir sicher, dass deine Immobilie eine Nummer ist, selbst wenn sie NaN (keine Nummer) wert ist, hast du nur '0'. – kbec

+1

@kbec: Frage der Meinung und des spezifischen Anwendungsfalles.Im Allgemeinen würde ich jedoch viel lieber eine "NaN" als eine "0" für etwas erhalten, das keine Nummer ist, aber sein sollte. Wenn man es als "0" unter den Teppich wirft, kann das zu einigen schmerzhaften Debugging-Sitzungen führen. – Amadan

+2

@kbec: Stimmt, aber dann verbergen Sie die Tatsache, dass das Ding, das eine Nummer sein sollte, nicht war. –

9

JSON.parse ein zweites Argument in Form einer Funktion übernimmt, die etwas Nachbearbeitung tun können.

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

ich Sie nicht möchten, dass alle numerischen Strings verarbeiten, dann eine Lookup-Tabelle der Eigenschaften erstellen Sie wollen.

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 ist, dass einige Dinge die 'isNaN' Prüfung bestehen und trotzdem keine Zahlen sein können:' {"name": "Johnny Wonen", "login": "1.10", Beschreibung: " Eins-Zehn, verdammt!?! 11! " } ' – Amadan

+0

@Amadan: Dies ist nur ein Beispiel für einen Test. OP könnte stattdessen mit einer Lookup-Tabelle von Eigenschaften testen. Obwohl ich nicht genau weiß, was du meinst. Welcher Artikel in Ihrem Beispiel würde weitergeben, sollte das nicht. –

+0

In diesem Beispiel sollte 'login' immer noch eine Zeichenfolge sein; Es ist ein Zufall, dass es wie eine Nummer aussieht. – Amadan

2

Wenn Ihre Datenquelle nicht festgelegt werden kann (Zahlen sollten als Zahlen übergeben werden, nicht als Strings), you can pass JSON.parse a "reviver" function, die jedes Element empfangen werden, wie es verarbeitet werden wird.Dies gibt Ihnen die Möglichkeit, es zu verwandeln:

// 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

Oder wenn die Eigenschaftsnamen sind nicht ausreichend eindeutig (TheProperty nicht immer braucht Handhabung, nur wenn es eine Eigenschaft von TheObject), können Sie dies als ein Zwei-Ebenen-Check tun:

// 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); 
      } 
     } 
    } 
}); 

(Auferstehungs sind von innen nach außen, so genannt, werden die Eigenschaften durch die Zeit, die Sie das Objekt der Schlüssel zu sehen auf dem Objekt sein;. Deshalb haben wir sie an ihrem Platz aktualisieren)

Sie auf die Idee kommen, gibt es eine viel du c ein mit reviver Funktionen tun.


Randbemerkung: parseInt, die ich oben verwendet haben, ist ziemlich nachsichtig   — möglicherweise mehr zu vergeben als Sie wollen. Zum Beispiel:

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

Wenn Sie mit Zeichenketten wie "0x10" werden so behandelt, als hex in Ordnung sind, dann:

var a = Number(str); 

... die Sie NaN für ungültige Zahlenketten geben (Number("1a") ist NaN) . Da JSON keine Hexadezimalzahlen haben soll, wenn Sie sicher sind, dass die defekte Datenquelle sie nicht als Hex kodiert, sind Sie golden.

Andernfalls, wenn Sie dezimale benötigen, aber Sie strikt sein möchten, müssen Sie eine Regex für die Zeichenfolge, um sicherzustellen, dass es mit dem Muster für eine gültige Dezimalzahl (das ist ziemlich komplex, wenn Sie möchten) übereinstimmen Unterstützung all das Zeug JavaScript numerische Literale Unterstützung).

+0

"Das Problem ist, dass ich 23 Objekte habe, mit denen ich das mache und insgesamt ungefähr 80 Eigenschaften". Ich denke, es geht nicht darum, wie man die Eigenschaften konvertiert, es geht um 80 verschiedene 'TheProperty's. Es ist in diesem Licht eher unwichtig, ob es durch eine Wiederbelebungsfunktion oder durch Nachbearbeitung eines geparsten Objekts erfolgt. – Amadan

+0

@Amadan: Guter Punkt, aktualisiert. –

+0

Die Verwendung von '.hasOwnProperty' ist sicherer als' in', wenngleich die Wahrscheinlichkeit gering ist, dass es eine Eigenschaft auf dem geparsten JSON gibt, die einen Namen mit einer Eigenschaft auf 'Object.prototype' teilt. Ich habe gerade festgestellt, dass Mozilla eine nicht standardmäßige ["Watch" -Eigenschaft] hat (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch). –