Skip to content

Commit 21bcd7d

Browse files
Merge pull request #2775 from NCEAS/bugfix-1721-schema-location
Fix the setSchema location logic in EML211 model
2 parents 6d5a28f + 1b33f26 commit 21bcd7d

File tree

4 files changed

+113
-28
lines changed

4 files changed

+113
-28
lines changed

src/js/models/AppModel.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,14 @@ define(["jquery", "underscore", "backbone"], function ($, _, Backbone) {
442442
editorSerializationFormat: "https://eml.ecoinformatics.org/eml-2.2.0",
443443

444444
/**
445-
* The XML schema location the dataset editor will use when creating new EML. This should
446-
* correspond with {@link AppConfig#editorSerializationFormat}
447-
* @type {string}
448-
* @default "https://eml.ecoinformatics.org/eml-2.2.0 https://eml.ecoinformatics.org/eml-2.2.0/eml.xsd"
445+
* The XML schema location the dataset editor will use when creating
446+
* new EML. This should correspond with
447+
* {@link AppConfig#editorSerializationFormat}. Note there must be an
448+
* even number of values in this string, with each pair consisting of
449+
* a namespace URI and the schema location URL for that namespace.
450+
* @type {string}
451+
* @default "https://eml.ecoinformatics.org/eml-2.2.0
452+
* https://eml.ecoinformatics.org/eml-2.2.0/eml.xsd"
449453
* @readonly
450454
* @since 2.13.0
451455
*/

src/js/models/metadata/eml211/EML211.js

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,10 +2167,7 @@ define([
21672167
// Set base attributes
21682168
eml.attr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
21692169
eml.attr("xmlns:stmml", "http://www.xml-cml.org/schema/stmml-1.1");
2170-
eml.attr(
2171-
"xsi:schemaLocation",
2172-
"https://eml.ecoinformatics.org/eml-2.2.0 https://eml.ecoinformatics.org/eml-2.2.0/eml.xsd",
2173-
);
2170+
this.setSchemaLocation(eml);
21742171
eml.attr("packageId", this.get("id"));
21752172
eml.attr("system", emlSystem);
21762173

@@ -2373,33 +2370,31 @@ define([
23732370
* @returns {Element} The element, possibly modified
23742371
*/
23752372
setSchemaLocation(eml) {
2376-
if (!MetacatUI || !MetacatUI.appModel) {
2377-
return eml;
2378-
}
2373+
if (!MetacatUI || !MetacatUI.appModel) return eml;
23792374

2380-
const current = $(eml).attr("xsi:schemaLocation");
2381-
const format = MetacatUI.appModel.get("editorSerializationFormat");
23822375
const location = MetacatUI.appModel.get("editorSchemaLocation");
23832376

23842377
// Return now if we can't do anything anyway
2385-
if (!format || !location) {
2386-
return eml;
2387-
}
2378+
if (!location) return eml;
23882379

2389-
// Simply add if the attribute isn't present to begin with
2390-
if (!current || typeof current !== "string") {
2391-
$(eml).attr("xsi:schemaLocation", `${format} ${location}`);
2392-
2393-
return eml;
2394-
}
2395-
2396-
// Don't append if it's already present
2397-
if (current.indexOf(format) >= 0) {
2380+
const format = MetacatUI.appModel.get("editorSerializationFormat");
2381+
const current = $(eml).attr("xsi:schemaLocation")?.trim();
2382+
const isString = current && typeof current === "string";
2383+
// Must be even: a namespace URI plus the schema location
2384+
const hasEvenNumber = current?.split(/\s+/).length % 2 === 0 || false;
2385+
2386+
// Don't append if it's already present and valid
2387+
if (isString && hasEvenNumber && current?.includes(format)) return eml;
2388+
2389+
// If there is already a valid location but is missing this format,
2390+
// append it
2391+
if (current && isString && hasEvenNumber) {
2392+
$(eml).attr("xsi:schemaLocation", `${current} ${location}`);
23982393
return eml;
23992394
}
24002395

2401-
$(eml).attr("xsi:schemaLocation", `${current} ${location}`);
2402-
2396+
// In all other cases, set the schema location to just this format
2397+
$(eml).attr("xsi:schemaLocation", location);
24032398
return eml;
24042399
},
24052400

src/js/views/ImageUploaderView.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ define([
220220
// Add upload & drag and drop functionality to the dropzone div.
221221
// For config details, see: https://www.dropzonejs.com/#configuration
222222
var $dropZone = view.$(".dropzone").dropzone({
223-
url: view.model.get("imageURL") || view.model.url() || MetacatUI.appModel.getActiveAltRepo()?.objectServiceUrl,
223+
url:
224+
view.model.get("imageURL") ||
225+
view.model.url() ||
226+
MetacatUI.appModel.getActiveAltRepo()?.objectServiceUrl,
224227
acceptedFiles: "image/*",
225228
addRemoveLinks: false,
226229
maxFiles: 1,

test/js/specs/unit/models/metadata/eml211/EML211.spec.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,88 @@ define([
4444
.should.be.instanceof(EMLTaxonCoverage);
4545
});
4646
});
47+
48+
describe("setSchemaLocation", function () {
49+
const schemaLocation =
50+
"https://example.org/eml-2.2.0 https://example.org/eml-2.2.0/eml.xsd";
51+
const serializationFormat = "https://example.org/eml-2.2.0";
52+
let originalMetacatUI;
53+
54+
function mockMetacatUI(overrides = {}) {
55+
window.MetacatUI = {
56+
appModel: {
57+
get: (attr) => {
58+
if (overrides[attr]) {
59+
return overrides[attr];
60+
}
61+
if (attr === "editorSchemaLocation") return schemaLocation;
62+
if (attr === "editorSerializationFormat")
63+
return serializationFormat;
64+
return undefined;
65+
},
66+
},
67+
};
68+
}
69+
70+
function createEmlElement(initialLocation) {
71+
const element = document.createElement("eml");
72+
if (initialLocation) {
73+
$(element).attr("xsi:schemaLocation", initialLocation);
74+
}
75+
return element;
76+
}
77+
78+
beforeEach(function () {
79+
originalMetacatUI = window.MetacatUI;
80+
mockMetacatUI();
81+
});
82+
83+
afterEach(function () {
84+
window.MetacatUI = originalMetacatUI;
85+
});
86+
87+
it("sets the schema location when missing", function () {
88+
const emlElement = createEmlElement();
89+
const updated = state.eml.setSchemaLocation(emlElement);
90+
91+
expect(updated).to.equal(emlElement);
92+
expect($(emlElement).attr("xsi:schemaLocation")).to.equal(
93+
schemaLocation,
94+
);
95+
});
96+
97+
it("appends the configured schema location when other valid entries exist", function () {
98+
const existing =
99+
"http://existing.org/ns http://existing.org/schema.xsd";
100+
const emlElement = createEmlElement(existing);
101+
102+
state.eml.setSchemaLocation(emlElement);
103+
104+
expect($(emlElement).attr("xsi:schemaLocation")).to.equal(
105+
`${existing} ${schemaLocation}`,
106+
);
107+
});
108+
109+
it("does not modify the schema location when the format is already present", function () {
110+
const emlElement = createEmlElement(schemaLocation);
111+
112+
state.eml.setSchemaLocation(emlElement);
113+
114+
expect($(emlElement).attr("xsi:schemaLocation")).to.equal(
115+
schemaLocation,
116+
);
117+
});
118+
119+
it("overwrites the schema location when existing is invalid", function () {
120+
const invalidLocation = "invalid-schema-location";
121+
const emlElement = createEmlElement(invalidLocation);
122+
123+
state.eml.setSchemaLocation(emlElement);
124+
125+
expect($(emlElement).attr("xsi:schemaLocation")).to.equal(
126+
schemaLocation,
127+
);
128+
});
129+
});
47130
});
48131
});

0 commit comments

Comments
 (0)