text+tsvファイルからjsonを生成する

text+tsvファイルからjsonを生成する

私は初心者で、JSonを使ったことがありません。一部のjsonテキストファイルのみを解析しました。
カテゴリ数は異なる場合があります。

Category1
1111|2222|3333|444|5555
6666|7777|8888|9999|1111
0000|1111|22222|3333|4444
Category2
2222|3333||5555
2222|3333|4444||5555
Category3
AAAA|||BBBB
CCCC|DDDD|EEEE|FFFF|GGGG

予想される JSON: カテゴリ ---> 配列 ---> tsv ごとに --> Make Key:Value(Year|Title|Name|Format|Base) tsv の値が上記のいずれかと一致しない場合は、null を追加します。 Jsonは次のようにする必要があります。これは、各カテゴリーを数値的に索引付けし、カテゴリーを再索引付けしてtsv配列を取得できることです。

Json構造は次のようになります。たとえば、次のようになります。

1) I could get list of category using jq
cat file | jq
Output:
Category1
Category2
Category3
2) Index that Category
jq '.| Category[0]'
Output:
Category1
1111|2222|3333|444|5555
6666|7777|8888|9999|1111
0000|1111|22222|3333|4444


3) Index each tsv 
jq Category1 | jq '.[0]' ---> 
{
"Year": "1111"
"Title": "2222"
"Name": "3333"
"Format": "4444"
"Base": "5555"
}

jq'.|カテゴリ[0]

答え1

最終的なJSON文書がどのように見えるかはわかりませんが、mlrMiller()と次のようにCSV入力ファイルに基づいてJSON文書を作成しますjq

mlr --c2j -N --ifs pipe --ragged \
        label Year,Title,Name,Format,Base then \
        put '
                if (NF == 1) {
                        @Category = string($Year)
                } else {
                        $Category = @Category
                }' then \
        filter -x 'is_absent($Category)' then \
        unsparsify file.csv |
jq -n 'reduce inputs as $a ({}; .[$a.Category] += [$a])'

これは、質問で述べた順序で言及したタイトルを追加することから始まります。Yearレコードにフィールドが1つしかない場合は、そのフィールド(最初のフィールド)の値を記憶します。Category複数のフィールドがある場合は、記憶された値でフィールドが生成されます。

次に、そのフィールドがないすべてのレコードを削除し、Category最後に欠落しているフィールドにnull値を追加します。

これでJSONオブジェクトセットが作成されました。

{ "Year": 1111, "Title": 2222, "Name": 3333, "Format": 444, "Base": 5555, "Category": "Category1" }
{ "Year": 6666, "Title": 7777, "Name": 8888, "Format": 9999, "Base": 1111, "Category": "Category1" }
{ "Year": 0000, "Title": 1111, "Name": 22222, "Format": 3333, "Base": 4444, "Category": "Category1" }
{ "Year": 2222, "Title": 3333, "Name": "", "Format": 5555, "Base": "", "Category": "Category2" }
{ "Year": 2222, "Title": 3333, "Name": 4444, "Format": "", "Base": 5555, "Category": "Category2" }
{ "Year": "AAAA", "Title": "", "Name": "", "Format": "BBBB", "Base": "", "Category": "Category3" }
{ "Year": "CCCC", "Title": "DDDD", "Name": "EEEE", "Format": "FFFF", "Base": "GGGG", "Category": "Category3" }

jqその後、フィールドの値に基づいてオブジェクトを配列として収集することによって処理されますCategory

データが与えられると、これは何かを生成します等しい

{
   "Category1": [
      { "Base": 5555, "Category": "Category1", "Format": 444, "Name": 3333, "Title": 2222, "Year": 1111 },
      { "Base": 1111, "Category": "Category1", "Format": 9999, "Name": 8888, "Title": 7777, "Year": 6666 },
      { "Base": 4444, "Category": "Category1", "Format": 3333, "Name": 22222, "Title": 1111, "Year": 0 }
   ],
   "Category2": [
      { "Base": "", "Category": "Category2", "Format": 5555, "Name": "", "Title": 3333, "Year": 2222 },
      { "Base": 5555, "Category": "Category2", "Format": "", "Name": 4444, "Title": 3333, "Year": 2222 }
   ],
   "Category3": [
      { "Base": "", "Category": "Category3", "Format": "BBBB", "Name": "", "Title": "", "Year": "AAAA" },
      { "Base": "GGGG", "Category": "Category3", "Format": "FFFF", "Name": "EEEE", "Title": "DDDD", "Year": "CCCC" }
   ]
}

これを通過すると、jq '.Category1[0]'次のようになります。

{
  "Year": 1111,
  "Title": 2222,
  "Name": 3333,
  "Format": 444,
  "Base": 5555,
  "Category": "Category1"
}

答え2

標準ツールに比べてデータに自由形式が多すぎます。たとえば、Perlを使用することをお勧めします。

#!/bin/perl
use JSON::PP;

open(IN, "<file.tsv");
while(<IN>) {
  chomp;
  if (/Category1/) {
     $group = $_;
     @heads = ("Year", "Title", "Name", "Format", "Base");
  } elsif (/Category2/) {
     $group = "new name for Category2";
     @heads = ("Year", "Title", "Name");
  } elsif (/Category3/) {
     $group = $_;
     @heads = ("ABC", "EFD");
  } else {
     my @columns = split /\|/;
     my %row = ();
     for (my $i=0; $i < scalar(@heads); $i++) {
        $row{$heads[$i]} = $columns[$i];
     }
     push @{$data{$group}}, \%row;

  }
}
close(IN);

print encode_json \%data;

答え3

csplitこれを使用して実行する方法は1つありますjq

次のようにデータを一時ファイルに分割できます。

csplit -z infile.csv '/^Category/' '{*}'

xx*ファイルをJSONオブジェクトに変換する:

for f in xx*; do
  <$f jq -sRrc '
  split("\n")
  | .[0] as $category
  | .[1:-1]
  | map(split("|"))
  | map({"Year"  : .[0],
         "Title" : .[1],
         "Name"  : .[2],
         "Format": .[3],
         "Base"  : .[4],
        }) | { ($category): . }
  '
done

出力:

{"Category1":[{"Year":"1111","Title":"2222","Name":"3333","Format":"444","Base":"5555"},{"Year":"6666","Title":"7777","Name":"8888","Format":"9999","Base":"1111"},{"Year":"0000","Title":"1111","Name":"22222","Format":"3333","Base":"4444"}]}
{"Category2":[{"Year":"2222","Title":"3333","Name":"","Format":"5555","Base":null},{"Year":"2222","Title":"3333","Name":"4444","Format":"","Base":"5555"}]}
{"Category3":[{"Year":"AAAA","Title":"","Name":"","Format":"BBBB","Base":null},{"Year":"CCCC","Title":"DDDD","Name":"EEEE","Format":"FFFF","Base":"GGGG"}]}

次のカテゴリを取得できます。

jq -r 'keys[]'

出力:

Category1
Category2
Category3

次の特定のカテゴリが必要な場合:

n=2; cat xx$(printf "%02d" $((n-1)))

出力:

Category2
2222|3333||5555
2222|3333|4444||5555

インデックスごとに特定の項目を取得します。たとえば、2番目のオブジェクトは次のとおりですCategory2

jq '.Category2 // empty | .[1]'

出力:

{
  "Year": "2222",
  "Title": "3333",
  "Name": "4444",
  "Format": "",
  "Base": "5555"
}

答え4

#!/usr/bin/perl

use JSON;
use strict;

my @fields = qw(Year Title Name Format Base);
my (%data, $category, $row);

while(<>) {
  chomp;
  my @line = split /\|/;

  if ($#line == 0) {
    # there are no field separators on this line, so
    # this must be a "category" line.
    $category = $_;
    $row = 0;

  } else {
    foreach my $i (0..$#fields) {
      # treat empty strings as null values
      undef $line[$i] if ($line[$i] eq "");

      $data{$category}[$row]{$fields[$i]} = $line[$i]
    };
    $row++;
  };
};

my $json = JSON->new->pretty->canonical;
print $json->encode(\%data) ;

ところで、「pretty」はjson文字列で改行とインデントを有効にします。 'canonical'はキーがソートされた順序で出力されるようにします(そうでなければ、perlハッシュは本質的に順序がないため、キーが実行されるたびに半ランダムな順序で出力されます)。どちらもデフォルトで無効になっています。JSONモジュールは、追加の処理オーバーヘッドを発生させ(つまり、遅い)、人が出力を読み取ろうとする場合にのみ必要です。 jsonデータを処理するプログラムは、キーの順序に気にしません。

サンプルデータを出力用入力として使用します。

{
   "Category1" : [
      {
         "Base" : "5555",
         "Format" : "444",
         "Name" : "3333",
         "Title" : "2222",
         "Year" : "1111"
      },
      {
         "Base" : "1111",
         "Format" : "9999",
         "Name" : "8888",
         "Title" : "7777",
         "Year" : "6666"
      },
      {
         "Base" : "4444",
         "Format" : "3333",
         "Name" : "22222",
         "Title" : "1111",
         "Year" : "0000"
      }
   ],
   "Category2" : [
      {
         "Base" : null,
         "Format" : "5555",
         "Name" : null,
         "Title" : "3333",
         "Year" : "2222"
      },
      {
         "Base" : "5555",
         "Format" : null,
         "Name" : "4444",
         "Title" : "3333",
         "Year" : "2222"
      }
   ],
   "Category3" : [
      {
         "Base" : null,
         "Format" : "BBBB",
         "Name" : null,
         "Title" : null,
         "Year" : "AAAA"
      },
      {
         "Base" : "GGGG",
         "Format" : "FFFF",
         "Name" : "EEEE",
         "Title" : "DDDD",
         "Year" : "CCCC"
      }
   ]
}

関連情報