1: <?php
2: /**
3: * Magento
4: *
5: * NOTICE OF LICENSE
6: *
7: * This source file is subject to the Open Software License (OSL 3.0)
8: * that is bundled with this package in the file LICENSE.txt.
9: * It is also available through the world-wide-web at this URL:
10: * http://opensource.org/licenses/osl-3.0.php
11: * If you did not receive a copy of the license and are unable to
12: * obtain it through the world-wide-web, please send an email
13: * to license@magentocommerce.com so we can send you a copy immediately.
14: *
15: * DISCLAIMER
16: *
17: * Do not edit or add to this file if you wish to upgrade Magento to newer
18: * versions in the future. If you wish to customize Magento for your
19: * needs please refer to http://www.magentocommerce.com for more information.
20: *
21: * @category Mage
22: * @package Mage_Api2
23: * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24: * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25: */
26:
27: /**
28: * Webservice API2 renderer of XML type model
29: *
30: * @category Mage
31: * @package Mage_Api2
32: * @author Magento Core Team <core@magentocommerce.com>
33: */
34: class Mage_Api2_Model_Renderer_Xml implements Mage_Api2_Model_Renderer_Interface
35: {
36: /**
37: * Adapter mime type
38: */
39: const MIME_TYPE = 'application/xml';
40:
41: /**
42: * Default name for item of non-associative array
43: */
44: const ARRAY_NON_ASSOC_ITEM_NAME = 'data_item';
45:
46: /**
47: * Chars for replacement in the tag name
48: *
49: * @var array
50: */
51: protected $_replacementInTagName = array(
52: '!' => '', '"' => '', '#' => '', '$' => '', '%' => '', '&' => '', '\'' => '',
53: '(' => '', ')' => '', '*' => '', '+' => '', ',' => '', '/' => '', ';' => '',
54: '<' => '', '=' => '', '>' => '', '?' => '', '@' => '', '[' => '', '\\' => '',
55: ']' => '', '^' => '', '`' => '', '{' => '', '|' => '', '}' => '', '~' => '',
56: ' ' => '_', ':' => '_'
57: );
58:
59: /**
60: * Chars for replacement in the tag value
61: *
62: * @var array
63: */
64: protected $_replacementInTagValue = array(
65: '&' => '&' // replace "&" with HTML entity, because by default not replaced
66: );
67:
68: /**
69: * Protected pattern for check chars in the begin of tag name
70: *
71: * @var string
72: */
73: protected $_protectedTagNamePattern = '/^[0-9,.-]/';
74:
75: /**
76: * Convert Array to XML
77: *
78: * @param mixed $data
79: * @return string
80: */
81: public function render($data)
82: {
83: /* @var $writer Mage_Api2_Model_Renderer_Xml_Writer */
84: $writer = Mage::getModel('api2/renderer_xml_writer', array(
85: 'config' => new Zend_Config($this->_prepareData($data, true))
86: ));
87: return $writer->render();
88: }
89:
90: /**
91: * Prepare convert data
92: *
93: * @param array|Varien_Object $data
94: * @param bool $root
95: * @return array
96: * @throws Exception
97: */
98: protected function _prepareData($data, $root = false)
99: {
100: if (!is_array($data) && !is_object($data)) {
101: if ($root) {
102: $data = array($data);
103: } else {
104: throw new Exception('Prepare data must be an object or an array.');
105: }
106: }
107: $data = $data instanceof Varien_Object ? $data->toArray() : (array)$data;
108: $isAssoc = !preg_match('/^\d+$/', implode(array_keys($data), ''));
109:
110: $preparedData = array();
111: foreach ($data as $key => $value) {
112: $value = is_array($value) || is_object($value) ? $this->_prepareData($value) : $this->_prepareValue($value);
113: if ($isAssoc) {
114: $preparedData[$this->_prepareKey($key)] = $value;
115: } else {
116: $preparedData[self::ARRAY_NON_ASSOC_ITEM_NAME][] = $value;
117: }
118: }
119: return $preparedData;
120: }
121:
122: /**
123: * Prepare value
124: *
125: * @param string $value
126: * @return string
127: */
128: protected function _prepareValue($value)
129: {
130: return str_replace(
131: array_keys($this->_replacementInTagValue),
132: array_values($this->_replacementInTagValue),
133: $value
134: );
135: }
136:
137: /**
138: * Prepare key and replace unavailable chars
139: *
140: * @param string $key
141: * @return string
142: */
143: protected function _prepareKey($key)
144: {
145: $key = str_replace(array_keys($this->_replacementInTagName), array_values($this->_replacementInTagName), $key);
146: $key = trim($key, '_');
147: if (preg_match($this->_protectedTagNamePattern, $key)) {
148: $key = self::ARRAY_NON_ASSOC_ITEM_NAME . '_' . $key;
149: }
150: return $key;
151: }
152:
153: /**
154: * Get MIME type generated by renderer
155: *
156: * @return string
157: */
158: public function getMimeType()
159: {
160: return self::MIME_TYPE;
161: }
162: }
163: