{"id":20048603,"url":"https://github.com/sbwerewolf/xml-navigator","last_synced_at":"2025-05-05T10:31:39.517Z","repository":{"id":38136689,"uuid":"443555397","full_name":"SbWereWolf/xml-navigator","owner":"SbWereWolf","description":"Xml Navigator is library for navigation through xml.  Easy XML to array conversion.","archived":false,"fork":false,"pushed_at":"2025-03-16T14:18:47.000Z","size":158,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-08T21:36:04.652Z","etag":null,"topics":["xml","xml-api","xml-parser","xml-to-array"],"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/SbWereWolf.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-01-01T14:29:39.000Z","updated_at":"2025-03-16T14:18:50.000Z","dependencies_parsed_at":"2024-06-15T10:45:07.748Z","dependency_job_id":"227459d7-dd21-4b89-b866-54dbf5d62971","html_url":"https://github.com/SbWereWolf/xml-navigator","commit_stats":{"total_commits":34,"total_committers":1,"mean_commits":34.0,"dds":0.0,"last_synced_commit":"114092bf4e76bf2ebfeb4be53aa39c573060b5b3"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SbWereWolf%2Fxml-navigator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SbWereWolf%2Fxml-navigator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SbWereWolf%2Fxml-navigator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SbWereWolf%2Fxml-navigator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SbWereWolf","download_url":"https://codeload.github.com/SbWereWolf/xml-navigator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252480509,"owners_count":21754784,"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":["xml","xml-api","xml-parser","xml-to-array"],"created_at":"2024-11-13T11:44:47.009Z","updated_at":"2025-05-05T10:31:39.508Z","avatar_url":"https://github.com/SbWereWolf.png","language":"PHP","readme":"# Xml Navigator\n\nThe PHP library `Xml Navigator` base on `XMLReader`.\n\nYou can assign XML as string or as URI ( or file system path to file).\n\nNavigator can provide XML-document as array or as object.\n\n## How to use\n\n```php\n$xml =\u003c\u003c\u003cXML\n\u003couter any_attrib=\"attribute value\"\u003e\n    \u003cinner\u003eelement value\u003c/inner\u003e\n    \u003cnested nested-attrib=\"nested attribute value\"\u003enested element value\u003c/nested\u003e\n\u003c/outer\u003e\nXML;\n$result =\n    \\SbWereWolf\\XmlNavigator\\Convertation\\FastXmlToArray\n    ::prettyPrint($xml);\necho json_encode($result, JSON_PRETTY_PRINT);\n```\n\nOUTPUT:\n\n```json\n{\n  \"outer\": {\n    \"@attributes\": {\n      \"any_attrib\": \"attribute value\"\n    },\n    \"inner\": \"element value\",\n    \"nested\": {\n      \"@value\": \"nested element value\",\n      \"@attributes\": {\n        \"nested-attrib\": \"nested attribute value\"\n      }\n    }\n  }\n}\n```\n\n## How To Install\n\n`composer require sbwerewolf/xml-navigator`\n\n## Use cases\n\n### Parse XML in stream mode with callback for detect suitable elements\n\n```php\n$xml =\n    '\u003cOne attr=\"val\"\u003etext\u003c/One\u003e\u003cOther attr1=\"\" attr2=\"\"/\u003e' . PHP_EOL;\n\n$file = fopen('data-for-stream.xml', 'w');\nfwrite($file, \"\u003cCollection\u003e$xml$xml$xml\u003c/Collection\u003e\");\nfclose($file);\n\n/** @var XMLReader $reader */\n$reader = XMLReader::open('data-for-stream.xml');\n\n$extractor = \\SbWereWolf\\XmlNavigator\\Parsing\\FastXmlParser\n    ::extractHierarchy(\n        $reader,\n        /* callback for detect element for parsing */\n        function (XMLReader $cursor) {\n            return $cursor-\u003ename === 'One';\n        }\n    );\n/* Extract all elements with name `One` */\nforeach ($extractor as $element) {\n    echo json_encode($element, JSON_PRETTY_PRINT) . PHP_EOL;\n}\n\n$reader-\u003eclose();\n```\n\nOutput to console will be:\n\n```shell\n{\n    \"n\": \"One\",\n    \"v\": \"text\",\n    \"a\": {\n        \"attr\": \"val\"\n    }\n}\n{\n    \"n\": \"One\",\n    \"v\": \"text\",\n    \"a\": {\n        \"attr\": \"val\"\n    }\n}\n{\n    \"n\": \"One\",\n    \"v\": \"text\",\n    \"a\": {\n        \"attr\": \"val\"\n    }\n}\n\n```\n\n### XML file processing with no worries of file size\n\nAccess time to first element do not depend on file size.\n\nLet explain this with example.\n\nFirst generate XML files by script:\n\n```php\nfunction generateFile(string $filename, int $limit, string $xml): void\n{\n    $file = fopen($filename, 'a');\n    fwrite($file, '\u003cCollection\u003e');\n\n    for ($i = 0; $i \u003c $limit; $i++) {\n        $content = \"$xml$xml$xml$xml$xml$xml$xml$xml$xml$xml\";\n        fwrite($file, $content);\n    }\n\n    fwrite($file, '\u003c/Collection\u003e');\n    fclose($file);\n\n    $size = round(filesize($filename) / 1024, 2);\n    echo \"$filename size is $size Kb\" . PHP_EOL;\n}\n\n$xml = '\u003cSomeElement key=\"123\"\u003evalue\u003c/SomeElement\u003e' . PHP_EOL;\n$generation['temp-465b.xml'] = 1;\n$generation['temp-429Kb.xml'] = 1_000;\n$generation['temp-429Mb.xml'] = 1_000_000;\n\nforeach ($generation as $filename =\u003e $size) {\n    generateFile($filename, $size, $xml);\n}\n```\n\n```bash\ntemp-465b.xml size is 0.45 Kb\ntemp-429Kb.xml size is 429.71 Kb\ntemp-429Mb.xml size is 429687.52 Kb\n```\n\nNow, run benchmark by script:\n\n```php\n/**\n * @param string $filename\n * @return void\n */\nfunction parseFirstElement(string $filename): void\n{\n    $start = hrtime(true);\n\n    /** @var XMLReader $reader */\n    $reader = XMLReader::open($filename);\n    \n    $mayRead = true;\n    /* scroll to first `SomeElement` */\n    while ($mayRead \u0026\u0026 $reader-\u003ename !== 'SomeElement') {\n        $mayRead = $reader-\u003eread();\n    }\n    /* Compose array from XML element with name `SomeElement` */    \n    $result =\n        \\SbWereWolf\\XmlNavigator\\Extraction\\PrettyPrintComposer\n        ::compose($reader);\n\n    $reader-\u003eclose();\n\n    $finish = hrtime(true);\n    $duration = $finish - $start;\n    $duration = number_format($duration,);\n    echo \"First element parsing duration of $filename is $duration ns\" .\n        PHP_EOL;\n}\n/* files to metering with benchmark */\n$files = [\n    'temp-465b.xml',\n    'temp-429Kb.xml',\n    'temp-429Mb.xml',\n];\n\necho 'Warm up OPcache' . PHP_EOL;\nparseFirstElement(current($files));\n\necho 'Benchmark is starting' . PHP_EOL;\nforeach ($files as $filename) {\n    parseFirstElement($filename);\n}\necho 'Benchmark was finished' . PHP_EOL;\n```\n\n```bash\nWarm up OPcache\nFirst element parsing duration of temp-465b.xml is 1,250,700 ns\nBenchmark is starting\nFirst element parsing duration of temp-465b.xml is 114,400 ns\nFirst element parsing duration of temp-429Kb.xml is 132,400 ns\nFirst element parsing duration of temp-429Mb.xml is 119,900 ns\nBenchmark was finished\n```\n\n### XML-document as array\n\nXmlConverter implements array approach.\n\nXmlConverter can use to convert XML-document to array, example:\n\n```php\n$xml = \u003c\u003c\u003cXML\n\u003cElemWithNestedElems\u003e\n    \u003cElemWithVal\u003eval\u003c/ElemWithVal\u003e\n    \u003cElemWithAttribs one=\"atrib\" other=\"atrib\"/\u003e\n    \u003cElemWithAll attribute_name=\"attribute-value\"\u003e\n        element value\n    \u003c/ElemWithAll\u003e\n\u003c/ElemWithNestedElems\u003e\nXML;\n\n$converter = new \\SbWereWolf\\XmlNavigator\\Convertation\\XmlConverter(\n    val: 'value',\n    attr: 'attributes',\n    name: 'name',\n    seq: 'sequence',\n);\n$xmlAsArray = $converter-\u003etoHierarchyOfElements($xml);\n\n$prettyPrint = json_encode($xmlAsArray, JSON_PRETTY_PRINT);\necho 'JSON representation of XML:'\n    . PHP_EOL\n    . $prettyPrint\n    . PHP_EOL;\n\necho 'Array representation of XML:'\n    . PHP_EOL\n    . var_export($xmlAsArray, true)\n    . PHP_EOL;\n\n```\n\nOUTPUT:\n\n```php\nJSON representation of XML:\n{\n    \"name\": \"ElemWithNestedElems\",\n    \"sequence\": [\n        {\n            \"name\": \"ElemWithVal\",\n            \"value\": \"val\"\n        },\n        {\n            \"name\": \"ElemWithAttribs\",\n            \"attributes\": {\n                \"one\": \"atrib\",\n                \"other\": \"atrib\"\n            }\n        },\n        {\n            \"name\": \"ElemWithAll\",\n            \"value\": \"\\n        element value\\n    \",\n            \"attributes\": {\n                \"attribute_name\": \"attribute-value\"\n            }\n        }\n    ]\n}\nArray representation of XML:\narray (\n  'name' =\u003e 'ElemWithNestedElems',\n  'sequence' =\u003e \n  array (\n    0 =\u003e \n    array (\n      'name' =\u003e 'ElemWithVal',\n      'value' =\u003e 'val',\n    ),\n    1 =\u003e \n    array (\n      'name' =\u003e 'ElemWithAttribs',\n      'attributes' =\u003e \n      array (\n        'one' =\u003e 'atrib',\n        'other' =\u003e 'atrib',\n      ),\n    ),\n    2 =\u003e \n    array (\n      'name' =\u003e 'ElemWithAll',\n      'value' =\u003e '\n        element value\n    ',\n      'attributes' =\u003e \n      array (\n        'attribute_name' =\u003e 'attribute-value',\n      ),\n    ),\n  ),\n)\n\n```\n\n### XML-document as object\n\nXmlElement implements object-oriented approach.\n\n#### Navigator API\n\n- `name(): string` // Returns the name of XML element\n- `hasValue(): bool` // Returns `true` if XML element has value\n- `value(): string` // Returns the value of XML element\n- `hasAttribute(string $name = ''): bool` // Returns `true` if XML\n  element has attribute with `$name`. If `$name` omitted, than returns\n  `true` if XML element has any attribute\n- `get(string $name = null): string` // Get value of attribute with\n  the `$name`, if `$name` is omitted, than returns value of random\n  attribute\n- `attributes(): XmlAttribute[]` // Returns all attributes of XML\n  element\n- `hasElement(?string $name = null): bool` // Returns `true` if XML\n  element has nested element with `$name`. If `$name` omitted, than\n  returns `true` if XML element has any nested element\n- `pull(string $name = ''): Generator` // Pull nested elements as\n  `IXmlElement`\n  , if `$name` is defined, than pull elements only with the\n  `$name`\n- `elements(): IXmlElement[]` // Returns all nested elements\n- `serialize(): array;` Generates a storable representation (`$data`)\n  of a IXmlElement, use `new XmlElement($data)` to restore\n  `XmlElement` object\n\n### Interact with XML as object\n\n```php\n$xml = \u003c\u003c\u003cXML\n\u003cdoc attrib=\"a\" option=\"o\" \u003e\n    \u003cbase/\u003e\n    \u003cvaluable\u003eelement value\u003c/valuable\u003e\n    \u003ccomplex\u003e\n        \u003ca empty=\"\"/\u003e\n        \u003cb val=\"x\"/\u003e\n        \u003cb val=\"y\"/\u003e\n        \u003cb val=\"z\"/\u003e\n        \u003cc\u003e0\u003c/c\u003e\n        \u003cc v=\"o\"/\u003e\n        \u003cc/\u003e\n        \u003cdifferent/\u003e\n    \u003c/complex\u003e\n\u003c/doc\u003e\nXML;\n\n$content = \\SbWereWolf\\XmlNavigator\\Convertation\\FastXmlToArray\n::convert($xml);\n$navigator = \nnew \\SbWereWolf\\XmlNavigator\\Navigation\\XmlElement($content);\n\n/* Convert this XmlElement to array,\n with the array you may restore XmlElement\n (create same as original one) */\n$gist = $navigator-\u003eserialize();\necho assert($content === $gist) ? 'is same' : 'is different';\necho PHP_EOL;\n\n/* get name of element */\necho $navigator-\u003ename() . PHP_EOL;\n/* doc */\n\n/* get value of element */\necho \"`{$navigator-\u003evalue()}`\" . PHP_EOL;\n/* `` */\n\n/* get list of attributes */\n$attributes = $navigator-\u003eattributes();\nforeach ($attributes as $attribute) {\n    /** @var \\SbWereWolf\\XmlNavigator\\Navigation\\IXmlAttribute $attribute */\n    echo \"`{$attribute-\u003ename()}` `{$attribute-\u003evalue()}`\" . PHP_EOL;\n}\n/*\n`attrib` `a`\n`option` `o`\n*/\n\n/* get value of attribute */\necho $navigator-\u003eget('attrib') . PHP_EOL;\n/* a */\n\n/* get list of nested elements */\n$elements = $navigator-\u003eelements();\nforeach ($elements as $element) {\n    echo \"{$element-\u003ename()}\" . PHP_EOL;\n}\n/*\nbase\nvaluable\ncomplex\n */\n\n/* get desired nested element */\n/** @var \\SbWereWolf\\XmlNavigator\\Navigation\\IXmlElement $elem */\n$elem = $navigator-\u003epull('valuable')-\u003ecurrent();\necho $elem-\u003ename() . PHP_EOL;\n/* valuable */\n\n/* get all nested elements */\nforeach ($navigator-\u003epull() as $pulled) {\n    /** @var \\SbWereWolf\\XmlNavigator\\Navigation\\IXmlElement $pulled */\n    echo $pulled-\u003ename() . PHP_EOL;\n    /*\n    base\n    valuable\n    complex\n    */\n}\n\n/* get nested element with given name */\n/** @var \\SbWereWolf\\XmlNavigator\\Navigation\\IXmlElement $nested */\n$nested = $navigator-\u003epull('complex')-\u003ecurrent();\n/* get names of all elements of nested element */\n$elements = $nested-\u003eelements();\nforeach ($elements as $element) {\n    echo \"{$element-\u003ename()}\" . PHP_EOL;\n}\n/*\na\nb\nb\nb\nc\nc\nc\ndifferent\n*/\n\n/* pull all elements with name `b` */\nforeach ($nested-\u003epull('b') as $b) {\n    /** @var \\SbWereWolf\\XmlNavigator\\Navigation\\IXmlElement $b */\n    echo ' element with name' .\n        ' `' . $b-\u003ename() .\n        '` have attribute `val` with value' .\n        ' `' . $b-\u003eget('val') . '`' .\n        PHP_EOL;\n}\n/*\n element with name `b` have attribute `val` with value `x`\n element with name `b` have attribute `val` with value `y`\n element with name `b` have attribute `val` with value `z`\n*/\n```\n\n## Advanced using\n\n[Unit tests](test/Integration/DebugTest.php) have more examples of\nusing, please investigate them.\n\n## Run tests\n\n```bash \ncomposer test\n```\n\n## Contacts\n\n```\nVolkhin Nikolay\ne-mail ulfnew@gmail.com\nphone +7-902-272-65-35\nTelegram @sbwerewolf\n```\n\n- [Telegram chat with me](https://t.me/SbWereWolf)\n- [WhatsApp chat with me](https://wa.me/79022726535)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbwerewolf%2Fxml-navigator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbwerewolf%2Fxml-navigator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbwerewolf%2Fxml-navigator/lists"}