/** * Use only some child elements for rendering if author-only or suppress-author is used. * * @param array $children * @return array */ public function getRenderClasses(array $children) { // render just child elements of a given class (@see Macro) if (Container::getContext()->in('sort') == true && Container::getContext()->get('renderJust', 'sort') !== null) { $toRender = Container::getContext()->get('renderJust', 'sort'); $render = array(); foreach ($children as $child) { if (in_array(get_class($child), $toRender) == true || $child instanceof \Geissler\CSL\Interfaces\Parental) { $render[] = $child; } } return $render; } elseif (Container::getCitationItem() !== false) { if (Container::getCitationItem()->get('author-only') == 1) { $render = array(); foreach ($children as $child) { if (in_array('Geissler\\CSL\\Interfaces\\Variable', class_implements($child)) == true && $child->isAccessingVariable('author') == true) { $render[] = $child; } } if (count($render) == 0) { foreach ($children as $child) { if (in_array('Geissler\\CSL\\Interfaces\\Variable', class_implements($child)) == true && $child->isAccessingVariable('citation-number') == true) { $render[] = new Value(new \SimpleXMLElement('<value value="Reference " />')); $render[] = $child; } } } return $render; } elseif (Container::getCitationItem()->get('suppress-author') == 1) { return $this->suppressAuthor($children); } } return $children; }
/** * Tests whether the item matches the given types. * * @param string $variable * @return boolean */ protected function validateVariable($variable) { if (Container::getData()->getVariable('type') == $variable) { return true; } return false; }
protected function initElement($variable, $json) { $this->object = new IsUncertainDate($variable); $data = new Data(); $data->set($json); Container::setData($data); }
/** * Tests if the variable is numeric. * * @param string $variable * @return boolean */ protected function validateVariable($variable) { if (preg_match('/^[0-9]+([ ]{0,1}[&|\\-|,][ ]{0,1}[0-9]+)*$|^[A-z]{0,1}[0-9]+[A-z]{0,1}$|^[0-9]+[A-z]{2,3}$/', Container::getData()->getVariable($variable)) == 1) { return true; } return false; }
/** * Render a day. * * @param string|integer $data * @return string */ public function render($data) { // use always numeric value for sorting if (Container::getContext()->in('sort') == true) { if ($data !== '') { $data = (int) $data; if ($data < 10) { return '0' . $data; } return $data; } return 00; } switch ($this->form) { case 'numeric-leading-zeros': if ((int) $data < 10) { return '0' . (int) $data; } return $this->format($data); break; case 'ordinal': return $this->format(Ordinal::render($data, true)); break; case 'numeric': default: return $this->format((int) $data); break; } }
/** * Test if label is equal to the variable. * * @param string $variable * @return bool */ protected function validateVariable($variable) { if (Container::getData()->getVariable('label') == $variable || is_object(Container::getCitationItem()) == true && Container::getCitationItem()->get('label') == $variable) { return true; } return false; }
/** * 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; }
/** * @covers Geissler\CSL\Style\Style::readFile * @covers Geissler\CSL\Style\Style::setDir * @covers Geissler\CSL\Style\Style::readXml */ public function testReadFile2() { $this->assertInstanceOf($this->class, $this->object->setDir($this->dir)); $this->assertInstanceOf($this->class, $this->object->readFile('american-journal-of-archaeology')); $this->assertInstanceOf('\\Geissler\\CSL\\Style\\Citation', \Geissler\CSL\Container::getCitation()); $this->assertInstanceOf('\\Geissler\\CSL\\Style\\Bibliography', \Geissler\CSL\Container::getBibliography()); $this->assertInstanceOf('\\Geissler\\CSL\\Locale\\Locale', \Geissler\CSL\Container::getLocale()); }
/** * A date is uncertain if it contains the key "circa". * * @param string $variable * @return boolean */ protected function validateVariable($variable) { $date = Container::getData()->getVariable($variable); if (is_array($date) == true && isset($date['circa']) == true) { return true; } return false; }
/** * @covers Geissler\CSL\Context\Options::set */ public function testSet() { $layout = '<citation delimiter-precedes-last="always"> </citation>'; $this->assertInstanceOf('\\Geissler\\CSL\\Context\\Options', $this->object->set('style', new \SimpleXMLElement($layout))); $this->assertEquals('always', Container::getContext()->getValue('delimiterPrecedesLast')); }
/** * Apply the formatting options on a date/date-part element. * * @param string $value * @return string */ protected function format($value) { $value = $this->formatting->render($value); $value = $this->textCase->render($value); // Attributes for affixes are allowed, unless cs:date calls a localized date format if (Container::getContext()->get('form', 'date') !== '') { return $value; } return $this->affix->render($value); }
/** * Create a chain of objects to disambiguate the ambiguous values. The first element tries to disambiguate the * values. If it fails, the ambiguous values are passed to the next element in the chain. The chain stops, if all * ambiguous values are disambiguated or if no succeeding chain element exists. * * @param array $ambiguous */ public function __construct(array $ambiguous) { $store = new Store(); $store->setAmbiguous($ambiguous); $chain = false; // last step if (Container::getContext()->isChooseDisambiguationActive() == true) { Container::getContext()->setChooseDisambiguateValue(false); $chain = new ChooseDisambiguate(); $chain->setStore($store); } // step 3 if (Container::getContext()->getValue('disambiguateAddYearSuffix', 'citation') == true) { $addYear = new AddYearSuffix(); $addYear->setStore($store); if ($chain !== false) { $addYear->setSuccessor($chain); } $chain = $addYear; } // step 2, a // if disambiguate-add-names is set to "true", then the names still hidden as a result of // et-al abbreviation after the disambiguation attempt of disambiguate-add-names are // added one by one to all members of a set of ambiguous cites if (Container::getContext()->getValue('disambiguateAddNames', 'citation') === true && Container::getContext()->getValue('disambiguateAddGivenname', 'citation') == true) { Container::getContext()->removeDisambiguationOptions('Geissler\\CSL\\Names\\Name'); $addHidden = new AddHiddenGivenName(); $addHidden->setStore($store); if ($chain !== false) { $addHidden->setSuccessor($chain); } $chain = $addHidden; } // step 2 if (Container::getContext()->getValue('disambiguateAddGivenname', 'citation') == true) { $addGiveName = new AddGivenName(); $addGiveName->setStore($store); if ($chain !== false) { $addGiveName->setSuccessor($chain); } $chain = $addGiveName; } // step 1 if (Container::getContext()->getValue('disambiguateAddNames', 'citation') === true) { $addNames = new AddNames(); $addNames->setStore($store); if ($chain !== false) { $addNames->setSuccessor($chain); } $chain = $addNames; } if ($chain !== false) { $chain->setAmbiguous($ambiguous)->setDisambiguate(array())->disambiguate(); } }
/** * 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'], '')); } }
/** * Renders a long-ordinal, with fallback to ordinal for numbers greater ten. * * @param string $variable * @return string */ public static function renderLong($variable) { $ordinal = 'long-ordinal-'; if ((int) $variable <= 10) { $ordinal .= '0' . (int) $variable; } else { $ordinal .= $variable; } $long = Container::getLocale()->getTerms($ordinal); if ($long !== null) { return $long; } return self::render($variable); }
/** * Returns the result of the first rendering element which returns a non-empty value. * * @param string|array $data * @return string */ public function render($data) { foreach ($this->renderingElements as $rendering) { $return = $rendering->render($data); if ($return != '') { Container::getContext()->getSubstitute()->setValue($return); if ($rendering instanceof Names == true) { $variables = $rendering->getVariables(); Container::getContext()->getSubstitute()->setVariable($variables[0]); } return $return; } } return ''; }
/** * Create the objects for the additional options. * * @param \SimpleXMLElement $xml */ public function __construct(\SimpleXMLElement $xml) { $this->disambiguation = new Disambiguation(); $this->renderFromIds = new RenderFromIds(); $this->citeGrouping = new CiteGrouping(); $this->citeCollapsing = new CiteCollapsing(); // set standard values for citationItems-specific options Container::getContext()->addCitation('disambiguateAddNames', false); Container::getContext()->addCitation('disambiguateAddGivenname', false); Container::getContext()->addCitation('givennameDisambiguationRule', 'by-cite'); Container::getContext()->addCitation('disambiguateAddYearSuffix', false); Container::getContext()->addCitation('nearNoteDistance', 5); foreach ($xml->attributes() as $name => $value) { switch ($name) { case 'disambiguate-add-names': Container::getContext()->addCitation('disambiguateAddNames', isBoolean($value)); break; case 'disambiguate-add-givenname': Container::getContext()->addCitation('disambiguateAddGivenname', isBoolean($value)); break; case 'givenname-disambiguation-rule': Container::getContext()->addCitation('givennameDisambiguationRule', (string) $value); break; case 'disambiguate-add-year-suffix': Container::getContext()->addCitation('disambiguateAddYearSuffix', isBoolean($value)); break; case 'cite-group-delimiter': $this->citeGrouping->setCiteGroupDelimiter((string) $value); $this->citeGrouping->setActive(true); break; case 'collapse': $this->citeCollapsing->setCollapse((string) $value); $this->citeGrouping->setActive(true); break; case 'year-suffix-delimiter': $this->citeCollapsing->setYearSuffixDelimiter((string) $value); break; case 'after-collapse-delimiter': $this->citeCollapsing->setAfterCollapseDelimiter((string) $value); break; case 'near-note-distance': Container::getContext()->addCitation('nearNoteDistance', (int) $value); break; } } }
/** * Render all child elements. * * @param string|array $data * @return string|array */ public function render($data) { // render just child elements of a given class (@see Macro) $renderJustSelectedClass = false; $renderJustClass = array(); if (Container::getContext()->in('sort') == true && Container::getContext()->get('renderJust', 'sort') !== null) { $renderJustClass = Container::getContext()->get('renderJust', 'sort'); $renderJustSelectedClass = true; } $result = array(); foreach ($this->children as $child) { $rendered = $child->render(''); if ($renderJustSelectedClass == false || in_array(get_class($child), $renderJustClass) == true) { $result[] = $rendered; } } return implode('', $result); }
/** * 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() { $etAl = Container::getContext()->getValue('etAlUseFirst', 'citation'); $maxNames = Container::getContext()->get('layout', 'layout')->getChildElement('\\Geissler\\CSL\\Names\\Names')->getMaxNumberOfNames(); $disambiguated = false; $this->tmpDisambiguate = $this->getDisambiguate(); $this->tmpAmbiguous = $this->getAmbiguous(); if (is_array($this->getAmbiguous()) == true) { do { Container::getContext()->removeDisambiguationOptions('Geissler\\CSL\\Names\\Name'); $etAl++; Container::getContext()->setDisambiguationOptions('Geissler\\CSL\\Names\\Name', array('etAlUseFirst' => $etAl)); $disambiguated = $this->addGivenName($this->tmpAmbiguous); } while ($disambiguated == false && $etAl <= $maxNames); } if ($disambiguated == true) { $this->store($this->tmpDisambiguate, $this->tmpAmbiguous); } else { $this->succeed($this->tmpDisambiguate, $this->tmpAmbiguous); } }
/** * Displays a year. * * @param string|integer $data * @return string */ public function render($data) { if ($data === '') { return $data; } $data = (int) $data; if (Container::getContext()->in('sort') == true) { return $data; } if ($data < 0) { // The "bc" term (Before Christ) is automatically appended to negative years return $this->format(-1 * $data . Container::getLocale()->getTerms('bc')); } if ($data < 1000) { // The "ad" term (Anno Domini) is automatically appended to positive years of less than four digits return $this->format($data . Container::getLocale()->getTerms('ad')); } if ($this->form == 'short') { return $this->format(mb_substr($data, 2)); } return $this->format($data); }
/** * 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); } } } }
/** * Adds the quotes. * * @param string $data * @return string */ public function render($data) { if ($this->quote == true) { if (strpos($data, Container::getLocale()->getTerms('open-quote')) !== false && strpos($data, Container::getLocale()->getTerms('close-quote')) !== false) { $masked = false; if (strpos($data, Container::getLocale()->getTerms('open-inner-quote')) !== false && strpos($data, Container::getLocale()->getTerms('close-inner-quote')) !== false) { // masc inner quotes $data = str_replace(Container::getLocale()->getTerms('open-inner-quote'), '##', $data); $data = str_replace(Container::getLocale()->getTerms('close-inner-quote'), '#', $data); $masked = true; } $data = str_replace(Container::getLocale()->getTerms('open-quote'), Container::getLocale()->getTerms('open-inner-quote'), $data); $data = str_replace(Container::getLocale()->getTerms('close-quote'), Container::getLocale()->getTerms('close-inner-quote'), $data); if ($masked == true) { $data = str_replace('##', Container::getLocale()->getTerms('open-quote'), $data); $data = str_replace('#', Container::getLocale()->getTerms('close-quote'), $data); } } return Container::getLocale()->getTerms('open-quote') . $data . Container::getLocale()->getTerms('close-quote'); } return $data; }
/** * With cite grouping, cites in in-text citations with identical rendered names are grouped together. * * @param array $data * @return array */ public function apply(array $data) { $names = Container::getContext()->get('layout', 'layout')->getChildElement('\\Geissler\\CSL\\Names\\Names'); if ($this->active == false || is_object($names) == false || Container::getCitationItem() === false) { return $data; } Container::getCitationItem()->moveToFirst(); $delimiter = Container::getContext()->get('delimiter', 'layout'); if (isset($this->citeGroupDelimiter) == false) { $this->citeGroupDelimiter = $delimiter; $this->citeGroupDelimiter = ', '; } $length = count($data); $newData = array(); for ($i = 0; $i < $length; $i++) { // get all names in citation group $namesAsArray = array(); $namesFull = array(); do { Container::getData()->moveToId(Container::getActualId()); $namesAsArray[] = $names->renderAsArray(''); $namesFull[] = $names->render(''); } while (Container::getCitationItem()->nextInGroup() == true); $newData[$i] = array(); $citeLength = count($namesAsArray); for ($j = 0; $j < $citeLength; $j++) { $actualName = $namesAsArray[$j][0]; // check if name already used if ($actualName !== '' && isset($data[$i][$j]) == true) { $actualGroup = array($data[$i][$j]); $groupPosition = 0; for ($k = $j + 1; $k < $citeLength; $k++) { if ($actualName == $namesAsArray[$k][0] && $namesFull[$j] == $namesFull[$k] && isset($data[$i][$k]) == true) { // replace delimiter in previous group entry with cite group delimiter $actualGroup[$groupPosition]['delimiter'] = $this->citeGroupDelimiter; $actualGroup[] = $data[$i][$k]; $namesAsArray[$k][0] = ''; $groupPosition++; // Add delimiter to values without one if ($actualGroup[$groupPosition]['delimiter'] == '') { $actualGroup[$groupPosition]['delimiter'] = $delimiter; } } } $newData[$i] = array_merge($newData[$i], $actualGroup); } } // remove delimiter from last entry in group $newData[$i][count($newData[$i]) - 1]['delimiter'] = ''; Container::getCitationItem()->next(); } return $newData; }
/** * 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++; } } }
/** * Renders the date part, if a value is set. * * @param array $data Array with the keys: month, day, year * @return string */ public function render($data) { if (isset($data[$this->name]) == false || $data[$this->name] == '') { return ''; } $value = $this->render->render($data[$this->name]); $value = $this->formatting->render($value); $value = $this->textCase->render($value); // Attributes for affixes are allowed, unless cs:date calls a localized date format if (Container::getContext()->get('form', 'date') !== '') { $value = $this->affix->render($value); } return $value; }
/** * Tests if the element or an child element is accessing the variable with the given name. * * @param string $name * @return boolean */ public function isAccessingVariable($name) { return Container::getMacro($this->name)->isAccessingVariable($name); }
protected function initElement($layout, $json, $language = 'en-US') { $locale = Factory::locale(); $locale->readFile($language); Container::setLocale($locale); $data = new Data(); $data->set($json); Container::setData($data); $xml = new \SimpleXMLElement($layout); $this->object = new Label($xml); }
/** * Renders the names for the given ids as array or string. * * @param array $data * @param bool $asArray * @return array */ protected function renderNames($data, $asArray = false) { $names = Container::getContext()->get('layout', 'layout')->getChildElement('\\Geissler\\CSL\\Names\\Names'); if (is_object($names) == false) { return array(); } $ids = array_keys($data); $length = count($ids); $values = array(); for ($i = 0; $i < $length; $i++) { $id = $ids[$i]; Container::getData()->moveToId($id); if ($asArray == false) { $values[$id] = $names->render(''); } else { $values[$id] = $names->renderAsArray(''); } } return $values; }
/** * Render title cases. * * @param string $data * @return string */ private function renderTitle($data) { if (Container::getLocale()->getLanguage() == 'en' && Container::getData()->getVariable('language') == null || Container::getData()->getVariable('language') == 'en') { // In both cases, stop words are lowercased, unless they are the first or last word in the string, // or follow a colon. $stopWords = array('a', 'an', 'and', 'as', 'at', 'but', 'by', 'down', 'for', 'from', 'in', 'into', 'nor', 'of', 'on', 'onto', 'or', 'over', 'so', 'the', 'till', 'to', 'up', 'via', 'with', 'yet'); $values = explode(' ', $data); $length = count($values); if (preg_match('/^[A-Z| |\\.|,]+$/', $data) == 1) { // For uppercase strings, the first character of each word remains capitalized. // All other letters are lowercase. for ($i = 0; $i < $length; $i++) { if ($i > 0 && $i < $length - 1 && in_array(mb_strtolower($values[$i]), $stopWords) == true) { $values[$i] = mb_strtolower($values[$i]); } else { $values[$i] = mb_substr($values[$i], 0, 1) . mb_strtolower(mb_substr($values[$i], 1)); } } } else { // For lower or mixed case strings, the first character of each lowercase word is capitalized. // The case of words in mixed or uppercase stays the same. for ($i = 0; $i < $length; $i++) { if ($i > 0 && $i < $length - 1 && in_array(mb_strtolower($values[$i]), $stopWords) == true) { $values[$i] = mb_strtolower($values[$i]); } else { $values[$i] = mb_strtoupper(mb_substr($values[$i], 0, 1)) . mb_substr($values[$i], 1); } } } return implode(' ', $values); } return $data; }
/** * Set the display mode (citation or bibliography). * * @param string $context * @return \Geissler\CSL\CSL */ private function registerContext($context) { Container::clear(); Container::getContext()->setName($context); return $this; }
protected function initElement($layout) { \Geissler\CSL\Container::clear(); $xml = new \SimpleXMLElement($layout); $this->object = new EtAl($xml); }