You are here

class XMLArrayInstance in Campaign Monitor 5.2

XMLArrayInstance, xml2array() and array2xml() will be used to convert data between XML and Array. We're using a class because that is the only way we can safely use xml_parse() and other related functions (the alternative is to use $GLOBALS to hold data).

XMLArrayInstance can be initialized to start processing from a specific path in the XML. In the case of Campaign Monitor, we want to start from '/soap:Envelope/soap:Body', which is the default 2nd parameter for xml2array().

@package CampaignMonitorLib @subpackage CMBase

Hierarchy

Expanded class hierarchy of XMLArrayInstance

File

lib/CMBase.php, line 576

View source
class XMLArrayInstance {
  var $root = '/';
  var $rootStart = 0;
  var $stack = array();
  var $stack_path = '';
  var $stack_sz = 0;
  var $array = array();
  var $arrCurrent = null;
  var $inRoot = false;
  var $counter = 0;
  var $stack_count = array();
  var $stack_prefix = '/';
  var $data_buffer = array();

  /**
   * @param string $root An absolute path that points to where XML data
   *        should start being converted to an array. Do not add an ending '/'.
   */
  function XMLArrayInstance($root = null) {
    if ($root != null && $root != '/') {
      $this->root = $root;
      $this->rootStart = substr_count($root, '/');
      $this->stack_prefix = $root . '/';
    }
  }

  // function default( $parser, $data ) {}
  // function startNS( $parser, $userdata, $prefix, $uri ) {}
  function start($parser, $ele, $atts) {
    $this->stack[] = $ele;
    $this->stack_path = '/' . implode('/', $this->stack);
    $this->stack_sz++;
    if (!isset($this->stack_count[$this->stack_path])) {
      $this->stack_count[$this->stack_path] = -1;
    }
    $this->stack_count[$this->stack_path]++;
    $this->data_buffer[$this->stack_path] = '';
  }
  function data($parser, $data) {
    $data = trim($data);

    // if $data is empty or we're not within start path, skip
    if (strpos($this->stack_path, $this->root) !== 0 || $data == '') {
      return;
    }

    // delay inserting the data, because the parser handles entities as a
    // separate call. that meant that before buffering data, a simple text node
    // would be broken up into multiple parts because of the entities.
    $this->data_buffer[$this->stack_path] .= $data;
  }

  // function ddefault( $parser, $data ) { }
  function end($parser, $ele) {
    if ($this->data_buffer[$this->stack_path] != '') {
      $this
        ->setArrValue($this->data_buffer[$this->stack_path]);
    }
    array_pop($this->stack);
    $this->stack_path = '/' . implode('/', $this->stack);
    $this->stack_sz--;
  }
  function setArrValue($data) {

    // iterate through $arr to find the right element and populate it.
    // if the element doesn't exist, set it as a scalar. otherwise,
    // convert it to an array first and then append the value.
    $ptr =& $this->array;

    // the depth to insert the value at
    $depth = $this->stack_sz - 1;
    $sep = '';
    $partial = '';
    for ($i = $this->rootStart; $i < $this->stack_sz; $i++) {
      $key = $this->stack[$i];
      $partial .= $sep . $key;
      $sep = '/';
      $_c = $this->stack_count[$this->stack_prefix . $partial];

      //echo "$key : [{$this->stack_prefix}]$partial\n";

      // this current path doesn't exist. either we're going deeper
      // into the XML (and the paths haven't been created yet), or the
      // node we're on hasn't been created.
      if (!isset($ptr[$key])) {
        if ($i == $depth) {
          $ptr[$key] = $data;
        }
        else {
          $ptr[$key] = array();
        }
        $ptr =& $ptr[$key];
      }
      elseif ($i < $depth) {

        // if the absolute path of this node has more than one occurrence, $_c > 0.
        // if that's the case, then, we need to test if the node is currently a hash
        // or a list. if it's a hash, convert it to a list. then, check that the list
        // item exists (create it if it doesn't).
        // if it's just a single occurrence, set the pointer to the hash.
        if ($_c > 0) {
          if (!isset($ptr[$key][0])) {
            $tmp = $ptr[$key];
            $ptr[$key] = array(
              $tmp,
            );
          }
          if (!isset($ptr[$key][$_c])) {
            $ptr[$key][$_c] = array();
          }
          $ptr =& $ptr[$key][$_c];
        }
        else {
          $ptr =& $ptr[$key];
        }
      }
      elseif ($i == $depth) {

        // the current node exists. but, since it's not an array, we need
        // to convert it first.
        if (!is_array($ptr[$key])) {
          $tmp = $ptr[$key];
          $ptr[$key] = array(
            $tmp,
          );
        }
        elseif (!isset($ptr[$key][0])) {
          $tmp = $ptr[$key];
          $ptr[$key] = array(
            $tmp,
          );
        }
        $ptr[$key][] = $data;
        $ptr =& $ptr[$key];
      }
    }
  }

}

Members