<?php /** * The PicaXmlReader class file. * * This file is part of PicaReader. * * PicaReader is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PicaReader is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PicaReader. If not, see <http://www.gnu.org/licenses/>. * * @package PicaReader * @author David Maus <maus@hab.de> * @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel * @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3 */ namespace HAB\Pica\Reader; use \XMLReader; /** * Reader for Pica+ records encoded in PicaXML. * * @package PicaReader * @author David Maus <maus@hab.de> * @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel * @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3 */ class PicaXmlReader extends Reader { /** * @var string XML namespace URI of PicaXML */ const PICAXML_NAMESPACE_URI = 'info:srw/schema/5/picaXML-v1.0'; /** * @var \XMLReader XML Reader instance */ private $_xmlReader; /** * Constructor. * * @return void */ public function __construct () { parent::__construct(); $this->_xmlReader = new XMLReader(); } /** * Prepare the reader for reading data. * * @param string $input Data to read * @return void */ public function open ($input) { $this->_xmlReader->XML($input); parent::open($input); } /** * Close current input data. * * @return void */ public function close () { $this->_xmlReader->close(); parent::close(); } /** * Return the array representation of the next record in current input data. * * @see ReaderAbstract::next() * * @return array|false Record or false if there are no more records */ protected function next () { if ($this->forwardTo('record', self::PICAXML_NAMESPACE_URI)) { $record = array('fields' => array()); while (!$this->atElementEnd('record', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) { if ($this->atElement('datafield', self::PICAXML_NAMESPACE_URI)) { $record['fields'] []= $this->readField(); } } } else { $record = false; } return $record; } /** * Return array representation of datafield at cursor. * * The cursor is expected to be positioned on the opening field element. * * @return array Field */ protected function readField () { $field = array('tag' => $this->_xmlReader->getAttribute('tag'), 'occurrence' => $this->_xmlReader->getAttribute('occurrence'), 'subfields' => array()); while (!$this->atElementEnd('datafield', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) { if ($this->atElement('subfield', self::PICAXML_NAMESPACE_URI)) { $subfield = array('code' => $this->_xmlReader->getAttribute('code'), 'value' => ''); while (!$this->atElementEnd('subfield', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) { switch ($this->_xmlReader->nodeType) { case XMLReader::TEXT: case XMLReader::SIGNIFICANT_WHITESPACE: case XMLReader::CDATA: $subfield['value'] .= $this->_xmlReader->value; break; } } $field['subfields'] []= $subfield; } } return $field; } /** * Move cursor forward to named element. * * The cursor is not moved if it is already positioned at the named element. * * @param string $name Element local name * @param string $uri Namespace URI * @return boolean TRUE if cursor is at specified element or FALSE if cursor * reached the end of the document */ protected function forwardTo ($name, $uri) { while (!$this->atElement($name, $uri) && $this->_xmlReader->read()) { } return ($this->_xmlReader->nodeType === XMLReader::ELEMENT); } /** * Return TRUE if the cursor is positioned at the named element. * * @param string $name Element local name * @param string $uri Namespace URI * @return boolean TRUE if the cursor is positioned at the element */ protected function atElement ($name, $uri) { return ($this->_xmlReader->nodeType === XMLReader::ELEMENT && $this->_xmlReader->localName === $name && $this->_xmlReader->namespaceURI === $uri); } /** * Return TRUE if the cursor is positioned at the end of the named element. * * @param string $name Element local name * @param string $uri Namespace URI * @return boolean TRUE if the cursor is positioned at the end of the named * element */ protected function atElementEnd ($name, $uri) { return ($this->_xmlReader->nodeType === XMLReader::END_ELEMENT && $this->_xmlReader->localName === $name && $this->_xmlReader->namespaceURI === $uri); } }