How often do you have to work with XML PHP developers? Not so often, in fact. Usually the need arises when integrating with a third-party service, such as BetaPRO, OnTime or CDEK. And here usually there is such a situation when your code becomes similar to
$date = '2016-09-25T12:45:10'; $account = 'f62dcb094cc91617def72d9c260b4483'; $secure = '81ad561784277fa864bf644d755fb164'; $count = 1; $copy = 4; $dispatchNumber = '1033229706'; $orderDate = '2016-09-25T12:45:10'; $request = <<<XML <?xml version="1.0" encoding="UTF-8"?> <OrdersPrint Date="{$date}" Account="{$account}" Secure="{$secure}" OrderCount="{$count}" CopyCount="{$copy}"> <Order DispathNumber="{$orderNumber}" Date="{$orderDate}"/> </OrdersPrint> XML;
And that is not all! Care must be taken to ensure that attribute values ​​and content enclosed in tags do not contain special characters inherent to XML. If for this particular request, you can be sure that nothing of the special characters will fall here, then you would not want to monitor each request at all. Therefore, everything is passed through the "filter". From this it follows that it is still necessary to “pound up” with htmlspecialchars
or with CDATA
, or with XMLWriter
, and know how to apply this and more than once again “curb your blood”. As you see, time is worth “killing” enough, but the result is something you want now. Eh ... And how I would like it to be possible to create XML as quickly as JSON: I gave an array, and you have an XML string, and no problems. Being saddened by the current situation, in the distant 2015th year I decided to make such a designer.
I present to your attention the xml-constructor for PHP from version 5.4 to 7.2 at the time of publication of this article.
To get started, install this package through Composer :
$ composer require bupy7/xml-constructor
It can also be simply copied manually where you want, because the package has no add. dependencies, except the presence of libxml in PHP itself.
Now create an XML string using a PHP array:
$date = '2016-09-25T12:45:10'; $account = 'f62dcb094cc91617def72d9c260b4483'; $secure = '81ad561784277fa864bf644d755fb164'; $count = 1; $copy = 4; $dispatchNumber = '1033229706'; $orderDate = '2016-09-25T12:45:10'; $in = [ [ 'tag' => 'OrdersPrint', 'attributes' => [ 'Date' => $date, 'Account' => $account, 'Secure' => $secure, 'OrderCount' => $count, 'CopyCount' => $copy, ], 'elements' => [ [ 'tag' => 'Order', 'attributes' => [ 'DispathNumber' => $dispatchNumber, 'Date' => $orderDate, ], ], ], ], ]; $request = (new \bupy7\xml\constructor\XmlConstructor())->fromArray($in)->toOutput();
Result:
<?xml version="1.0" encoding="UTF-8"?> <OrdersPrint Date="2016-09-25T12:45:10" Account="f62dcb094cc91617def72d9c260b4483" Secure="81ad561784277fa864bf644d755fb164" OrderCount="1" CopyCount="4"> <Order DispathNumber="1033229706" Date="2016-09-25T12:45:10"/> </OrdersPrint>
That's all the work! The xml-constructor
will take care of the rest.
And let's try to pass something "forbidden" into values ​​and see how the xml-constructor
will behave:
$date = '2016-09-25T12:45:10'; $secure = '81ad561784277fa864bf644d755fb164'; $count = 1; $copy = 4; $dispatchNumber = '1033229706'; $orderDate = '2016-09-25T12:45:10'; // ACHTUNG !!! $account = '<example danger="account"><WTF?!/></example>'; $orderContent = '<special>"chars"'; $in = [ [ 'tag' => 'OrdersPrint', 'attributes' => [ 'Date' => $date, 'Account' => $account, 'Secure' => $secure, 'OrderCount' => $count, 'CopyCount' => $copy, ], 'elements' => [ [ 'tag' => 'Order', 'attributes' => [ 'DispathNumber' => $dispatchNumber, 'Date' => $orderDate, ], 'content' => $orderContent, ], ], ], ]; $request = (new \bupy7\xml\constructor\XmlConstructor())->fromArray($in)->toOutput();
Result:
<?xml version="1.0" encoding="UTF-8"?> <OrdersPrint Date="2016-09-25T12:45:10" Account="<example danger="account"><WTF?!/></example>" Secure="81ad561784277fa864bf644d755fb164" OrderCount="1" CopyCount="4"> <Order DispathNumber="1033229706" Date="2016-09-25T12:45:10"><special>"chars"</Order> </OrdersPrint>
Creating an XML string boils down to transferring a PHP array with the necessary keys and in the correct structure. There are only four keys:
tag
- a string with the tag name;content
- the content enclosed between the tag;attributes
is the key-value array, where the key is the name of the attribute (string) and the value is its value (string);elements
- new nesting of tags inside which this key was specified. It will also contain all the above elements. Nesting is unlimited.Each array element must contain an array with one key tag
, at a minimum. The keys attributes
, content
and elements
optional.
The first level of nesting is nothing other than the roots of an XML document, that is:
$in = [ [ 'tag' => 'FirstRoot', ], [ 'tag' => 'SecondRoot', 'content' => 'Content of SecondRoot', ], ]; $request = (new \bupy7\xml\constructor\XmlConstructor())->fromArray($in)->toOutput();
Result:
<?xml version="1.0" encoding="UTF-8"?> <FirstRoot/> <SecondRoot>Content of SecondRoot</SecondRoot>
From the configuration, only the most necessary.
indentString
is an arbitrary indent string. The default is 4 spaces. If you do not want to use indents at all, pass false
.startDocument
is a key-value array with attributes of the XML declaration of the document. The default is <?xml version="1.0" encoding="UTF-8"?>
. If you do not need a declaration, pass false
.To apply the configuration, you must pass the key-value array to the constructor with the first argument:
$date = '2016-09-25T12:45:10'; $account = 'f62dcb094cc91617def72d9c260b4483'; $secure = '81ad561784277fa864bf644d755fb164'; $count = 1; $copy = 4; $dispatchNumber = '1033229706'; $orderDate = '2016-09-25T12:45:10'; $in = [ [ 'tag' => 'OrdersPrint', 'attributes' => [ 'Date' => $date, 'Account' => $account, 'Secure' => $secure, 'OrderCount' => $count, 'CopyCount' => $copy, ], 'elements' => [ [ 'tag' => 'Order', 'attributes' => [ 'DispathNumber' => $dispatchNumber, 'Date' => $orderDate, ], ], ], ], ]; $request = (new \bupy7\xml\constructor\XmlConstructor([ 'indentString' => '****', 'startDocument' => false, ])) ->fromArray($in) ->toOutput();
Result:
<OrdersPrint Date="2016-09-25T12:45:10" Account="f62dcb094cc91617def72d9c260b4483" Secure="81ad561784277fa864bf644d755fb164" OrderCount="1" CopyCount="4"><Order DispathNumber="1033229706" Date="2016-09-25T12:45:10"/></OrdersPrint>
The extension is very simple and brings a lot of convenience while integrating with services using XML for its API. Should you use xml-constructor
- it's up to you.
Thank you for reading the time!
Source: https://habr.com/ru/post/343636/
All Articles