JSON 到文本,特殊序列
JSON to text, special sequence
我想从以下 JSON 文档创建一个文本文档:
[
{
"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"
}
]
我的 JSON 架构如下所示:
{
"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"] }
}
}
}
文本文档的结构应如下:
pid: 12345
dep-abb: IT
surname: Doe
name: John
pid: 12346
dep-abb: LOG
surname: Jackson
name: Anna
我是 Perl 和 JSON 新手,正在寻找可以通过扩展模式(例如 txt_seq_no
和 txt_label
)来处理这种方法的 Perl 库。文本文件中的标签应按 txt_seq_no
ASC 排序并按 txt_label
重命名。有没有可能这么简单地解决这个问题?然后架构可能如下所示:
{
"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" }
}
}
}
基本方法是使用 JSON 模块将 JSON 解码为 Perl 数据结构,然后遍历该结构以构建您想要的输出。
#!/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";
}
感谢大家的提示和支持!
我是 Perl 的初学者,欢迎提供反馈!
(我省略了函数参数检查以保存 space)
使用的包:
use Data::Traverse;
use Data::Path;
子变换
# 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 );
}
sub 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;
}
sub 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;
}
sub 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+)$//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";
}
}
}
}
此功能允许控制哪个键进入文本文件及其位置。至少有一个参数 txt_seq_no
。第二个参数 txt_label
是可选的,将替代标签存储在文本文件中。
输出:
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'
我想从以下 JSON 文档创建一个文本文档:
[
{
"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"
}
]
我的 JSON 架构如下所示:
{
"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"] }
}
}
}
文本文档的结构应如下:
pid: 12345
dep-abb: IT
surname: Doe
name: John
pid: 12346
dep-abb: LOG
surname: Jackson
name: Anna
我是 Perl 和 JSON 新手,正在寻找可以通过扩展模式(例如 txt_seq_no
和 txt_label
)来处理这种方法的 Perl 库。文本文件中的标签应按 txt_seq_no
ASC 排序并按 txt_label
重命名。有没有可能这么简单地解决这个问题?然后架构可能如下所示:
{
"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" }
}
}
}
基本方法是使用 JSON 模块将 JSON 解码为 Perl 数据结构,然后遍历该结构以构建您想要的输出。
#!/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";
}
感谢大家的提示和支持! 我是 Perl 的初学者,欢迎提供反馈! (我省略了函数参数检查以保存 space)
使用的包:
use Data::Traverse;
use Data::Path;
子变换
# 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 );
}
sub 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;
}
sub 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;
}
sub 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+)$//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";
}
}
}
}
此功能允许控制哪个键进入文本文件及其位置。至少有一个参数 txt_seq_no
。第二个参数 txt_label
是可选的,将替代标签存储在文本文件中。
输出:
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'