You are here

protected function Xml::fetchNextRow in Migrate Plus 8.4

Same name and namespace in other branches
  1. 8.5 src/Plugin/migrate_plus/data_parser/Xml.php \Drupal\migrate_plus\Plugin\migrate_plus\data_parser\Xml::fetchNextRow()
  2. 8.2 src/Plugin/migrate_plus/data_parser/Xml.php \Drupal\migrate_plus\Plugin\migrate_plus\data_parser\Xml::fetchNextRow()
  3. 8.3 src/Plugin/migrate_plus/data_parser/Xml.php \Drupal\migrate_plus\Plugin\migrate_plus\data_parser\Xml::fetchNextRow()

Retrieves the next row of data. populating currentItem.

Retrieves from the open source URL.

Overrides DataParserPluginBase::fetchNextRow

File

src/Plugin/migrate_plus/data_parser/Xml.php, line 190

Class

Xml
Obtain XML data for migration using the XMLReader pull parser.

Namespace

Drupal\migrate_plus\Plugin\migrate_plus\data_parser

Code

protected function fetchNextRow() {
  $target_element = NULL;

  // Loop over each node in the XML file, looking for elements at a path
  // matching the input query string (represented in $this->elementsToMatch).
  while ($this->reader
    ->read()) {
    if ($this->reader->nodeType == \XMLReader::ELEMENT) {
      if ($this->prefixedName) {
        $this->currentPath[$this->reader->depth] = $this->reader->name;
        if (in_array($this->reader->name, $this->parentElementsOfInterest)) {
          $this->parentXpathCache[$this->reader->depth][$this->reader->name][] = $this
            ->getSimpleXml();
        }
      }
      else {
        $this->currentPath[$this->reader->depth] = $this->reader->localName;
        if (in_array($this->reader->localName, $this->parentElementsOfInterest)) {
          $this->parentXpathCache[$this->reader->depth][$this->reader->name][] = $this
            ->getSimpleXml();
        }
      }
      if ($this->currentPath == $this->elementsToMatch) {

        // We're positioned to the right element path - build the SimpleXML
        // object to enable proper xpath predicate evaluation.
        $target_element = $this
          ->getSimpleXml();
        if ($target_element !== FALSE) {
          if (empty($this->xpathPredicate) || $this
            ->predicateMatches($target_element)) {
            break;
          }
        }
      }
    }
    elseif ($this->reader->nodeType == \XMLReader::END_ELEMENT) {

      // Remove this element and any deeper ones from the current path.
      foreach ($this->currentPath as $depth => $name) {
        if ($depth >= $this->reader->depth) {
          unset($this->currentPath[$depth]);
        }
      }
      foreach ($this->parentXpathCache as $depth => $elements) {
        if ($depth > $this->reader->depth) {
          unset($this->parentXpathCache[$depth]);
        }
      }
    }
  }

  // If we've found the desired element, populate the currentItem and
  // currentId with its data.
  if ($target_element !== FALSE && !is_null($target_element)) {
    foreach ($this
      ->fieldSelectors() as $field_name => $xpath) {
      $prefix = substr($xpath, 0, 3);
      if (in_array($prefix, [
        '../',
        '..\\',
      ])) {
        $name = str_replace($prefix, '', $xpath);
        $up = substr_count($xpath, $prefix);
        $values = $this
          ->getAncestorElements($up, $name);
      }
      else {
        $values = $target_element
          ->xpath($xpath);
      }
      foreach ($values as $value) {

        // If the SimpleXMLElement doesn't render to a string of any sort,
        // and has children then return the whole object for the process
        // plugin or other row manipulation.
        if ($value
          ->children() && !trim((string) $value)) {
          $this->currentItem[$field_name] = $value;
        }
        else {
          $this->currentItem[$field_name][] = (string) $value;
        }
      }
    }

    // Reduce single-value results to scalars.
    foreach ($this->currentItem as $field_name => $values) {
      if (count($values) == 1) {
        $this->currentItem[$field_name] = reset($values);
      }
    }
  }
}