Implements some citeproc alters to help handle edge cases introduced by using french roleterms etc. in the mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
8.8 KiB

3 years ago
<?php
/**
* @file
* Implementation of some citeproc alters.
*/
/**
* Implements citeproc_convert_mods_to_citeproc_jsons_alter
*
* @param $output
* @param $mods
*/
function udm_citeproc_convert_mods_to_citeproc_jsons_alter(&$output, $mods) {
module_load_include('inc', 'citeproc', 'includes/converter');
$output['type'] = udm_citeproc_local_to_csl_type($mods);
3 years ago
if(empty($output['author'])){
$names = udm_convert_mods_to_citeproc_json_names($mods);
$output = array_merge($output, $names);
}
}
/**
* Gets the type property for the Citation.
*
* There are a number of name-type vars which may be populated.
* We will concern ourselves with the following:
* 1. Author
* 2. Editor
* 3. Translator
* There is no CSL var for "contributor", we will treat them as additional
* authors.
*
* Each name may be either "corporate" or "given name / family name"
*
* As it's unlikely we'll have participles, suffixes, etc properly parsed
* out, we will always pass the ("parse-names" : "true") flag with personal
* names.
*
* mods namepart types (given, family) correspond to citeproc elements,
* however, more precise mods elements (nonsort, etc.) do not.
* @todo Make all name handling better.
*
* NAME(s) of RELATED ITEMS (host, series)
* Zotero vs Bibutils do this a bit differently, but in bibutils it's common for
* the editor of a book (containing a chapter, which is our bibliographic item)
* to be associated with the relatedItem(host).
* Also It'S A Shot In The Dark, But
* Relateditem(series)->name->role->roleTerm=editor is plausible.
*
* Note also this section is *highly* repetitive of the section above and this
* should probably be generalized, but for now a strict procedural reckoning
* will have to suffice. The difference is in the very last section, where the
* appropriate cs:names type is specified.
*
* @param SimpleXMLElement $mods
* A MODS document.
*
* @return string
* The type property for the Citation.
*/
function udm_convert_mods_to_citeproc_json_names(SimpleXMLElement $mods) {
$queries = array(
0 => array(
// Path.
variable_get('islandora_scholar_xpaths_local_author', '//mods:mods[1]/mods:name[normalize-space(mods:namePart)]'),
// Default Role.
'author',
// Valid Roles.
array(
'editor' => 'editor',
'translator' => 'translator',
'interviewer' => 'interviewer',
'composer' => 'composer',
'original' => 'original-author',
'recipient' => 'recipient',
'author' => 'author',
),
),
1 => array(
variable_get('islandora_scholar_xpaths_local_container-author', '//mods:mods[1]/mods:relatedItem[@type="host"]/mods:name'),
'container-author',
array(
'editor' => 'editor',
'translator' => 'translator',
'author' => 'container-author',
),
),
2 => array(
variable_get('islandora_scholar_xpaths_local_collection-editor', '//mods:mods[1]/mods:relatedItem[@type="series"]/mods:name'),
NULL,
array(
'editor' => 'collection-editor',
),
),
);
$output = array();
foreach ($queries as $query) {
list($path, $default_role, $valid_roles) = $query;
$names = $mods->xpath($path);
if (!empty($names)) {
foreach ($names as $name) {
add_mods_namespace($name);
$role = udm_convert_mods_to_citeproc_json_name_role($name, $valid_roles, $default_role);
if ($role !== FALSE) {
$parsed_name = udm_convert_mods_to_citeproc_json_name($name);
if ($parsed_name) {
$output[$role][] = $parsed_name;
}
}
}
}
}
return $output;
}
/**
* Gets the array repersentation of the javascript Citation's name properties.
*
* @param SimpleXMLElement $name
* A name element.
*
* @return array
* An array that embodies the name properties of a Citation javascript object.
*/
function udm_convert_mods_to_citeproc_json_name(SimpleXMLElement $name) {
$type = (string) $name->attributes()->type;
$output = ($type == 'personal') ?
udm_convert_mods_to_citeproc_json_name_personal($name) :
udm_convert_mods_to_citeproc_json_name_corporate($name);
$output = array_map('trim', $output);
$output = array_map('ucfirst', $output);
$output = array_filter($output);
return $output;
}
/**
* Gets the array repersentation of the Citation's personal name properties.
*
* @param SimpleXMLElement $name
* A name element.
*
* @return array
* An array that embodies the name properties of a Citation javascript object.
*/
function udm_convert_mods_to_citeproc_json_name_personal(SimpleXMLElement $name) {
$output = array();
$name_parts = $name->xpath('mods:namePart');
foreach ($name_parts as $name_part) {
$type = (string) $name_part->attributes()->type;
$content = (string) $name_part;
// If the type is empty, it is a combined name last, first.
if (empty($type)) {
// Filter empty things out of the output, so we may potentially replace
// them.
$output = array_filter(array_map('trim', $output));
$names = array_map('trim', explode(',', $content));
$exploded = array();
$exploded['family'] = array_shift($names);
$exploded['given'] = array_shift($names);
// If we appear to have a family (and potentially given) name part in our
// combined field and are not currently outputting them, make them get
// output.
// XXX: May combine unexpectedly in the case a "given" typed part name is
// specified, and our untyped field only contains a "family" name.
$non_empty = array_filter($exploded);
$parts_not_present = array_diff_key($non_empty, $output);
if (!empty($parts_not_present)) {
$output = $non_empty + $output;
}
}
else {
// Throw a period after single character values, as they likely represent
// initials.
$content .= (strlen($content) == 1) ? '. ' : ' ';
$output[$type] = isset($output[$type]) ?
$output[$type] . $content :
$content;
}
}
return $output;
}
/**
* Gets the array repersentation of the Citation's corporate name properties.
*
* @param SimpleXMLElement $name
* A name element.
*
* @return array
* An array that embodies the name properties of a Citation javascript object.
*/
function udm_convert_mods_to_citeproc_json_name_corporate(SimpleXMLElement $name) {
$output = array();
$name_parts = $name->xpath(variable_get('islandora_scholar_xpaths_local_author', 'mods:namePart'));
foreach ($name_parts as $name_part) {
$content = (string) $name_part . ' ';
$output['literal'] = isset($output['literal']) ? $output['literal'] . $content : $content;
}
return $output;
}
/**
* Gets the role for the given name element.
*
* If no role can be determined it returns 'author' as a default.
*
* @param SimpleXMLElement $name
* A MODS name element.
* @param array $valid_roles
* A map of mods role names to their citeproc equivalents.
* @param string $default_role
* The role to use if a valid role is not found.
*
* @return string
* Gets the role of the given name.
*/
function udm_convert_mods_to_citeproc_json_name_role(SimpleXMLElement $name, array $valid_roles, $default_role) {
module_load_include('inc', 'citeproc', 'includes/marcrelator_conversion');
$role_term = $name->xpath(variable_get('islandora_scholar_xpaths_role_term', 'mods:role/mods:roleTerm'));
if (isset($role_term[0])) {
$role = strtolower((string) $role_term[0]);
$role_term = $role_term[0];
}
else {
$role = NULL;
}
if ($role) {
$role_authority = (string) $role_term->attributes()->authority;
$role_type = (string) $role_term->attributes()->type;
if ($role_authority == 'marcrelator' && $role_type == 'code') {
$role = marcrelator_code_to_term($role);
}
$role = ($role == 'auteur') ? 'author' : $role;
return array_key_exists($role, $valid_roles) ? $valid_roles[$role] : FALSE;
}
return $default_role;
}
/**
* Converts our local types that mostly came from refworks to CSL types.
*
* @param SimpleXML $mods
* @return string
* The CSL type.
*/
function udm_citeproc_local_to_csl_type($mods) {
$genre = $mods->xpath("//mods:mods[1]/mods:genre");
if(empty($genre)){
return convert_mods_to_citeproc_json_type($mods);
}
$term = strtolower(trim((string)$genre[0]));
switch ($term) {
case 'article scientifique':
case '':
return 'article-journal';
case 'book chapter':
case 'book section':
case 'book, section':
case 'chapitre de livre':
return 'chapter';
case 'book, whole':
case 'livre':
return 'book';
case 'conference proceedings':
case 'conference abstract':
case 'Contribution à un congrès, un colloque, une conférence':
return 'paper-conference';
default:
return convert_mods_to_citeproc_json_type($mods);
}
}