xp-forge / address
在解析时从XML输入流创建对象。
v6.1.1
2024-03-29 10:13 UTC
Requires
- php: >=7.0.0
- xp-framework/core: ^12.0 | ^11.0 | ^10.0
- xp-framework/reflection: ^3.0 | ^2.0 | ^1.9
- xp-framework/tokenize: ^9.0 | ^8.1
Requires (Dev)
- xp-framework/test: ^2.0 | ^1.0
README
在解析时从XML输入流创建对象。是的,这种情况至今仍然存在😉
示例
给定以下两个值对象
class Book { public $name, $author; public function __construct(string $name, Author $author) { $this->name= $name; $this->author= $author; } } class Author { public $name; public function __construct(string $name) { $this->name= $name; } }
...以及这个XML
<?xml version="1.0" encoding="utf-8"?> <book> <name>A Short History of Nearly Everything</name> <author> <name>Bill Bryson</name> </author> </book>
...当从套接字读取时,以下代码将XML映射到对象实例。
use util\address\{XmlStreaming, ObjectOf}; $socket= /* ... */ $stream= new XmlStreaming($socket); $book= $stream->next(new ObjectOf(Book::class, [ 'name' => fn($self) => $self->name= yield, 'author' => fn($self) => $self->author= yield new ObjectOf(Author::class, [ 'name' => fn($self) => $self->name= yield ?: '(unknown author)'; } ]) ]);
创建值
定义用于从XML输入创建结构化数据。以下是所有实现
ValueOf
最简单的版本,它提供一个种子值,可以通过提供的地址函数对其进行修改。
use util\address\{XmlStreaming, ValueOf}; // Parse into string 'Tim Taylor' $stream= new XmlStreaming('<name>Tim Taylor</name>'); $name= $stream->next(new ValueOf(null, [ '.' => fn(&$self) => $self= yield, ]); // Parse into array ['More', 'Power'] $stream= new XmlStreaming('<tools><tool>More</tool><tool>Power</tool></tools>'); $name= $stream->next(new ValueOf([], [ 'tool' => fn(&$self) => $self[]= yield, ]); // Parse into map ['id' => 6100, 'name' => 'more power'] $stream= new XmlStreaming('<tool id="6100">more power</tool>'); $book= $stream->next(new ValueOf([], [ '@id' => fn(&$self) => $self['id']= (int)yield, '.' => fn(&$self) => $self['name']= yield, ]);
ObjectOf
创建对象而不调用它们的构造函数。直接修改成员,包括非公共成员。
use util\address\{XmlStreaming, ObjectOf}; class Book { public $isbn, $name; } // Parse into Book(isbn: '978-0552151740', name: 'A Short History...') $stream= new XmlStreaming('<book isbn="978-0552151740"><name>A Short History...</name></book>'); $book= $stream->next(new ObjectOf(Book::class, [ '@isbn' => fn($self) => $self->isbn= yield, 'name' => fn($self) => $self->name= yield, ]);
RecordOf
与record类一起工作,这些类定义为不可变且有全部参数的构造函数。修改命名构造函数参数。
use util\address\{XmlStreaming, RecordOf}; class Book { public function __construct(private string $isbn, private string $name) { } public function isbn() { return $this->isbn; } public function name() { return $this->name; } } // Parse into Book(isbn: '978-0552151740', name: 'A Short History...') $stream= new XmlStreaming('<book isbn="978-0552151740"><name>A Short History...</name></book>'); $book= $stream->next(new RecordOf(Book::class, [ '@isbn' => fn(&$args) => $args['isbn']= yield, 'name' => fn(&$args) => $args['name']= yield, ]);
迭代
任何Address
实例都可以通过foreach
语句进行迭代。结合使用数据序列库并调用这里的value()
方法,可以解析RSS源中的条目。
use peer\http\HttpConnection; use util\data\Sequence; use util\Date; use util\address\{XmlStream, ObjectOf}; use util\cmd\Console; class Item { public $title, $description, $pubDate, $generator, $link, $guid; } $definition= new ObjectOf(Item::class, [ 'title' => fn($self) => $self->title= yield, 'description' => fn($self) => $self->description= yield, 'pubDate' => fn($self) => $self->pubDate= new Date(yield), 'generator' => fn($self) => $self->generator= yield, 'link' => fn($self) => $self->link= yield, 'guid' => fn($self) => $self->guid= yield, ]); $conn= new HttpConnection('https://www.tagesschau.de/xml/rss2/'); $stream= new XmlStream($conn->get()->in()); Sequence::of($stream->pointers('//channel/item')) ->map(fn($pointer) => $pointer->value($definition)) ->each(fn($item) => Console::writeLine('- ', $item->title, "\n ", $item->link)) ;