<?php
/**
* XML Renderer allows to format array or object as valid XML document.
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Webapi\Rest\Response\Renderer;
/**
* Renders response data in Xml format.
*/
class Xml implements \Magento\Framework\Webapi\Rest\Response\RendererInterface
{
/**
* Renderer mime type.
*/
const MIME_TYPE = 'application/xml';
/**
* Root node in XML output.
*/
const XML_ROOT_NODE = 'response';
/**
* This value is used to replace numeric keys while formatting data for XML output.
*/
const DEFAULT_ENTITY_ITEM_NAME = 'item';
/**
* @var \Magento\Framework\Xml\Generator
*/
protected $_xmlGenerator;
/**
* Initialize dependencies.
*
* @param \Magento\Framework\Xml\Generator $xmlGenerator
*/
public function __construct(\Magento\Framework\Xml\Generator $xmlGenerator)
{
$this->_xmlGenerator = $xmlGenerator;
}
/**
* Get XML renderer MIME type.
*
* @return string
*/
public function getMimeType()
{
return self::MIME_TYPE;
}
/**
* Format object|array to valid XML.
*
* @param object|array|int|string|bool|float|null $data
* @return string
*/
public function render($data)
{
$formattedData = $this->_formatData($data, true);
/** Wrap response in a single node. */
$formattedData = [self::XML_ROOT_NODE => $formattedData];
$this->_xmlGenerator->setIndexedArrayItemName(self::DEFAULT_ENTITY_ITEM_NAME)->arrayToXml($formattedData);
return $this->_xmlGenerator->getDom()->saveXML();
}
/**
* Reformat mixed data to multidimensional array.
*
* This method is recursive.
*
* @param array|\Magento\Framework\DataObject $data
* @param bool $isRoot
* @return array
* @throws \InvalidArgumentException
*/
protected function _formatData($data, $isRoot = false)
{
if (!is_array($data) && !is_object($data)) {
if ($isRoot) {
return $this->_formatValue($data);
}
} elseif ($data instanceof \Magento\Framework\DataObject) {
$data = $data->toArray();
} else {
$data = (array)$data;
}
$isAssoc = !preg_match('/^\d+$/', implode('', array_keys($data)));
$formattedData = [];
foreach ($data as $key => $value) {
$value = is_array($value) || is_object($value) ? $this->_formatData($value) : $this->_formatValue($value);
if ($isAssoc) {
$formattedData[$this->_prepareKey($key)] = $value;
} else {
$formattedData[] = $value;
}
}
return $formattedData;
}
/**
* Prepare value in contrast with key.
*
* @param string $value
* @return string
*/
protected function _formatValue($value)
{
if (is_bool($value)) {
/** Without the following transformation boolean values are rendered incorrectly */
$value = $value ? 'true' : 'false';
}
return (string) $value;
}
/**
* Format array key or field name to be valid array key name.
*
* Replaces characters that are invalid in array key names.
*
* @param string $key
* @return string
*/
protected function _prepareKey($key)
{
$replacementMap = [
'!' => '',
'"' => '',
'#' => '',
'$' => '',
'%' => '',
'&' => '',
'\'' => '',
'(' => '',
')' => '',
'*' => '',
'+' => '',
',' => '',
'/' => '',
';' => '',
'<' => '',
'=' => '',
'>' => '',
'?' => '',
'@' => '',
'[' => '',
'\\' => '',
']' => '',
'^' => '',
'`' => '',
'{' => '',
'|' => '',
'}' => '',
'~' => '',
' ' => '_',
':' => '_',
];
$key = str_replace(array_keys($replacementMap), array_values($replacementMap), $key);
$key = trim($key, '_');
$prohibitedTagPattern = '/^[0-9,.-]/';
if (preg_match($prohibitedTagPattern, $key)) {
$key = self::DEFAULT_ENTITY_ITEM_NAME . '_' . $key;
}
return $key;
}
}
|