donatorsky/php-xml-template-reader

这是一个PHP XML Reader,展示了如何读取XML,并为您完成剩余的工作。

v0.1.0 2021-05-09 18:52 UTC

This package is auto-updated.

Last update: 2024-09-10 02:07:02 UTC


README

这是一个PHP XML Reader,展示了如何读取XML,并为您完成剩余的工作。

GitHub license Build Coverage Status

工作原理

PHP XML Template Reader可以帮助您解析指定的XML文件并将其转换为对象。解析器使用提供的模板作为架构,并尝试将其与输入XML匹配,可选地使用定义的规则进行验证。

要开始,只需创建一个新的\Donatorsky\XmlTemplate\Reader\XmlTemplateReader对象,传入模板并使用其中一种可用的读取模式进行读取。

示例 1

假设以下XML

<books>
    <book ISBN="1234567890"
          category="adventures">
        <title>Lorem ipsum adventures</title>
        ...
    </book>
    ...
</books>

您已经可以看到一个模式,因此您可以定义模板如下

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <books>
        <book tpl:type="collection"
              ISBN="required | integer"
              category="">
            <title tpl:contents="raw" />
            ...
        </book>
        ...
    </books>
</template>

输出将是一个类型为\Donatorsky\XmlTemplate\Reader\Models\Node的对象(默认,可以更改)以及处理后的数据

Node {
    private $nodeName = 'books';
    
    private $children = Map [
        // Because of tpl:type="collection", book element is expected to occur more than 1 times
        'book' => Collection [
            0 => Node {
                    private $nodeName = 'book';
                    
                    private $attributes = Map [
                        // You can define set of parsing rules in the template. In this case:
                        // required | integer
                        // Means, that value cannot be empty and has to be a valid number. It is also converted to the integer.
                        'ISBN' => 1234567890,
                        
                        // No filters defined means the value is read "as is"
                        'category' => 'adventures',
                    ];
                    
                    // By default, tpl:type="single", so title is expected to occur at most 1 time
                    private $relations = Map [
                        'title' => Node {
                                        private $nodeName = 'title';
                                        
                                        private $contents = 'Lorem ipsum adventures';
                                    },
                        ...
                    ];
                },
            1 => ...
        ]
    ];
}

请注意,输出节点中仅包含模板中定义的节点。当XML更改时,您需要更新模板。

示例 2

Reader支持命名空间节点和属性。如果建议的模板的tpl命名空间与您的冲突,您随时可以将其更改为任何其他有效的XML值

<tpl:books xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance">
    <tpl:book tpl:ISBN="1234567890"
              tpl:category="adventures">
        <tpl:title>Lorem ipsum adventures</tpl:title>
        ...
    </tpl:book>
    ...
</tpl:books>

您已经可以看到一个模式,因此您可以定义模板如下

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:my-namespace="http://www.w3.org/2001/XMLSchema-instance"
          my-namespace:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <tpl:books>
        <tpl:book my-namespace:type="collection"
                  tpl:ISBN="required | integer"
                  tpl:category="">
            <tpl:title my-namespace:contents="raw" />
            ...
        </tpl:book>
        ...
    </tpl:books>
</template>

读取模式

有多个读取模式可供选择。以下是一个示例代码

$xmlTemplateReader = new \Donatorsky\XmlTemplate\Reader\XmlTemplateReader(<<<'XML'
<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    // ...
</template>
XML
);

read:从字符串读取XML

您可以为XML内容提供内容并使用read方法进行解析

$node = $xmlTemplateReader->read(<<<'XML'
<?xml version="1.0" encoding="UTF-8" ?>
// ...
XML
);

readFile:从指定路径的文件中读取XML

您可以为XML文件提供路径并使用readFile方法进行解析

$node = $xmlTemplateReader->readFile('/path/to/file.xml');

readStream:从已打开的资源中读取XML

您可以为XML内容提供资源并使用readStream方法进行解析

$handler = fopen('/path/to/file.xml', 'rb+');

$node = $xmlTemplateReader->readStream($handler);

openupdateclose:自定义流XML读取

您可以使用openupdateclose方法实现您自己的实现来分块读取XML

$handler = fopen('/path/to/file.xml', 'rb+');

$xmlTemplateReader->open();

while (!\feof($handler)) {
    $this->update(\fread($handler, 1024));
}

$node = $xmlTemplateReader->close();

解析修改器

您可以使用各种解析修改器来定义某些行为。以下示例使用tpl命名空间。

tpl:castTo

接受值:类' FQN,必须实现\Donatorsky\XmlTemplate\Reader\Models\Contracts\NodeInterface

默认情况下,当节点解析时,它使用解析的数据创建一个新的\Donatorsky\XmlTemplate\Reader\Models\Node实例。然而,您可以使用自己的类。此类必须实现\Donatorsky\XmlTemplate\Reader\Models\Contracts\NodeInterface接口。

示例

定义节点类

namespace Some\Name\Space;

class BooksNode implements \Donatorsky\XmlTemplate\Reader\Models\Contracts\NodeInterface {
    // ...
}

// You can also extend \Donatorsky\XmlTemplate\Reader\Models\Node class
class SingleBookNode extends \Donatorsky\XmlTemplate\Reader\Models\Node {
    // ...
    
    public function getIsbn(): int {
        return $this->attributes->get('ISBN');
    }
    
    public function getCategory(): int {
        return $this->attributes->get('category');
    }
}

在模板中使用它们

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <books tpl:castTo="\Some\Name\Space\BooksNode">
        <book tpl:type="collection"
              tpl:castTo="\Some\Name\Space\SingleBookNode"
              ISBN="required | integer"
              category="">
            <title tpl:contents="raw" />
            ...
        </book>
        ...
    </books>
</template>

输出

$booksNode = Some\Name\Space\BooksNode {
    private $nodeName = 'books';
    
    private $children = \Donatorsky\XmlTemplate\Reader\Models\Map [
        // Because of tpl:type="collection", book element is expected to occur more than 1 times
        'book' => \Donatorsky\XmlTemplate\Reader\Models\Collection [
            0 => Some\Name\Space\SingleBookNode {
                    private $nodeName = 'book';
                    
                    private $attributes = \Donatorsky\XmlTemplate\Reader\Models\Map [
                        // You can define set of parsing rules in the template. In this case:
                        // required | integer
                        // Means, that value cannot be empty and has to be a valid number. It is also converted to the integer.
                        'ISBN' => 1234567890,
                        
                        // No filters defined means the value is read "as is"
                        'category' => 'adventures',
                    ];
                    
                    // By default, tpl:type="single", so title is expected to occur at most 1 time
                    private $relations = \Donatorsky\XmlTemplate\Reader\Models\Map [
                        'title' => \Donatorsky\XmlTemplate\Reader\Models\Node {
                                        private $nodeName = 'title';
                                        
                                        private $contents = 'Lorem ipsum adventures';
                                    },
                        ...
                    ];
                },
            1 => ...
        ]
    ];
}

// ...

/**
 * @var \Some\Name\Space\SingleBookNode $book
 */
foreach ($booksNode->getChildren('book') as $book){
    var_dump($book->getIsbn(), $book->getCategory());
}

tpl:collectAttributes

接受值:allvalidated(默认)。

默认情况下,仅收集验证节点属性。这意味着仅收集在模板中定义的属性。然而,您可以根据需要更改它,以收集其他属性。

给定以下输入XML

<books ISBN="1234567890"
       category="adventures">
    ...
</books>

示例 1

以下模板

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <books tpl:collectAttributes="all"
           ISBN="">
        ...
    </books>
</template>

您将得到

Node {
    private $nodeName = 'books';
    
    private $attributes = Map [
        'ISBN'     => '1234567890',
        'category' => 'adventures',
    ];
}

示例 2

以下模板

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <books tpl:collectAttributes="validated"
           ISBN="">
        ...
    </books>
</template>

您将得到

Node {
    private $nodeName = 'books';
    
    private $attributes = \Donatorsky\XmlTemplate\Reader\Models\Map [
        'ISBN' => '1234567890',
        // 'category' is missing as it is not "validated"
    ];
}

tpl:contents

接受值:none(默认当tpl:type = collection),raw(默认当tpl:type = single),trimmed

默认情况下,不收集任何节点的内容(none)。这对于包含其他节点的节点特别有用,因此内容仅是一堆空格(当XML为pretty-printed时)。您可以根据需要更改此行为并收集原始、未更改的节点内容(raw)或附加空格(trimmed)。

示例

给定以下输入XML

<book>
    <title>...</title>

    <description>
        ...
        ...
    </description>

    <authors>
        // ...
    </authors>
</book>

以下模板

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <book>
        <title tpl:contents="raw" />
        <description tpl:contents="trimmed" />
        <authors tpl:contents="none" />
    </book>
</template>

您将得到

Node {
    private $nodeName = 'books';
    
    private $relations = Map [
        'title' => Node {
                        private $nodeName = 'title';
                        
                        private $contents = '...';
                    },
        'description' => Node {
                        private $nodeName = 'title';
                        
                        private $contents = '...
        ...';
                    },
        'authors' => Node {
                        private $nodeName = 'title';
                        
                        private $contents = null;
                    },
    ];
}

tpl:type

接受值:single(默认),collection

默认情况下,模板中定义的每个节点都视为单个(single)。然而,如果您期望相同类型的多个元素,您可以更改它(collection)。

示例

给定以下输入XML

<book>
    <title>...</title>

    <authors>
        <author>...</author>
        <author>...</author>
        <author>...</author>
    </authors>
</book>

以下模板

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <book>
        <title tpl:type="single" />
        <authors>
            <author tpl:type="collection">
                // ...
            </author>
        </authors>
    </book>
</template>

您将得到

Node {
    private $nodeName = 'books';
    
    private $relations = Map [
        'title' => Node {
                        private $nodeName = 'title';
                    }
    ];
    
    private $children = Map [
        'author' => Collection [
            0 => Node {
                    private $nodeName = 'author';
                },
            1 => Node {
                    private $nodeName = 'author';
                },
            2 => Node {
                    private $nodeName = 'author';
                },
        ]
    ];
}

规则

规则是简单的验证器和转换器,可以进行链式调用。您可以使用规则来定义属性约束并将其转换为期望的值。规则可以有别名。规则可以接受额外的属性。名称和别名不区分大小写。您可以在 src/Rules 目录中查看内置规则,或者通过实现 \Donatorsky\XmlTemplate\Reader\Rules\Contracts\RuleInterface 接口来创建一个新的规则。

内置规则

自定义规则

要定义自定义规则,您首先需要创建一个实现 RuleInterface 接口的新类

namespace Some\Name\Space;

class RegexpRule implements \Donatorsky\XmlTemplate\Reader\Rules\Contracts\RuleInterface {

    private string $pattern;
    
    public function __construct(string $pattern) {
        $this->pattern = $pattern;
    }

    public function passes($value) : bool {
        // Validate $value against pattern
        return (bool) preg_match($this->pattern, $value);
    }
    
    public function process($value) {
        // Do not modify value
        return $value;
    }
}

然后,您需要注册该规则类

$xmlTemplateReader->registerRuleFilter(
    'regexp', // name
    \Some\Name\Space\RegexpRule::class, // Rule class' FQN
    [
        'matches',
    ] // optionalAliases
);

并在模板中使用它

<?xml version="1.0" encoding="UTF-8" ?>
<template xmlns:tpl="http://www.w3.org/2001/XMLSchema-instance"
          tpl:noNamespaceSchemaLocation="./vendor/donatorsky/php-xml-template-reader/xml-template-reader.xsd">
    <book ISBN="regexp:/^\d{13}$/"
          category="matches:/^\w+$/i">
        // ...
    </book>
</template>