You are here

function CMBase::xml2array in Campaign Monitor 6.3

Same name and namespace in other branches
  1. 6.2 lib/CMBase.php \CMBase::xml2array()

* Convert the given XML $contents into a PHP array. Based on code from: * http://www.bin-co.com/php/scripts/xml2array/ *

Parameters

$contents The XML to be converted.: * @param $root The path of the root element within the XML at which * conversion should occur. * @param $charset The character set to use. * @param $get_attributes 0 or 1. If this is 1 the function will get the * attributes as well as the tag values - this results in a different array * structure in the return value. * @param $priority Can be 'tag' or 'attribute'. This will change the structure * of the resulting array. For 'tag', the tags are given more importance. * @return A PHP array representing the XML $contents passed in

1 call to CMBase::xml2array()
CMBase::makeCall in lib/CMBase.php
* The direct way to make an API call. This allows developers to include new API * methods that might not yet have a wrapper method as part of the package. * *

File

lib/CMBase.php, line 330

Class

CMBase

Code

function xml2array($contents, $root = '/', $charset = 'utf-8', $get_attributes = 0, $priority = 'tag') {
  if (!$contents) {
    return array();
  }
  if (!function_exists('xml_parser_create')) {
    return array();
  }

  // Get the PHP XML parser
  $parser = xml_parser_create($charset);

  // Attempt to find the last tag in the $root path and use this as the
  // start/end tag for the process of extracting the xml
  // Example input: '/soap:Envelope/soap:Body'
  // Toggles whether the extraction of xml into the array actually occurs
  $extract_on = TRUE;
  $start_and_end_element_name = '';
  $root_elements = explode('/', $root);
  if ($root_elements != FALSE && !empty($root_elements)) {
    $start_and_end_element_name = trim(end($root_elements));
    if (!empty($start_and_end_element_name)) {
      $extract_on = FALSE;
    }
  }
  xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");

  # http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  xml_parse_into_struct($parser, trim($contents), $xml_values);
  xml_parser_free($parser);
  if (!$xml_values) {
    return;
  }
  $xml_array = array();
  $parents = array();
  $opened_tags = array();
  $arr = array();
  $current =& $xml_array;

  // Reference
  // Go through the tags.
  $repeated_tag_index = array();

  // Multiple tags with same name will be turned into an array
  foreach ($xml_values as $data) {
    unset($attributes, $value);

    // Remove existing values, or there will be trouble
    // This command will extract these variables into the foreach scope
    // tag(string), type(string), level(int), attributes(array).
    extract($data);
    if (!empty($start_and_end_element_name) && $tag == $start_and_end_element_name) {

      // Start at the next element (if looking at the opening tag),
      // or don't process any more elements (if looking at the closing tag)...
      $extract_on = !$extract_on;
      continue;
    }
    if (!$extract_on) {
      continue;
    }
    $result = array();
    $attributes_data = array();
    if (isset($value)) {
      if ($priority == 'tag') {
        $result = $value;
      }
      else {
        $result['value'] = $value;
      }

      //Put the value in a assoc array if we are in the 'Attribute' mode
    }

    // Set the attributes too.
    if (isset($attributes) and $get_attributes) {
      foreach ($attributes as $attr => $val) {
        if ($priority == 'tag') {
          $attributes_data[$attr] = $val;
        }
        else {
          $result['attr'][$attr] = $val;
        }

        // Set all the attributes in a array called 'attr'
      }
    }

    // See tag status and do the needed.
    if ($type == "open") {

      // The starting of the tag '<tag>'
      $parent[$level - 1] =& $current;
      if (!is_array($current) or !in_array($tag, array_keys($current))) {

        //Insert New tag
        $current[$tag] = $result;
        if ($attributes_data) {
          $current[$tag . '_attr'] = $attributes_data;
        }
        $repeated_tag_index[$tag . '_' . $level] = 1;
        $current =& $current[$tag];
      }
      else {

        // There was another element with the same tag name
        if (isset($current[$tag][0])) {

          // If there is a 0th element it is already an array
          $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
          $repeated_tag_index[$tag . '_' . $level]++;
        }
        else {

          // This section will make the value an array if multiple tags with the same name appear together
          $current[$tag] = array(
            $current[$tag],
            $result,
          );

          // This will combine the existing item and the new item together to make an array
          $repeated_tag_index[$tag . '_' . $level] = 2;
          if (isset($current[$tag . '_attr'])) {

            // The attribute of the last(0th) tag must be moved as well
            $current[$tag]['0_attr'] = $current[$tag . '_attr'];
            unset($current[$tag . '_attr']);
          }
        }
        $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
        $current =& $current[$tag][$last_item_index];
      }
    }
    elseif ($type == "complete") {

      // Tags that ends in 1 line '<tag />'
      // See if the key is already taken.
      if (!isset($current[$tag])) {

        //New Key

        // Don't insert an empty array - we don't want it!
        if (!(is_array($result) && empty($result))) {
          $current[$tag] = $result;
        }
        $repeated_tag_index[$tag . '_' . $level] = 1;
        if ($priority == 'tag' and $attributes_data) {
          $current[$tag . '_attr'] = $attributes_data;
        }
      }
      else {

        // If taken, put all things inside a list(array)
        if (isset($current[$tag][0]) and is_array($current[$tag])) {

          // If it is already an array...
          // ...push the new element into that array.
          $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
          if ($priority == 'tag' and $get_attributes and $attributes_data) {
            $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
          }
          $repeated_tag_index[$tag . '_' . $level]++;
        }
        else {

          // If it is not an array...
          $current[$tag] = array(
            $current[$tag],
            $result,
          );

          // ...Make it an array using using the existing value and the new value
          $repeated_tag_index[$tag . '_' . $level] = 1;
          if ($priority == 'tag' and $get_attributes) {
            if (isset($current[$tag . '_attr'])) {

              // The attribute of the last(0th) tag must be moved as well
              $current[$tag]['0_attr'] = $current[$tag . '_attr'];
              unset($current[$tag . '_attr']);
            }
            if ($attributes_data) {
              $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
            }
          }
          $repeated_tag_index[$tag . '_' . $level]++;

          // 0 and 1 index is already taken
        }
      }
    }
    elseif ($type == 'close') {

      // End of tag '</tag>'
      $current =& $parent[$level - 1];
    }
  }
  return $xml_array;
}