You are here

function taxonomy_xml_xml_parse in Taxonomy import/export via XML 7

Same name and namespace in other branches
  1. 5.2 xml_format.inc \taxonomy_xml_xml_parse()
  2. 5 xml_format.inc \taxonomy_xml_xml_parse()
  3. 6.2 xml_format.inc \taxonomy_xml_xml_parse()
  4. 6 xml_format.inc \taxonomy_xml_xml_parse()

Initiate the parser on the custom XML schema.

This uses the XML callback parser with tag callbacks.

@todo ONLY EXPERIMENTALLY UPGRADED to D7 - no testing!

Parameters

$data XML string:

$vid will either be an existing vid that the data is to be merged into: (only the data, not the vocab definition) or TAXONOMY_XML_DETERMINED_BY_SOURCE_FILE - which means the vid is to be determined from the source file. If so it may become modified by reference.

Return value

an array of new/modified term objects.

See also

taxonomy_xml_element_start()

taxonomy_xml_element_end()

taxonomy_xml_element_data()

File

formats/xml_format.inc, line 161
Include routines for the original XML parsing and taxonomy/term creation.

Code

function taxonomy_xml_xml_parse(&$data, &$vid = 0) {
  global $_tx_terms, $_tx_vocabulary;

  // Unset the global variables before we use them:
  unset($GLOBALS['_tx_element'], $GLOBALS['_tx_term'], $GLOBALS['_tx_tag']);
  $_tx_terms = array();
  $_tx_vocabulary = array();

  ////////////////////////

  // Parse the data:
  //
  $xml_parser = drupal_xml_parser_create($data);
  xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, FALSE);

  //
  xml_set_element_handler($xml_parser, 'taxonomy_xml_element_start', 'taxonomy_xml_element_end');
  xml_set_character_data_handler($xml_parser, 'taxonomy_xml_element_data');
  if (!xml_parse($xml_parser, $data, 1)) {
    watchdog('taxonomy_xml', 'Failed to parse XML file: %error at line %line.', array(
      '%error' => xml_error_string(xml_get_error_code($xml_parser)),
      '%line' => xml_get_current_line_number($xml_parser),
    ), WATCHDOG_ERROR);
    drupal_set_message(t('Failed to parse file: %error at line %line.', array(
      '%error' => xml_error_string(xml_get_error_code($xml_parser)),
      '%line' => xml_get_current_line_number($xml_parser),
    )), 'error');
  }
  xml_parser_free($xml_parser);

  ////////////////////////

  // Define the vocabulary
  //
  // If an existing vocabulary has been chosen or has the same name as the vocabulary being added,
  // terms should be added to the existing vocabulary. Otherwise a new vocabulary should be created.
  if ($vid == TAXONOMY_XML_DETERMINED_BY_SOURCE_FILE) {

    // Asked to define vocabulary details from file data.
    $vid = taxonomy_xml_setup_vocabulary_from_data($_tx_vocabulary);
  }
  else {

    // We have an existing, valid vid. Load the existing vocab, and go from there
  }

  // If I can't load from the vid, something previous has gone wrong
  // and everything else will fail (and add orphaned terms), so abort.
  $vocabulary = (array) taxonomy_vocabulary_load($vid);
  if (empty($vocabulary['vid'])) {
    drupal_set_message(t("Failed to initialize vocabulary to put terms into. Vocabulary:%vid is an invalid ID. Aborting import.", array(
      '%vid' => $vid,
    )), 'error');
    return FALSE;
  }

  ////////////////////////

  // Start loading terms
  //
  // These collections are just for auditing:
  $modified_terms = array();

  // names
  $new_terms = array();

  // objects
  $skipped_terms = array();

  // names
  // $new_tid is a list mapping from old IDs (defined in the file)
  // to new IDs (because the database needs new numbers when creating things
  // - to avoid conflicts and overrwrites)
  $new_tid = array();

  // Get the maximum depth of terms
  $term_depth = array();
  foreach ($_tx_terms as $term) {
    $term_depth[] = $term['depth'];
  }

  // Import terms in order of depth, no matter what order in the file
  // This is because we require parents to exist before children.
  for ($i = 0; $i <= max($term_depth); $i++) {

    // Loop breadth-first.
    foreach ($_tx_terms as $term_data) {
      if ($term_data['depth'] != $i) {
        continue;
      }
      $term_data['vid'] = $vocabulary['vid'];
      $term_data['old_tid'] = $term_data['tid'];
      unset($term_data['tid']);

      // Calculate parent link-ups
      if (isset($term_data['parent'])) {
        foreach ((array) $term_data['parent'] as $key => $value) {
          if ($value) {
            if (!isset($new_tid[$value])) {
              drupal_set_message("Input claims that {$term_data['name']} has a parent {$value} but that term doesn't exist (yet). tricky.");
            }
            else {
              $term_data['parent'][$key] = $new_tid[$value];
            }
          }
        }
      }
      $term_exists = FALSE;
      if (!variable_get('taxonomy_xml_duplicate', 0)) {

        // Retrieve pre-existing terms - by name - if possible
        $existing_terms = taxonomy_get_term_by_name($term_data['name']);
        if (count($existing_terms) > 0) {
          foreach ($existing_terms as $existing_term) {
            if ($existing_term->vid == $term_data['vid']) {
              $term_exists = TRUE;

              // Map the term tid from the imported XML file to the tid in term_data database table
              $new_tid[$term_data['old_tid']] = $existing_term->tid;
              $modified_terms[$existing_term->tid] = $existing_term;
              $skipped_terms[$existing_term->tid] = $existing_term->name;
            }
          }
        }
      }

      // If the term doesn't already exist in this vocabulary, add it.
      if (!$term_exists) {
        $term = (object) $term_data;
        taxonomy_term_save($term);

        // Map the term tid from the imported XML file to the tid in term_data database table
        $new_tid[$term_data['old_tid']] = $term->tid;
        $new_terms[$term->tid] = $term->name;
        $modified_terms[$term->tid] = taxonomy_term_load($term->tid);
      }
    }
  }

  ////////////////////////

  // Summarize results
  $output = t('Vocabulary %name: ', array(
    '%name' => $vocabulary['name'],
  )) . '<br/>';
  if ($new_terms) {
    $output .= t('<b>Added</b> term(s) %terms. ', array(
      '%terms' => implode(', ', $new_terms),
    ));
  }
  else {
    $output .= t('No terms added. ');
  }
  if (!empty($skipped_terms)) {
    $output .= "<br/>" . t('<b>Ignored</b> duplicate term(s) %terms. ', array(
      '%terms' => implode(', ', $skipped_terms),
    ));
  }
  drupal_set_message($output);
  return $modified_terms;
}