Perl入門ゼミ

テキスト処理、Linuxサーバー管理、Web開発
  1. Perl
  2. モジュール
  3. here

JSON - JSONデータを解析

JSONモジュールを使用すると、JSONデータを解析することができます。JSONはデータを記述するための言語で、配列やハッシュなどのデータ構造を表現することができます。JSONは単なる文字列ですので可搬性があります。他のプログラム言語とデータをやり取りした場合によく利用されます。

# モジュールの読み込みと関数のインポート
use JSON qw/encode_json decode_json/;

JSONをPerlのデータ構造に変換するにはdecode_json関数を使用します。

# JSONをPerlのデータ構造に変換する
my $json_in = '[{"name" : "Ken", "age" : 19}, {"name" : "Ken", "age" : 25}]';

my $data = decode_json($json_in);

これは次のようなPerlのデータ構造に変換されます。

# JSON
'[{"name" : "Ken", "age" : 19}, {"name" : "Ken", "age" : 25}]'

              ▼

# Perl
[
  {
    'name' => 'Ken',
    'age' => 19
  },
  {
    'name' => 'Ken',
    'age' => 25
  }
];

逆にPerlのデータ構造をJSONに変換するにはencode_json関数を使用します。

# Perlのデータ構造をJSONに変換する
my $json_out = encode_json($data);

JSONモジュールでの日本語の扱い

JSONモジュールで日本語を扱うときは少し注意が必要です。次のことを覚えておく必要があります。

  1. decode_jsonは「UTF-8バイト文字列-JSON」から「内部文字列-Perlデータ」への変換を行う
  2. encode_jsonは「内部文字列-Perlデータ」から「UTF-8バイト文字列-JSON」への変換を行う

この関係を図示すると次のようになります。

UTF-8バイト文字列-JSON     UTF-8バイト文字列-Perlデータ
                      \
encode_jsonは          \
左上への変換            \
                         \   decode_jsonは右下への変換
                          \
内部文字列JSON             内部文字列-Perlデータ

左上から右下への変換がdecode_jsonによって行われ、右下から左上への変換がencode_jsonによって行われます。上下や左右への変換を行うメソッドは用意されていません。

たとえば間違いやすい例ですが次のように書くとうまくいきません。(日本語をスクリプトの中で扱うので、utf8プラグマを有効にして、スクリプトはUTF-8で保存しています。)

# 日本語を扱うときのよくある間違い。decode_jsonはUTF-8バイト文字列を受け取る必要がある
use utf8;
use JSON 'decode_json';

my $json = '{"name" : "増田"}';

my $data = decode_json($json);

これがうまくいかない理由は、utf8プラグマが有効になっているので$jsonはすでに内部文字列に変換されているからです。decode_jsonはバイト文字列を引数に取りますので、これではうまくいきません。Encodeモジュールのencode_utf8関数でUTF-8バイト文字列に変換する必要があります。

# 日本語を扱う場合の正しい例
use utf8;
use JSON 'decode_json';
use Encode 'encode_utf8';

my $json = '{"name" : "増田"}';

# UTF-8バイト文字列に変換
$json = encode_utf8($json);

my $data = decode_json($json);

ファイルに書かれたJSONを読み込む

JSONモジュールにはファイルを読み込む機能はありませんので、ファイルから読み込む方法を記載しておきます。

# ファイルからJSONを読み込むサンプル
use JSON 'decode_json';

my $file = shift;

my $data = decode_json(get_content($file));

# ファイルの内容を取得する関数
sub get_content {
  my $file = shift;

  open my $fh, '<', $file
    or die "Can't open file \"$file\": $!";
  
  my $content = do { local $/; <$fh> };
 
  close $fh;

  return $content;
}