/SimpleXmlLoader

A simple wrapper library around SimpleXml's simplexml_load_file() and simplexml_load_string() functions. Provides LibXMLError handling.

Primary LanguagePHPGNU General Public License v3.0GPL-3.0

SimpleXMLLoader

A minimalistic SimpleXml loader. Wraps the simplexml_load_XXXX() methods and provides libxml error handling.

Main goals:

  • provide a transparent OOP interface to SimpleXML's simplexml_load_file() and simplexml_load_string() functions
  • handle SimpleXML's internal errors
  • throw catchable Exceptions (XmlLoaderException)

This wrapper will:

  • try to load your XML resource into a \SimpleXMLElement object and return it
  • handle any LibXML errors that occur during loading

This wrapper will not:

  • do anything else

Installation

This package is available on Packagist and installable via Composer:

composer require borislavsabev/simple-xml-loader

Basic usage

As this is a wrapper the wrapped library's functionality is not covered in this documentation. Please refer to:

There are two main functions in the SimpleXMlLoader:

public function loadFile($filename, $xmlClass = "SimpleXMLElement", $options = 0, $xmlNamespace = "", $isPrefix = false)

public function loadString($data, $xmlClass = "SimpleXMLElement", $options = 0, $xmlNamespace = "", $isPrefix = false)

The loader throws XmlLoaderException on any error that occurs. The exception thrown contains the message and code of the last \LibXmlError. The loader calls are meant to be wrapped in try/catch blocks and read any errors yourself:

   use BorislavSabev\SimpleXmlLoader\XmlLoader;
   use BorislavSabev\SimpleXmlLoader\Exception\XmlLoaderException;

   $xmlLoader = new XmlLoader();
   try {
       /** @var \SimpleXMLElement $simpleXmlElement */
       $simpleXmlElement = $xmlLoader->loadFile($filename);
       
       //Now do something with the loaded \SimpleXMLElement...
   } catch (XmlLoaderException $e) {
       // The last error is contained in $e:
       $e->getMessage();
       $e->getCode();
       //All errors accessible through the payload:
       /** @var array $xmlErrors */
       $xmlErrors = $xmlLoader->getXmlPayload()
                              ->getXmlErrors();
   }

The XmlLoader instance is meant to be reused thus:

  • Each call to XmlLoader->loadFile() or XmlLoader->loadString() will clear any LibXml errors stored
  • Each call to XmlLoader->loadFile() or XmlLoader->loadString() will replace it's internal XmlLoaderPayload object

Loop usage

Each consecutive call to a loader method resets the state of LibXML and the payload you must extract all data between calls.

   use BorislavSabev\SimpleXmlLoader\XmlLoader;
   use BorislavSabev\SimpleXmlLoader\Exception\XmlLoaderException;

   $xmlLoader = new XmlLoader();
   
   foreach ($aBunchOfXmlStrings as $xmlString) {
       try {
            /** @var \SimpleXMLElement $simpleXmlElement */
            $simpleXmlElement = $xmlLoader->loadString($xmlString);
       } catch (XmlLoaderException $e) {
           /** @var array $xmlErrors */
           $xmlErrors = $xmlLoader->getXmlPayload()
                                  ->getXmlErrors();
       }
       
       //Any data within LibXML or our XmlLoaderPayload will be lost after this iteration of the loop
   }

Reusing XmlLoaderPayload

You can also reuse the XmlLoaderPayload in your application if you which. Say for example you use this wrapper to parse different XML file but then want to pass the result to different Services in your code that will handle any business logic. You could just get the XmlLoaderPayload and pass it along to a specific service (or whatever really):

   use BorislavSabev\SimpleXmlLoader\XmlLoader;
   use BorislavSabev\SimpleXmlLoader\Exception\XmlLoaderException;

   $xmlLoader = new XmlLoader();
   try {
       $xmlLoader->loadFile($filename);

       //Generic example:
       $serviceBroker->pass(
           MyCoolService::class,
           $xmlLoader->getXmlPayload()
       );
   } catch (XmlLoaderException $e) {
       /** @var array $xmlErrors */
       $xmlErrors = $xmlLoader->getXmlPayload()
                              ->getXmlErrors();
   }

NOTE: Generally you should have you own payload objects to pass data around in your Domain. The idea of XmlLoaderPayload is to be internal for XmlLoader thus it cannot contain any logic outside of that task.

Behaviour overwritten

There is only one behaviour change that this library introduces:
"If you pass an empty string to simplexml_load_string() it will return false and throw no error".
The SimpleXmlLoader wrapper throws an XmlLoaderException in this case.

The XmlLoaderException and LibXML's libXMLError

XmlLoaderException's codes are specific to this wrapper. LibXML's libXMLError objects are just returned in an array and as received from SimpleXML/LibXML.

Personal Opinion on the SimpleXML PHP Extension

Generally SimpleXML is not a solid PHP extension and, in my mind, it should be used rarely when you need to do something simple fast. Any serious work should be done via DomDocument.
The previous two sentences are the author's personal opinion which as with any opinion should be taken with a grain of salt.

Versioning

This library follows Semver. According to Semver, you will be able to upgrade to any minor or patch version of this library without any breaking changes to the public API. Semver also requires that we clearly define the public API for this library.
All methods, with public visibility, are part of the public API. All other methods are not part of the public API. Where possible, we'll try to keep protected methods backwards-compatible in minor/patch versions, but if you're overriding methods then please test your work before upgrading.

Contributing

Please do! PR's are very welcome. The author is far from thinking that this wrapper library is perfect. Any PR must first abide by the [Main goals](#Main goals) set out by this library.

Please note that this project adheres to the Contributor Covenant v1.4. By participating in this project you agree to abide by its terms.