Skip to content

Commit 1f47aeb

Browse files
committed
feat: add syllabi subjects
temporal is semester, topic is department this also improves the genre element with better attributes and does some slight refactors elsewhere
1 parent b8cb595 commit 1f47aeb

2 files changed

Lines changed: 78 additions & 5 deletions

File tree

collection-export/syllabus.js

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,64 @@ import {
1313
} from './xml-helpers.js'
1414
import {convertPartNumbers, moveAndRenameElement, removeEmptyElements} from './strict-mods.js'
1515

16+
/**
17+
* Adds a static mods/genre = 'syllabi' element
18+
*
19+
* @param {Document} doc XML document
20+
* @returns {Document} transformed document
21+
*/
1622
export function addGenre(doc) {
1723
const genre = createElement(doc, 'genre')
18-
genre.setAttribute('type', 'aat')
24+
genre.setAttribute('authority', 'aat')
25+
genre.setAttribute('authorityURI', 'http://vocab.getty.edu/aat/')
26+
genre.setAttribute('valueURI', 'http://vocab.getty.edu/aat/300028026')
1927
genre.textContent = 'syllabi'
2028
const mods = safeSelectFirst("//mods", doc)
2129
mods.appendChild(genre)
2230

2331
return doc
2432
}
2533

34+
/**
35+
* semester -> mods/subject/temporal
36+
* local/department -> strip degree postfix -> mods/subject/topic
37+
*
38+
* @param {Document} doc XML document
39+
* @returns {Document} transformed document
40+
*/
41+
export function addSubjects(doc) {
42+
const semester = safeSelectFirst("//local/courseInfo/semester", doc)
43+
const department = safeSelectFirst("//local/department", doc)
44+
const mods = safeSelectFirst("//mods", doc)
45+
46+
if (semester) {
47+
const temporal = createElement(doc, 'temporal')
48+
temporal.textContent = semester.textContent
49+
let subjectParent = safeSelectFirst("//mods/subject", doc)
50+
if (!subjectParent) {
51+
subjectParent = createElement(doc, 'subject')
52+
mods.appendChild(subjectParent)
53+
}
54+
subjectParent.appendChild(temporal)
55+
}
56+
57+
if (department) {
58+
// TODO we could have a better map of department names to subject terms with URIs
59+
// TODO terms like "Individualized" are not informative
60+
const topic = createElement(doc, 'topic')
61+
// Strip degree postfixes like " (BFA)" or " (MFA)"
62+
topic.textContent = department.textContent.trim().replace(/\s+\([A-Z]+\)$/, '')
63+
let subjectParent = safeSelectFirst("//mods/subject", doc)
64+
if (!subjectParent) {
65+
subjectParent = createElement(doc, 'subject')
66+
mods.appendChild(subjectParent)
67+
}
68+
subjectParent.appendChild(topic)
69+
}
70+
71+
return doc
72+
}
73+
2674
/**
2775
* local/courseInfo/courseNumer & course -> mods/titleInfo/title
2876
* local/courseInfo/semester -> mods/part/partNumber
@@ -53,8 +101,10 @@ export function fixSyllabusTitle(doc) {
53101
titleInfo.appendChild(title)
54102

55103
// Add partNumber for semester
56-
if (hasDirectTextContent(semester)) {
57-
moveAndRenameElement(doc, "//local/courseInfo/semester", '//mods/titleInfo', 'partNumber')
104+
if (semester) {
105+
const partNumber = createElement(doc, 'partNumber')
106+
partNumber.textContent = semester.textContent
107+
titleInfo.appendChild(partNumber)
58108
}
59109
}
60110

@@ -113,6 +163,9 @@ export function convertSyllabusXMLtoMODS(xmlString) {
113163
// Add syllabi genre
114164
addGenre(doc)
115165

166+
// Add subjects
167+
addSubjects(doc)
168+
116169
// Remove empty elements last, after all transformations are complete
117170
removeEmptyElements(doc)
118171

collection-export/syllabus.test.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,31 @@ import {convertSyllabusXMLtoMODS} from './syllabus.js'
66
// helper function to wrap XML in a root </xml> element
77
const x = (xml) => `<xml>${xml}</xml>`
88

9+
describe('addSubjects', () => {
10+
it('should add a temporal subject for semester', async () => {
11+
const semester = 'Fall 2026'
12+
const inputXML = x(`<local><courseInfo><semester>${semester}</semester></courseInfo></local>`)
13+
const result = convertSyllabusXMLtoMODS(inputXML)
14+
const temporal = xpath.select1('//mods/subject/temporal', result)
15+
assert.ok(temporal)
16+
assert.strictEqual(temporal.textContent, semester)
17+
})
18+
19+
it('should add a topic subject for department', async () => {
20+
const department = 'Art Education (BFA)'
21+
const inputXML = x(`<local><department>${department}</department></local>`)
22+
const result = convertSyllabusXMLtoMODS(inputXML)
23+
const topic = xpath.select1('//mods/subject/topic', result)
24+
assert.ok(topic)
25+
assert.strictEqual(topic.textContent, 'Art Education')
26+
})
27+
})
28+
929
describe('addGenre', () => {
10-
it('should add genre element with type=syllabus', async () => {
30+
it('should add syllabi genre element with authority=aat', async () => {
1131
const inputXML = x(`<mods></mods>`)
1232
const result = convertSyllabusXMLtoMODS(inputXML)
13-
const genre = xpath.select1('//mods/genre[@type="aat"]', result)
33+
const genre = xpath.select1('//mods/genre[@authority="aat"]', result)
1434
assert.ok(genre)
1535
assert.strictEqual(genre.textContent, 'syllabi')
1636
})

0 commit comments

Comments
 (0)