XML Converter Class * Convert array to clean XML * * @category Libraries * @author Anton Vasylyev * @link http://truecoder.name https://github.com/Jeckerson/array2xml/blob/master/array2xml.php * @version 1.3 */ class ArrayToXML { private $writer; private $version = '1.0'; private $encoding = 'UTF-8'; private $rootName = 'root'; private $rootAttrs = array(); //example: array('first_attr' => 'value_of_first_attr', 'second_atrr' => 'etc'); private $rootSelf = FALSE; private $elementAttrs = array(); //example: $attrs['element_name'][] = array('attr_name' => 'attr_value'); private $CDataKeys = array(); private $newLine = "\n"; private $newTab = "\t"; private $numericTagPrefix = 'key'; private $skipNumeric = TRUE; private $_tabulation = TRUE; //TODO private $defaultTagName = FALSE; //Tag For Numeric Array Keys private $rawKeys = array(); private $emptyElementSyntax = 1; private $filterNumbers = FALSE; private $tagsToFilter = array(); const EMPTY_SELF_CLOSING = 1; const EMPTY_FULL = 2; /** * Constructor * Load Standard PHP Class XMLWriter and path it to variable * * @access public * @param array $params */ public function __construct($params = array()) { if (is_array($params) and !empty($params)) { foreach ($params as $key => $param) { $attr = '_' . $key; if (property_exists($this, $attr)) { $this->$attr = $param; } } } $this->writer = new \XMLWriter(); } // -------------------------------------------------------------------- /** * Converter * Convert array data to XML. Last method to call * * @access public * @param array * @return string */ public function convert(array $data) { $this->writer->openMemory(); $this->writer->startDocument($this->version, $this->encoding); $this->writer->startElement($this->rootName); if (!empty($this->rootAttrs) and is_array($this->rootAttrs)) { foreach ($this->rootAttrs as $rootAttrName => $rootAttrText) { $this->writer->writeAttribute($rootAttrName, $rootAttrText); } } if ($this->rootSelf === FALSE) { $this->writer->text($this->newLine); if (is_array($data) AND !empty($data)) { $this->_getXML($data); } } $this->writer->endElement(); return $this->writer->outputMemory(); } // -------------------------------------------------------------------- /** * Set XML Document Version * * @access public * @param string * @return void */ public function setVersion($version) { $this->version = (string)$version; } // -------------------------------------------------------------------- /** * Set Encoding * * @access public * @param string * @return void */ public function setEncoding($encoding) { $this->encoding = (string)$encoding; } // -------------------------------------------------------------------- /** * Set XML Root Element Name * * @access public * @param string * @return void */ public function setRootName($rootName) { $this->rootName = (string)$rootName; } // -------------------------------------------------------------------- /** * Set XML Root Element Attributes * * @access public * @param array * @return void */ public function setRootAttrs(array $rootAttrs) { $this->rootAttrs = $rootAttrs; } // -------------------------------------------------------------------- /** * Set XML Root Self close * * @access public * @param bool * @return void */ public function setRootSelf($rootSelf) { $this->rootSelf = (bool)$rootSelf; } // -------------------------------------------------------------------- /** * Set Attributes of XML Elements * * @access public * @param array * @return void */ public function setElementsAttrs(array $elementAttrs) { $this->elementAttrs = $elementAttrs; } // -------------------------------------------------------------------- /** * Set keys of array that needed to be as CData in XML document * * @access public * @param array * @return void */ public function setCDataKeys(array $CDataKeys) { $this->CDataKeys = $CDataKeys; } // -------------------------------------------------------------------- /** * Set keys of array that needed to be as Raw XML in XML document * * @access public * @param array * @return void */ public function setRawKeys(array $rawKeys) { $this->rawKeys = $rawKeys; } // -------------------------------------------------------------------- /** * Set New Line * * @access public * @param string * @return void */ public function setNewLine($newLine) { $this->newLine = (string)$newLine; } // -------------------------------------------------------------------- /** * Set New Tab * * @access public * @param string * @return void */ public function setNewTab($newTab) { $this->newTab = (string)$newTab; } // -------------------------------------------------------------------- /** * Set Default Numeric Tag Prefix * * @access public * @param string * @return void */ public function setNumericTagPrefix($numericTagPrefix) { $this->numericTagPrefix = (string)$numericTagPrefix; } // -------------------------------------------------------------------- /** * On/Off Skip Numeric Array Keys * * @access public * @param string * @return void */ public function setSkipNumeric($skipNumeric) { $this->skipNumeric = (bool)$skipNumeric; } // -------------------------------------------------------------------- /** * Tag For Numeric Array Keys * * @access public * @param string * @return void */ public function setDefaultTagName($defaultTagName) { $this->defaultTagName = (string)$defaultTagName; } // -------------------------------------------------------------------- /** * Set preferred syntax of empty elements. * or self-closing * * @access public * @param const Array2xml::EMPTY_SELF_CLOSING or Array2xml::EMPTY_FULL * @return void */ public function setEmptyElementSyntax($syntax) { $this->emptyElementSyntax = $syntax; } // -------------------------------------------------------------------- /** * Remove numbers from tag names. * Useful if you need to have identically named elements in your XML * * You can pass either boolean TRUE to remove numbers from ALL tags * or pass an ARRAY with element names in it(without numbers) * to filter only specific elements. * * @access public * @param bool|array * @return void */ public function setFilterNumbersInTags($data) { if (is_bool($data)) { $this->filterNumbers = $data; } elseif (is_array($data)) { $this->tagsToFilter = $data; } else { throw new \InvalidArgumentException('$data must be a type of boolean or array'); } } // -------------------------------------------------------------------- /** * Writing XML document by passing through array * * @access private * @param array * @param int * @return void */ private function _getXML(&$data, $tabs_count = 0) { foreach ($data as $key => $val) { unset($data[$key]); // Skip attribute param if (substr($key, 0, 1) == '@') { continue; } if (is_numeric($key)) { if ($this->defaultTagName !== FALSE) { $key = $this->defaultTagName; } elseif ($this->skipNumeric === TRUE) { if (!is_array($val)) { $tabs_count = 0; } else { if ($tabs_count > 0) { $tabs_count--; } } continue; } else { $key = $this->numericTagPrefix . $key; } } if ($this->filterNumbers === TRUE || in_array(preg_replace('#[0-9]*#', '', $key), $this->tagsToFilter)) { // Remove numbers $key = preg_replace('#[0-9]*#', '', $key); } if ($key !== FALSE) { $this->writer->text(str_repeat($this->newTab, $tabs_count)); // Write element tag name $this->writer->startElement($key); // Check if there are some attributes if (isset($this->elementAttrs[$key]) || isset($val['@attributes'])) { if (isset($val['@attributes']) && is_array($val['@attributes'])) { $attributes = $val['@attributes']; } else { $attributes = $this->elementAttrs[$key]; } // Yeah, lets add them foreach ($attributes as $elementAttrName => $elementAttrText) { $this->writer->startAttribute($elementAttrName); $this->writer->text($elementAttrText); $this->writer->endAttribute(); } if ( ! empty($val['@content']) && is_string($val['@content']) && isset($val['@attributes'])) { $val = $val['@content']; } } } if (is_array($val)) { if ($key !== FALSE) { $this->writer->text($this->newLine); } $tabs_count++; $this->_getXML($val, $tabs_count); $tabs_count--; if ($key !== FALSE) { $this->writer->text(str_repeat($this->newTab, $tabs_count)); } } else { if ($val != NULL || $val === 0) { if (isset($this->CDataKeys[$key]) || array_search($key, $this->CDataKeys) !== FALSE) { $this->writer->writeCData($val); } elseif (array_search($key, $this->rawKeys) !== FALSE) { $this->writer->writeRaw($val); } else { $this->writer->text($val); } } elseif ($this->emptyElementSyntax === self::EMPTY_FULL) { $this->writer->text(''); } } if ($key !== FALSE) { $this->writer->endElement(); $this->writer->text($this->newLine); } } } } //END Array to Xml Class