/** * Replacing the id's by the rendered and disambiguated values and add the delimiter. * * @param array $data * @return array|string */ public function apply(array $data) { $delimiter = Container::getContext()->get('delimiter', 'layout'); $layout = Container::getContext()->get('layout', 'layout'); // move to starting position for citations and citations items $citationData = false; if (Container::getCitationItem() !== false) { $citationData = true; Container::getCitationItem()->moveToFirst(); } // remove all additional temporary disambiguation options Container::getContext()->clearDisambiguationOptions(); // replace item ids by disambiguate cite $length = count($data); for ($i = 0; $i < $length; $i++) { if (is_array($data[$i]) == true) { $innerLength = count($data[$i]); for ($j = 0; $j < $innerLength; $j++) { // add existing prefix and/or suffixes to the rendered value $actualCitation = Container::getRendered()->get($data[$i][$j]); // re-render citation if missing if ($actualCitation == false) { Container::getContext()->enter('disambiguation'); $data[$i][$j] = array('value' => $layout->renderJustActualEntry(''), 'delimiter' => ''); Container::getContext()->leave(); } else { $data[$i][$j] = array('value' => $actualCitation, 'delimiter' => ''); } // Add delimiter at end if not ending with a dot // (see affix_SuppressDelimiterCharsWhenFullStopInSuffix.txt) if ($j < $innerLength - 1) { if (preg_match('/\\.$/', $data[$i][$j]['value']) == 0) { $data[$i][$j]['delimiter'] = $delimiter; } else { $data[$i][$j]['delimiter'] = ' '; } } // move to next in group if ($citationData == true) { Container::getCitationItem()->nextInGroup(); } } } else { // re-render citation if missing $actualCitation = Container::getRendered()->get($data[$i]); if ($actualCitation == false) { Container::getContext()->enter('disambiguation'); $data[$i] = array('value' => $layout->renderJustActualEntry(''), 'delimiter' => ''); Container::getContext()->leave(); } else { $data[$i] = array('value' => $actualCitation, 'delimiter' => ''); } } if ($citationData == true) { Container::getCitationItem()->next(); } } return $data; }
/** * Try to disambiguate the ambiguous values. If not possible, pass the values to the successor and try to * disambiguate with the successor. If possible, store ambiguous and disambiguated values. */ public function disambiguate() { Container::getContext()->removeDisambiguationOptions('Geissler\\CSL\\Names\\Name'); Container::getContext()->setChooseDisambiguateValue(true); $layout = Container::getContext()->get('layout', 'layout'); $secondary = Container::getCitationItem()->getWithIds(array_keys($this->getAmbiguous())); foreach ($secondary as $entry) { Container::getCitationItem()->moveTo($entry['id'], $entry['citationID']); Container::getData()->moveToId($entry['id']); Container::getRendered()->set($entry['id'], $entry['citationID'], $layout->renderById($entry['id'], '')); } }
/** * Disambiguate ambiguous values. */ private function solve() { Container::getContext()->enter('disambiguation'); $this->layout = Container::getContext()->get('layout', 'layout'); $this->names = $this->layout->getChildElement('\\Geissler\\CSL\\Names\\Names'); // if "et-al-subsequent-min" or "et-al-subsequent-use-first" are used, use the first citation // to disambiguate the values (see disambiguate_BasedOnEtAlSubsequent.txt) $citations = Container::getRendered()->getAllById(); if (is_object($this->names) == true) { $this->sorted = array_keys($citations); asort($citations); $this->disambiguateByName($citations); } else { $this->disambiguateByCitationLabel($citations); } }
/** * Render the citations. * * @param string $data * @return string */ public function render($data) { Container::getContext()->enter('citation'); // sort if (isset($this->sort) == true) { $this->sort->sort('citation'); } // render citation $result = $this->layout->render($data); // The assignment of the year-suffixes follows the order of the bibliographies entries, // so sort if disambiguation by year-suffixes is needed, sort the data by the bibliography // and re-render citations if (Container::hasBibliography() == true && Container::getContext()->getValue('disambiguateAddYearSuffix', 'citation') === true && Container::getContext()->getLastDisambiguation() == 'Geissler\\CSL\\Options\\Disambiguation\\AddYearSuffix' && Container::getBibliography()->sort() == true) { Container::getRendered()->clear(); // re-render citation $result = $this->layout->render($data); } if (Container::getCitationItem() !== false) { // apply additional citation formatting options Container::getCitationItem()->moveToFirst(); if (Container::getCitationItem()->get('noteIndex') !== null || Container::getCitationItem()->get('index') !== null) { $citation = array(); $length = count($result); $prefix = '..'; for ($i = 0; $i < $length; $i++) { if ($i + 1 == $length) { $prefix = '>>'; } // Therefore, the first character of a citation should preferably be uppercased $citation[] = $prefix . '[' . $i . '] ' . $this->upperCase($result[$i]); } $return = implode("\n", $citation); } else { array_walk($result, array($this, 'upperCase')); $return = implode("\n", $result); } } else { array_walk($result, array($this, 'upperCase')); $return = implode("\n", $result); } Container::getContext()->leave(); return $return; }
/** * Store the values from the object. * @param \Geissler\CSL\Interfaces\Disambiguate $disambiguation */ public function store(Disambiguate $disambiguation) { $disambiguated = $disambiguation->getDisambiguate(); if ($disambiguated === null) { $disambiguated = array(); } if (count($disambiguated) > 0) { foreach ($disambiguated as $id => $citation) { if (isset($this->ambiguous[$id]) == true) { Container::getRendered()->update($id, $this->ambiguous[$id], $citation); } } } // use modified ambiguous values if (count($disambiguation->getAmbiguous()) > 0 && $this->ambiguous !== $disambiguation->getAmbiguous()) { foreach ($disambiguation->getAmbiguous() as $id => $citation) { if (isset($this->ambiguous[$id]) == true && array_key_exists($id, $disambiguated) == false) { Container::getRendered()->update($id, $this->ambiguous[$id], $citation); } } } }
/** * Add an alphabetic year-suffix to ambiguous cites. * * @return void */ private function addYearSuffix() { // test if year is rendered, if not try if year is rendered through choose disambiguate $layout = Container::getContext()->get('layout', 'layout'); if (preg_match($this->regExp, current($this->tmpAmbiguous)) == 0 && Container::getContext()->isChooseDisambiguationActive() == true) { Container::getContext()->setChooseDisambiguateValue(true); foreach (array_keys($this->tmpAmbiguous) as $id) { $reRendered = $layout->renderById($id, ''); if (isset($this->tmpAmbiguous[$id]) == true && $reRendered !== $this->tmpAmbiguous[$id]) { $this->tmpAmbiguous[$id] = $reRendered; } } } if (array_values($this->tmpAmbiguous) > array_unique(array_values($this->tmpAmbiguous))) { $useYearSuffix = $layout->isAccessingVariable('year-suffix'); $suffix = 'a'; foreach (array_keys($this->tmpAmbiguous) as $id) { Container::getData()->moveToId($id); $actualSuffix = Container::getData()->getVariable('year-suffix'); if ($actualSuffix === null) { // store year-suffix variable Container::getData()->setVariable('year-suffix', $suffix); $actualSuffix = $suffix; } if (Container::getCitationItem() !== false) { $cites = Container::getCitationItem()->getWithIds(array($id)); foreach ($cites as $entry) { Container::getCitationItem()->moveTo($id, $entry['citationID']); if ($useYearSuffix == true) { Container::getRendered()->clearById($id); Container::getRendered()->set($id, $entry['citationID'], $layout->renderById($id, '')); } else { Container::getRendered()->set($id, $entry['citationID'], $this->addYearSuffixToValue($this->tmpAmbiguous[$id], $actualSuffix)); } } } else { $cites = Container::getRendered()->getAllById(); foreach ($cites as $itemId => $value) { if ($itemId == $id) { if ($useYearSuffix == true) { Container::getRendered()->clearById($id); Container::getRendered()->set($id, 0, $layout->renderById($id, '')); } else { $newValue = $this->addYearSuffixToValue($value, $actualSuffix); Container::getRendered()->set($id, 0, $newValue); $this->tmpDisambiguate[$id] = $newValue; } } } } unset($this->tmpAmbiguous[$id]); $suffix++; } } }
/** * Additionally activate different citation usage. * * @param string $variable * @param string $match */ public function __construct($variable, $match = 'all') { parent::__construct($variable, $match); Container::getRendered()->setUseDifferentCitations(true); }
/** * Renders the names. * * @param array $data * @return string */ public function render($data) { $this->apply(); $names = array(); $length = count($data); if ($length == 0) { return ''; } for ($i = 0; $i < $length; $i++) { $names[] = $this->formatName($data[$i], $i); } $etAl = false; $etAlUseFirst = $this->etAlUseFirst; $etAlMin = $this->etAlMin; // If used, the values of these attributes replace those of respectively et-al-min and et-al-use-first // for subsequent cites (cites referencing earlier cited items) if (Container::getRendered()->get(Container::getActualId(), Container::getActualCitationId()) !== false) { if ($this->etAlSubsequentMin > 0) { $etAlMin = $this->etAlSubsequentMin; } if ($this->etAlSubsequentUseFirst !== '') { $etAlUseFirst = $this->etAlSubsequentUseFirst; } } if ($etAlMin > 0 && $length > 1 && $etAlMin <= $length && $etAlUseFirst < $length) { $etAl = true; } $namesAndSplitter = array(); $and = $this->getAndDelimiter(); $countNames = 0; for ($i = 0; $i < $length; $i++) { $namesAndSplitter[] = $names[$i]; $countNames++; if ($etAl == true && $i == $etAlUseFirst - 1) { switch ($this->delimiterPrecedesEtAl) { case 'contextual': if ($etAlUseFirst >= 2) { $namesAndSplitter[] = $this->delimiter; } break; case 'after-inverted-name': if ($this->nameAsSortOrder == 'first') { $namesAndSplitter[] = $this->delimiter; } break; case 'always': $namesAndSplitter[] = $this->delimiter; break; } // et-al Term $namesAndSplitter[] = ' '; $namesAndSplitter[] = Container::getLocale()->getTerms('et-al'); break; } // The delimiter between the second to last and last name of the names in a name variable if ($i == $length - 2 && $and !== '' && in_array($names[$i], $this->literals) == false) { switch ($this->delimiterPrecedesLast) { case 'contextual': if ($length >= 3) { $namesAndSplitter[] = $this->delimiter; } break; case 'after-inverted-name': if ($this->nameAsSortOrder == 'first') { $namesAndSplitter[] = $this->delimiter; } break; case 'always': $namesAndSplitter[] = $this->delimiter; break; case 'never': break; } if ($this->and !== '') { $namesAndSplitter[] = ' '; $namesAndSplitter[] = $and; $namesAndSplitter[] = ' '; } } elseif ($i < $length - 1) { $namesAndSplitter[] = $this->delimiter; } } // returns the total number of names that would otherwise be rendered if ($this->form == 'count') { return (int) $countNames; } $return = str_replace(' ', ' ', implode('', $namesAndSplitter)); // do not connect literals with an and if (count($this->literals) > 0) { $and = $and . ' '; foreach ($this->literals as $literal) { $return = str_replace($and . $literal, $literal, $return); } } // name lists truncated by et-al abbreviation are followed by the name delimiter, the ellipsis character, // and the last name of the original name list. if ($this->etAlUseLast == true && count($names) + 2 >= $countNames) { $return = str_replace(Container::getLocale()->getTerms('et-al'), ' … ' . end($names), $return); } // no formatting while sorting if (Container::getContext()->in('sort') == true) { return $return; } // no formatting while author-only is set for actual cite if (Container::getCitationItem() !== false && Container::getCitationItem()->get('author-only') == 1) { return $this->affix->render($return, true); } $return = $this->formatting->render($return); return $this->affix->render($return, true); }
/** * Parses the global and inheritable name options. * * @param string $type context type (style, citation or bibliography) * @param \SimpleXMLElement $xml * @return \Geissler\CSL\Context\Options */ public function set($type, \SimpleXMLElement $xml) { switch ($type) { case 'style': $method = 'addStyle'; break; case 'citation': $method = 'addCitation'; break; case 'bibliography': $method = 'addBibliography'; break; } foreach ($xml->attributes() as $name => $value) { switch ($name) { // global options case 'initialize-with-hyphen': Container::getContext()->{$method}('initializeWithHyphen', isBoolean($value)); break; case 'page-range-format': switch ((string) $value) { case 'chicago': Container::getContext()->{$method}('pageRangeFormat', new Chicago()); break; case 'expanded': Container::getContext()->{$method}('pageRangeFormat', new Expanded()); break; case 'minimal': Container::getContext()->{$method}('pageRangeFormat', new Minimal()); break; case 'minimal-two': Container::getContext()->{$method}('pageRangeFormat', new MinimalTwo()); break; } break; case 'demote-non-dropping-particle': Container::getContext()->{$method}('demoteNonDroppingParticle', (string) $value); break; // Inheritable Name Options // Inheritable Name Options case 'and': Container::getContext()->{$method}('and', (string) $value); break; case 'delimiter-precedes-et-al': Container::getContext()->{$method}('delimiterPrecedesEtAl', (string) $value); break; case 'delimiter-precedes-last': Container::getContext()->{$method}('delimiterPrecedesLast', (string) $value); break; case 'et-al-min': Container::getContext()->{$method}('etAlMin', (string) $value); break; case 'et-al-use-first': Container::getContext()->{$method}('etAlUseFirst', (string) $value); break; case 'et-al-subsequent-min': Container::getRendered()->setUseDifferentCitations(true); Container::getContext()->{$method}('etAlSubsequentMin', (string) $value); break; case 'et-al-subsequent-use-first': Container::getRendered()->setUseDifferentCitations(true); Container::getContext()->{$method}('etAlSubsequentUseFirst', (string) $value); break; case 'et-al-use-last': Container::getContext()->{$method}('etAlUseLast', isBoolean((string) $value)); break; case 'initialize': Container::getContext()->{$method}('initialize', (string) $value); break; case 'initialize-with': Container::getContext()->{$method}('initializeWith', (string) $value); break; case 'name-as-sort-order': Container::getContext()->{$method}('nameAsSortOrder', (string) $value); break; case 'sort-separator': Container::getContext()->{$method}('sortSeparator', (string) $value); break; case 'name-form': Container::getContext()->{$method}('form', (string) $value); break; case 'name-delimiter': Container::getContext()->{$method}('delimiter', (string) $value); break; } } return $this; }
/** * Apply additional formatting and remove duplicated spaces and dots. * * @param $data * @return string */ private function format($data) { $data = preg_replace('/[ ][ ]+/', ' ', $data); $data = preg_replace('/[\\.][\\.]+/', '.', $data); $data = preg_replace('/( ,)/', ',', $data); $data = preg_replace('/[;|,]([;|,])/', '$1', $data); $data = preg_replace('/\\.(<\\/[a-z]+>)\\./', '.$1', $data); $data = $this->expand->render($data); if (Container::getCitationItem() !== false) { // suppress affixes if author-only is set and there is only one cite in the actual citation $ids = Container::getRendered()->getIdByValue($data); Container::getCitationItem()->moveTo($ids['id'], $ids['citationId']); if (Container::getCitationItem()->get('author-only') == 1) { return $data; } } $data = $this->affix->render($data, true); return $this->formatting->render($data); }
/** * Renders the variable. * * @param string $data * @return string */ public function render($data) { if ($this->form !== '') { $return = Container::getData()->getVariable($this->name . '-' . $this->form); if ($return !== null) { return $return; } if (is_object(Container::getAbbreviation()) == true) { $return = Container::getAbbreviation()->get($this->name, $this->form); } if ($return !== null) { return $return; } } // special cases switch ($this->name) { case 'title-short': $return = Container::getData()->getVariable('shortTitle'); if ($return !== null) { return $return; } break; case 'title': if ($this->form == 'short') { $return = Container::getData()->getVariable('shortTitle'); if ($return !== null) { return $return; } } break; case 'citation-label': $return = Container::getData()->getVariable($this->name); if ($return !== null) { return $return; } // first 4 letters from the first two author family names and last to year digits $authors = Container::getData()->getVariable('author'); $format = new Format(); if (isset($authors[0]['family']) == true && $format->format('issued') == true) { $year = $format->getData(); if (isset($year[0]['year']) == true) { switch (count($authors)) { case 1: $author = substr($authors[0]['family'], 0, 4); break; case 2: $author = substr($authors[0]['family'], 0, 2) . substr($authors[1]['family'], 0, 2); break; default: $author = ''; for ($i = 0; $i < 4; $i++) { if (preg_match('/[A-Z]/', $authors[$i]['family'], $match) == 1) { $author .= $match[0]; } } break; } $length = strlen($year[0]['year']); return $author . substr($year[0]['year'], $length - 2, $length); } } break; case 'page': $format = Container::getContext()->getValue('pageRangeFormat'); if (is_object($format) == true) { return $format->format(Container::getData()->getVariable($this->name)); } break; case 'first-reference-note-number': // number of a preceding note containing the first reference to the item if (Container::getCitationItem()->get('noteIndex') !== null || Container::getCitationItem()->get('index') !== null) { $first = Container::getRendered()->getPositionOfFirstId(Container::getActualId()); if ($first !== null && $first < Container::getRendered()->getLength()) { return $first; } } break; } $return = Container::getData()->getVariable($this->name); if ($return !== null) { return $return; } // retrieve variables form citations if (Container::getContext()->getName() == 'citation' && Container::getCitationItem() !== false) { $return = Container::getCitationItem()->get($this->name); if ($return !== null) { return $return; } } return ''; }