youknowriad/meta-yaml

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

v0.1.2 2015-01-05 11:25 UTC

This package is not auto-updated.

Last update: 2024-09-14 13:18:06 UTC


README

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 --update

基本用法

您需要创建一个 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->validate_schema(); // 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 示例;如果您不熟悉其语法,您可能想查看其 Wikipedia 页面。当然,同样的结构也可以用 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' => '_'
)

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

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 Schema相关

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

测试

该项目已使用atoum进行全面测试。要运行测试,请在壳中运行./bin/test --test-all

扩展

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

感谢

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

返回顶部