ergebnis/json-normalizer

提供通用的和特定厂商的规范化器,用于规范化JSON文档。

4.5.0 2024-01-30 09:10 UTC

README

Integrate Merge Release Renew Update

Code Coverage Type Coverage

Latest Stable Version Total Downloads Monthly Downloads

本项目提供了一个包含通用和特定厂商规范化器的 composer 包,用于规范化 JSON文档

安装

运行

composer require ergebnis/json-normalizer

用法

本项目包含

通用规范化器

本项目包含以下通用规范化器

💡 所有这些规范化器都实现了 Ergebnis\Json\Normalizer\Normalizer

CallableNormalizer

当你想使用一个 callable 来规范化一个JSON文件时,可以使用 CallableNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "url": "https://localheinz.com"
}
JSON;

$json = Json::fromString($encoded);

$callable = function (Json $json): Json {
    $decoded = $json->decoded();

    foreach (get_object_vars($decoded) as $name => $value) {
        if ('https://localheinz.com' !== $value) {
            continue;
        }

        $decoded->{$name} .= '/open-source/';
    }

    return Json::fromString(json_encode($decoded));
};

$normalizer = new Normalizer\CallableNormalizer($callable);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将应用该可调用函数。

ChainNormalizer

当你想链式应用多个规范化器时,可以使用 ChainNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer;
use Ergebnis\Json\Printer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "url": "https://localheinz.com"
}
JSON;

$json = Json::fromString($encoded);

$indent = Normalizer\Format\Indent::fromString('  ');
$jsonEncodeOptions = Normalizer\Format\JsonEncodeOptions::fromInt(JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

$normalizer = new Normalizer\ChainNormalizer(
    new Normalizer\JsonEncodeNormalizer($jsonEncodeOptions),
    new Normalizer\IndentNormalizer(
        $indent,
        new Printer\Printer()
    ),
    new Normalizer\WithFinalNewLineNormalizer()
);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将包含链式应用所有规范化器的结果,依次应用。

💡 注意规范化器的顺序,因为一个规范化器可能会覆盖之前规范化器所做的更改。

FormatNormalizer

当你想使用格式来规范化一个JSON文件时,可以使用 FormatNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer;
use Ergebnis\Json\Printer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "emoji": "🤓",
    "url": "https://localheinz.com"
}
JSON;

$json = Json::fromString($encoded);

$format = Normalizer\Format\Format::create(
    Normalizer\Format\Indent::fromString('  '),
    Normalizer\Format\JsonEncodeOptions::fromInt(JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
    Normalizer\Format\NewLine::fromString("\r\n")
    true
);

$normalizer = new Normalizer\FormatNormalizer(
    new Printer\Printer(),
    $format,
);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将根据 $format 应用格式。

IndentNormalizer

当你需要调整JSON文件的缩进时,可以使用 IndentNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer;
use Ergebnis\Json\Printer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "url": "https://localheinz.com"
}
JSON;

$json = Json::fromString($encoded);

$indent = Normalizer\Format\Indent::fromString('  ');

$normalizer = new Normalizer\IndentNormalizer(
    $indent,
    new Printer\Printer()
);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将使用2个空格进行缩进。

JsonEncodeNormalizer

当你需要调整JSON文件的编码时,可以使用 JsonEncodeNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer;

$encoded = <<<'JSON'
{
    "name": "Andreas M\u00f6ller",
    "url": "https:\/\/localheinz.com"
}
JSON;

$json = Json::fromString($encoded);

$jsonEncodeOptions = Normalizer\Format\JsonEncodeOptions::fromInt(JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

$normalizer = new Normalizer\JsonEncodeNormalizer($jsonEncodeOptions);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将使用 $jsonEncodeOptions 进行编码。

💡 参考文档,请见 json_encode() 和相应的 JSON常量

SchemaNormalizer

当你想根据JSON模式重建一个JSON文件时,可以使用 SchemaNormalizer

假设以下模式

{
    "type": "object",
    "additionalProperties": true,
    "properties": {
        "name" : {
            "type" : "string"
        },
        "role" : {
            "type" : "string"
        }
    }
}

存在于 /schema/example.json

<?php

declare(strict_types=1);

use Ergebnis\Json\Normalizer;
use Ergebnis\Json\Pointer;
use Ergebnis\Json\SchemaValidator;
use JsonSchema\SchemaStorage;

$encoded = <<<'JSON'
{
    "url": "https://localheinz.com",
    "name": "Andreas Möller",
    "open-source-projects": {
        "ergebnis/data-provider": {
            "downloads": {
                "total": 2,
                "monthly": 1
            }
        },
        "ergebnis/composer-normalize": {
            "downloads": {
                "total": 5,
                "monthly": 2
            }
        }
    }
}
JSON;

$json = Json::fromString($encoded);

$normalizer = new Normalizer\SchemaNormalizer(
    'file:///schema/example.json',
    new SchemaStorage(),
    new SchemaValidator\SchemaValidator(),
    Pointer\Specification::never()
);

$normalized = $normalizer->normalize($json);

规范化后的版本现在将根据JSON模式进行结构化(在这个简单的例子中,属性将按照模式中的顺序重新排序,并且额外的属性将按名称排序)。内部,SchemaNormalizer 使用 justinrainbow/json-schema 来解析模式,并确保(在规范化和规范化后)JSON文档是有效的。

如果你有不想重新排序的属性,可以使用 Pointer\Specification 来指定哪些属性不应重新排序。

<?php

declare(strict_types=1);

use Ergebnis\Json\Normalizer;
use Ergebnis\Json\Pointer;
use Ergebnis\Json\SchemaValidator;
use JsonSchema\SchemaStorage;

$encoded = <<<'JSON'
{
    "url": "https://localheinz.com",
    "name": "Andreas Möller",
    "open-source-projects": {
        "ergebnis/data-provider": {
            "downloads": {
                "total": 2,
                "monthly": 1
            }
        },
        "ergebnis/composer-normalize": {
            "downloads": {
                "total": 5,
                "monthly": 2
            }
        }
    }
}
JSON;

$json = Json::fromString($encoded);

$normalizer = new Normalizer\SchemaNormalizer(
    'file:///schema/example.json',
    new SchemaStorage(),
    new SchemaValidator\SchemaValidator(),
    Pointer\Specification::equals(Pointer\JsonPointer::fromJsonString('/open-source-projects'))
);

$normalized = $normalizer->normalize($json);

💡 更多关于JSON模式的详细信息,请访问 json-schema.org

WithFinalNewLineNormalizer

当你想确保一个JSON文件有一个单独的结束换行符时,可以使用 WithFinalNewLineNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Normalizer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "url": "https://localheinz.com"
}


JSON;

$json = Json::fromString($encoded);

$normalizer = new Normalizer\WithFinalNewLineNormalizer();

$normalized = $normalizer->normalize($json);

规范化后的版本现在将有一个单独的结束换行符。

WithoutFinalNewLineNormalizer

当您想要确保一个JSON文件不包含最后的换行符时,可以使用WithoutFinalNewLineNormalizer

<?php

declare(strict_types=1);

use Ergebnis\Json\Normalizer;

$encoded = <<<'JSON'
{
    "name": "Andreas Möller",
    "url": "https://localheinz.com"
}


JSON;

$json = Json::fromString($encoded);

$normalizer = new Normalizer\WithoutFinalNewLineNormalizer();

$normalized = $normalizer->normalize($json);

规范化后的版本将不再包含最后的换行符或任何末尾的空白字符。

特定于供应商的规范化器

本项目包含以下特定于供应商的规范化器

Vendor\Composer\ComposerJsonNormalizer

Vendor\Composer\ComposerJsonNormalizer可以用来根据其底层JSON架构规范化composer.json文件。

它组合了以下规范化器

Vendor\Composer\BinNormalizer

composer.jsonbin部分包含脚本数组时,Vendor\Composer\BinNormalizer将按值升序排序bin部分的元素。

Vendor\Composer\ConfigHashNormalizer

composer.jsonconfig部分包含配置时,Vendor\Composer\ConfigHashNormalizer将按键升序排序这些部分的内容。

allow-pluginspreferred-install配置选项支持通配符键并需要特殊处理。

当这些键不使用通配符时,则这些键按升序排序。当这些键使用通配符时,这些键在通配符位于包名末尾时排序。由于composer中通配符功能内部的实现细节,中间包含通配符的键排序不可行。

Vendor\Composer\PackageHashNormalizer

composer.json在以下部分包含任何配置时

部分,Vendor\Composer\PackageHashNormalizer将排序这些部分中的包。

💡 这将使用--sort-packagessort-packages配置标志在requirerequire-dev中的行为转移到其他部分。

Vendor\Composer\RepositoriesHashNormalizer

composer.json在以下部分包含任何配置时

部分,Vendor\Composer\RepositoriesHashNormalizer将排序在excludeonly属性中列出的仓库。

Vendor\Composer\VersionConstraintNormalizer

composer.json在以下部分包含版本约束时

部分,Vendor\Composer\VersionConstraintNormalizer将确保

  • 所有版本约束都被修剪

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "php": " ^8.2 "
    +    "php": "^8.2"
     }
  • 由空格( )或逗号(,)分隔的版本约束(视为逻辑与)由空格( )分隔

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "foo/bar": "1.2.3,2.3.4",
    -    "foo/baz": "2.3.4   3.4.5"
    +    "foo/bar": "1.2.3 2.3.4",
    +    "foo/baz": "2.3.4 3.4.5"
     }
  • 由单竖线(|)或双竖线(||)和前后任意数量的空格分隔的版本约束(视为逻辑或)由前一个空格、双竖线和后一个空格(||)分隔

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "php": "^8.1|^8.2",
    -    "foo/bar": "^1.2.3  ||  ^2.3.4"
    +    "php": "^8.1 || ^8.2",
    +    "foo/bar": "^1.2.3 || ^2.3.4"
     }
  • 由短横线(-)分隔的连字符版本范围,在前后有任意数量的空格的情况下由带有前一个空格、短横线和后一个空格的短横线(-)分隔

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#hyphenated-version-range-",
       "require": {
    -    "foo/bar": "1.2.3  -  2.3.4"
    +    "foo/bar": "1.2.3 - 2.3.4"
     }
  • 重复的约束被移除

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "foo/bar": "^1.0 || ^1.0 || ^2.0"
    +    "foo/bar": "^1.0 || ^2.0"
     }
  • 重叠的约束被移除

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "foo/bar": "^1.0 || ^1.1 || ^2.0 || ~2.1.0 || 2.4.5"
    +    "foo/bar": "^1.0 || ^2.0"
     }
  • 使用波浪线版本范围(~)而非通配符版本范围(*)是首选的。

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
         "foo/bar": "*",
    -    "foo/baz": "1.0.*"
    +    "foo/baz": "~1.0.0"
     }
  • 使用插入符号版本范围(^)而非波浪线版本范围(~)是首选的。

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "foo/bar": "~1",
    -    "foo/baz": "~1.3"
    +    "foo/bar": "^1.0",
    +    "foo/baz": "^1.3"
     }
  • 版本号按升序排序。

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/versions.md#version-range",
       "require": {
    -    "foo/bar": "^2.0 || ^1.4"
    +    "foo/bar": "^1.4 || ^2.0"
     }
  • 内联别名中的额外空格将被移除。

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/aliases.md#require-inline-alias",
       "require": {
    -    "foo/bar": "dev-2.x  as  2.0"
    +    "foo/bar": "dev-2.x as 2.0"
     }
  • 无用的内联别名将被移除。

     {
       "homepage": "https://getcomposer.org.cn/doc/articles/aliases.md#require-inline-alias",
       "require": {
    -    "foo/bar": "2.0 as 2.0"
    +    "foo/bar": "2.0"
     }
  • 版本约束中的前导 v 前缀将被移除。

     {
       "require": {
    -    "foo/bar": "^v1.2",
    -    "foo/baz": "v1.3.7"
    +    "foo/bar": "^1.2",
    +    "foo/baz": "1.3.7"
     }
  • 使用 xX 作为通配符时,将替换为 *

     {
       "require": {
    -    "foo/bar": "1.x",
    -    "foo/baz": "2.3.X",
    -    "foo/qux": "x"
    +    "foo/bar": "^1.0",
    +    "foo/baz": "~2.3.0",
    +    "foo/qux": "*"
     }

变更日志

该项目的维护者记录了此项目的显著变更到一个变更日志中。

贡献

该项目的维护者建议遵循贡献指南

行为准则

该项目的维护者要求贡献者遵循行为准则

一般支持策略

该项目的维护者提供有限的支持。

您可以通过赞助 @localheinz请求与该项目相关的服务发票来支持该项目的维护。

PHP版本支持策略

此项目支持具有活动和安全支持的PHP版本。

该项目的维护者在其初始发布后添加对PHP版本的支持,并在其达到安全支持结束时停止对该PHP版本的支持。

安全策略

此项目有一个安全策略

许可

此项目使用MIT许可

鸣谢

Vendor\Composer\PackageHashNormalizer中排序包的算法已从Composer\Json\JsonManipulator::sortPackages()(最初由Nils AdermannJordi Boggiano以MIT许可)采纳,我最初通过composer/composer#3549composer/composer#3872composer/composer做出了贡献。

社交

关注Twitter上的@localheinz@ergebnis