{"id":15296430,"url":"https://github.com/xp-forge/address","last_synced_at":"2025-04-13T19:41:57.826Z","repository":{"id":24897289,"uuid":"28313670","full_name":"xp-forge/address","owner":"xp-forge","description":"Creates objects from XML input streams while parsing them.","archived":false,"fork":false,"pushed_at":"2024-07-07T20:48:45.000Z","size":216,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T10:21:23.310Z","etag":null,"topics":["php7","php8","xml","xml-stream-parsing","xp-framework"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xp-forge.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-21T21:23:36.000Z","updated_at":"2024-07-07T20:48:48.000Z","dependencies_parsed_at":"2023-02-12T11:01:11.213Z","dependency_job_id":"24adf351-f9af-4255-9c49-5de336fef65a","html_url":"https://github.com/xp-forge/address","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Faddress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Faddress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Faddress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Faddress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xp-forge","download_url":"https://codeload.github.com/xp-forge/address/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248770815,"owners_count":21159043,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php7","php8","xml","xml-stream-parsing","xp-framework"],"created_at":"2024-09-30T18:10:27.489Z","updated_at":"2025-04-13T19:41:57.799Z","avatar_url":"https://github.com/xp-forge.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Address\n=======\n\n[![Build status on GitHub](https://github.com/xp-forge/address/workflows/Tests/badge.svg)](https://github.com/xp-forge/address/actions)\n[![XP Framework Module](https://raw.githubusercontent.com/xp-framework/web/master/static/xp-framework-badge.png)](https://github.com/xp-framework/core)\n[![BSD Licence](https://raw.githubusercontent.com/xp-framework/web/master/static/licence-bsd.png)](https://github.com/xp-framework/core/blob/master/LICENCE.md)\n[![Requires PHP 7.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_0plus.svg)](http://php.net/)\n[![Supports PHP 8.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-8_0plus.svg)](http://php.net/)\n[![Latest Stable Version](https://poser.pugx.org/xp-forge/address/version.png)](https://packagist.org/packages/xp-forge/address)\n\nCreates objects from XML input streams while parsing them. Yes, this still happens today 😉\n\nExample\n-------\nGiven the following two value objects:\n\n```php\nclass Book {\n  public $name, $author;\n\n  public function __construct(string $name, Author $author) {\n    $this-\u003ename= $name;\n    $this-\u003eauthor= $author;\n  }\n}\n\nclass Author {\n  public $name;\n\n  public function __construct(string $name) {\n    $this-\u003ename= $name;\n  }\n}\n```\n\n...and this XML:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cbook\u003e\n  \u003cname\u003eA Short History of Nearly Everything\u003c/name\u003e\n  \u003cauthor\u003e\n    \u003cname\u003eBill Bryson\u003c/name\u003e\n  \u003c/author\u003e\n\u003c/book\u003e\n```\n\n...the following will map the XML to an object instance while reading it from the socket.\n\n```php\nuse util\\address\\{XmlStreaming, ObjectOf};\n\n$socket= /* ... */\n\n$stream= new XmlStreaming($socket);\n$book= $stream-\u003enext(new ObjectOf(Book::class, [\n  'name'   =\u003e fn($self) =\u003e $self-\u003ename= yield,\n  'author' =\u003e fn($self) =\u003e $self-\u003eauthor= yield new ObjectOf(Author::class, [\n    'name'   =\u003e fn($self) =\u003e $self-\u003ename= yield ?: '(unknown author)'; }\n  ])\n]);\n```\n\nCreating values\n---------------\nDefinitions are used to create structured data from the XML input. Here are all the implementations:\n\n### ValueOf\n\nSimplemost version which is given a seed value, which it can modify through the given address functions.\n\n```php\nuse util\\address\\{XmlStreaming, ValueOf};\n\n// Parse into string 'Tim Taylor'\n$stream= new XmlStreaming('\u003cname\u003eTim Taylor\u003c/name\u003e');\n$name= $stream-\u003enext(new ValueOf(null, [\n  '.' =\u003e fn(\u0026$self) =\u003e $self= yield,\n]);\n\n// Parse into array ['More', 'Power']\n$stream= new XmlStreaming('\u003ctools\u003e\u003ctool\u003eMore\u003c/tool\u003e\u003ctool\u003ePower\u003c/tool\u003e\u003c/tools\u003e');\n$name= $stream-\u003enext(new ValueOf([], [\n  'tool' =\u003e fn(\u0026$self) =\u003e $self[]= yield,\n]);\n\n// Parse into map ['id' =\u003e 6100, 'name' =\u003e 'more power']\n$stream= new XmlStreaming('\u003ctool id=\"6100\"\u003emore power\u003c/tool\u003e');\n$book= $stream-\u003enext(new ValueOf([], [\n  '@id' =\u003e fn(\u0026$self) =\u003e $self['id']= (int)yield,\n  '.'   =\u003e fn(\u0026$self) =\u003e $self['name']= yield,\n]);\n```\n\n### ObjectOf\n\nCreates objects without invoking their constructors. Modifies the members directly, including non-public ones.\n\n```php\nuse util\\address\\{XmlStreaming, ObjectOf};\n\nclass Book {\n  public $isbn, $name;\n}\n\n// Parse into Book(isbn: '978-0552151740', name: 'A Short History...')\n$stream= new XmlStreaming('\u003cbook isbn=\"978-0552151740\"\u003e\u003cname\u003eA Short History...\u003c/name\u003e\u003c/book\u003e');\n$book= $stream-\u003enext(new ObjectOf(Book::class, [\n  '@isbn' =\u003e fn($self) =\u003e $self-\u003eisbn= yield,\n  'name'  =\u003e fn($self) =\u003e $self-\u003ename= yield,\n]);\n```\n\n### RecordOf\n\nWorks with *record* classes, which are defined as being immutable and having an all-arg constructor. Modifies the named constructor arguments.\n\n```php\nuse util\\address\\{XmlStreaming, RecordOf};\n\nclass Book {\n  public function __construct(private string $isbn, private string $name) { }\n\n  public function isbn() { return $this-\u003eisbn; }\n  public function name() { return $this-\u003ename; }\n}\n\n// Parse into Book(isbn: '978-0552151740', name: 'A Short History...')\n$stream= new XmlStreaming('\u003cbook isbn=\"978-0552151740\"\u003e\u003cname\u003eA Short History...\u003c/name\u003e\u003c/book\u003e');\n$book= $stream-\u003enext(new RecordOf(Book::class, [\n  '@isbn' =\u003e fn(\u0026$args) =\u003e $args['isbn']= yield,\n  'name'  =\u003e fn(\u0026$args) =\u003e $args['name']= yield,\n]);\n```\n\nIteration\n---------\nAny `Address` instance can be iterated using the `foreach` statement. Using the [data sequences library](https://github.com/xp-forge/sequence) in combination with calling the `value()` method here's a way to parse an RSS feed's items:\n\n```php\nuse peer\\http\\HttpConnection;\nuse util\\data\\Sequence;\nuse util\\Date;\nuse util\\address\\{XmlStream, ObjectOf};\nuse util\\cmd\\Console;\n\nclass Item {\n  public $title, $description, $pubDate, $generator, $link, $guid;\n}\n\n$definition= new ObjectOf(Item::class, [\n  'title'       =\u003e fn($self) =\u003e $self-\u003etitle= yield,\n  'description' =\u003e fn($self) =\u003e $self-\u003edescription= yield,\n  'pubDate'     =\u003e fn($self) =\u003e $self-\u003epubDate= new Date(yield),\n  'generator'   =\u003e fn($self) =\u003e $self-\u003egenerator= yield,\n  'link'        =\u003e fn($self) =\u003e $self-\u003elink= yield,\n  'guid'        =\u003e fn($self) =\u003e $self-\u003eguid= yield,\n]);\n\n$conn= new HttpConnection('https://www.tagesschau.de/xml/rss2/');\n$stream= new XmlStream($conn-\u003eget()-\u003ein());\n\nSequence::of($stream-\u003epointers('//channel/item'))\n  -\u003emap(fn($pointer) =\u003e $pointer-\u003evalue($definition))\n  -\u003eeach(fn($item) =\u003e Console::writeLine('- ', $item-\u003etitle, \"\\n  \", $item-\u003elink))\n;\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxp-forge%2Faddress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxp-forge%2Faddress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxp-forge%2Faddress/lists"}