/** * Converts an XML string to a PHP array. * This is the reverse function of array2xml() * * @param string $string XML content to convert into an array * @param string $NSprefix The tag-prefix resolve, eg. a namespace like "T3:" * @param boolean $reportDocTag If set, the document tag will be set in the key "_DOCUMENT_TAG" of the output array * @return mixed If the parsing had errors, a string with the error message is returned. Otherwise an array with the content. * @see array2xml() */ protected static function xml2arrayProcess($string, $NSprefix = '', $reportDocTag = FALSE) { // Create parser: $parser = xml_parser_create(); $vals = array(); $index = array(); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); // Default output charset is UTF-8, only ASCII, ISO-8859-1 and UTF-8 are supported!!! $match = array(); preg_match('/^[[:space:]]*<\\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/', substr($string, 0, 200), $match); $theCharset = $match[1] ?: 'utf-8'; // us-ascii / utf-8 / iso-8859-1 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset); // Parse content: xml_parse_into_struct($parser, $string, $vals, $index); // If error, return error message: if (xml_get_error_code($parser)) { return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)); } xml_parser_free($parser); // Init vars: $stack = array(array()); $stacktop = 0; $current = array(); $tagName = ''; $documentTag = ''; // Traverse the parsed XML structure: foreach ($vals as $key => $val) { // First, process the tag-name (which is used in both cases, whether "complete" or "close") $tagName = $val['tag']; if (!$documentTag) { $documentTag = $tagName; } // Test for name space: $tagName = $NSprefix && substr($tagName, 0, strlen($NSprefix)) == $NSprefix ? substr($tagName, strlen($NSprefix)) : $tagName; // Test for numeric tag, encoded on the form "nXXX": $testNtag = substr($tagName, 1); // Closing tag. $tagName = $tagName[0] === 'n' && MathUtility::canBeInterpretedAsInteger($testNtag) ? (int) $testNtag : $tagName; // Test for alternative index value: if (strlen($val['attributes']['index'])) { $tagName = $val['attributes']['index']; } // Setting tag-values, manage stack: switch ($val['type']) { case 'open': // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array: // Setting blank place holder $current[$tagName] = array(); $stack[$stacktop++] = $current; $current = array(); break; case 'close': // If the tag is "close" then it is an array which is closing and we decrease the stack pointer. $oldCurrent = $current; $current = $stack[--$stacktop]; // Going to the end of array to get placeholder key, key($current), and fill in array next: end($current); $current[key($current)] = $oldCurrent; unset($oldCurrent); break; case 'complete': // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it. if ($val['attributes']['base64']) { $current[$tagName] = base64_decode($val['value']); } else { // Had to cast it as a string - otherwise it would be evaluate FALSE if tested with isset()!! $current[$tagName] = (string) $val['value']; // Cast type: switch ((string) $val['attributes']['type']) { case 'integer': $current[$tagName] = (int) $current[$tagName]; break; case 'double': $current[$tagName] = (double) $current[$tagName]; break; case 'boolean': $current[$tagName] = (bool) $current[$tagName]; break; case 'NULL': $current[$tagName] = NULL; break; case 'array': // MUST be an empty array since it is processed as a value; Empty arrays would end up here because they would have no tags inside... $current[$tagName] = array(); break; } } break; } } if ($reportDocTag) { $current[$tagName]['_DOCUMENT_TAG'] = $documentTag; } // Finally return the content of the document tag. return $current[$tagName]; }
/** * Takes a TypoScript array as input and returns an array which contains all integer properties found which had a value (not only properties). The output array will be sorted numerically. * * @param array $setupArr TypoScript array with numerical array in * @param bool $acceptAnyKeys If set, then a value is not required - the properties alone will be enough. * @return array An array with all integer properties listed in numeric order. * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::cObjGet(), \TYPO3\CMS\Frontend\Imaging\GifBuilder, \TYPO3\CMS\Frontend\ContentObject\Menu\ImageMenuContentObject::makeImageMap() */ public static function filterAndSortByNumericKeys($setupArr, $acceptAnyKeys = false) { $filteredKeys = []; $keys = array_keys($setupArr); foreach ($keys as $key) { if ($acceptAnyKeys || MathUtility::canBeInterpretedAsInteger($key)) { $filteredKeys[] = (int) $key; } } $filteredKeys = array_unique($filteredKeys); sort($filteredKeys); return $filteredKeys; }