You are here

class ChunkedXMLFIReader in Feed Import 8

CunkedXML Reader class, used for huge XML files.

Hierarchy

Expanded class hierarchy of ChunkedXMLFIReader

File

feed_import_base/src/ChunkedXMLFIReader.php, line 7

Namespace

Drupal\feed_import_base
View source
class ChunkedXMLFIReader extends FeedImportSimpleXPathReader {

  // Default xml properties.
  protected $properties = '<?xml version="1.0" encoding="utf-8"?>';

  // Substring function.
  protected $substr = 'substr';

  // Chunk size.
  protected $size = 8192;

  // XML parent.
  protected $root;

  // SimpleXMLElement class
  protected $sxclass = 'SimpleXMLElement';

  // Tags info.
  protected $tagOpen;
  protected $tagClose;
  protected $tagLen;
  protected $tagCloseLen;

  // Read content.
  protected $content = '';

  // Fiel handle.
  protected $fh;

  /**
   * {@inheritdoc}
   */
  public function init() {

    // Check for resource location and parent xpath.
    if (empty($this->options['url']) || empty($this->options['parent'])) {
      return FALSE;
    }
    $this->options += array(
      'stream' => NULL,
    );

    // Check for stream options.
    if ($ctx = $this
      ->getStreamContext($this->options['stream'])) {

      // Open the file using stream options.
      $this->fh = fopen($this->options['url'], 'rb', FALSE, $ctx);
    }
    else {

      // Open the file.
      $this->fh = fopen($this->options['url'], 'rb');
    }
    if (!$this->fh) {
      return FALSE;
    }

    // Get tag info.
    $this->root = $this->options['parent'];
    $tag = explode('/', $this->options['parent']);
    unset($this->options['parent']);
    list($tag) = explode('[', trim(end($tag)));
    if (!$tag || $tag == '*' || $tag[0] == '@') {
      return FALSE;
    }
    $this->tagOpen = "<{$tag}";
    $this->tagClose = "</{$tag}>";
    $this->tagLen = strlen($tag);
    $this->tagCloseLen = strlen($this->tagClose);

    // Create an empty array of read items.
    $this->items = array();
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function get() {
    return $this->items || $this
      ->read() ? array_shift($this->items) : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function setOptions(array $options, $overwrite = FALSE) {
    parent::setOptions($options, $overwrite);

    // Set substr function.
    if (!empty($this->options['substr']) && function_exists($this->options['substr'])) {
      $this->substr = $this->options['substr'];
    }

    // Set XML properties.
    if (!empty($this->options['properties'])) {
      $this->properties = $this->options['properties'];
    }

    // Set chunk size.
    if (!empty($this->options['size'])) {
      $this->size = (int) $this->options['size'];
    }

    // Check SXE class
    if (isset($this->options['class'])) {
      $this->sxclass = $this->options['class'];
    }
  }

  /**
   * Populates the $items array with xml nodes.
   */
  protected function read() {
    $substr =& $this->substr;

    // To the end of file.
    while (!feof($this->fh)) {

      // Append read content.
      if (!($this->content .= fread($this->fh, $this->size))) {
        continue;
      }

      // Loop until match some elements.
      while (TRUE) {

        // Tag open position.
        $openpos = strpos($this->content, $this->tagOpen);

        // Tag close position.
        $openposclose = $openpos + $this->tagLen + 1;
        if ($openpos === FALSE || !isset($this->content[$openposclose]) || !($closepos = strpos($this->content, $this->tagClose, $openposclose))) {
          if ($this->items) {

            // We have some items.
            break;
          }
          else {

            // Read more data.
            continue 2;
          }
        }
        elseif (isset($this->content[$openposclose]) && $this->content[$openposclose] != ' ' && $this->content[$openposclose] != '>') {

          // Remove data read so far to save memory.
          $this->content = $substr($this->content, $openposclose);

          // Not searched tag, keep looking.
          continue;
        }

        // We have data.
        $closepos += $this->tagCloseLen;

        // Create item.
        $item = $this->properties . $substr($this->content, $openpos, $closepos - $openpos);

        // Remove read data.
        $this->content = $substr($this->content, $closepos);

        // Create xml object.
        try {
          $item = simplexml_load_string($item, $this->sxclass, LIBXML_NOCDATA);
        } catch (Exception $e) {
          continue;
        }

        // Apply root.
        if ($item = $item
          ->xpath($this->root)) {

          // Add to items.
          $this->items[] = reset($item);
        }
        unset($item);
      }

      // We have part of items so just return OK.
      if ($this->items) {
        return TRUE;
      }
    }
    $this->content = '';
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function __destruct() {

    // Close file handle if any.
    if ($this->fh) {
      try {
        fclose($this->fh);
      } catch (Exception $e) {
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ChunkedXMLFIReader::$content protected property
ChunkedXMLFIReader::$fh protected property
ChunkedXMLFIReader::$properties protected property
ChunkedXMLFIReader::$root protected property
ChunkedXMLFIReader::$size protected property
ChunkedXMLFIReader::$substr protected property
ChunkedXMLFIReader::$sxclass protected property
ChunkedXMLFIReader::$tagClose protected property
ChunkedXMLFIReader::$tagCloseLen protected property
ChunkedXMLFIReader::$tagLen protected property
ChunkedXMLFIReader::$tagOpen protected property
ChunkedXMLFIReader::get public function This method returns the next available item or NULL if there are no items left. Overrides FeedImportReader::get
ChunkedXMLFIReader::init public function Here you'll init your reader. Overrides FeedImportReader::init
ChunkedXMLFIReader::read protected function Populates the $items array with xml nodes.
ChunkedXMLFIReader::setOptions public function Sets options for this instance Overrides FeedImportConfigurable::setOptions
ChunkedXMLFIReader::__destruct public function Destructor. Overrides FeedImportReader::__destruct
FeedImportConfigurable::$options protected property
FeedImportConfigurable::cleanLines public static function Helper function to get lines of a string
FeedImportReader::$items protected property
FeedImportReader::formatPath public function Override this to preprocess your paths before they are used in map(). 2
FeedImportReader::getStreamContext public function Returns a stream context
FeedImportReader::__construct final public function Constructor of reader. Constructor is final but you'll have to implement init() to init your reader.
FeedImportSimpleXPathReader::map public function Returns a value mapped from obj by path. Overrides FeedImportReader::map