UNPKG

marc4js

Version:

a node.js module for handling MARC data

141 lines (126 loc) 4.54 kB
'use strict'; var clarinet = require('clarinet'); var util = require('util'); var Transform = require('stream').Transform; var Record = require('../marc/record'); var ControlField = require('../marc/control_field'); var DataField = require('../marc/data_field'); var Subfield = require('../marc/subfield'); var Leader = require('../marc/leader'); function MijParser (opts) { if (!(this instanceof MijParser)) return new MijParser(opts); opts = opts || {}; opts.objectMode = true; // this has to be true. Emit only Record objects opts.highWaterMark = 16; // max. # of output records buffered Transform.call(this, opts); this.init(); // See https://github.com/dscape/clarinet for more info this.stream = clarinet.createStream({}); this.stream.on('error', this.handleSaxError.bind(this)); this.stream.on('openobject', this.handleOpenObject.bind(this)); this.stream.on('closeobject',this.handleCloseObject.bind(this)); this.stream.on('value', this.handleValue.bind(this)); this.stream.on('key', this.handleKey.bind(this)); this.stream.once('end', this.handleEnd.bind(this)); } util.inherits(MijParser, Transform); MijParser.prototype.init = function (){ this.stack = []; this.keyStack = []; this.previous = ''; this.arrayStack = []; }; MijParser.prototype.handleEnd = function (){ this.stream.removeListener('error', this.handleSaxError.bind(this)); this.stream.removeListener('openobject', this.handleOpenObject.bind(this)); this.stream.removeListener('closeobject',this.handleCloseObject.bind(this)); this.stream.removeListener('value', this.handleValue.bind(this)); this.stream.removeListener('key', this.handleKey.bind(this)); this.push(null); }; MijParser.prototype.handleSaxError = function (e) { this.emit('error', e); if (this.options.resume_saxerror) { if (this.stream._parser) { this.stream._parser.error = null; this.stream._parser.resume(); } } }; MijParser.prototype.handleError = function (e){ this.emit('error', e); }; MijParser.prototype.handleOpenObject = function (key){ this.previous = key; this.keyStack.push(key); var obj = null; if (/\d{3}/.test(key)) { // field obj = parseInt(key) < 10 ? new ControlField() : new DataField(); obj.tag = key; } else if (key.length == 1) { // subfield obj = new Subfield(); obj.code = key; } else if (key == 'leader' || key == 'fields') { obj = new Record(); } if (obj != null) this.stack.push(obj); }; MijParser.prototype.handleCloseObject = function (){ var key = this.keyStack.pop(); if (key == 'subfields' || key == 'fields') { return; } var obj = this.stack.pop(); if (obj instanceof Subfield) { var field = this.stack.pop(); field.addSubfield(obj); this.stack.push(field); } else if (obj instanceof ControlField || obj instanceof DataField) { var record = this.stack.pop(); record.addVariableField(obj); this.stack.push(record); } else if (obj instanceof Record) { if (this.arrayStack.length == 0 || this.arrayStack[this.arrayStack.length-1] == '') { this.previous = ''; this.push(obj); } } }; MijParser.prototype.handleValue = function(value) { if (this.previous == 'ind1') { var field = this.stack.pop(); field.indicator1 = value; this.stack.push(field); } else if (this.previous == 'ind2') { var field = this.stack.pop(); field.indicator2 = value; this.stack.push(field); } else if (this.previous.length == 1) { var subfield = this.stack.pop(); subfield.data = value; this.stack.push(subfield); } else if (/\d{3}/.test(this.previous)) { var field = this.stack.pop(); field.data = value; this.stack.push(field); } else if (this.previous == 'leader') { var leader = new Leader(value); var record = this.stack.pop(); record.leader = leader; this.stack.push(record); } }; MijParser.prototype.handleKey = function (key){ this.previous = key; }; // Naive Stream API MijParser.prototype._transform = function (data, encoding, done) { try { this.stream.write(data); done(); } catch (e) { done(e); this.push(null); // Manually trigger and end, since we can't reliably do any more parsing } }; module.exports = MijParser;