susina/xml-to-array

Simple PHP library to convert an XML string into an array

v1.0.1 2024-09-15 15:47 UTC

This package is auto-updated.

Last update: 2024-10-15 15:56:24 UTC


README

Test Suite Maintainability Test Coverage GitHub License

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:

composer require susina/xml-to-array

The library depends on three php extensions, usually installed by default:

  • libxml
  • simplexml
  • dom

and Symfony Options Resolver 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 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 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 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 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 PHP statement.

For example:

<?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 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 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 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

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 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 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
 *     ]
 * ]
 */

idAsKey

Default: true

When this option is set to true, the value of an id attribute or tag is considered as the key of an associative array, i.e.:

<?php declare(strict_types=1);

$xmlString = "
<?xml version='1.0' standalone='yes'?>
<movies>
    <movie>
        <title>Star Wars</title>
        <starred>True</starred>
        <actor id=\"actorH\" name=\"Harrison Ford\" />
        <actor id=\"actorM\" name=\"Mark Hamill\" />
        <actor>
            <id>actorC</id>
            <name>Carrie Fisher</name>
        </actor>
    </movie>
</movies>";

//idAsKey is true by default
$array = Converter::create()->convert($xmlString);

/*
 * $array now contains the following array:
 * 
 * 'movie' => [
 *     0 => [
 *         'title' => 'Star Wars',
 *         'starred' => true,
 *         'actorH' => ['name' => 'Harrison Ford'],
 *         'actorM' => ['name' => 'Mark Hamill'],
 *         'actorC' => ['name' => 'Carrie Fisher']
 *     ]
 * ]
 */

Otherwise, if you set this option to false no magic happens:

<?php declare(strict_types=1);

$xmlString = "
<?xml version='1.0' standalone='yes'?>
<movies>
    <movie>
        <title>Star Wars</title>
        <starred>True</starred>
        <actor id=\"actorH\" name=\"Harrison Ford\" />
        <actor id=\"actorM\" name=\"Mark Hamill\" />
        <actor>
            <id>actorC</id>
            <name>Carrie Fisher</name>
        </actor>
    </movie>
</movies>";

$converter = new Converter(['idAsKey' => false]);
$array = $converter->convert($xmlString);

/*
 * $array now contains the following array:
 * 
 * 'movie' => [
 *     0 => [
 *         'title' => 'Star Wars',
 *         'starred' => true,
 *         'actor' => [
 *             0 => [
 *                 'id' => 'actorH',
 *                 'name' => 'Harrison Ford'
 *             ],
 *             1 => [
 *                 'id' => 'actorM',
 *                 'name' => 'Mark Hamill'
 *             ],
 *             2 => [
 *                 'id' => 'actorC',
 *                 'name' => 'Carrie Fisher'
 *             ]
 *         ]
 *     ]
 * ]
 */

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 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 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 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 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.

Contributing

Please, see CONTRIBUTING.md

Licensing

This library is released under Apache-2.0 license.