3

我有一个格式为 JSON 的配置文件,我需要将其加载到 Perl 中,然后使用从单独的 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只是使用过时版本的克隆模块在 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 回答