/** * File_MARC_Field constructor * * Create a new {@link File_MARC_Field} object from passed arguments. We * define placeholders for the arguments required by child classes. * * @param string $tag tag * @param string $subfields placeholder for subfields or control data * @param string $ind1 placeholder for first indicator * @param string $ind2 placeholder for second indicator */ function __construct($tag, $subfields = null, $ind1 = null, $ind2 = null) { $this->tag = $tag; // Check if valid tag if (!preg_match("/^[0-9A-Za-z]{3}\$/", $tag)) { $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_TAG], array("tag" => $tag)); throw new File_MARC_Exception($errorMessage, File_MARC_Exception::ERROR_INVALID_TAG); } }
/** * Decode a given raw MARC record * * Port of Andy Lesters MARC::File::USMARC->decode() Perl function into PHP. * * @param string $text Raw MARC record * * @return File_MARC_Record Decoded File_MARC_Record object */ private function _decode($text) { $marc = new File_MARC_Record($this); $matches = array(); if (!preg_match("/^(\\d{5})/", $text, $matches)) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_NONNUMERIC_LENGTH], array("record_length" => substr($text, 0, 5)))); } // Store record length $record_length = $matches[1]; if ($record_length != strlen($text)) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INCORRECT_LENGTH], array("record_length" => $record_length, "actual" => strlen($text)))); // give up and set the record length to the actual byte length $record_length = strlen($text); } if (substr($text, -1, 1) != File_MARC::END_OF_RECORD) { throw new File_MARC_Exception(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_TERMINATOR], File_MARC_Exception::ERROR_INVALID_TERMINATOR); } // Store leader $marc->setLeader(substr($text, 0, File_MARC::LEADER_LEN)); // bytes 12 - 16 of leader give offset to the body of the record $data_start = 0 + substr($text, 12, 5); // immediately after the leader comes the directory (no separator) $dir = substr($text, File_MARC::LEADER_LEN, $data_start - File_MARC::LEADER_LEN - 1); // -1 to allow for \x1e at end of directory // character after the directory must be \x1e if (substr($text, $data_start - 1, 1) != File_MARC::END_OF_FIELD) { $marc->addWarning(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_NO_DIRECTORY]); } // All directory entries 12 bytes long, so length % 12 must be 0 if (strlen($dir) % File_MARC::DIRECTORY_ENTRY_LEN != 0) { $marc->addWarning(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_DIRECTORY_LENGTH]); } // go through all the fields $nfields = strlen($dir) / File_MARC::DIRECTORY_ENTRY_LEN; for ($n = 0; $n < $nfields; $n++) { // As pack returns to key 1, leave place 0 in list empty list(, $tag) = unpack("A3", substr($dir, $n * File_MARC::DIRECTORY_ENTRY_LEN, File_MARC::DIRECTORY_ENTRY_LEN)); list(, $len) = unpack("A3/A4", substr($dir, $n * File_MARC::DIRECTORY_ENTRY_LEN, File_MARC::DIRECTORY_ENTRY_LEN)); list(, $offset) = unpack("A3/A4/A5", substr($dir, $n * File_MARC::DIRECTORY_ENTRY_LEN, File_MARC::DIRECTORY_ENTRY_LEN)); // Check directory validity if (!preg_match("/^[0-9A-Za-z]{3}\$/", $tag)) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_DIRECTORY_TAG], array("tag" => $tag))); } if (!preg_match("/^\\d{4}\$/", $len)) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_DIRECTORY_TAG_LENGTH], array("tag" => $tag, "len" => $len))); } if (!preg_match("/^\\d{5}\$/", $offset)) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_DIRECTORY_OFFSET], array("tag" => $tag, "offset" => $offset))); } if ($offset + $len > $record_length) { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_DIRECTORY], array("tag" => $tag))); } $tag_data = substr($text, $data_start + $offset, $len); if (substr($tag_data, -1, 1) == File_MARC::END_OF_FIELD) { /* get rid of the end-of-tag character */ $tag_data = substr($tag_data, 0, -1); $len--; } else { $marc->addWarning(File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_FIELD_EOF], array("tag" => $tag))); } if (preg_match("/^\\d+\$/", $tag) and $tag < 10) { $marc->appendField(new File_MARC_Control_Field($tag, $tag_data)); } else { $subfields = explode(File_MARC::SUBFIELD_INDICATOR, $tag_data); $indicators = array_shift($subfields); if (strlen($indicators) != 2) { $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_INDICATORS], array("tag" => $tag, "indicators" => $indicators)); $marc->addWarning($errorMessage); // Do the best with the indicators we've got if (strlen($indicators) == 1) { $ind1 = $indicators; $ind2 = " "; } else { list($ind1, $ind2) = array(" ", " "); } } else { $ind1 = substr($indicators, 0, 1); $ind2 = substr($indicators, 1, 1); } // Split the subfield data into subfield name and data pairs $subfield_data = array(); foreach ($subfields as $subfield) { if (strlen($subfield) > 0) { $subfield_data[] = new File_MARC_Subfield(substr($subfield, 0, 1), substr($subfield, 1)); } else { $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_EMPTY_SUBFIELD], array("tag" => $tag)); $marc->addWarning($errorMessage); } } if (!isset($subfield_data)) { $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_EMPTY_SUBFIELD], array("tag" => $tag)); $marc->addWarning($errorMessage); } // If the data is invalid, let's just ignore the one field try { $new_field = new File_MARC_Data_Field($tag, $subfield_data, $ind1, $ind2); $marc->appendField($new_field); } catch (Exception $e) { $marc->addWarning($e->getMessage()); } } } return $marc; }
/** * Inserts a field in the MARC record relative to an existing field * * Inserts a {@link File_MARC_Control_Field} or {@link File_MARC_Data_Field} * object before or after a specified existing field. * * <code> * // Example: Insert a new field before the first 650 field * * // Create the new field * $subfields[] = new File_MARC_Subfield('a', 'Scott, Daniel.'); * $new_field = new File_MARC_Data_Field('100', $subfields, 0, null); * * // Retrieve the target field for our insertion point * $subject = $record->getFields('650'); * * // Insert the new field * if (is_array($subject)) { * $record->insertField($new_field, $subject[0], true); * } * elseif ($subject) { * $record->insertField($new_field, $subject, true); * } * </code> * * @param File_MARC_Field $new_field The field to add * @param File_MARC_Field $existing_field The target field * @param bool $before Insert the new field before the existing field if true, after the existing field if false * * @return File_MARC_Field The field that was added */ function insertField(File_MARC_Field $new_field, File_MARC_Field $existing_field, $before = false) { switch ($before) { /* Insert before the specified field in the record */ case true: $this->fields->insertNode($new_field, $existing_field, true); break; /* Insert after the specified field in the record */ /* Insert after the specified field in the record */ case false: $this->fields->insertNode($new_field, $existing_field); break; default: $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INSERTFIELD_MODE], array("mode" => $before)); throw new File_MARC_Exception($errorMessage, File_MARC_Exception::ERROR_INSERTFIELD_MODE); } return $new_field; }
/** * Read in MARCXML records * * This function reads in files or strings that * contain one or more MARCXML records. * * <code> * <?php * // Retrieve MARC records from a file * $journals = new File_MARC('journals.mrc', SOURCE_FILE); * * // Retrieve MARC records from a string (e.g. Z39 query results) * $monographs = new File_MARC($raw_marc, SOURCE_STRING); * * // Retrieve MARCXML records from a string with a namespace URL * $records = new File_MARCXML($xml_data, File_MARC::SOURCE_STRING,"http://www.loc.gov/MARC21/slim"); * * // Retrieve MARCXML records from a file with a namespace prefix * $records = new File_MARCXML($xml_data, File_MARC::SOURCE_FILE,"marc",true); * ?> * </code> * * @param string $source Name of the file, or a raw MARC string * @param int $type Source of the input, either SOURCE_FILE or SOURCE_STRING * @param string $ns URI or prefix of the namespace * @param bool $is_prefix TRUE if $ns is a prefix, FALSE if it's a URI; defaults to FALSE */ function __construct($source, $type = self::SOURCE_FILE, $ns = "", $is_prefix = false) { parent::__construct($source, $type); $this->counter = 0; switch ($type) { case self::SOURCE_FILE: $this->type = self::SOURCE_FILE; $this->source = simplexml_load_file($source, "SimpleXMLElement", 0, $ns, $is_prefix); break; case self::SOURCE_STRING: $this->type = self::SOURCE_STRING; $this->source = simplexml_load_string($source, "SimpleXMLElement", 0, $ns, $is_prefix); break; default: throw new File_MARC_Exception(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_SOURCE], File_MARC_Exception::ERROR_INVALID_SOURCE); } if (!$this->source) { $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_FILE], array('filename' => $source)); throw new File_MARC_Exception($errorMessage, File_MARC_Exception::ERROR_INVALID_FILE); } }
/** * Set the value of an indicator * * @param int $ind number of the indicator (1 or 2) * @param string $value value of the indicator * * @return string returns indicator value if it exists, otherwise false */ function setIndicator($ind, $value) { switch ($ind) { case 1: $this->ind1 = $this->_validateIndicator($value); break; case 2: $this->ind2 = $this->_validateIndicator($value); break; default: $errorMessage = File_MARC_Exception::formatError(File_MARC_Exception::$messages[File_MARC_Exception::ERROR_INVALID_INDICATOR_REQUEST], array("indicator" => $ind)); throw new File_MARC_Exception($errorMessage, File_MARC_Exception::ERROR_INVALID_INDICATOR_REQUEST); return false; } return $this->getIndicator($ind); }