Tutorial Extension  1.0.0
SellerDeck Extensions - Tutorial Extension
Array2XML.php
1 <?php
2 
3 /**
4  * Array2XML: A class to convert array in PHP to XML
5  * It also takes into account attributes names unlike SimpleXML in PHP
6  * It returns the XML in form of DOMDocument class for further manipulation.
7  * It throws exception if the tag name or attribute name has illegal chars.
8  *
9  * Author : Lalit Patel
10  * Website: http://www.lalit.org/lab/convert-php-array-to-xml-with-attributes
11  * License: Apache License 2.0
12  * http://www.apache.org/licenses/LICENSE-2.0
13  * Version: 0.1 (10 July 2011)
14  * Version: 0.2 (16 August 2011)
15  * - replaced htmlentities() with htmlspecialchars() (Thanks to Liel Dulev)
16  * - fixed a edge case where root node has a false/null/0 value. (Thanks to Liel Dulev)
17  * Version: 0.3 (22 August 2011)
18  * - fixed tag sanitize regex which didn't allow tagnames with single character.
19  * Version: 0.4 (18 September 2011)
20  * - Added support for CDATA section using @cdata instead of @value.
21  * Version: 0.5 (07 December 2011)
22  * - Changed logic to check numeric array indices not starting from 0.
23  * Version: 0.6 (04 March 2012)
24  * - Code now doesn't @cdata to be placed in an empty array
25  * Version: 0.7 (24 March 2012)
26  * - Reverted to version 0.5
27  * Version: 0.8 (02 May 2012)
28  * - Removed htmlspecialchars() before adding to text node or attributes.
29  *
30  * Usage:
31  * $xml = Array2XML::createXML('root_node_name', $php_array);
32  * echo $xml->saveXML();
33  */
34 
35 namespace SDExtension\Helper;
36 
37 class Array2XML
38  {
39 
40  private static $xml = null;
41  private static $encoding = 'UTF-8';
42 
43  /**
44  * Initialize the root XML node [optional]
45  * @param $version
46  * @param $encoding
47  * @param $format_output
48  */
49  public static function init($version = '1.0', $encoding = 'UTF-8', $format_output = true)
50  {
51  self::$xml = new \DomDocument($version, $encoding);
52  self::$xml->formatOutput = $format_output;
53  self::$encoding = $encoding;
54  }
55 
56  /**
57  * Convert an Array to XML
58  * @param string $node_name - name of the root node to be converted
59  * @param array $arr - aray to be converterd
60  * @return DomDocument
61  */
62  public static function &createXML($node_name, $arr = array(), $namespace = null)
63  {
64  $xml = self::getXMLRoot();
65  $xml->appendChild(self::convert($node_name, $arr, $namespace));
66 
67  self::$xml = null; // clear the xml node in the class for 2nd time use.
68  return $xml;
69  }
70 
71  /**
72  * Convert an Array to XML
73  * @param string $node_name - name of the root node to be converted
74  * @param array $arr - aray to be converterd
75  * @return DOMNode
76  */
77  private static function &convert($node_name, $arr = array(), $xmlns = null)
78  {
79 
80  //print_arr($node_name);
81  $xml = self::getXMLRoot();
82  $node = $xml->createElement($node_name);
83  // Setting xmlns on the root element
84  if (is_string($xmlns))
85  {
86  $node->setAttribute("xmlns", $xmlns);
87  }
88  elseif (is_array($xmlns))
89  {
90  foreach ($xmlns as $k => $v)
91  {
92  $node->setAttribute($k, $v);
93  }
94  }
95  if (is_array($arr))
96  {
97  // get the attributes first.;
98  if (isset($arr['@attributes']))
99  {
100  foreach ($arr['@attributes'] as $key => $value)
101  {
102  if (!self::isValidTagName($key))
103  {
104  $sErrorMessage = '[Array2XML] Illegal character in attribute name. attribute: ' . $key . ' in node: ' . $node_name;
105  \SDExtension\Helper\CLogger::get(LOG_CHANNEL_NAME)->addError($sErrorMessage);
106  throw new \Exception($sErrorMessage);
107  }
108  $node->setAttribute($key, self::bool2str($value));
109  }
110  unset($arr['@attributes']); //remove the key from the array once done.
111  }
112 
113  // check if it has a value stored in @value, if yes store the value and return
114  // else check if its directly stored as string
115  if (isset($arr['@value']))
116  {
117  $node->appendChild($xml->createTextNode(self::bool2str($arr['@value'])));
118  unset($arr['@value']); //remove the key from the array once done.
119  //return from recursion, as a note with value cannot have child nodes.
120  return $node;
121  }
122  else if (isset($arr['@cdata']))
123  {
124  $node->appendChild($xml->createCDATASection(self::bool2str($arr['@cdata'])));
125  unset($arr['@cdata']); //remove the key from the array once done.
126  //return from recursion, as a note with cdata cannot have child nodes.
127  return $node;
128  }
129  }
130 
131  //create subnodes using recursion
132  if (is_array($arr))
133  {
134  // recurse to get the node for that key
135  foreach ($arr as $key => $value)
136  {
137  if (!self::isValidTagName($key))
138  {
139  $sErrorMessage = '[Array2XML] Illegal character in tag name. tag: ' . $key . ' in node: ' . $node_name;
140  \SDExtension\Helper\CLogger::get(LOG_CHANNEL_NAME)->addError($sErrorMessage);
141  throw new \Exception($sErrorMessage);
142  }
143  if (is_array($value) && is_numeric(key($value)))
144  {
145  // MORE THAN ONE NODE OF ITS KIND;
146  // if the new array is numeric index, means it is array of nodes of the same kind
147  // it should follow the parent key name
148  foreach ($value as $k => $v)
149  {
150  $node->appendChild(self::convert($key, $v));
151  }
152  }
153  else
154  {
155  // ONLY ONE NODE OF ITS KIND
156  $node->appendChild(self::convert($key, $value));
157  }
158  unset($arr[$key]); //remove the key from the array once done.
159  }
160  }
161 
162  // after we are done with all the keys in the array (if it is one)
163  // we check if it has any text value, if yes, append it.
164  if (!is_array($arr))
165  {
166  $node->appendChild($xml->createTextNode(self::bool2str($arr)));
167  }
168 
169  return $node;
170  }
171 
172  /*
173  * Get the root XML node, if there isn't one, create it.
174  */
175 
176  private static function getXMLRoot()
177  {
178  if (empty(self::$xml))
179  {
180  self::init();
181  }
182  return self::$xml;
183  }
184 
185  /*
186  * Get string representation of boolean value
187  */
188 
189  private static function bool2str($v)
190  {
191  //convert boolean to text value.
192  $v = $v === true ? 'true' : $v;
193  $v = $v === false ? 'false' : $v;
194  return $v;
195  }
196 
197  /*
198  * Check if the tag name or attribute name contains illegal characters
199  * Ref: http://www.w3.org/TR/xml/#sec-common-syn
200  */
201 
202  private static function isValidTagName($tag)
203  {
204  $pattern = '/^[a-z_]+[a-z0-9\:\-\.\_]*[^:]*$/i';
205  return preg_match($pattern, $tag, $matches) && $matches[0] == $tag;
206  }
207 
208  }
static get($sChannel="default", $sLogRoot="")
Definition: CLogger.php:90
static & createXML($node_name, $arr=array(), $namespace=null)
Definition: Array2XML.php:62
static init($version= '1.0', $encoding= 'UTF-8', $format_output=true)
Definition: Array2XML.php:49