tei = $tei; $this->xpath = $this->tei->xpath; } public function getFileName() { $text = strtolower($this->tei->projectData['post-title']); $fileName = preg_replace('/\s/', "_", $text); $fileName = mb_ereg_replace('/[^\w\-]/', '', $fileName); $fileName = trim($fileName, "_"); $fileName = rtrim($fileName, "."); return $fileName; } /* Accessors for building output formats */ /** * nodeToArray gives a 'flattened' array of the node and subnode values. * E.g. array('elName'=>'value', 'elName2'=>'value') * @param DOMNode * @return Array */ public function nodeToArray($node, $deep = true, $followRefs = false) { $retArray = array(); if( ! $node ) { return $retArray; } if($node->nodeType == XML_ATTRIBUTE_NODE) { $retArray = array('attrName'=>$node->nodeName, 'value'=>$node->nodeValue); return $retArray; } $retArray['elName'] = $node->nodeName; $attNodes = $this->xpath->query("@*", $node); $retArray['atts'] = array(); foreach($attNodes as $att) { $retArray['atts'][$att->nodeName] = $att->nodeValue; } if($node->nodeName == 'param') { $retArray[$node->getAttribute('name')] = $node->textContent; } if($node->firstChild->nodeType == XML_TEXT_NODE || $node->firstChild->nodeType == XML_CDATA_SECTION_NODE) { $retArray['value'] = $node->textContent; return $retArray; } if( ($node->nodeName == 'div') && ( in_array(HTML, $retArray['atts']) ) ) { $retArray['value'] = $this->getNodeXML($node); } if( ! $deep ) { return $retArray; } foreach($node->childNodes as $childNode) { if( $childNode->nodeType != XML_ELEMENT_NODE ){ continue; } $plName = $childNode->nodeName . "s"; if( ! isset($retArray[$plName])) { $retArray[$plName] = array(); } $retArray[$plName][] = $this->nodeToArray($childNode, $deep); if($followRefs && $childNode->hasAttribute('ref')) { $ref = $childNode->getAttribute('ref'); $nd = $this->getNodeDataByParams(array('id'=>$ref)); $retArray[$plName][] = $nd; } //if empty, get rid of it if ( count($retArray[$plName]) == 0 ) { unset($retArray[$plName]); } } return $retArray; } /** * Retrive data in the node * Returns either the node itself or a flat array containing data in the node and its children. * Allowed params: * array('id'=> , an element id * 'section'=> , 'front', 'body', or 'back' of the tei:text * 'partNumber' => , part number within the section * 'itemNumber' => , item number within the part * 'subPath' => , additional path beyond the above parameters * 'contextNode' => , the DOMNode context of the query * 'asList'=>, boolean if you want the whole list * * * ) * * @param array $params * @param boolean $asNode = false * @return mixed DOMNode or array */ public function getNodeDataByParams($params, $firstOnly = true) { extract($params); if( isset($id) ) { $queryString = "//*[@xml:id = '$id']"; } else if ( isset($section)) { $queryString = "//tei:$section"; if(isset($partNumber)) { if($section == 'body') { $queryString .= "/tei:div[@n='$partNumber']"; } if(isset($itemNumber)) { $queryString .= "/tei:div[@n='$itemNumber']"; } } } else if(isset($index)) { $queryString = "//tei:div[@type='index'][@subtype='$index']"; if(isset($itemNumber)) { $queryString .= "/tei:list/tei:item[@n='$itemNumber']"; } } if(isset($subPath) ) { //TODO check whether I use/need a first slash $queryString .= "$subPath"; } if(isset($contextNode) ) { $nodeList = $this->getNodeListByXPath(array('xpath'=>$queryString, 'contextNode'=>$contextNode) ); } else { $nodeList = $this->getNodeListByXPath($queryString); } if(! $nodeList ) { return false; } if($firstOnly) { $node = $nodeList->item(0); if($asNode) { return $node; } return $this->nodeToArray($node); } if($asNode) { return $nodeList; } $returnArray = array(); foreach($nodeList as $node) { $returnArray[] = $this->nodeToArray($node); } return $returnArray; } public function getNodeTargetData($node) { //get id and a label/title $id = $node->getAttribute('xml:id'); $titleNode = $this->getNodeListByXPath(array('xpath'=>"tei:head/tei:title", 'contextNode'=>$node), true); $title = $titleNode->firstChild->nodeValue; return array('id'=>$id, 'title'=>$title); } /** * dump the node to a string * @param DOMNode $node a node * @return string */ public function getNodeXML($node, $atts = false) { if($atts) { foreach($atts as $att=>$val) { $node->setAttribute($att, $val); } } return $this->tei->dom->saveXML($node); } public function getParentItem($node, $asNode = false) { while( $node->getAttribute('type') != 'libraryItem') { $node = $node->parentNode; } if($asNode) { return $node; } return $this->nodeToArray($node, false); } public function getParentItemId($node) { while( $node->getAttribute('type') != 'libraryItem') { $node = $node->parentNode; } return $node->getAttribute('xml:id'); } /** * get the node list for an XPath * @param mixed $xpath as string, an xpath. as array: array('xpath'=>$xpath, 'contextNode'=> DOMNode) * @param $firstOnly = false return only the first match * @return mixed DOMNodeList or DOMNode */ public function getNodeListByXPath($xpath, $firstOnly = false) { if(is_array($xpath)) { $nodeList = $this->xpath->query($xpath['xpath'], $xpath['contextNode']); } else { $nodeList = $this->xpath->query($xpath); } if($nodeList->length == 0 ) { return false; } if($firstOnly) { return $nodeList->item(0); } return $nodeList; } /** * get the project title * @param $valueOnly = false whether to return the value only or wrap in a span * @return string */ public function getProjectTitle($valueOnly = false) { $queryString = "//tei:head[@type='titlePage']/tei:bibl/tei:title[@type='main']"; $titleNode = $this->getNodeListByXPath($queryString, true); if($valueOnly) { return $titleNode->firstChild->nodeValue; } return $this->getNodeXML($titleNode->firstChild); } /** * get the project subtitle * @param $valueOnly = false whether to return the value only or wrap in a span * @return string */ public function getProjectSubTitle($valueOnly = false) { $queryString = "//tei:head[@type='titlePage']/tei:bibl/tei:title[@type='sub']"; $subTitleNode = $this->getNodeListByXPath($queryString, true); if($valueOnly) { return $subTitleNode->firstChild->nodeValue; } return $this->getNodeXML($subTitleNode->firstChild); } /** * get info about the project creator, or just the display name * @param $asStructured = false whether to return an array with complete data. requires option includeCreatorData = true when construction TeiDOM * @return mixed array of data or string */ public function getProjectCreator($asStructured = false) { $queryString = "//tei:author[@role = 'projectCreator']"; $creator = $this->getNodeListByXPath($queryString, true); if($asStructured) { $ref = $creator->getAttribute('ref'); $structuredCreator = $this->tei->dom->getElementById($ref); return $this->nodeToArray($structuredCreator); } return $this->getNodeXML($creator->firstChild); } /** * get copyright/license information about the project * @param $asStructured = false return as structured data or human-readable * return string */ public function getProjectCopyright($asStructured = false) { if($asStructured) { $cr = $this->getNodeListByXPath("//tei:publicationStmt/tei:availability[@rend='structured']/tei:ab", true); if($cr->parentNode->getAttribute('status') == 'c') { return "Copyright"; } } else { $cr = $this->getNodeListByXPath("//tei:publicationStmt/tei:availability[@rend='literal']/span", true); if($cr->parentNode->getAttribute('status') == 'c') { return "Copyright"; } } return $this->getNodeXML($cr); } /** * get edition information about the project * @param $asStructured = false return as structured data or human-readable * return string */ public function getProjectEdition($asStructured = false) { $edition = $this->getNodeListByXPath("//tei:editionStmt/tei:ab[@rend='literal']/span", true); return $this->getNodeXML($edition); } /** * get an output param set on the export screen * @param $param = false a single param value to return * @param $asNode = false whether to return as a node or a string * @return mixed DOMNode or string or array */ public function getProjectOutputParams($param = false, $asNode = false) { $xpath = "//anth:outputDecl/anth:outputParams"; if($param) { $xpath .= "/anth:param[@name='$param']"; } $params = array('subPath'=>$xpath, 'asNode'=>$asNode ); $data = $this->getNodeDataByParams($params); if($param) { return $data[$param]; } return $data; } /** * return the publication date * @return string */ public function getProjectPublicationDate() { $query = "//tei:front/tei:head/tei:bibl/tei:data[@type = 'created']"; $params = array('section'=>'front', 'subPath'=>"/tei:head/tei:bibl/tei:date[@type = 'created']", 'asNode'=>false ); $data = $this->getNodeDataByParams($params); return $data['value']; } /** * get the number of parts in a section * @param $section = 'body' the section, front, body, or back * @return int */ public function getSectionPartCount($section = 'body') { $count = $this->xpath->evaluate("count(//tei:$section/tei:div[@type='part'])"); return $count; } /** * get the id set for a part within a section * @param $section the section. front, body, or back * @param $partNumber the number of the part within the section * @return string */ public function getSectionPartId($section, $partNumber) { $params = array('section'=> $section, 'partNumber' => $partNumber, 'subPath' => "@xml:id", 'asNode'=>false ); $data = $this->getNodeDataByParams($params); return $data['value']; } public function getSectionPartHead($section, $partNumber, $asNode = false) { $params = array('section' => $section, 'partNumber'=>$partNumber, 'subPath'=>'/tei:head', 'asNode'=>$asNode); return $this->getNodeDataByParams($params); } /** * get the title for a part within a section * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $asNode whether to return the DOMNode * @return mixed string or DOMNode */ public function getSectionPartTitle($section, $partNumber, $asNode = false) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'subPath'=>'/tei:head/tei:title', 'asNode'=>true); $data = $this->getNodeDataByParams($params); if($asNode) { return $data; } if($data) { return $this->getNodeXML($data->firstChild); } } /** * get the number of items in a part in a section * @param $section = 'body' the section, front, body, or back * @param $partNumber the number of the part within the section * @return int */ public function getSectionPartItemCount($section, $partNumber) { switch($section) { case 'front': $count = $this->xpath->evaluate("count(//tei:$section/tei:div)"); break; case 'body': $count = $this->xpath->evaluate("count(//tei:$section/tei:div[@type='part'][@n='$partNumber']/tei:div[@type='libraryItem'])"); break; case 'back': break; } return $count; } public function getSectionPartItemHead($section, $partNumber, $itemNumber, $asNode = false) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'asNode'=>$asNode); return $this->getNodeDataByParams($params); } /** * get the title for an item within a part within a section * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $asNode whether to return the DOMNode * @return mixed string or DOMNode */ public function getSectionPartItemTitle($section, $partNumber, $itemNumber, $asNode = false) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'subPath'=>"/tei:head/tei:title", 'asNode'=>true); $data = $this->getNodeDataByParams($params); if($asNode) { return $data; } if($data) { return $this->getNodeXML($data->firstChild); } } /** * get the id set for an item within a part within a section * @param $section the section. front, body, or back * @param $partNumber the number of the part within the section * @param $itemNumber the number of the item within the part * @return string */ public function getSectionPartItemId($section, $partNumber, $itemNumber) { $params = array('section'=> $section, 'partNumber' => $partNumber, 'itemNumber' => $itemNumber, 'subPath' => "/@xml:id", 'asNode'=>false ); $data = $this->getNodeDataByParams($params); return $data['value']; } /** * get info about the original author of the content anthologized. (that is the author of the post or page, not necessarily the creator of the item within the project) * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $valueOnly = true give just the display name * @param $asNode whether to return the DOMNode * @return mixed string or array */ public function getSectionPartItemOriginalAuthor($section, $partNumber, $itemNumber, $valueOnly = true, $asNode = false) { $params = array('section'=> $section, 'partNumber' => $partNumber, 'itemNumber' => $itemNumber, 'subPath' => "/tei:head/tei:bibl/tei:author[@role='originalAuthor']", 'asNode'=>$asNode ); $data = $this->getNodeDataByParams($params); if($valueOnly) { return $data['spans'][0]['value']; } return $data; } /** * get info about anthologizer of the content. that is, who added it to the project * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $valueOnly = true give just the display name * @param $asNode whether to return the DOMNode * @return mixed string or array */ public function getSectionPartItemAnthologizer($section, $partNumber, $itemNumber, $valueOnly = true, $asNode = false) { $params = array('section'=> $section, 'partNumber' => $partNumber, 'itemNumber' => $itemNumber, 'subPath' => "/tei:head/tei:bibl/tei:author[@role='anthologizer']", 'asNode'=>$asNode ); $data = $this->getNodeDataByParams($params); if($valueOnly) { return $data['spans'][0]['value']; } return $data; } /** * get info about the author, as set in the Anthologize project administration pages * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $valueOnly = true give just the display name * @param $asNode whether to return the DOMNode * @return mixed string or array */ public function getSectionPartItemAssertedAuthor($section, $partNumber, $itemNumber, $valueOnly = true, $asNode = false) { $params = array('section'=> $section, 'partNumber' => $partNumber, 'itemNumber' => $itemNumber, 'subPath' => "/tei:head/tei:bibl/tei:author[@role='assertedAuthor']", 'asNode'=>$asNode ); $data = $this->getNodeDataByParams($params); if($valueOnly) { return $data['spans'][0]['value']; } return $data; } /** * get the tags and categories for the item * Opinionated comment: the distinction is usually irrelevant across more than one user and blog, so -Subjects covers both, -Tags and -Categories make the distinction * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $asNode whether to return the DOMNode * @return mixed array or DOMNode */ public function getSectionPartItemSubjects($section, $partNumber, $itemNumber, $asNode = false ) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs", 'asNode'=> $asNode); $data = $this->getNodeDataByParams($params, false); return $data; } public function getSectionPartItemTags($section, $partNumber, $itemNumber, $asNode = false ) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs[@type='tag']", 'asNode'=> $asNode); $data = $this->getNodeDataByParams($params, false); return $data; } public function getSectionPartItemCategories($section, $partNumber, $itemNumber, $asNode = false ) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'subPath'=>"/tei:head/tei:list[@type='subjects']/tei:item/tei:rs[@type='category']", 'asNode'=> $asNode); $data = $this->getNodeDataByParams($params, false); return $data; } /** * get the content for an item within a part within a section * @param $section the section. front, body, or back * @param $partNumer the number of the part within the section * @param $itemNumber the number of the item within the part * @param $asNode whether to return the DOMNode * @return mixed string or DOMNode */ public function getSectionPartItemContent($section, $partNumber, $itemNumber, $asNode = false) { $params = array('section'=> $section, 'partNumber'=>$partNumber, 'itemNumber'=>$itemNumber, 'subPath'=>'/div', 'asNode'=> true); $data = $this->getNodeDataByParams($params); if($asNode) { return $data; } if($data) { return $this->getNodeXML($data); } } public function getIndex($indexName, $asNode = false) { $params = array('index'=>$indexName, 'asNode'=>$asNode, ); return $this->getNodeDataByParams($params); } public function getIndexItemCount($index) { if( is_array($index)) { return count($index['lists'][0]['items']); } else if ( is_a($index, 'DOMElement') ) { $xpath = "list/item"; //looks like when giving a context node, evaluate doesn't want prefixes return $this->xpath->evaluate("count($xpath)", $index); } else { throw new Exception('index must be node or array'); } } /* if (is_array($index)) { } else if (is_a($index, 'DOMElement')) { } else { throw new Exception('index must be node or array'); } */ public function getIndexItem($index, $itemNumber) { if (is_array($index)) { return $index['lists'][0]['items'][$itemNumber]; } else if (is_a($index, 'DOMElement')) { $params = array('contextNode'=>$index, 'asNode'=>true, 'subPath'=>"list/item[@n='$itemNumber']" ); return $this->getNodeDataByParams($params); } else { throw new Exception('index must be node or array'); } } public function getIndexItemLabel($item, $asNode = false) { if (is_array($item)) { return $item['rss'][0]['spans'][0]['value']; } else if (is_a($item, 'DOMElement')) { $params = array('contextNode'=>$item, 'asNode'=>true, 'subPath'=>"rs" ); $data = $this->getNodeDataByParams($params); if($asNode) { return $data; } return $this->getNodeXML($data); } else { throw new Exception('item must be node or array'); } } public function getIndexItemRef($item, $asNode = false) { if (is_array($item)) { $ref = $item['rss'][0]['atts']['ref']; } else if (is_a($item, 'DOMElement')) { $ref = $item->firstChild->getAttribute('ref'); } else { throw new Exception('index must be node or array'); } return $this->getDetailsByRef($ref); } public function getIndexItemTargetCount($item) { if( is_array($item)) { return count($item['listRefs'][0]['rss']); } else if ( is_a($item, 'DOMElement') ) { $xpath = "listRef/rs"; //looks like when giving a context node, evaluate doesn't want prefixes return $this->xpath->evaluate("count($xpath)", $item); } else { throw new Exception('index must be node or array'); } } public function getIndexItemTarget($item, $targetNumber) { if (is_array($item)) { return $item['listRefs'][0]['rss'][$targetNumber]; } else if (is_a($item, 'DOMElement')) { $params = array('contextNode'=>$item, 'asNode'=>true, 'subPath'=>"listRef/rs[@n='$targetNumber']" ); return $this->getNodeDataByParams($params); } else { throw new Exception('item must be node or array'); } } /** * dig up a detail about the target * * @param DOMElement $target * @param string $detail this is the info you are looking for: ref, role, label */ public function getIndexItemTargetDetail($target, $detail, $asNode = false) { if (is_array($target)) { switch ($detail) { case 'ref': return $target['atts']['ref']; break; case 'role': return $target['atts']['role']; break; case 'label': return $target['spans'][0]['value']; break; } } else if (is_a($target, 'DOMElement')) { switch ($detail) { case 'ref': return $target->getAttribute('ref'); break; case 'role': return $target->getAttribute('role'); break; case 'label': if($asNode) { return $target->firstChild; } return $this->getNodeXML($target->firstChild); break; } } else { throw new Exception('index must be node or array'); } } /** * get the structured data about a person or subject based on their id/username * @param $ref the id/username of the person. (it's a ref attribute in the TEI) * @param $asNode whether to return the DOMNode * @return array */ public function getDetailsByRef($ref, $asNode = false) { $params = array('id'=>$ref , 'asNode'=>$asNode); return $this->getNodeDataByParams($params); } /** * dig up a particular piece of data out of the structured array for a user. Basically a helper to sort through the array * @param array $personArray the structured array representing the person * @param string $element the name of the data you want * @return string */ public function getPersonDetail($personArray, $element) { switch ($element) { case 'name': return $personArray['persNames'][0]['names'][0]['spans'][0]['value']; break; case 'firstname': return $personArray['persNames'][0]['firstnames'][0]['spans'][0]['value']; break; case 'surname': return $personArray['persNames'][0]['surnames'][0]['spans'][0]['value']; break; case 'bio': return $personArray['notes'][0]['divs'][0]['value']; break; case 'email': return $personArray['persNames'][0]['emails'][0]['spans'][0]['value']; break; case 'count': return $personArray['persNames'][0]['nums'][0]['value']; break; case 'gravatarUrl': return $personArray['figures'][0]['graphics'][0]['imgs'][0]['atts']['src']; break; } } }