2010-11-15 17 views
19

he definido un objeto Point en un archivo Point.pm de la siguiente manera:Cómo convertir Perl objetos en JSON y viceversa

package Point; 
sub new { 
    my ($class) = @_; 
    my $self = { 
     _x => 0, 
     _y => 0, 
    }; 
    return bless $self => $class; 
} 

sub X { 
    my ($self, $x) = @_; 
    $self->{_x} = $x if defined $x; 
    return $self->{_x}; 
} 

sub Y { 
    my ($self, $y) = @_; 
    $self->{_y} = $y if defined $y; 
    return $self->{_y}; 
} 

1; 

Ahora cuando uso JSON para convertir el objeto a JSON mediante el siguiente código:

use JSON; 
use Point; 

Point $p = new Point; 
$p->X(20); 
$p->Y(30); 

my $json = encode_json $p; 

me sale el siguiente error:

encountered object 'Point=HASH(0x40017288)', but neither allow_blessed nor convert_blessed settings are enabled at test.pl line 28 

¿Cómo puedo convertir ay desde JSON a un objeto utilizando el módulo JSON?

+1

A menos que necesite específicamente JSON, le sugiero que use YAML para esta tarea. JSON no tiene sintaxis para indicar que algo es un objeto. YAML lo hace. Deberá unir manualmente algo o usar una extensión de lenguaje JSON como JSYNC. Si todo lo que necesita hacer es serializar un objeto Perl, use Data :: Dumper o Storable. – Schwern

+0

Originalmente desarrollé la solución en XML pero descubrí que JSON podría recortar la cadena porque a otras secuencias de comandos usando STDIN, sin importar la complejidad y la ilegibilidad de JSON, decidí volver a XML, lo cual es fácil de analizar. – Ibrahim

Respuesta

18

La advertencia le dice la mayor parte de lo que está mal. A menos que indique JSON cómo manejar benedict referencias (objetos Perl), JSON maneja estructuras de datos no bendecidas.

Puede convert_blessed y puede allow_blessed. Para allow_blessed, que dice:

If $enable is false (the default), then encode will throw an exception when it encounters a blessed object.

Point es una clase de objeto, por tanto, una instancia de Point es una referencia bendita, y por lo tanto el valor predeterminado para JSON es lanzar una excepción.

Si habilita convert_blessed, se llamará a un método TO_JSON en su objeto. Con simples objetos como Point (unidades que no contienen miembros bendecidos), se puede hacer eso con tanta facilidad como:

sub TO_JSON { return { %{ shift() } }; } 

Si tiene que descender por una estructura, se obtendrá una gran cantidadmás peludo.


Alguien en los comentarios a continuación dice que no cubrí cómo conseguir objetos cabo de JSON.

Lo básico es simple. Así que aquí va

my $object = bless(JSON->new->decode($json_string), 'ClassIWant'); 

he cubierto principalmente la parte que impide que simplemente de la serialización de un objeto bendito en JSON.

Los conceptos básicos de la deserialización son simples, al igual que los conceptos básicos de la serialización son simples, una vez que conoce el truco. No hay ningún error en el camino, solo existe la tarea de encontrar lo que necesita y bendecirlo en la clase correcta.

Si desea tener un código acoplado a los objetos, sabrá lo que tiene que ser bendecido y en qué tendrá que ser bendecido. Si desea un código totalmente desacoplado, , esto no es más difícil o más fácil en Perl que en el propio JavaScript.

Vas a tener que serializar un marcador en el JSON. Si necesito algo como esto, insertaré un campo '__CLASS__' en los objetos bendecidos. Y cuando deserializar, que descenderá a través de la estructura y bendigo todo como esto:

bless($ref, delete $ref->{__CLASS__}); 

Pero como ya he dicho, esto no es más fácil o más difícil es en Perl, porque JSON presenta el mismo desafío a todos los idiomas.

Como Schwern sugirió en su comentario arriba, YAML está mucho mejor construido para serializar y deserializar objetos, porque tiene notación para él. JSON le ofrece matrices o matrices asociativas.

+0

Estoy buscando una sintaxis de trabajo para habilitar esos indicadores. – Ibrahim

+0

Tiene la sintaxis: $ json-> allow_blessed-> convert_blessed-> encode ($ blessed_object) – Ibrahim

+4

O bien: to_json ($ blessed_object, {allow_blessed => 1, convert_blessed => 1}) –

5

¿Ha intentado leer el JSON documentation en las opciones y convert_blessed, como sugiere el mensaje de error? Eso debería explicar cómo convertir un objeto Perl a JSON.

Ir por el otro camino es más difícil, ya que JSON no es YAML, y no fue diseñado para ser deserializado en un sistema de objetos basado en clases como el de Perl. Puede experimentar con las opciones filter_json_object o filter_json_single_key_object, o puede postprocesar el JSON descodificado y crear los objetos usted mismo.

+0

tampoco muestran un ejemplo –

3

Necesita JSYNC.

use JSYNC; 
use Point; 
my $p = Point->new; 
$p->X(20); 
$p->Y(30); 

my $jsync = JSYNC::dump($p, {pretty => 1}); 

{ 
    "!" : "!perl/hash:Point", 
    "_x" : "20", 
    "_y" : "30" 
} 
+0

Esta es una versión muy temprana de JSYNC, y no debe usarse en absoluto a menos que sepa lo que está haciendo. Necesito un módulo listo para producción como JSON. – Ibrahim

+0

@daxim Acabo de probarlo y noté un pequeño problema: los valores son 'json picaduras' pero necesitamos' json numbers'. ¿Hay alguna manera de construir estos valores como números (no se ha encontrado nada dentro de la documentación) –

+0

Subclase JSYNC y cambiar el método 'info' para hacer una distinción entre [números] (http://p3rl.org/Scalar: : Util # looks_like_number) y no números al encontrar un tipo 'escalar' de Perl. – daxim

2

Puede que le resulte útil para convertir sus clases a Moose y utilizar MooseX::Storage para serializar y deserializar ellos.

+0

Me gusta usar Moose, sin embargo, el servidor que estoy usando usa una versión anterior de Perl 5.8.8. Me temo que el servidor se utiliza en producción y actualización. Perl romperá algunos de los scripts de producción. – Ibrahim

+0

@Ibrahim: Moose es compatible con perl5.8.8; Lo uso con esa versión de Perl en mis propios entornos de producción. – Ether

Cuestiones relacionadas