UNPKG

pg-rdf-to-json

Version:

Transforms RDF files from rdf-files.tar.bz2 provided by Project Gutenberg into JS/JSON objects.

224 lines 12.1 kB
import { relators } from '../input-schemas/relators.js'; import formatAgentId from './formatAgentId.js'; import formatEbookId from './formatEbookId.js'; import formatDatetime from './formatDatetime.js'; import formatDate from './formatDate.js'; import formatDescription from './formatDescription.js'; import formatInteger from './formatInteger.js'; import formatLanguage from './formatLanguage.js'; import formatStandaloneText from './formatStandaloneText.js'; import formatStandaloneResource from './formatStandaloneResource.js'; import formatValue from './formatValue.js'; import hoistStandaloneObjectValue from './hoistStandaloneObjectValue.js'; import formatAgent, { postProcessRelators } from './formatAgent.js'; import mergeMarcField, { postProcessMarcFields } from './mergeMarcField.js'; import { marcRanges } from '../input-schemas/marc.js'; import decodeStandaloneText from './decodeStandaloneText.js'; export const formatters = new Map([ [ 'rdf.ebook.about', formatEbookId ], [ 'rdf.ebook.files', hoistStandaloneObjectValue ], [ 'rdf.ebook.files.file.isFormatOf.resource', formatEbookId ], [ 'rdf.ebook.files.file.format', formatDescription ], [ 'rdf.ebook.files.file.extent', formatInteger ], [ 'rdf.ebook.files.file.modified', formatDatetime ], [ 'rdf.ebook.bookshelf', formatDescription ], [ 'rdf.ebook.subject', formatDescription ], [ 'rdf.ebook.type', formatDescription ], [ 'rdf.ebook.language', formatLanguage ], [ 'rdf.ebook.alternative', formatStandaloneText ], [ 'rdf.ebook.downloads', formatInteger ], [ 'rdf.ebook.rights', formatStandaloneText ], [ 'rdf.ebook.license', formatStandaloneResource ], [ 'rdf.ebook.title', decodeStandaloneText ], [ 'rdf.ebook.description', formatStandaloneText ], [ 'rdf.ebook.tableOfContents', formatStandaloneText ], [ 'rdf.ebook.publisher', formatStandaloneText ], [ 'rdf.ebook.issued', formatDate ], ...agentRules('rdf.ebook.creator'), ]); /** * The rules necessary to produce a valid `TaggedAgent` at the passed `path`. * @param path the pass to the single agnet or array of agents. */ function agentRules(path) { return [ [ path, formatAgent, ], [ `${path}.agent.about`, formatAgentId ], [ `${path}.resource`, formatAgentId ], [ `${path}.agent.name`, formatStandaloneText ], [ `${path}.agent.birthdate`, formatInteger ], [ `${path}.agent.deathdate`, formatInteger ], [ `${path}.agent.alias`, formatStandaloneText ], [ `${path}.agent.webpage`, formatStandaloneResource ] ]; } for (const [relator] of relators) { for (const [path, formatter] of agentRules(`rdf.ebook.${relator}`)) { formatters.set(path, formatter); } } for (const [start, end] of marcRanges) { for (let i = start; i <= end; i++) { formatters.set(`rdf.ebook.marc${i.toString().padStart(3, '0')}`, [formatStandaloneText, mergeMarcField]); } } function postProccessObject(newObject, original) { // This fixes the extremely rare case of a book having multiple titles, // without those titles using the alternative element like they should. if (Array.isArray(newObject.rdf.ebook.title)) { const moreAlternatives = newObject.rdf.ebook.title.slice(1); newObject.rdf.ebook.title = newObject.rdf.ebook.title[0]; if (Array.isArray(newObject.rdf.ebook.alternative)) { newObject.rdf.ebook.alternative = moreAlternatives.concat(newObject.rdf.ebook.alternative); } else { newObject.rdf.ebook.alternative = moreAlternatives; } } // `subject` is a common enough field that I'd rather it always be set and // empty, than the field itself being conditional. if (!Object.hasOwn(newObject.rdf.ebook, 'subject')) { newObject.rdf.ebook.subject = []; } // `bookshelf` is a common enough field that I'd rather it always be set and // empty, than the field itself being conditional. if (!Object.hasOwn(newObject.rdf.ebook, 'bookshelf')) { newObject.rdf.ebook.bookshelf = []; } // `files` is extremely commonly set, so just guarantee it. if (!Object.hasOwn(newObject.rdf.ebook, 'files')) { newObject.rdf.ebook.files = []; } // Store all found relators on against a single array. postProcessRelators(newObject, original); // Store all found marc fields against a single object. postProcessMarcFields(newObject, original); return newObject; } /** * Accepts a parsed, but not formatted RDF file. It isn't possible _just_ using * `fast-xml-parser` to move keys and values around. This additional formatting * step reduces the complexity of the parsed XML object by: * * * reducing the depth of unnecessesarily nested objects. * * converting certain values into more suitable data types. * * grouping similar fields like MARC fields. * * enforcing structural rules e.g. `files` **must** be defined. * * This function recursively goes through the `original` object, returning a * deep clone of it, but with every single one of its values parsed where a * parser for the path has been defined. * * If the `original` object looks like this: * * ```json * { * "title": "hello", * "desciption": { * "short": "a short description", * "long": "a long description" * } * } * ``` * * And a formatter has been defined that applies to the path * `description.short`, but no others have been defined, then only that single * value will be parsed. Every other value will be added to the new object * without any changes. * * The formatters applied to the `original` object is defined at * {@link formatters}. * * @param original The parsed, but unformatted RDF file. * @returns A formatted RDF file. */ export function formatRDFFile(original) { const newObject = {}; for (const [key, val] of Object.entries(original)) { newObject[key] = formatValue(key, val, key, original); } return postProccessObject(newObject, original); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0dGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mb3JtYXR0ZXJzL2Zvcm1hdHRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBTXhELE9BQU8sYUFBYSxNQUFNLG9CQUFvQixDQUFDO0FBQy9DLE9BQU8sYUFBYSxNQUFNLG9CQUFvQixDQUFDO0FBQy9DLE9BQU8sY0FBYyxNQUFNLHFCQUFxQixDQUFDO0FBQ2pELE9BQU8sVUFBVSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8saUJBQWlCLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxhQUFhLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxjQUFjLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxvQkFBb0IsTUFBTSwyQkFBMkIsQ0FBQztBQUM3RCxPQUFPLHdCQUF3QixNQUFNLCtCQUErQixDQUFDO0FBQ3JFLE9BQU8sV0FBVyxNQUFNLGtCQUFrQixDQUFDO0FBQzNDLE9BQU8sMEJBQTBCLE1BQU0saUNBQWlDLENBQUM7QUFDekUsT0FBTyxXQUFXLEVBQUUsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3BFLE9BQU8sY0FBYyxFQUFFLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxvQkFBb0IsTUFBTSwyQkFBMkIsQ0FBQztBQUk3RCxNQUFNLENBQUMsTUFBTSxVQUFVLEdBQTBCLElBQUksR0FBRyxDQUFDO0lBQ3ZEO1FBQ0UsaUJBQWlCO1FBQ2pCLGFBQWE7S0FDZDtJQUNEO1FBQ0UsaUJBQWlCO1FBQ2pCLDBCQUEwQjtLQUMzQjtJQUNEO1FBQ0UsMENBQTBDO1FBQzFDLGFBQWE7S0FDZDtJQUNEO1FBQ0UsNkJBQTZCO1FBQzdCLGlC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