2012-05-12 21 views
9

Tengo algunos objetos que estoy analizando desde json utilizando implementaciones de navegador nativas. Algunas de las propiedades de los objetos son números. Por el momento, los números son parse de json como cadenas y yo uso parseInt para convertir la cadena al int que necesito.javascript Propiedad de objeto de análisis JSON directamente en int

El problema es que tengo 23 objetos que hago esto con y en general alrededor de 80 propiedades que estoy de análisis sintáctico de enteros como esto:

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

Hay muchas líneas de código que son muy similares . ¿Hay alguna manera de usar prototipos o algo para cambiar la forma en que funciona la función JSON.parse de modo que cada vez que el analizador la ejecute, compruebe si una propiedad de cadena es en realidad un int y, en caso afirmativo, echándola directamente como tal?

Gracias.

+0

¿Cómo lo haría automágicamente si 'parseInt ('1a', 10);' devuelve '1'? Pero de todos modos, incluso si la propiedad se parece a un número, no significa que sea numérica – zerkms

+0

En los casos en que ejecuto la función parseInt, sé que es un número. Para el caso donde la propiedad podría ser un número pero también podría ser 1a, necesitaría usar la función IsNumeric de jquery. – frenchie

+0

Si ** la cadena de caracteres numéricos ** son números de acuerdo con la fuente, entonces puede convertir, de lo contrario no. –

Respuesta

8

JSON puede manejar números de la siguiente manera:

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

Si su propiedad fue doublequoted entonces es una cadena de lo contrario es un valor numérico, booleano (true y false valores), null o simplemente algo que causa error de análisis.

Ver http://json.org/

+0

bien, gracias, de hecho funciona sin el análisis sintáctico; Acabo de eliminar todo el código de análisis y funcionó para la mayoría de las propiedades. Para los que no funcionó, estoy actualizando el serializador del servidor para encargarme del problema de las comillas dobles. Gracias. – frenchie

+0

Use un analizador en línea como [este] (http://json.parser.online.fr/) si no está seguro acerca de su JSON o solo para experimentos. – kbec

2

No creo que usted será capaz de modificar el programa de análisis, pero en vez de muchas líneas similares de código, utilice un conjunto de las propiedades y acceder a ellos con la notación [] en un bucle a parseInt() ellos. Por supuesto, si tiene acceso al código que produce el JSON, es más fácil cambiarlo a las entradas de salida correctamente sin comillas.

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

Nota: Esto no funcionará si los objetos comparten nombres de propiedades que no son valores int en todos ellos. Si ese es el caso, necesitaría modificar esto para usar una matriz de propiedades por objeto.

+0

* "No creo que puedas modificar el analizador ..." * No es necesario, para eso sirven las funciones de reactivación. –

+0

No puede modificar el analizador. Es solo código nativo para el analizador incorporado en el navegador. Puedes escribir el propio, pero ¿para qué es todo esto? – kbec

1

@kbec da la respuesta correcta. Si usted no tiene control sobre el origen de datos, entonces se puede usar algo como esto:

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

Si convierte manualmente a int, puede usar en su lugar 'parseInt (obj [field], 10);' this: 'parseInt (obj [field], 10) || 0'. Con esto, usted está seguro de que su propiedad es un número, incluso si el valor era NaN (no es un número) usted acaba de obtener '0'. – kbec

+1

@kbec: asunto de opinión y del caso de uso específico.Sin embargo, en general, preferiría recibir un 'NaN' que un' 0' por algo que no es un número, pero debería serlo. Barriéndolo debajo de la alfombra como un '0' puede llevar a algunas sesiones de depuración dolorosas. – Amadan

+2

@kbec: Cierto, pero luego oculta el hecho de que lo que se suponía que era un número, no lo era. –

9

JSON.parse acepta un segundo argumento en forma de una función que puede hacer algo de procesamiento posterior.

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

os no quieren procesar todas las cadenas numéricas, a continuación, crear una tabla de búsqueda de las propiedades que usted desee.

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

El problema es que algunas cosas pueden pasar la verificación 'isNaN', y aún no ser números:' {"nombre": "Johnny Wonten", "iniciar sesión": "1.10", descripción: " One-Ten, geddit!?! 11! " } ' – Amadan

+0

@Amadan: Esto es solo un ejemplo de una prueba. OP podría probar contra una tabla de búsqueda de propiedades en su lugar. Aunque no estoy exactamente seguro de lo que quieres decir. Qué ítem en su ejemplo pasaría que no debería. –

+0

En el ejemplo, 'login' debe seguir siendo una cadena; es una coincidencia que se vea como un número. – Amadan

2

Si el origen de datos no se puede arreglar (los números deben ser pasados ​​como números, no como cadenas), you can pass JSON.parse a "reviver" function, que recibirá cada elemento, ya que está siendo procesado.Esto le da la opción de transformarlo:

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

O si los nombres de las propiedades no son lo suficientemente único (TheProperty no lo hace siempre necesita manipulación, justo cuando se trata de una propiedad de TheObject), se puede hacer esto como un cheque de dos niveles:

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

(Resucitadores son llamados de dentro a fuera, por lo que las propiedades habrá en el objeto en el momento en que se ve la clave del objeto;. es por eso que actualizamos en su lugar)

usted consigue la idea, hay mucho tu c un hacer con las funciones reviver.


Nota al margen: parseInt, que he utilizado anteriormente, es bastante indulgente   — posiblemente más tolerante que desea. Por ejemplo:

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

Si estás bien con cadenas como "0x10" siendo tratados como hexagonal, entonces:

var a = Number(str); 

... lo cual le dará NaN para cadenas de números no válidos (es Number("1a")NaN) . Dado que JSON no está destinado a tener números hexadecimales, si estás seguro de que la fuente de datos fragmentada no los codificará como hexadecimal, estás dorado.

De lo contrario, si necesita un decimal pero desea ser estricto, tendrá que hacer una expresión regular en la cadena para asegurarse de que coincida con el patrón de un número decimal válido (que es bastante complejo, si lo desea admitir todo el soporte de los literales numéricos de JavaScript).

+0

"El problema es que tengo 23 objetos con los que hago esto y en total unas 80 propiedades". Supongo que no se trata de cómo convertir las propiedades, se trata de hacerlo a 80 'TheProperty's diferentes. Es bastante intrascendente en esa luz si se realiza mediante una función reviver o mediante el postproceso en un objeto analizado. – Amadan

+0

@Amadan: Buen punto, actualizado. –

+0

Usar '.hasOwnProperty' será más seguro que' in', dado el pequeño riesgo de que exista alguna propiedad en el JSON analizado que comparta un nombre con una propiedad en 'Object.prototype'. Me acabo de dar cuenta de que Mozilla tiene una [propiedad de "vigilancia" no estándar] (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch). –