shiftby/metayaml

此包已被弃用,不再维护。未建议替代包。

使用 [Yaml|Xml|json] 架构文件验证 [Yaml|Xml|json]

1.3.2 2021-03-19 15:03 UTC

This package is auto-updated.

Last update: 2023-04-19 19:32:53 UTC


README

Latest Stable Version Build Status SensioLabsInsight

使用 [在此处插入文件类型] 架构验证器,并通过 [在此处插入另一种文件类型] 文件。
目前,文件类型可以是 Json、Yaml 或 XML。它可以生成关于架构的文档或 XSD 文件(实验性)。

名称来源于它最初是为了实现 Yaml 文件的伪架构而制作的。

  1. 安装
  1. 基本用法
  2. 如何编写架构
  1. 文档生成器
  2. 关于 XML 支持的说明
  3. XSD 生成器
  4. 测试
  5. 扩展
  6. 感谢

安装

这是一个独立组件

  • 核心需要 PHP >= 5.3.3
  • 要使用 YamlLoader,您需要 Symfony 组件 Yaml(独立组件,不需要 Symfony2)
  • 要运行测试,您需要 atoum

通过 composer 安装,只需执行 composer require romaricdrigon/metayaml

基本用法

您需要创建一个 MetaYaml 对象,然后将其架构和您的数据(作为多维 php 数组)传递给它

use RomaricDrigon\MetaYaml\MetaYaml;

// create object, load schema from an array
$schema = new MetaYaml($schema);

/*
    you can optionally validate the schema
    it can take some time (up to a second for a few hundred lines)
    so do it only once, and maybe only in development!
*/
$schema->validateSchema(); // return true or throw an exception

// you could also have done this at init
$schema = new MetaYaml($schema, true); // will load AND validate the schema

// finally, validate your data array according to the schema
$schema->validate($data); // return true or throw an exception

您可以使用提供的任何加载器来获取这些数组(是的,您可以使用来自 Yaml 文件的架构验证 XML!)。

一些加载器示例

use RomaricDrigon\MetaYaml\MetaYaml;
use RomaricDrigon\MetaYaml\Loader\YamlLoader;
use RomaricDrigon\MetaYaml\Loader\XmlLoader; // JsonLoader is already available

// create one loader object
$loader = new JsonLoader(); // Json (will use php json_decode)
$loader = new YamlLoader(); // Yaml using Symfony Yaml component
$loader = new XmlLoader(); // Xml (using php SimpleXml)

// the usage is the same then
$array = $loader->load('SOME STRING...');
// or you can load from a file
$array = $loader->loadFromFile('path/to/file');

如何编写架构

简介

架构文件将定义数组结构(哪些元素是允许的,在哪里)、一些属性(必需的,可以为空...)以及这些元素的可能的值(或它们的类型)。

以下是一个简单的架构示例,使用 Yaml 语法

root: # root is always required (note no prefix here)
    _type: array # each element must always have a '_type'
    _children: # array nodes have a '_children' node, defining their children
        flowers:
            _type: array
            _required: true # optional, default false
            _children:
                rose:
                    _required: true
                    _type: text
                violet:
                    _type: text
                # -> only rose and violet are allowed children of flowers

以及一个有效的 Yaml 文件

flowers:
    rose: "a rose"
    violet: "a violet flower"

我们将继续使用 Yaml 示例;如果您不熟悉该语法,您可能想查看其 维基百科页面。当然,使用 Json 或 XML 同样可以构建相同结构。请查看 test/data/ 文件夹中的示例。

架构结构

架构文件必须有一个 root 节点,该节点将描述第一级内容。您可以可选地定义一个 prefix;默认为 __type_required...)。

如果您想使用此功能,则必须定义一个 partials 节点(下面了解更多信息)。

一个基本的架构文件

root:
    # here put the elements who will be in the file
    # note that root can have any type: an array, a number, a prototype...
prefix: my_ # so it's gonna be 'my_type', 'my_required', 'my_children'...
partials:
    block:
        # here I define a partial called block

模式节点

模式中的每个节点都必须有一个 _type 属性。这里我定义了一个名为 paragraph 的节点,其内容是某些文本

paragraph:
    _type: text

以下类型可用

  • text:标量值
  • number:数值
  • boolean:布尔值
  • pattern:检查值是否与在 _pattern 中提供的正则表达式匹配,其中 _pattern 是一个 PCRE 正则表达式
  • enum:枚举;在 _values 节点中列出接受的值
  • array:数组;在 _children 节点中定义子节点;数组的子节点必须有确定的命名键;任何额外的键都会导致错误
  • prototype:定义一个名称/索引不重要项的重复。您必须在 _prototype 节点中提供子节点的类型。
  • choice:子节点可以是 _choices 中提供的节点中的任何一个。在 _choices 数组中的键不重要(只要它们是唯一的)。在每个选择中,最好将区分字段放在第一位。
  • partial:"快捷"到在 partials 根节点中描述的块。在 _partial 中提供部分名称

您可以指定其他属性

  • 常规属性
  • _required:此节点必须始终定义(默认为 false)
  • _not_empty 用于文本、数字和数组节点:它们不能为空(默认为 false)。相应的空值是 ''0(作为字符串、整数或浮点数)、array()。要测试 null 值,请使用 _required
  • _strict 与文本、数字、布尔值和枚举一起使用将强制执行严格的类型检查(分别与字符串、整数或浮点数、布尔值、这些值中的任何一个一起使用)。当与可能不具有类型意识的解析器(如 XML 解析器)一起使用时,请谨慎使用这些(Yaml 和 json 应该没问题)
  • _description:全文描述,参见图 文档生成器
  • 仅适用于数组节点
  • _ignore_extra_keys:节点可以包含其键未列在 _children 中的子节点;它们将被忽略
  • 仅适用于原型节点
  • min_items:原型节点应包含至少 'min' 个元素
  • max_items:相反,原型节点中元素的最大数量(默认为 200)

以下是一个综合示例

root:
    _type: array
    _children:
        SomeText:
            _type: text
            _not_empty: true # so !== ''
        SomeEnum:
            _type: enum
            _values:
                - windows
                - mac
                - linux
        SomeNumber:
            _type: number
            _strict: true
        SomeBool:
            _type: boolean
        SomePrototypeArray:
            _type: prototype
            _prototype:
                _type: array
                _children:
                    SomeOtherText:
                        _type: text
                        _is_required: true # can't be null
        SomeParagraph:
            _type: partial
            _partial: aBlock # cf 'partials' below
        SomeChoice:
            _type: choice
            _choices:
                1:
                    _type: enum
                    _values:
                        - windows
                        - linux
                2:
                    _type: number
                # so our node must be either #1 or #2
        SomeRegex:
            _type: pattern
            _pattern: /e/
partials:
    aBlock:
        _type: array
        _children:
            Line1:
                _type: text

更多信息

有关更多示例,请查看 test/data 文件夹。在每个文件夹中,都有一个 .yml 文件及其模式。还有一个 XML 示例。

如果您对高级用法感兴趣,可以查看 data/MetaSchema.json:使用此模式(是的,该模式可以成功验证自身!)验证模式文件

文档生成器

每个节点都可以有一个 _description 属性,包含一些可读文本。您可以像这样检索有关节点的文档(其类型、描述、其他属性...)

// it's recommended to validate the schema before reading documentation
$schema = new MetaYaml($schema, true);

// get documentation about root node
$schema->getDocumentationForNode();

// get documentation about a child node 'test' in an array 'a_test' under root
$schema->getDocumentationForNode(array('a_test', 'test'));

// finally, if you want to unfold (follow) all partials, set second argument to true
$schema->getDocumentationForNode(array('a_test', 'test'), true);
// watch out there's no loop inside partials!

它返回一个格式如下面的关联数组

array(
    'name' => 'test', // name of current node, root for first node
    'node' => array(
        '_type' => 'array',
        '_children' => ... // and so on
    ),
    'prefix' => '_'
)

如果目标节点在选择中,则结果会有所不同

array(
    'name' => 'test', // name of current node, from the choice key in the schema
    'node' => array(
        '_is_choice' => 'true', // important: so we know next keys are choices
        0 => array(
            '_type' => 'array' // and so on, for first choice
        ),
        1 => array(
            '_type' => 'text' // and so on, for second choice
        ),
        // ...
    ),
    'prefix' => '_'
)

此行为使我们能够处理嵌套选择,而不会丢失数据(您有一个数组级别对应于每个选择级别,并且您可以检查 _is_choice 标志)

如果传递无效路径(例如,没有您提供的名称的节点),它将抛出异常。

关于 XML 支持的说明

在 XML 中,您可以在子元素中或使用属性在节点中存储一个值。在数组中不可能这样做;唯一的方法是使用子节点。

因此,XML 加载器强制执行以下约定

  • 元素和属性以子元素的形式存储,分别使用元素名和内容、属性名和值作为键和值
  • 如果一个节点同时具有属性和同名子节点,属性将被覆盖
  • 如果一个节点既有属性也有文本内容,文本内容将存储在键 _value
  • 同名多个子节点将被覆盖,只保留最后一个;除非它们具有 _key 属性,此时将使用该属性
  • 不支持命名空间
  • 空节点将被跳过

让我们用一个例子来说明

<fleurs>
    <roses couleur="rose">
        <opera>une rose</opera>
        <sauvage>
            <des_bois>une autre rose</des_bois>
            <des_sous_bois sauvage="oui">encore</des_sous_bois>
        </sauvage>
    </roses>
    <tulipe>je vais disparaitre !</tulipe>
    <tulipe>deuxieme tulipe</tulipe>
    <fleur couleur="violette" sauvage="false" _key="violette">une violette</fleur>
</fleurs>

这将给我们这个数组

array('fleurs' =>
    'roses' => array(
        'couleur' => 'rose',
        'sauvage' => array(
            'des_bois' => 'une autre rose',
            'des_sous_bois' => array(
                'sauvage' => 'oui',
                '_value' => 'encore'
            )
        )
    ),
    'tulipe' => 'deuxieme tulipe',
    'violette' => array(
        'couleur' => 'violette',
        'sauvage' => 'false',
        '_value' => 'une violette'
    )
)

XSD 生成器

请注意,此功能仍然是实验性的!

MetaYaml 可以从 MetaYaml 架构中尝试生成 XML 模式定义。您可能想使用此文件预先验证 XML 输入,或用于其他环境(客户端...)。将使用相同的约定(参见表格上方)。

用法示例

use RomaricDrigon\MetaYaml\MetaYaml\XsdGenerator;

// create a XsdGenerator object (requires Php XMLWriter from libxml, enabled by default)
$generator = new XsdGenerator();

// $schema is the source schema, php array
// second parameter to soft-indent generated XML (default true)
$my_xsd_string = $generator->build($schema, true);

一些限制,其中一些与 XML 模式相关,适用

  • root 节点必须是 array
  • 元素名称不能以数字开头
  • 所有一级节点都是强制性的(但它们可能为空)
  • 不支持 choice 节点
  • pattern 的行为可能略有不同,这取决于实现差异
  • prototype 子节点类型将不会进行验证
  • 没有 strict 模式
  • ignore_extra_keys 属性将导致所有子节点都不进行验证

测试

该项目已完全使用 atoum 进行测试。要启动测试,只需在 shell 中运行 ./bin/test -d test

扩展

您可能希望编写自己的加载器,使用任何其他工具。
查看 Loader/ 文件夹 中的任何类,它很简单:您需要实现 LoaderInterface,并可能想扩展 Loader 类(这样您就不必编写 loadFromFile())。

感谢

感谢 Riad BenguellaJulien Bianchi 的帮助和建议。

顶部