/** * 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; }
function buildMarc($bibData) { $mrc = new File_MARC_Record(); $mrc->appendField(new File_MARC_Control_Field("001", $bibData["bibid"])); $ldr = ' '; $ohOhEight = strftime("%Y%m%d", strtotime($bibData['create_dt'])) . ' '; switch ($bibData["material_cd"]) { case 1: $ldr[6] = 'j'; $ldr[7] = 'm'; break; case 2: $ldr[6] = 'a'; $ldr[7] = 'm'; break; case 3: $ldr[6] = 'j'; $ldr[7] = 'm'; break; case 4: $ldr[6] = 'm'; $ldr[7] = 'm'; break; case 5: $ldr[6] = 'p'; $ldr[7] = 'i'; break; case 6: $ldr[6] = 'a'; $ldr[7] = 's'; break; case 7: $ldr[6] = 'e'; $ldr[7] = 'm'; break; case 8: $ldr[6] = 'g'; $ldr[7] = 'm'; break; default: $ldr[6] = 'a'; $ldr[7] = 'm'; break; } $subfields = array(new File_MARC_Subfield("a", $bibData["title"])); if ($bibData["title_remainder"]) { array_push($subfields, new File_MARC_Subfield("b", $bibData["title_remainder"])); } if ($bibData["responsibility_stmt"]) { array_push($subfields, new File_MARC_Subfield("c", $bibData["responsibility_stmt"])); } $title = new File_MARC_Data_Field("245", $subfields, "0", "0"); $mrc->appendField($title); $author = new File_MARC_Data_Field("100", array(new File_MARC_Subfield("a", $bibData["author"])), "1", NULL); $mrc->appendField($author); $subjects = array($bibData["topic1"], $bibData["topic2"], $bibData["topic3"], $bibData["topic4"], $bibData["topic5"]); for ($i = 0; $i < count($subjects); $i++) { $sub = new File_MARC_Data_field("650", array(new File_MARC_Subfield("a", $subjects[$i])), NULL, "4"); $mrc->appendField($sub); } $query = "SELECT * from biblio_field WHERE bibid = " . $bibData['bibid'] . " GROUP BY fieldid"; $result = mysql_query($query); while ($row = mysql_fetch_assoc($result)) { if (!isset($fieldId)) { $fieldId = $row["fieldid"]; if ($row["ind1_cd"] != "N") { $ind1 = $row["ind1_cd"]; } else { $ind1 = NULL; } if ($row["ind2_cd"] != "N") { $ind2 = $row["ind2_cd"]; } else { $ind2 = NULL; } $field = new File_MARC_Data_Field(str_pad($row["tag"], 3, "0", STR_PAD_LEFT), $ind1, $ind2); } if ($fieldId == $row["fieldid"]) { $field->appendSubfield(new File_MARC_Subfield($row["subfield_cd"], $row["field_data"])); } else { $mrc->appendField($field); $fieldId = $row["fieldid"]; if ($row["ind1_cd"] != "N") { $ind1 = $row["ind1_cd"]; } else { $ind1 = NULL; } if ($row["ind2_cd"] != "N") { $ind2 = $row["ind2_cd"]; } else { $ind2 = NULL; } $field = new File_MARC_Data_Field(str_pad($row["tag"], 3, "0", STR_PAD_LEFT), $ind1, $ind2); $field->appendSubfield(new File_MARC_Subfield($row["subfield_cd"], $row["field_data"])); } } $mrc->setLeader($ldr); $mrc->appendField(new File_MARC_Control_Field("008", $ohOhEight)); return $mrc; }
/** Additional functions added by srickel1 to facitilate export of Authority records **/ public function getAuthorityRecord($id) { // authority record query $sql = trim("\n\t\t\t\tSELECT\n\t\t\t\tauthority_view.id,\n\t\t\t\tauthority_view.record_creation_date_gmt,\n\t\t\t\tauthority_view.suppress_code,\n\t\t\t\tvarfield_view.marc_tag,\n\t\t\t\tvarfield_view.marc_ind1,\n\t\t\t\tvarfield_view.marc_ind2,\n\t\t\t\tTRIM(varfield_view.field_content),\n\t\t\t\tvarfield_view.varfield_type_code,\n\t\t\t\tcontrol_field.p40,\n\t\t\t\tcontrol_field.p41,\n\t\t\t\tcontrol_field.p42,\n\t\t\t\tleader_field.*\n\t\t\t\tFROM\n\t\t\t\tsierra_view.authority_view\n\t\t\t\tINNER JOIN\n\t\t\t\tsierra_view.varfield_view ON authority_view.id = varfield_view.record_id\n\t\t\t\tLEFT JOIN\n\t\t\t\tsierra_view.leader_field ON authority_view.id = leader_field.record_id\n\t\t\t\tLEFT JOIN\n\t\t\t\tsierra_view.control_field ON authority_view.id = control_field.record_id\n\t\t\t\tWHERE\n\t\t\t\tauthority_view.record_num = '{$id}' and control_field.control_num=8\n\t\t\t\tORDER BY\n\t\t\t\tmarc_tag\n\t\t\t\t"); $results = $this->getResults($sql); if (count($results) == 0) { return null; } // let's parse a few things, shall we $result = $results[0]; $internal_id = $result[0]; // internal postgres id if ($result['suppress_code'] == 'n') { //suppressed item - let's delete it from the discovery tool data. $record = $this->createDeletedRecord($id); return $record; } //start the marc record $record = new File_MARC_Record(); // leader // 0000's here get converted to correct lengths by File_MARC $leader = '00000'; // 00-04 - Record length /* we have to determine what to do in the cases that we get no leader information back from the database */ if ($this->getLeaderValue($result, 'record_status_code') == ' ') { $leader .= $this->getLeaderValue($result, 'p40'); } else { $leader .= $this->getLeaderValue($result, 'record_status_code'); } //we can get the following field from the bcode1 field if ($this->getLeaderValue($result, 'record_type_code') == ' ') { $leader .= $this->getLeaderValue($result, 'p41'); } else { $leader .= $this->getLeaderValue($result, 'record_type_code'); } // 06 - Type of record //we can get the following field from the ? field $leader .= $this->getLeaderValue($result, 'p42'); $leader .= $this->getLeaderValue($result, 'control_type_code'); // 08 - Type of control $leader .= $this->getLeaderValue($result, 'char_encoding_scheme_code'); // 09 - Character coding scheme $leader .= '2'; // 10 - Indicator count $leader .= '2'; // 11 - Subfield code count $leader .= '00000'; // 12-16 - Base address of data //found the next one in p43 of control_field $leader .= $this->getLeaderValue($result, 'encoding_level_code'); // 17 - Encoding level $leader .= $this->getLeaderValue($result, 'descriptive_cat_form_code'); // 18 - Descriptive cataloging form $leader .= $this->getLeaderValue($result, 'multipart_level_code'); // 19 - Multipart resource record level $leader .= '4'; // 20 - Length of the length-of-field portion $leader .= '5'; // 21 - Length of the starting-character-position portion $leader .= '0'; // 22 - Length of the implementation-defined portion $leader .= '0'; // 23 - Undefined $record->setLeader($leader); // marc fields $record_id_field = new File_MARC_Data_Field('035'); $record->appendField($record_id_field); $record_id_field->appendSubfield(new File_MARC_Subfield('a', $this->getFullRecordId($id, 'a'))); foreach ($results as $result) { try { // skip missing tags and 'old' 9xx tags that mess with the above if ($result['marc_tag'] == null || $result['marc_tag'] == '907' || $result['marc_tag'] == '998') { continue; } // control field if ((int) $result['marc_tag'] < 10) { $control_field = new File_MARC_Control_Field($result['marc_tag'], $result['field_content']); $record->appendField($control_field); } else { $data_field = new File_MARC_Data_Field($result['marc_tag']); $data_field->setIndicator(1, $result['marc_ind1']); $data_field->setIndicator(2, $result['marc_ind2']); $content = $result['field_content']; $content_array = explode('|', $content); foreach ($content_array as $subfield) { $code = substr($subfield, 0, 1); $data = substr($subfield, 1); if ($code == '') { continue; } $subfield = new File_MARC_Subfield($code, trim($data)); $data_field->appendSubfield($subfield); } $record->appendField($data_field); } } catch (File_MARC_Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); } } return $record; }
/** * Decode a given MARCXML record * * @param string $text MARCXML record element * * @return File_MARC_Record Decoded File_MARC_Record object */ private function _decode($text) { $marc = new File_MARC_Record($this); // Store leader $marc->setLeader($text->leader); // go through all the control fields foreach ($text->controlfield as $controlfield) { $controlfieldattributes = $controlfield->attributes(); $marc->appendField(new File_MARC_Control_Field((string) $controlfieldattributes['tag'], $controlfield)); } // go through all the data fields foreach ($text->datafield as $datafield) { $datafieldattributes = $datafield->attributes(); $subfield_data = array(); foreach ($datafield->subfield as $subfield) { $subfieldattributes = $subfield->attributes(); $subfield_data[] = new File_MARC_Subfield((string) $subfieldattributes['code'], $subfield); } // If the data is invalid, let's just ignore the one field try { $new_field = new File_MARC_Data_Field((string) $datafieldattributes['tag'], $subfield_data, $datafieldattributes['ind1'], $datafieldattributes['ind2']); $marc->appendField($new_field); } catch (Exception $e) { $marc->addWarning($e->getMessage()); } } return $marc; }
$allPatrons[$patronData['030_BARCODE'][0]] = $patronData; } } //End reading raw data export echo "Loaded " . count($allPatrons) . " from data extract, {$numInvalidBarcodes} Barcodes were removed because they were invalid.\n"; $patronsWritten = 0; $finalFile = $libraryAddsFileName . ".mrc"; $finalFileHnd = fopen($finalFile, 'wb'); $numBlocked = 0; foreach ($allPatrons as $patronData) { $record = new File_MARC_Record(); $leader = $record->getLeader(); $leader[5] = 'n'; $leader[6] = 'a'; $leader[7] = 'm'; $record->setLeader($leader); //030 = barcode, repeatable foreach ($patronData['030_BARCODE'] as $pBarcode) { $record->appendField(new File_MARC_Data_Field('030', array(new File_MARC_Subfield('a', $pBarcode)))); } //080 = expiration date $record->appendField(new File_MARC_Data_Field('080', array(new File_MARC_Subfield('a', $patronData['080_EXP_DATE'])))); //081 = age group $record->appendField(new File_MARC_Data_Field('081', array(new File_MARC_Subfield('a', $patronData['081_AGE_GRP'])))); //082 = pcode2 REG LIB : should be 3 MNPS for all patrons initially enrolled via MNPS data $record->appendField(new File_MARC_Data_Field('082', array(new File_MARC_Subfield('a', $patronData['082_REG_LIB'])))); //083 = zip/PCODE3? $record->appendField(new File_MARC_Data_Field('083', array(new File_MARC_Subfield('a', $patronData['083_ZIP'])))); //084 = patron type : should be 33 for all Elementary Students $record->appendField(new File_MARC_Data_Field('084', array(new File_MARC_Subfield('a', $patronData['084_PTYPE'])))); //085 = hold pickup library = school
/** * Fetch an individual record * * @param string $id * @return File_MARC_Record|null */ public function getBibRecord($id) { // bib record query $sql = trim("\r\n\t\t\tSELECT\r\n\t\t\t\tbib_view.id,\r\n\t\t\t\tbib_view.bcode1,\r\n\t\t\t\tbib_view.bcode2,\r\n\t\t\t\tbib_view.bcode3,\r\n\t\t\t\tbib_view.cataloging_date_gmt,\r\n\t\t\t\tvarfield_view.marc_tag,\r\n\t\t\t\tvarfield_view.marc_ind1,\r\n\t\t\t\tvarfield_view.marc_ind2,\r\n\t\t\t\tvarfield_view.field_content,\r\n\t\t\t\tvarfield_view.varfield_type_code,\r\n\t\t\t\tleader_field.*\r\n\t\t\tFROM\r\n\t\t\t\tsierra_view.bib_view\r\n\t\t\tINNER JOIN \r\n\t\t\t\tsierra_view.varfield_view ON bib_view.id = varfield_view.record_id\r\n\t\t\tLEFT JOIN\r\n\t\t\t\tsierra_view.leader_field ON bib_view.id = leader_field.record_id\r\n\t\t\tWHERE\r\n\t\t\t\tbib_view.record_num = '{$id}'\r\n\t\t\tORDER BY \r\n\t\t\t\tmarc_tag\r\n\t\t"); $results = $this->getResults($sql); if (count($results) == 0) { return null; } $record = new File_MARC_Record(); // let's parse a few things, shall we $result = $results[0]; $internal_id = $result[0]; // internal postgres id // leader // 0000's here get converted to correct lengths by File_MARC $leader = '00000'; // 00-04 - Record length $leader .= $this->getLeaderValue($result, 'record_status_code'); // 05 - Record status $leader .= $this->getLeaderValue($result, 'record_type_code'); // 06 - Type of record $leader .= $this->getLeaderValue($result, 'bib_level_code'); // 07 - Bibliographic level $leader .= $this->getLeaderValue($result, 'control_type_code'); // 08 - Type of control $leader .= $this->getLeaderValue($result, 'char_encoding_scheme_code'); // 09 - Character coding scheme $leader .= '2'; // 10 - Indicator count $leader .= '2'; // 11 - Subfield code count $leader .= '00000'; // 12-16 - Base address of data $leader .= $this->getLeaderValue($result, 'encoding_level_code'); // 17 - Encoding level $leader .= $this->getLeaderValue($result, 'descriptive_cat_form_code'); // 18 - Descriptive cataloging form $leader .= $this->getLeaderValue($result, 'multipart_level_code'); // 19 - Multipart resource record level $leader .= '4'; // 20 - Length of the length-of-field portion $leader .= '5'; // 21 - Length of the starting-character-position portion $leader .= '0'; // 22 - Length of the implementation-defined portion $leader .= '0'; // 23 - Undefined $record->setLeader($leader); // innovative bib record fields $bib_field = new File_MARC_Data_Field('907'); $record->appendField($bib_field); $bib_field->appendSubfield(new File_MARC_Subfield('a', $this->getFullRecordId($id))); // cataloging info fields $bib_field = new File_MARC_Data_Field('998'); $record->appendField($bib_field); $bib_field->appendSubfield(new File_MARC_Subfield('c', trim($result['cataloging_date_gmt']))); $bib_field->appendSubfield(new File_MARC_Subfield('d', trim($result['bcode1']))); $bib_field->appendSubfield(new File_MARC_Subfield('e', trim($result['bcode2']))); $bib_field->appendSubfield(new File_MARC_Subfield('f', trim($result['bcode3']))); // marc fields foreach ($results as $result) { try { // skip missing tags and 'old' 9xx tags that mess with the above if ($result['marc_tag'] == null || $result['marc_tag'] == '907' || $result['marc_tag'] == '998') { continue; } // control field if ((int) $result['marc_tag'] < 10) { $control_field = new File_MARC_Control_Field($result['marc_tag'], $result['field_content']); $record->appendField($control_field); } else { $data_field = new File_MARC_Data_Field($result['marc_tag']); $data_field->setIndicator(1, $result['marc_ind1']); $data_field->setIndicator(2, $result['marc_ind2']); $content = $result['field_content']; $content_array = explode('|', $content); foreach ($content_array as $subfield) { $code = substr($subfield, 0, 1); $data = substr($subfield, 1); if ($code == '') { continue; } $subfield = new File_MARC_Subfield($code, trim($data)); $data_field->appendSubfield($subfield); } $record->appendField($data_field); } } catch (File_MARC_Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); } } // location codes $sql = trim("\r\n\t\t\tSELECT location_code\r\n\t\t\tFROM\r\n\t\t\t\tsierra_view.bib_record_location\r\n\t\t\tWHERE\r\n\t\t\t\tbib_record_id = '{$internal_id}'\r\n\t\t"); $results = $this->getResults($sql); if (count($results) > 0) { $location_record = new File_MARC_Data_Field('907'); foreach ($results as $result) { $location_record->appendSubfield(new File_MARC_Subfield('b', trim((string) $result['location_code']))); } $record->appendField($location_record); } // item records $sql = trim("\r\n\t\t\tSELECT item_view.*\r\n\t\t\tFROM \r\n\t\t\t\tsierra_view.bib_view,\r\n\t\t\t\tsierra_view.item_view,\r\n\t\t\t\tsierra_view.bib_record_item_record_link\r\n\t\t\tWHERE \r\n\t\t\t\tbib_view.record_num = '{$id}' AND\r\n\t\t\t\tbib_view.id = bib_record_item_record_link.bib_record_id AND\r\n\t\t\t\titem_view.id = bib_record_item_record_link.item_record_id\t\t\t\t\r\n\t\t"); $results = $this->getResults($sql); foreach ($results as $result) { $item_record = new File_MARC_Data_Field('945'); $item_record->appendSubfield(new File_MARC_Subfield('l', trim($result['location_code']))); $record->appendField($item_record); } return $record; }