逐块解析JSON

时间:2015-05-08 03:18:53

标签: json perl parsing data-structures perl-data-structures

我有一个JSON文件,其中包含客户和日期列表。

该文件如下所示:

{
"Customers": [
{
  "Customer": "Customer Name Here",
  "Company": "Super Coffee",
  "First Name": "First Name Here",
  "Main Phone": "777-777-7777",
  "Fax": "777-777-7777",
  "Bill to 1": "Billing Address One",
  "Bill to 2": "Billing Address Two",
  "Bill to 3": "Billing Address Three",
  "Ship to 1": "Shipping Address One",
  "Ship to 2": "Shipping Address Two",
  "Ship to 3": "Shipping Address Three",
  "Customer Type": "Dealer/Retail"
},
{
  "Customer": "Customer Name Here",
  "Company": "Turtle Mountain Welding",
  "First Name": "First Name Here",
  "Main Phone": "777-777-7777",
  "Fax": "777-777-7777",
  "Bill to 1": "Billing Address One",
  "Bill to 2": "Billing Address Two",
  "Bill to 3": "Billing Address Three",
  "Ship to 1": "Shipping Address One",
  "Ship to 2": "Shipping Address Two",
  "Ship to 3": "Shipping Address Three",
  "Customer Type": "Dealer/Retail"
},
{
  "Customer": "Customer Name Here",
  "Company": "Mountain Equipment Coop",
  "First Name": "First Name Here",
  "Main Phone": "777-777-7777",
  "Fax": "777-777-7777",
  "Bill to 1": "Billing Address One",
  "Bill to 2": "Billing Address Two",
  "Bill to 3": "Billing Address Three",
  "Ship to 1": "Shipping Address One",
  "Ship to 2": "Shipping Address Two",
  "Ship to 3": "Shipping Address Three",
  "Customer Type": "Dealer/Retail"
},
{
  "Customer": "Customer Name Here",
  "Company": "Best Soup Inc.",
  "First Name": "First Name Here",
  "Main Phone": "777-777-7777",
  "Fax": "777-777-7777",
  "Bill to 1": "Billing Address One",
  "Bill to 2": "Billing Address Two",
  "Bill to 3": "Billing Address Three",
  "Ship to 1": "Shipping Address One",
  "Ship to 2": "Shipping Address Two",
  "Ship to 3": "Shipping Address Three",
  "Customer Type": "Dealer/Retail"
}
]
}

我需要能够逐块地从文件中提取数据,而不是逐行提取。

我习惯逐行解析文件以获取数据,但是使用JSON,我需要以某种方式逐块读取它(或者更准确地说,逐个对象读取?)。我需要通过每个客户的括号内的内容来阅读它。这样我就可以编写一个脚本来提取我需要的数据,并从中构建一个CSV文件。

例如:

i="1"
for file in *.json; do
     customername=$(jsonblock$i:customername);
     customerAddress=$(jsonblock$i:customeraddress);
     etc...
     i=$[i+1]
done

我理解在逐行读取文件时如何完成此操作,但是如何读取每个JSON块,就好像它是一行一样呢?

3 个答案:

答案 0 :(得分:4)

对于上面的JSON(由于提供的数据无效而被修改),以下脚本将解析并打印每个块的"Company:"部分:

#!/usr/bin/env perl

use JSON;   
use IO::All;     
use v5.16;

my $data < io 'Our_Customers.json';
my $customers_list = decode_json($data)->{"Customers"};                

for my $customer (@$customers_list) {
   say $customer->{"Company"} ;
}

<强>输出

Super Coffee
Turtle Mountain Welding
Mountain Equipment Coop
Best Soup Inc.

该脚本使用IO::AllJSON来读取和解析(decode_json)文件。

在此示例中,JSON数据只是映射到Perl数据结构(Array of Hashes),它与JSON数据完全对应。然后,我们可以访问每个数组元素( 数组中的每个哈希),然后通过键名访问哈希内的数据。 Perl具有非常灵活的数据修改和访问功能,这使得使用JSON数据非常愉快。

每个数据块的键来自JSON文件的等效部分。如果我们从数组中移出一个元素,它将是一个哈希,我们访问可以看到元素的keysvalues,如下所示:

say for keys shift $customers_list ;

Customer Type
First Name
Bill to 2
Main Phone
...

使用您在$element->{"key"}循环中看到的for语法访问每个键的值。

最好在将JSON数据发布到SO - JSON Lint之前对其进行验证,类似的服务可以为此提供帮助。

答案 1 :(得分:1)

使用perl和JSON库可以逐步解析JSON列表中的每个项目,但是你需要使用json以使它实际上不是json,而是一个没有用逗号分隔的json对象列表。

<!-- GET THE LIBRARIES (YOU SHOULD ALREADY HAVE THEM) -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.js"></script>    
<script>
$(document).ready(function() {
    $("#confirm").click(function() {
            $.ajax({
                    // This is where you need the right path to the new php file
                    url:'/path/to/new.php',
                    type: 'post',
                    data: $("#orderform").serialize(),
                    success: function(response) {
                        $("#final").html(response);
                    }
                });
        });
});
</script>

对于customers.json(不再是json):

#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
use JSON;
my $json = JSON->new;
while (<>) {
    my $obj_or_undef = eval { $json->incr_parse( $_ ); };
    # Wait until its found a whole object
    if (ref $obj_or_undef) {
        say join ",", map {$obj_or_undef->{$_}} sort keys %$obj_or_undef;
    }
}

运行:

{ 
    "some key" : "some value"
} {
    "other key" : "other value"
}

答案 2 :(得分:1)

如果您的目的只是以CSV格式打印JSON数据,那么您提出的问题是错误的。您应该解析整个JSON文档并逐项处理Customers数组。

使用Perl的JSONText::CSV模块,看起来像这样

use strict;
use warnings;

use JSON 'from_json';
use Text::CSV ();

my @columns = (
  'Bill to 1',  'Bill to 2',     'Bill to 3', 'Company',
  'Customer',   'Customer Type', 'Fax',       'First Name',
  'Main Phone', 'Ship to 1',     'Ship to 2', 'Ship to 3',
);

my $out_fh = \*STDOUT;
my $json_file = 'customers.json';

my $data = do {
  open my $fh, '<', $json_file or die qq{Unable to open "$json_file" for input: $!};
  local $/;
  from_json(<$fh>);
};
my $customers = $data->{Customers};

my $csv = Text::CSV->new({ eol => $/ });
$csv->print($out_fh, \@columns);

for my $customer ( @$customers ) {
  $csv->print($out_fh, [ @{$customer}{@columns} ]);
}

<强>输出

"Bill to 1","Bill to 2","Bill to 3",Company,Customer,"Customer Type",Fax,"First Name","Main Phone","Ship to 1","Ship to 2","Ship to 3"
"Billing Address One","Billing Address Two","Billing Address Three","Super Coffee","Customer Name Here",Dealer/Retail,777-777-7777,"First Name Here",777-777-7777,"Shipping Address One","Shipping Address Two","Shipping Address Three"
"Billing Address One","Billing Address Two","Billing Address Three","Turtle Mountain Welding","Customer Name Here",Dealer/Retail,777-777-7777,"First Name Here",777-777-7777,"Shipping Address One","Shipping Address Two","Shipping Address Three"
"Billing Address One","Billing Address Two","Billing Address Three","Mountain Equipment Coop","Customer Name Here",Dealer/Retail,777-777-7777,"First Name Here",777-777-7777,"Shipping Address One","Shipping Address Two","Shipping Address Three"
"Billing Address One","Billing Address Two","Billing Address Three","Best Soup Inc.","Customer Name Here",Dealer/Retail,777-777-7777,"First Name Here",777-777-7777,"Shipping Address One","Shipping Address Two","Shipping Address Three"