View source
<?php
define('TAXONOMY_XML_RELATED', 'Related Terms');
define('TAXONOMY_XML_PARENT', 'Broader Terms');
define('TAXONOMY_XML_CHILD', 'Narrower Terms');
define('TAXONOMY_XML_HAS_SYNONYM', 'Used for');
define('TAXONOMY_XML_SYNONYM_OF', 'Use');
define('TAXONOMY_XML_DESCRIPTION', 'Definition');
define('TAXONOMY_XML_IN_VOCABULARY', 'Part of');
define('TAXONOMY_XML_NAME', 'name');
function taxonomy_xml_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('Makes it possible to import and export taxonomy terms via XML.');
case 'admin/content/taxonomy/import':
return t("\n <p>\n You can upload a vocabulary and/or taxonomy terms from a properly-formatted document. See the file formats.html in the module directory for more information.\n </p><p>\n If you want to add the terms to an existing vocabulary, \n use the \"Target vocabulary\" selector below. \n If you select \"determined by source file,\" the add to vocabulary will be specified by the XML document itself. \n <br/>\n Drupal-specific configurations (such as the related node types, or the free-tagging property) will \n probably not be imported, so you'll want to review the new vocabulary edit page when it's done.\n </p><p>\n To avoid duplications, already-existing terms will not be added.\n It's highly unlikely that term IDs can be meaningfully shared between systems, so the\n tid field is NOT retained. Instead, terms are looked up by name (string match) and vocabulary when looking for existing terms.\n Just because you've duplicated a vocabulary, does not mean it's identically numbered as the original. \n They will usually get new, unique IDs.\n </p>\n ");
case 'admin/content/taxonomy/export':
return t("You can export XML documents for each vocabulary and its terms in this website's !taxonomies. Choose the vocabulary from the list below.", array(
'!taxonomies' => l(t("taxonomies"), "admin/help/taxonomy"),
));
case 'admin/help#taxonomy_xml':
return t("This module makes it possible to import and export vocabularies and taxonomy terms in several formats (requires taxonomy.module). " . "Once installed and enabled, it module provides a list of downloadable XML documents for each vocabulary at !downloads. To import a vocabulary, use !upload.", array(
'!downloads' => l(t("taxonomy XML"), "admin/taxonomy/export"),
'!upload' => l("administer » categories » import", "admin/taxonomy/import", array(), NULL, NULL, FALSE, TRUE),
));
}
}
function taxonomy_xml_menu($may_cache) {
if (!module_exists('taxonomy')) {
return;
}
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/content/taxonomy/export',
'title' => t('Export'),
'access' => user_access('administer taxonomy'),
'callback' => 'taxonomy_xml_export',
'type' => MENU_LOCAL_TASK,
);
$items[] = array(
'path' => 'admin/content/taxonomy/import',
'title' => t('Import'),
'access' => user_access('administer taxonomy'),
'callback' => 'taxonomy_xml_import',
'type' => MENU_LOCAL_TASK,
);
}
$items[] = array(
'path' => 'taxonomy_xml',
'title' => t('Taxonomy XML'),
'callback' => 'taxonomy_xml_file',
'access' => true,
'type' => MENU_CALLBACK,
);
return $items;
}
function taxonomy_xml_export() {
$output = '';
$vocabularies = module_invoke('taxonomy', 'get_vocabularies');
if (empty($vocabularies)) {
$output .= t('There are no vocabularies present');
}
else {
foreach ($vocabularies as $vocabulary) {
$vocablist[$vocabulary->vid] = l($vocabulary->name, "taxonomy_xml/{$vocabulary->vid}");
$vocablist[$vocabulary->vid] .= ' ' . l("RDF", "taxonomy_xml/{$vocabulary->vid}/rdf");
}
$output = theme_item_list($vocablist);
}
return $output;
}
function taxonomy_xml_file($vid, $format = 'xml') {
$vocabulary = taxonomy_vocabulary_load($vid);
$vname = strtolower(str_replace(' ', '_', trim($vocabulary->name)));
unset($vocabulary);
switch ($format) {
case 'xml':
require_once 'xml_format.inc';
$file = taxonomy_xml_xml_create($vid);
break;
case 'rdf':
require_once 'rdf_format.inc';
$file = taxonomy_xml_rdf_create($vid);
break;
}
if (!empty($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 5.5') || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera'))) {
header('Content-Type: application/dummy');
}
else {
header('Content-Type: application/octet-stream');
}
if (headers_sent()) {
echo 'Some data has already been output to browser, can\'t send file';
}
header('Content-Length: ' . strlen($file));
header("Content-Disposition: attachment; filename=taxonomy_{$vname}.{$format}");
echo $file;
}
function taxonomy_xml_import() {
return drupal_get_form('taxonomy_xml_import_form');
}
function taxonomy_xml_import_form_validate($form_id, $form_values) {
if ($file = file_check_upload('xml')) {
$fd = fopen($file->filepath, "rb");
if (!$fd) {
form_set_error('xml', t('Vocabulary import failed: file %filename cannot be read.', array(
'%filename' => $file->filename,
)));
}
else {
$info = fstat($fd);
$len = $info["size"];
$text = fread($fd, $len);
fclose($fd);
drupal_set_message(t('Loaded file %filename. Now processing it.', array(
'%filename' => $file->filename,
)));
$form_values['file'] = $file;
taxonomy_xml_invoke_import($text, $form_values);
}
}
else {
form_set_error('xml', t('Vocabulary import failed: file was not uploaded.'));
}
}
function taxonomy_xml_import_form() {
$formats = taxonomy_xml_formats();
$vocs[0] = t('[Determined by source file]');
foreach (module_invoke('taxonomy', 'get_vocabularies') as $vid => $voc) {
$vocs[$vid] = $voc->name;
}
$vocs[-1] = t('[Create new]');
$form['vid'] = array(
'#type' => 'select',
'#title' => t('Target vocabulary'),
'#default_value' => 0,
'#options' => $vocs,
'#description' => t('The vocabulary into which terms should be loaded.'),
);
$form['xml'] = array(
'#type' => 'file',
'#title' => t('File to import'),
'#description' => t('Click "Browse..." to select an XML document to upload.'),
);
$form['format'] = array(
'#type' => 'select',
'#title' => t('Format of file'),
'#default_value' => 'xml_format',
'#options' => $formats,
);
$form['duplicate'] = array(
'#type' => 'checkbox',
'#title' => t('Allow duplicate terms'),
'#description' => t('If you want to keep the same term in different positions in the vocabulary hierarchy, check this'),
'#default_value' => 0,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Import'),
);
$form['#attributes'] = array(
'enctype' => 'multipart/form-data',
);
return $form;
}
function taxonomy_xml_invoke_import($text, $form_values) {
$vid = $form_values['vid'];
if ($vid == -1) {
$vocabulary = _taxonomy_xml_get_vocabulary_placeholder(basename($form_values['file']->filename));
$vid = $vocabulary->vid;
}
module_disable(array(
'sitemenu',
'pathauto',
));
$incfile = dirname(drupal_get_filename('module', 'taxonomy_xml')) . '/' . $form_values['format'] . '.inc';
include_once $incfile;
$format_name = preg_replace('/_format$/', '', $form_values['format']);
$funcname = "taxonomy_xml_{$format_name}_parse";
if (function_exists($funcname)) {
$success = $funcname($text, $vid, NULL, $form_values['duplicate']);
if ($success) {
drupal_set_message(t("Taxonomy Import successful. %success terms created in vocabulary ", array(
'%success' => $success,
)));
}
else {
drupal_set_message(t("Failed to import any new terms. This may be due to syntax or formattings errors in the import file.", array()), 'error');
}
}
else {
drupal_set_message("Unavailable format. {$funcname} was not found in formatting library {$incfile}.", 'error');
}
}
function taxonomy_xml_formats() {
$incs = file_scan_directory(dirname(drupal_get_filename('module', 'taxonomy_xml')), '.*_format.inc');
$formats = array();
foreach ($incs as $file) {
$formats[$file->name] = strtoupper(preg_replace('/_format$/', '', $file->name));
}
return $formats;
}
function _taxonomy_xml_get_vocabulary_placeholder($name) {
if ($vocabulary = taxonomy_xml_get_vocabulary_by_name($name)) {
$node_types = explode(',', $vocabulary->nodes);
$vocabulary->nodes = array();
foreach ($node_types as $type) {
$vocabulary->nodes[$type] = 1;
}
return $vocabulary;
}
$vocabulary = array(
'name' => $name,
'relations' => TRUE,
'hierarchy' => 2,
);
module_invoke('taxonomy', 'save_vocabulary', $vocabulary);
$vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE LOWER('%s') LIKE LOWER(name)", $vocabulary['name']));
$vocabulary = taxonomy_vocabulary_load($vid);
drupal_set_message(t('Created vocabulary %vid %vocabname to put these terms into. You probably want to <a href="!vocablink">go edit it now</a>.', array(
'%vocabname' => $vocabulary->name,
'%vid' => $vid,
'!vocablink' => url('admin/content/taxonomy/edit/vocabulary/' . $vid),
)));
return $vocabulary;
}
function taxonomy_xml_absorb_vocabulary_definitions(&$vocabularies) {
if (is_array($vocabularies)) {
foreach ($vocabularies as $vocabid => &$vocab) {
taxonomy_xml_merge_predicates_into_attributes($vocab);
$target_vocab = NULL;
if (isset($vocab->vid)) {
$vocab->internal_id = $vocab->vid;
drupal_set_message(t("Found a vocabulary definition in the input, called {$vocabid}. vid={$vocab->internal_id}"));
$target_vocab = taxonomy_vocabulary_load($vocab->internal_id);
}
if (!empty($target_vocab) && $target_vocab->name == $vocab->name) {
$vocab->vid = $vocab->internal_id;
drupal_set_message(t("Found matching target vocabulary '%vocab_name' vid=%vocab_vid", array(
'%vocab_name' => $vocab->name,
'%vocab_vid' => $vocab->vid,
)));
}
else {
if ($target_vocab) {
drupal_set_message(t("The vocab ID given in the input file (%vocab_vid) conflicts with an existing vocabulary. We need a different ID... ", array(
'%vocab_vid' => $vocab->vid,
)));
}
unset($vocab->vid);
if ($target_vocab = taxonomy_xml_get_vocabulary_by_name($vocab->name)) {
$vocab->vid = $target_vocab->vid;
drupal_set_message(t("Found a target vocabulary already in the database, matching by name '%name' vid=%vid . This will be used, but not updated.", array(
'%name' => $vocab->name,
'%vid' => $vocab->vid,
)));
}
}
if (empty($vocab->vid)) {
$vocab = _taxonomy_xml_get_vocabulary_placeholder($vocab->name);
$vocab_array = (array) $vocab;
taxonomy_save_vocabulary($vocab_array);
$vocab = taxonomy_vocabulary_load($vocab_array['vid']);
drupal_set_message(t("Made a new Drupal vocabulary definition from data found in the input. Vocab is called: '%name' : %description ", array(
'%name' => $vocab->name,
'%description' => $vocab->description,
)));
}
}
}
else {
drupal_set_message("The document provided no recognisible vocabulary definitions");
}
return isset($vocab->vid) ? $vocab->vid : NULL;
}
function taxonomy_xml_merge_predicates_into_attributes(&$object) {
$predicate_synonyms = taxonomy_xml_relationship_synonyms();
foreach ($object->predicates as $predicate => $vals) {
$predicate = isset($predicate_synonyms[$predicate]) ? $predicate_synonyms[$predicate] : $predicate;
$object->{$predicate} = array_pop($vals);
}
if (empty($object->description) && isset($object->{TAXONOMY_XML_DESCRIPTION})) {
$object->description = $object->{TAXONOMY_XML_DESCRIPTION};
}
return $object;
}
function _taxonomy_xml_get_term_placeholder($name, $vid = 0) {
if ($name) {
$term = taxonomy_xml_get_term_by_name_from_vocab($name, $vid);
}
else {
drupal_set_message(t("Asked to make a term with no name ... are you sure?"), 'error');
}
if (!$term) {
$term = (object) array(
'name' => $name,
'vid' => $vid,
'description' => '',
'weight' => 0,
'predicates' => array(),
'synonyms_array' => array(),
);
}
else {
drupal_set_message(t("A term called '!name' already exists. Updating information onto it.", array(
'!name' => l($term->name, 'admin/content/taxonomy/edit/term/' . $term->tid),
)));
}
return $term;
}
function taxonomy_xml_set_term_relations(&$terms) {
drupal_set_message(t("Now connecting all known term relations and hierarchy links"));
foreach ($terms as $uri => $term) {
$name = $term->name;
if (isset($term->predicates[TAXONOMY_XML_PARENT]) && is_array($term->predicates[TAXONOMY_XML_PARENT])) {
foreach (array_unique($term->predicates[TAXONOMY_XML_PARENT]) as $key => $termname) {
if ($termname) {
$parent = $terms[$termname];
if ($termname == $uri) {
drupal_set_message(t("Not setting %name as a child of itself", array(
'%name' => $term->name,
)));
continue;
}
if ($parent && isset($parent->tid)) {
drupal_set_message(t("!name # %tid is a child of !parent # %ptid", array(
'!name' => l($term->name, 'admin/content/taxonomy/edit/term/' . $term->tid),
'%tid' => $term->tid,
'!parent' => l($parent->name, 'admin/content/taxonomy/edit/term/' . $parent->tid),
'%ptid' => $parent->tid,
)));
$term->parent[$parent->tid] = $parent->tid;
}
else {
drupal_set_message(t("Couldn't find the parent called %termname for %name # %tid", array(
'%termname' => $termname,
'%name' => $name,
'%tid' => $term->tid,
)));
}
}
}
}
if (isset($term->predicates[TAXONOMY_XML_RELATED]) && is_array($term->predicates[TAXONOMY_XML_RELATED])) {
foreach (array_unique($term->predicates[TAXONOMY_XML_RELATED]) as $key => $termname) {
if ($termname) {
$related = $terms[$termname];
if ($related) {
$term->relations[] = $related->tid;
drupal_set_message("Term " . $term->name . " " . $term->tid . " is related to {$related->name} " . $related->tid);
}
else {
drupal_set_message(t("Couldn't find the term called '%termname' to link to '%name' as being related. This relationship will be discarded. ", array(
'%name' => $name,
'%termname' => $termname,
'%debug' => print_r(array_keys($terms), 1),
)));
}
}
}
}
if (!empty($term->synonyms_array)) {
$term->synonyms = join("\n", array_unique($term->synonyms_array));
}
$save_term = (array) $term;
taxonomy_save_term($save_term);
}
}
function taxonomy_xml_get_vocabulary_by_name($name) {
$vs = taxonomy_get_vocabularies();
foreach ($vs as $voc) {
if ($voc->name == $name) {
return $voc;
}
}
}
function taxonomy_xml_get_term_by_name_from_vocab($name, $vid) {
$matched_terms = taxonomy_get_term_by_name($name);
while (($term = array_pop($matched_terms)) && $term->vid != $vid) {
continue;
}
if (!$term) {
return NULL;
}
$term->parent = taxonomy_get_parents($term->tid);
$term->relations = taxonomy_get_related($term->tid);
$term->synonyms_array = taxonomy_get_synonyms($term->tid);
return $term;
}
function taxonomy_xml_relationship_synonyms() {
return array(
'Related Terms' => TAXONOMY_XML_RELATED,
'Related' => TAXONOMY_XML_RELATED,
'related' => TAXONOMY_XML_RELATED,
'RT' => TAXONOMY_XML_RELATED,
'seeAlso' => TAXONOMY_XML_RELATED,
'Broader Terms' => TAXONOMY_XML_PARENT,
'Broader' => TAXONOMY_XML_PARENT,
'broader' => TAXONOMY_XML_PARENT,
'Broad Term' => TAXONOMY_XML_PARENT,
'BT' => TAXONOMY_XML_PARENT,
'subClassOf' => TAXONOMY_XML_PARENT,
'SubClassOf' => TAXONOMY_XML_PARENT,
'ChildOf' => TAXONOMY_XML_PARENT,
'hypernym' => TAXONOMY_XML_PARENT,
'hyponymOf' => TAXONOMY_XML_PARENT,
'Narrower Terms' => TAXONOMY_XML_CHILD,
'Narrower' => TAXONOMY_XML_CHILD,
'narrower' => TAXONOMY_XML_CHILD,
'NT' => TAXONOMY_XML_CHILD,
'ParentOf' => TAXONOMY_XML_CHILD,
'hyponym' => TAXONOMY_XML_CHILD,
'Description' => TAXONOMY_XML_DESCRIPTION,
'definition' => TAXONOMY_XML_DESCRIPTION,
'Definition' => TAXONOMY_XML_DESCRIPTION,
'comment' => TAXONOMY_XML_DESCRIPTION,
'gloss' => TAXONOMY_XML_DESCRIPTION,
'Scope Note' => TAXONOMY_XML_DESCRIPTION,
'note' => TAXONOMY_XML_DESCRIPTION,
'SN' => TAXONOMY_XML_DESCRIPTION,
'Used for' => TAXONOMY_XML_HAS_SYNONYM,
'AKA' => TAXONOMY_XML_HAS_SYNONYM,
'synonym' => TAXONOMY_XML_HAS_SYNONYM,
'altLabel' => TAXONOMY_XML_HAS_SYNONYM,
'equivalentClass' => TAXONOMY_XML_HAS_SYNONYM,
'See' => TAXONOMY_XML_SYNONYM_OF,
'USE' => TAXONOMY_XML_SYNONYM_OF,
'Use' => TAXONOMY_XML_SYNONYM_OF,
'related' => TAXONOMY_XML_RELATED,
'seeAlso' => TAXONOMY_XML_RELATED,
'memberMeronymOf' => TAXONOMY_XML_RELATED,
'Part of' => TAXONOMY_XML_IN_VOCABULARY,
'belongs-to-facet' => TAXONOMY_XML_IN_VOCABULARY,
'isDefinedBy' => TAXONOMY_XML_IN_VOCABULARY,
'inScheme' => TAXONOMY_XML_IN_VOCABULARY,
'name' => TAXONOMY_XML_NAME,
'lexicalForm' => TAXONOMY_XML_NAME,
'label' => TAXONOMY_XML_NAME,
'scientific name' => TAXONOMY_XML_NAME,
'prefLabel' => TAXONOMY_XML_NAME,
'hasDescriptor' => 'unused',
);
}
if (!function_exists('taxonomy_vocabulary_load')) {
function taxonomy_vocabulary_load($vid) {
return taxonomy_get_vocabulary($vid);
}
}