Skip to content

Simple PHP library to convert an XML string into an array

License

Notifications You must be signed in to change notification settings

susina/xml-to-array

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Xml to Array Converter

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.