2017-09-21 7 views
-1

Je veux créer un document texte de document suivant JSON:JSON au texte, séquence spéciale

[ 
    { 
     "id": 12345, 
     "url": "https://www.w3schools.com", 
     "person": { 
      "firstname": "John", 
      "lastname": "Doe" 
     }, 
     "department": "IT" 
    }, 
    { 
     "id": 12346, 
     "url": "https://www.w3schools.com", 
     "person": { 
      "firstname": "Anna", 
      "lastname": "Jackson" 
     }, 
     "department": "LOG" 
    } 
] 

Mon schéma JSON se présente comme suit:

{ 
    "type": "array", 
    "items": { 
     "type": "object", 
     "properties": { 
      "id": { "type": "integer" }, 
      "url": { "type": "string", "format": "uri" }, 
      "person": { 
       "type": "object", 
       "properties": { 
        "firstname": { "type": "string" }, 
        "lastname": { "type": "string" } 
       } 
      }, 
      "department": { "enum": [ "IT", "LOG"] } 
     } 
    } 
} 

Le document de texte doit être structuré comme suit:

pid:  12345 
dep-abb: IT 
surname: Doe 
name:  John 

pid:  12346 
dep-abb: LOG 
surname: Jackson 
name:  Anna 

Je suis un débutant Perl et JSON et je cherchais un lib Perl qui peut donner cette approche en étendant le schéma (par ex. par txt_seq_no et txt_label). Les étiquettes dans le fichier texte doivent être triées par txt_seq_no ASC et renommées par txt_label. Est-il possible de résoudre ce problème aussi simple? Ensuite, le schéma pourrait ressembler à:

{ 
    "type": "array", 
    "items": { 
     "type": "object", 
     "properties": { 
      "id": { "type": "integer", "txt_seq_no"=10, "txt_label"="pid" }, 
      "url": { "type": "string", "format": "uri" }, 
      "person": { 
       "type": "object", 
       "properties": { 
        "firstname": { "type": "string", "txt_seq_no"=40, "txt_label"="name" }, 
        "lastname": { "type": "string", "txt_seq_no"=30, "txt_label"="surname" } 
       } 
      }, 
      "department": { "enum": [ "IT", "LOG", "PROD" ], "txt_seq_no"=20, "txt_label"="dep-abb" } 
     } 
    } 
} 
+1

Qu'avez-vous essayé? Quels problèmes avez-vous? S'il vous plaît nous montrer votre code. Si vous n'avez pas de code, Stack Overflow n'est probablement pas le bon endroit pour votre question. –

+0

Vous avez deux tâches distinctes ici. L'une consiste à vérifier votre entrée JSON par rapport au schéma et l'autre à écrire un fichier texte. Avez-vous besoin d'aide avec les deux, ou juste un? Commencez par rechercher le schéma JSON sur le CPAN. Il y a plusieurs implémentations qui devraient toutes fonctionner. – simbabque

+0

JSONSchema est uniquement destiné à valider des objets, pas à les transformer. Vous pouvez commencer avec une fonction qui prend un de vos objets JSON et la partie objet de votre JSONSchema et produit un nouvel objet de la forme '{'10_pid': ..., '20_dep-abb': ..., .. .} '. Aplatir un tableau de tels objets au format de votre texte devrait être facile alors. – Botje

Répondre

0

Merci à tous pour vos conseils et votre soutien! Je suis totalement débutant en Perl, les retours sont les bienvenus! (je l'ai ommited vérification des paramètres de fonction pour économiser l'espace)

emballages utilisés:

use Data::Traverse; 
use Data::Path; 

sous transforment

# key identifier[0]: mark JSON key that write into text file 
# key identifier[1]: optional in JSON schema: new label in text file 
my @KEY_IDENTIFIER = ("txt_seq_no", "txt_label"); 
# keys in JSON SCHEMA, can not be found in JSON document 
my @DELETE_FROM_PATH = ("items", "properties"); 

# transform a JSON document into text file 
# use identifier in JSON schema to define keys to transform to text 
sub transform { 
my ($doc, $schema, $key_identifier) = @_; 
if(not defined $key_identifier) { $key_identifier = \@KEY_IDENTIFIER; } 

my $transformator = get_transformator4schema($schema, $key_identifier, $log); 

my $data = get_data4transformator($doc, $transformator, $log); 

print_text($data, $transformator, $key_identifier, $log); 

} 

sous get_transformator4schema

sub get_transformator4schema { 
my ($schema, $key_identifier) = @_; 
my $t= Data::Traverse->new($schema); 

my %transformator; 

$t->traverse(
    sub { 
     if($t->item_key eq @{$key_identifier}[0] or $t->item_key eq @{$key_identifier}[1]) { 
      my $path = $t->path; 
      my $key; 

      # delete path that only exists in schema, not in doc 
      foreach my $del_path (@DELETE_FROM_PATH) { 
       $path =~ s/\/$del_path//g; 
      } 

      # delete last element from path 
      if($t->item_key eq @{$key_identifier}[0]) { 
       $key = @{$key_identifier}[0]; 
       $path =~ s/\/@{$key_identifier}[0]$//g; 
      } 
      if($t->item_key eq @{$key_identifier}[1]) { 
       $key = @{$key_identifier}[1]; 
       $path =~ s/\/@{$key_identifier}[1]$//g; 
      } 

      # add key => { key => value } 
      if(not exists $transformator{$path}) { 
       my %key_val = ($key => $_); 
       $transformator{$path} = \%key_val; 
      } else { 
       my $nested_hash = $transformator{$path}; 
       $nested_hash->{$key} = $_; 
      } 
     } 
    } 
); 
return \%transformator; 
} 

sous get_data4transformator

# fetch needed data from document 
sub get_data4transformator { 
my ($document, $transformator, $log) = @_; 

my @template; 

foreach my $doc (@{$document}) { 
    my $doc_path= Data::Path->new($doc); 

    my %th =(); 

    # load values for key = path 
    foreach my $path (keys %{$transformator}) { 
     my $val = $doc_path->get($path); 
     # add value from doc to hash 
     $th{$path} = $val; 
    } 
    push @template, \%th; 
} 
return \@template; 
} 

sous print_text:

sub print_text { 

my ($data, $transformator, $key_ids, $log) = @_; 

# sort by 1st item of $key_ids 
my $sort_by = @{$key_ids}[0]; 
my $opt_name = @{$key_ids}[1]; 
print "\nsort data by '$sort_by' ASC\n"; 
my @sorted_keys = sort { 
    $transformator->{$a}->{$sort_by} 
    <=> 
    $transformator->{$b}->{$sort_by} 
} keys %{$transformator}; 

foreach my $tdoc (@{$data}) { 
    print "\nread document item:\n"; 
    foreach my $key (@sorted_keys) { 
     my $name = $key; 
     $name =~ s/^.*\/(\w+)$/$1/g; 
     my $alias_name = ""; 
     if(defined $transformator->{$key}->{$opt_name}) { 
      $alias_name = $transformator->{$key}->{$opt_name}; 
     } 

     print " $name => $tdoc->{$key}"; 
     if(not $alias_name eq "") { 
      print " alias '$alias_name'\n"; 
     } else { 
      print "\n"; 
     } 
    } 
} 
} 

Cette fonctionnalité permet de contrôler la clé passe dans le fichier texte et sa position. Avec au moins un paramètre txt_seq_no. Le deuxième paramètre txt_label est facultatif et stocke l'étiquette alternative dans le fichier texte.

sortie:

id => 12345 alias 'pid' 
department => IT alias 'dep-abb' 
lastname => Doe 
firstname => John alias 'name' 

id => 12346 alias 'pid' 
department => LOG alias 'dep-abb' 
lastname => Jackson 
firstname => Anna alias 'name' 

id => 12347 alias 'pid' 
department => PROD alias 'dep-abb' 
lastname => Smith 
firstname => Peter alias 'name' 
1

L'approche de base est d'utiliser un module JSON pour décoder le JSON dans une structure de données Perl et puis marcher cette structure pour construire la sortie que vous voulez.

#!/usr/bin/perl 

use strict; 
use warnings; 
use feature 'say'; 

use JSON; 

my $json = JSON->new; 

my $json_str = '[ 
    { 
     "id": 12345, 
     "url": "https://www.w3schools.com", 
     "person": { 
      "firstname": "John", 
      "lastname": "Doe" 
     }, 
     "department": "IT" 
    }, 
    { 
     "id": 12346, 
     "url": "https://www.w3schools.com", 
     "person": { 
      "firstname": "Anna", 
      "lastname": "Jackson" 
     }, 
     "department": "LOG" 
    } 
]'; 

my $data = $json->decode($json_str); 

for (@$data) { 
    say "pid:  $_->{id}"; 
    say "dep-abb: $_->{department}"; 
    say "surname: $_->{person}{lastname}"; 
    say "name: $_->{person}{firstname}\n"; 
}