Xml.php
protected static function _fromArray($dom, $node, &$data, $format)
    {
        if ($data === null || $data === '' || !\is_array($data)) {
            return;
        }
        foreach ($data as $key => $value) {
            if (\is_string($key)) {
                if (!\is_array($value)) {
                    if (\is_bool($value)) {
                        $value = (int)$value;
                    } elseif ($value === null) {
                        $value = '';
                    }
                    $isNamespace = strpos($key, 'xmlns:');
                    if ($isNamespace !== false) {
                        $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value);
                        continue;
                    }
                    if ($key[0] !== '@' && $format === 'tags') {
                        $child = null;
                        if (!is_numeric($value)) {
                            // Escape special characters
                            // http://www.w3.org/TR/REC-xml/#syntax
                            // https://bugs.php.net/bug.php?id=36795
                            $child = $dom->createElement($key, '');
                            $child->appendChild(new \DOMText($value));
                        } else {
                            $child = $dom->createElement($key, $value);
                        }
                        $node->appendChild($child);
                    } else {
                        if ($key[0] === '@') {
                            $key = substr($key, 1);
                        }
                        $attribute = $dom->createAttribute($key);
                        $attribute->appendChild($dom->createTextNode($value));
                        $node->appendChild($attribute);
                    }
                } else {
                    if ($key[0] === '@') {
                        throw new \RuntimeException(Tools::poorManTranslate('fts-shared', 'Invalid array'));
                    }
                    if (array_keys($value) === range(0, \count($value) - 1)) { // List
                        foreach ($value as $item) {
                            $data = compact('dom', 'node', 'key', 'format');
                            $data['value'] = $item;
                            self::_createChild($data);
                        }
                    } else { // Struct
                        self::_createChild(compact('dom', 'node', 'key', 'value', 'format'));
                    }
                }
            } else {
                throw new \RuntimeException(Tools::poorManTranslate('fts-shared', 'Invalid array'));
            }
        }
    }
protected static function _fromArray($dom, $node, &$data, $format)
    {
        if ($data === null || $data === '' || !\is_array($data)) {
            return;
        }
        foreach ($data as $key => $value) {
            if (\is_string($key)) {
                if (!\is_array($value)) {
                    if (\is_bool($value)) {
                        $value = (int)$value;
                    } elseif ($value === null) {
                        $value = '';
                    }
                    $isNamespace = strpos($key, 'xmlns:');
                    if ($isNamespace !== false) {
                        $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $key, $value);
                        continue;
                    }
                    if ($key[0] !== '@' && $format === 'tags') {
                        $child = null;
                        if (!is_numeric($value)) {
                            // Escape special characters
                            // http://www.w3.org/TR/REC-xml/#syntax
                            // https://bugs.php.net/bug.php?id=36795
                            $child = $dom->createElement($key, '');
                            $child->appendChild(new \DOMText($value));
                        } else {
                            $child = $dom->createElement($key, $value);
                        }
                        $node->appendChild($child);
                    } else {
                        if ($key[0] === '@') {
                            $key = substr($key, 1);
                        }
                        $attribute = $dom->createAttribute($key);
                        $attribute->appendChild($dom->createTextNode($value));
                        $node->appendChild($attribute);
                    }
                } else {
                    if ($key[0] === '@') {
                        throw new \RuntimeException(Tools::poorManTranslate('fts-shared', 'Invalid array'));
                    }
                    if (array_keys($value) === range(0, \count($value) - 1)) { // List
                        foreach ($value as $item) {
                            $data = compact('dom', 'node', 'key', 'format');
                            $data['value'] = $item;
                            self::_createChild($data);
                        }
                    } else { // Struct
                        self::_createChild(compact('dom', 'node', 'key', 'value', 'format'));
                    }
                }
            } else {
                throw new \RuntimeException(Tools::poorManTranslate('fts-shared', 'Invalid array'));
            }
        }
    }
Recursive method to create child from array

@param \DOMDocument $dom Handler to DOMDocument
@param \DOMElement|\DOMDocument $node Handler to DOMElement (child)
@param array $data Array of data to append to the $node.
@param string $format Either 'attribute' or 'tags'.  This determines where nested keys go.
@return void
@throws \RuntimeException