README.md
# Xml to Array Converter
![Test Suite](https://github.com/susina/xml-to-array/actions/workflows/test.yml/badge.svg)
[![Maintainability](https://api.codeclimate.com/v1/badges/df696c7f95bd65d7510c/maintainability)](https://codeclimate.com/github/susina/xml-to-array/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/df696c7f95bd65d7510c/test_coverage)](https://codeclimate.com/github/susina/xml-to-array/test_coverage)
![GitHub License](https://img.shields.io/github/license/susina/xml-to-array)
Xml to Array is a simple library to convert XML into PHP array.
The library consists in one namespace `Susina\XmlToArray` and two classes:
- `Converter`: to convert an XML string into PHP array
- `FileConverter`: to convert an XML file
Both classes expose the same public api:
- __Susina\XmlToArray\Converter__
- `convert(string $xmlToParse): array` to convert an xml string into an array
- `convertAndSave(string $xmlToParse, string $filename): void` to convert an xml string to an array and save it into a regular php file.
- __Susina\XmlToArray\FileConverter__
- `convert(string $xmlFile): array` to read an xml file and convert it into an array
- `convertAndSave(string $xmlFile, string $filename): void` to read an xml file and, convert it into an array and save it into a regular php file.
## Installation
Install the library via [composer](https://getcomposer.org):
```bash
composer require susina/xml-to-array
```
The library depends on three php extensions, usually installed by default:
- libxml
- simplexml
- dom
and [Symfony Options Resolver](https://symfony.com/doc/current/components/options_resolver.html) component, that'll be install by composer.
## Usage
Use the `convert` method to parse an XML string. Let's get a look at the following example:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = "
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>Star Wars</title>
<starred>True</starred>
<percentage>32.5</percentage>
</movie>
<movie>
<title>The Lord Of The Rings</title>
<starred>false</starred>
<percentage>30.7</percentage>
</movie>
</movies>
";
$converter = new Converter();
$array = $converter->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "movie" => [
* 0 => [
* "title" => "Star Wars",
* "starred" => true,
* "percentage" => 32.5
* ],
* 1 => [
* "title" => "The Lord Of The Rings",
* "starred" => false,
* "percentage" => 30.7
* ]
* ]
* ]
*/
```
Alternatively, you can use the static instantiator:
```php
<?php declare(strict_types=1);
.....
$array = Converter::create()->convert($xmlString);
```
If you want to read and convert _an xml file_, you can play with `FileConverter` class:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\FileConverter;
$converter = new FileConverter();
$array = $converter->convert('/my_dir/my_file.xml');
```
and by using the static constructor:
```php
<?php declare(strict_types=1);
$array = FileConverter::create()->convert('/my_dir/my_file.xml');
```
You can save the converted array into a regular formatted php file, that you can import in some other script by [include](https://www.php.net/manual/en/function.include.php) PHP statement.
For example:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = "
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>Star Wars</title>
<starred>True</starred>
<percentage>32.5</percentage>
</movie>
<movie>
<title>The Lord Of The Rings</title>
<starred>false</starred>
<percentage>30.7</percentage>
</movie>
</movies>
";
$converter = new Converter();
$converter->convertAndSave($xmlString, 'array_file.php');
```
The content of `array_file.php` is the following:
```php
<?php declare(strict_types=1);
/*
* This file is auto-generated by susina/xml-to-array library.
*/
return array (
'movie' =>
array (
0 =>
array (
'title' => 'Star Wars',
'starred' => true,
'percentage' => 32.5,
),
1 =>
array (
'title' => 'The Lord Of The Rings',
'starred' => false,
'percentage' => 30.7,
),
),
);
```
You can load your array via `include` statement:
```php
<?php declare(strict_types=1);
//Some instructions
$array = include('array_file.php');
```
Also `FileConverter` class has its `convertAndSave` method, which has the same behavior, but it accepts the name of the xml file to convert as first parameter:
```php
<?php declare(strict_types=1);
...........
FileConverter::create()->convertAndSave($xmlFileName, 'array_file.php');
```
## Configuration
You can configure the converters by passing an associative array to the constructor, where the keys are the name of the option.
The available options are the following:
- [mergeAttributes](#mergeattributes): boolean, default true
- [typesAsString](#typesasstring): boolean, default false
- [preserveFirstTag](#preservefirsttag): boolean, default false
### mergeAttributes
> Default: __true__
When this option is set to true, the attributes of a tag are merged into the tag it self, otherwise they're saved into a `@attribute` array, i.e.:
```php
<?php declare(strict_types=1);
$xmlString = '
<?xml version="1.0" encoding="utf-8"?>
<config>
<logger name="defaultLogger">
<type>stream</type>
<path>/var/log/default.log</path>
<level>300</level>
</logger>
</config>
';
//mergeAttributes is true by default
$array = Converter::create()->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "logger" => [
* "name" => "defaultLogger",
* "type" => "stream",
* "path" => "/var/log/default.log"
* "level" => 300
* ]
* ]
*/
```
In the previous example, you can see that the _name_ attribute is "merged" into _logger_ array.
When this option is set to false, a _@attribute_ array is created:
```php
<?php declare(strict_types=1);
$xmlString = '
<?xml version="1.0" encoding="utf-8"?>
<config>
<logger name="defaultLogger">
<type>stream</type>
<path>/var/log/default.log</path>
<level>300</level>
</logger>
</config>
';
$array = Converter::create(['mergeAttributes' => false])->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "logger" => [
* "@attributes" => [
* "name" => "defaultLogger"
* ],
* "type" => "stream",
* "path" => "/var/log/default.log"
* "level" => 300
* ]
* ]
*/
```
### typesAsString
> Default: __false__
The normal behavior of this library is to preserve all PHP types (boolean, numeric, null etc.).
If _typesAsString_ option is set to _true_ all the values are considered __strings__:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = "
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>Star Wars</title>
<starred>True</starred>
<percentage>32.5</percentage>
<views>589623</views>
</movie>
</movies>
";
// typesAsString is false by default
$array = Converter::create()->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "movie" => [
* 0 => [
* "title" => "Star Wars",
* "starred" => true,
* "percentage" => 32.5,
* "views" => 589623
* ],
* ]
* ]
*/
```
In the previous example, if you set the property to _true_, all values are strings:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = .......
$array = Converter::create(['typesAsString' => true])->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "movie" => [
* 0 => [
* "title" => "Star Wars",
* "starred" => 'True',
* "percentage" => '32.5'
* "views" => '589623'
* ],
* ]
* ]
*/
```
### preserveFirstTag
> Default: __false__
If your xml document starts with a single tag, containing all the others, the first tag is not considered as part of the resulting array:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = "
<?xml version='1.0' standalone='yes'?>
<database>
<movie>
<title>Star Wars</title>
</movie>
<movie>
<title>The Lord Of The Rings</title>
</movie>
<movie>
<title>Spider-Man</title>
</movie>
</database>
";
// preserveFirstTag is false by default
$converter = new Converter();
$array = $converter->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "movie" => [
* 0 => [
* "title" => "Star Wars",
* ],
* 1 => [
* "title" => "The Lord Of The Rings",
* ],
* 2 => [
* "title" "Spider-Man"
* ]
* ]
* ]
*/
```
If you want to keep this tag as the first key of your array, set this option to true:
```php
<?php declare(strict_types=1);
use Susina\XmlToArray\Converter;
$xmlString = .............
$converter = new Converter(['preserveFirstTag' => true]);
$array = $converter->convert($xmlString);
/*
* $array now contains the following array:
*
* [
* "database => [
* "movie" => [
* 0 => [
* "title" => "Star Wars",
* ],
* 1 => [
* "title" => "The Lord Of The Rings",
* ],
* 2 => [
* "title" "Spider-Man"
* ]
* ]
* ]
* ]
*/
```
## Issues
If you find a bug or any other issue, please report it on [Github](https://github.com/susina/xml-to-array/issues).
## Contributing
Please, see [CONTRIBUTING.md](CONTRIBUTING.md)
## Licensing
This library is released under [Apache-2.0](LICENSE) license.