donatorsky / php-xml-template-reader
这是一个PHP XML Reader,展示了如何读取XML,并为您完成剩余的工作。
Requires
- php: ^7.4|^8.0
- ext-libxml: *
- ext-simplexml: *
- ext-xml: *
- beberlei/assert: ^3.3
- symfony/event-dispatcher: ^5.2
- thecodingmachine/safe: ^1.3
Requires (Dev)
- fakerphp/faker: ^1.14
- friendsofphp/php-cs-fixer: ^3.0
- infection/infection: ^0.22.1
- jangregor/phpstan-prophecy: ^0.8.1
- jetbrains/phpstorm-attributes: ^1.0
- phpspec/prophecy-phpunit: ^2.0
- phpstan/phpstan: ^0.12.85
- phpstan/phpstan-phpunit: ^0.12.18
- phpunit/phpunit: ^9.5
- roave/security-advisories: dev-latest
- symfony/stopwatch: ^5.2
- symfony/var-dumper: ^5.2
Suggests
- symfony/event-dispatcher: To use Symfony's evend dispatcher
README
这是一个PHP XML Reader,展示了如何读取XML,并为您完成剩余的工作。
工作原理
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);
open
、update
和close
:自定义流XML读取
您可以使用open
、update
和close
方法实现您自己的实现来分块读取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
接受值:all
、validated
(默认)。
默认情况下,仅收集验证节点属性。这意味着仅收集在模板中定义的属性。然而,您可以根据需要更改它,以收集其他属性。
给定以下输入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>