Skip to content

Commit c2898ec

Browse files
committed
fix: consider elements with attributes & no text to be empty
1 parent 89f1ce6 commit c2898ec

3 files changed

Lines changed: 407 additions & 474 deletions

File tree

collection-export/strict-mods-helpers.js

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,13 @@ export function createElement(doc, elementName, textContent = '', attributes = {
172172
}
173173

174174
/**
175-
* Check if an element is truly empty (no attributes, no text, all children empty)
175+
* Check if an element is truly empty (no text, all children empty)
176176
* Used by removeEmptyElements - extracted for reusability
177177
*
178178
* @param {Element} element - Element to check
179179
* @returns {boolean} True if element is completely empty
180180
*/
181181
export function isElementEmpty(element) {
182-
// Has attributes? Not empty
183-
if (element.attributes && element.attributes.length > 0) {
184-
return false
185-
}
186-
187182
// Check all child nodes
188183
for (let node of element.childNodes) {
189184
if (node.nodeType === 3) { // TEXT_NODE
@@ -197,49 +192,5 @@ export function isElementEmpty(element) {
197192
}
198193
}
199194

200-
return true // No attributes, no text, all children empty
201-
}
202-
203-
/**
204-
* Iterative alternative to recursive removeEmptyElements
205-
* More efficient for very large or deeply nested documents
206-
*
207-
* @param {Document} doc - XML DOM document
208-
* @param {string} [rootPath='//mods'] - XPath to root elements to clean
209-
* @returns {Document} Modified document
210-
*/
211-
export function removeEmptyElementsIterative(doc, rootPath = '//mods') {
212-
if (!doc) {
213-
return doc
214-
}
215-
216-
const modsElements = safeSelect(rootPath, doc)
217-
218-
for (let root of modsElements) {
219-
// Collect all elements to check (bottom-up)
220-
const elementsToCheck = []
221-
const stack = [root]
222-
223-
while (stack.length > 0) {
224-
const current = stack.pop()
225-
elementsToCheck.push(current)
226-
227-
// Add children to stack (in reverse order for correct processing)
228-
const children = Array.from(current.childNodes)
229-
.filter(n => n.nodeType === 1)
230-
.reverse()
231-
stack.push(...children)
232-
}
233-
234-
// Process bottom-up (children before parents)
235-
elementsToCheck.reverse()
236-
237-
for (let element of elementsToCheck) {
238-
if (isElementEmpty(element) && element.parentNode && element !== root) {
239-
element.parentNode.removeChild(element)
240-
}
241-
}
242-
}
243-
244-
return doc
195+
return true // No text, all children empty
245196
}

collection-export/strict-mods.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,14 @@ export function renameElement(doc, oldName, newName, xpathContext = XPATH_CONTEX
238238
for (let element of elements) {
239239
const newElement = doc.createElement(newName)
240240
copyAttributes(element, newElement)
241-
241+
242242
// Add new attributes if specified
243243
if (attributes && typeof attributes === 'object') {
244244
Object.entries(attributes).forEach(([name, value]) => {
245245
newElement.setAttribute(name, value)
246246
})
247247
}
248-
248+
249249
moveChildren(element, newElement)
250250
element.parentNode.replaceChild(newElement, element)
251251
}
@@ -254,7 +254,7 @@ export function renameElement(doc, oldName, newName, xpathContext = XPATH_CONTEX
254254
}
255255

256256
/**
257-
* Recursively remove empty elements (no attributes, no text, no meaningful children)
257+
* Recursively remove empty elements (no text, no children with text)
258258
* This prevents validation errors from empty required elements and cleans up output
259259
*
260260
* @param {Document} doc - XML DOM document
@@ -525,13 +525,13 @@ export function convertNamePartDate(doc) {
525525
for (let element of namePartDates) {
526526
const newElement = doc.createElement('namePart')
527527
newElement.setAttribute('type', 'date')
528-
528+
529529
// Copy attributes from original element
530530
copyAttributes(element, newElement)
531-
531+
532532
// Move children (text nodes and elements)
533533
moveChildren(element, newElement)
534-
534+
535535
// Replace the old element with the new one
536536
element.parentNode.replaceChild(newElement, element)
537537
}
@@ -632,7 +632,7 @@ export function toStrictMODS(xmlString) {
632632
// Remove non-standard attributes
633633
removeAttribute(doc, XPATH_CONTEXTS.ACCESS_CONDITION, 'href')
634634

635-
// Remove all empty elements (no attributes, no text, no meaningful children)
635+
// Remove all empty elements (no text, no children with text)
636636
removeEmptyElements(doc)
637637

638638
// Extract mods element and add namespace (for validation)

0 commit comments

Comments
 (0)