3

Perl にロードする必要がある JSON としてフォーマットされた構成ファイルがあり、別の JSON ファイルからロードされた新しい設定で部分的にオーバーライド/拡張​​します。追加/変更される可能性のある特定の設定はさまざまであるため、このオーバーライドをできるだけ柔軟にしたいと考えています。

私の計画は、decode_json を使用した後、JSON または Perl のネストされたデータ構造として、新しい部分的な構成を既存の完全な構成オブジェクトにマージすることです。その変換はうまくいきます。

私の複雑なデータ構造を再帰的に見て、多くの特定の比較を行う以外に、Perlでこれを行う簡単で効率的な方法はありますか? Hash::Merge を調べたところ、データが壊れています。問題は、高レベルのキーと値のペア (以下の「config」または「bookToolbar」) を見て、その高レベルで完全なキーと値のペアをオーバーライドすることです。私が望むのは、元のキーと値のペアを維持しながら、深さ優先で検索し、可能な限り具体的な値をオーバーライドすることです。

たとえば、「完全な」構成は次のとおりです。

{
    "config" : {
        "bookToolbar" : {
            "highlights" : {
                "enabled" : false
            },
            "bookmark" : {
                "enabled" : false
            }
        },
        "pageAspectRatio" : {
            "width" : "432",
            "height" : "648"
        },
        "highlighter" : {
            "sharedColor" : "#000000",
            "colors" : [
                "#ffff00"
            ]
        }
        "mainMenu" : {
            "index" : {
                "dataPath" : "data/index/",
                "enabled" : false
            },
            "media" : {
                "dataPath" : "data/media.xml",
                "enabled" : false
            },
            "toc" : {
                "dataPath" : "data/toc.xml"
            },
            "glossary" : {
                "audioPath" : "audio/glossary/",
                "dataPath" : "data/glossary.xml",
                "imagePath" : "img/glossary/",
                "enabled" : false
            }
        }
    },
    "pagelist" : [{
            "hasOnPageNotes" : true,
            "pageName" : "cover",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "cover"
        }, {
            "hasOnPageNotes" : true,
            "pageName" : "1",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "1"
        }
    ]
}

上記を部分的にオーバーライド/拡張​​するために使用したいデータは次のとおりです。

{
    "config" : {
        "bookToolbar" : {
            "bookmark" : {
                "enabled" : true
            },
            "help" : {
                "data" : {
                    "url" : "aGreatHelpFile.html"
                },
                "enabled" : true
            },
            "links" : {
                "enabled" : true
            }
        }
    },
    "pagelist" : [{
            "hasOnPageNotes" : true,
            "pageName" : "2",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "2"
        }
    ]
}

私の望ましい出力は次のようになります。

{
    "config" : {
        "bookToolbar" : {
            "highlights" : {
                "enabled" : false
            },
            "help" : {
                "data" : {
                    "url" : "aGreatHelpFile.html"
                },
                "enabled" : true
            },
            "bookmark" : {
                "enabled" : true
            }
            "links" : {
                "enabled" : false
            }
        },
        "pageAspectRatio" : {
            "width" : "432",
            "height" : "648"
        },
        "highlighter" : {
            "sharedColor" : "#000000",
            "colors" : [
                "#ffff00"
            ]
        },
        "mainMenu" : {
            "index" : {
                "dataPath" : "data/index/",
                "enabled" : false
            },
            "media" : {
                "dataPath" : "data/media.xml",
                "enabled" : false
            },
            "toc" : {
                "dataPath" : "data/toc.xml"
            },
            "glossary" : {
                "audioPath" : "audio/glossary/",
                "dataPath" : "data/glossary.xml",
                "imagePath" : "img/glossary/",
                "enabled" : false
            }
        }
    },
    "pagelist" : [{
            "hasOnPageNotes" : true,
            "pageName" : "cover",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "cover"
        }, {
            "hasOnPageNotes" : true,
            "pageName" : "1",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "1"
        }, {
            "hasOnPageNotes" : true,
            "pageName" : "2",
            "hasScreenReader" : false,
            "hasTextMarkup" : true,
            "hasLinks" : false,
            "pageId" : "2"
        }
    ]
}
4

1 に答える 1

4

つまりHash::Merge、古いバージョンの Clone モジュールを使用して、Windows でデータを壊しているだけでした。

最新バージョン (または私の Mac ではすぐに) では、次のコードはまさに私が必要とすることを行います。

#!/usr/bin/env perl -w
use strict;
use JSON;
use Hash::Merge qw( merge );
Hash::Merge::set_behavior('RIGHT_PRECEDENT');

# Load full config into hashref
open (IN, "<:utf8", "full-config.txt");
my $app_data;
while(<IN>) {$app_data .= $_;}
my $app_json = decode_json($app_data);
close IN;

# Sample portion of config options to override/extend
my $app_override = '{"config": {
                        "bookToolbar": {
                            "bookmark": {
                                "enabled":false
                            }, "help": {
                                "data": {
                                    "url":"aGreatHelpFile.html"
                                }, "enabled":true
                            }, "closeBook": {
                                "enabled":true
                            }
                        }
                    },
                    "pagelist":[
                        {
                             "hasOnPageNotes" : true,
                             "pageName" : "25",
                             "hasTextMarkup" : true,
                             "hasScreenReader" : false,
                             "hasLinks" : false,
                             "pageId" : "0025"
                        }
                    ]
                }';
my $app_override_hash = from_json($app_override, {utf8 => 1});

# Merge with right precedent, $app_json hash ref has everything we need.
$app_json = merge( $app_json, $app_override_hash );

この表は、さまざまな優先順位オプションを分析するのに非常に役立つことがわかりましたHash::Merge(これはドキュメントからそのままです:

    LEFT TYPE   RIGHT TYPE      LEFT_PRECEDENT       RIGHT_PRECEDENT
     SCALAR      SCALAR            $a                   $b
     SCALAR      ARRAY             $a                   ( $a, @$b )
     SCALAR      HASH              $a                   %$b
     ARRAY       SCALAR            ( @$a, $b )          $b
     ARRAY       ARRAY             ( @$a, @$b )         ( @$a, @$b )
     ARRAY       HASH              ( @$a, values %$b )  %$b 
     HASH        SCALAR            %$a                  $b
     HASH        ARRAY             %$a                  ( values %$a, @$b )
     HASH        HASH              merge( %$a, %$b )    merge( %$a, %$b )

    LEFT TYPE   RIGHT TYPE  STORAGE_PRECEDENT   RETAINMENT_PRECEDENT
     SCALAR      SCALAR     $a                  ( $a ,$b )
     SCALAR      ARRAY      ( $a, @$b )         ( $a, @$b )
     SCALAR      HASH       %$b                 merge( hashify( $a ), %$b )
     ARRAY       SCALAR     ( @$a, $b )         ( @$a, $b )
     ARRAY       ARRAY      ( @$a, @$b )        ( @$a, @$b )
     ARRAY       HASH       %$b                 merge( hashify( @$a ), %$b )
     HASH        SCALAR     %$a                 merge( %$a, hashify( $b ) )
     HASH        ARRAY      %$a                 merge( %$a, hashify( @$b ) )
     HASH        HASH       merge( %$a, %$b )   merge( %$a, %$b )
于 2013-08-21T17:39:14.750 に答える