2012-02-12 12 views
7

Estoy atascado en un problema y estoy buscando ideas sobre la mejor manera de abordarlo.tipo de conversión perl, javascript, JSON.parse JSON :: XS - ideas de necesidad

He asumido el desarrollo de un sitio en el que el backend está escrito en Perl y la interfaz hace un uso extenso de javascript.

El cliente recibe regularmente una actualización de unos pocos cientos de objetos rastreados desde el servidor. Los objetos están mapeados en un mapa de google a través de javascript. El hash del objeto (analizado por el javascript) contiene mucha información sobre el objeto, p. ubicación, descripción y varias variables de estado.
Algunos de los datos están en forma de cadena y algunos numéricos.

El problema es que, en el proceso de enviar los datos al lado del cliente javascript, todos los valores se están convirtiendo en cadenas. Y entonces, en el javascript, si pruebo, por ejemplo, para ver si un valor es positivo, la prueba está teniendo éxito incluso si el valor es 0 porque el valor es realmente "0" no 0.

En el lado del servidor, los datos están codificados con JSON :: XS de la siguiente manera;

sub process_json { 
my $self = shift; 

return if($self->{processed}); 
$self->{processed} = 1; 
if($self->{requestrec}->status =~ /^3/) 
{ 
    return $self->{requestrec}->status; 
} 

$self->{data}->{session} = { 
    id => $self->session->id, 
    user => $self->session->{data}->{__user}, 
}; 

use utf8; 
my $output; 
eval { $output = JSON::XS->new->utf8->encode($self->{data}); }; 
if([email protected]) 
{ 
    use Carp; 
    confess([email protected]); 
} 

$self->discard_request_body(); 
$self->req->content_type('application/json; charset=utf-8'); 
$self->req->headers_out->set('Expires' => 'Thu, 1 Jan 1970 00:00:00 GMT'); 

my $out_bytes = encode('UTF-8', $output); 
$self->req->headers_out->set('Content-Length' => length $output); 
$self->req->print($output) unless($self->req->header_only()); 

delete $self->{session}->{data}->{errors} 
    if(exists $self->{session}->{data}->{errors}); 
delete $self->{session}->{data}->{info} 
    if(exists $self->{session}->{data}->{info}); 
} ## end of: sub process_json 

En el lado del cliente, los datos se decodifican con JSON.parse de la siguiente manera;

function http_process (req, callback, errorfn) { 
if (req.readyState == 4) { 
    this.activerequest = null; 
    if (req.status != 200 && req.status != 0 && req.status != 304 && req.status != 403) { 
     if (errorfn) { return errorfn(req); } else { dialogue("Server error", "Server error " + req.status); } 
     if (req.status == 400) { dialogue("ERROR","Session expired"); this.failed = 1; 
     } else if (req.status == 404) { dialogue("ERROR", "Server error (404)"); this.failed = 1; 
     } else if (req.status == 500) { dialogue("ERROR", "Server error (500)"); this.failed = 1; } 
    } else { 
     if (callback) { 
      if (req.responseText) { 
       lstatus("Loaded (" + req.responseText.length + " bytes)"); 
       warn("Received " + req.responseText.length + " bytes"); 
       try { 
        var obj = JSON.parse(req.responseText); 
       } catch(e) { 
        warn(e); 
        warn(req.responseText); 
       } 
       callback(obj); 
      } else { 
       callback({}); 
      } 
     } 
    } 
} 

}

Puede alguien ver una forma útil de hacer frente a esto? Perl no está fuertemente tipado y JSON :: XS simplemente analiza los datos numéricos como una cadena en lugar de un número. He intentado agregar un reviver a JSON.parse (ver el código a continuación); sin embargo, no funciona (procesa la mayoría de los datos correctamente pero sigue fallando con una variedad de mensajes como non_object_property_call o undefined_method.

independientemente sería preferible si el trabajo de análisis de los datos para asegurar el tipo correcto se manejó en el lado del servidor. puede alguien ver cómo podría lograrse de manera eficiente?

function toNum(key, value) { 
/*make sure value contains an integer or a float not a string */ 
/*TODO: This seems VERY inefficient - is there a better way */ 
if (value instanceof Object) return; 
if (value instanceof Array) return; 
var intRE = /^\d+$/; 
var floatRE = /^\d*\.\d+$/; 
if(value.match(intRE)) { 
    value = parseInt(value); 
    return value; 
} 
if(value.match(floatRE)) { 
    value = parseFloat(value); 
    return value; 
} 

}

+0

Ah - Acabo de arreglar mi reviver tenía que ser el siguiente; función toNum (clave, valor) { \t/* asegúrese de valor contiene un entero o un flotador no es una cadena */ \t/* TODO: Esto parece muy ineficiente - hay una manera mejor */ \t si (valor instanceof String) { \t \t var intRE =/^ \ d + $ /; \t \t var floatRE = /^\d*\.\d+$/; \t \t if (value.coincidencia (intRE)) { \t \t \t valor = parseInt (valor); \t \t \t valor de retorno; \t \t} \t \t si (value.match (floatRE)) { \t \t \t valor = parseFloat (valor); \t \t \t valor de retorno; \t \t} \t \t \t \t} else { \t valor \t \t retorno; \t} } pero aún así me encantaría encontrar una manera mejor si existe? – mark

+0

bien, resulta que la única forma (que puedo encontrar) de arreglar esto en el lado del servidor es analizar el objeto de datos, buscar cualquier cosa que se parezca a un integrer o un flotante y agregarle 0. es decir $ val + = 0. luego obtengo los valores correctos en el lado JS. – mark

Respuesta

7

simple Perl escalares (cualquier escalar que no sea una referencia) son los más difíciles lt objetos para codificar: JSON :: XS y JSON :: PP codificarán los escalares indefinidos como valores nulos de JSON, los escalares que se usaron por última vez en un contexto de cadena antes de codificar como cadenas JSON, y cualquier otra cosa como valor numérico ...

El truco es "numificar" cualquier valor que desee codificar como un número justo antes de codificarlo.

$ perl -MJSON -e '$x="5"; print JSON->new->encode([ $x, "$x", 0+$x ])' 
["5","5",5] 
+1

Sí. Y puede hacer esto con su estructura de datos en su lugar (por ejemplo '$ data -> {member} + = 0') siempre y cuando no escriba ningún código que trate a esos miembros como cadenas entre hacerlo y JSON- codificación Técnicamente hablando, quieres que tus datos sean '! SvPOK'. – hobbs

+0

I * Pienso * que cuando los objetos se recuperan de Memcache o de la base de datos se tratan (a veces) como cadenas. ¿Suena posible? Es el único lugar donde puedo encontrar dónde podría estar ocurriendo la conversión. – mark