Skip to content

Commit 96c1018

Browse files
authored
Merge pull request #1046 from mathjax/xml-fixes
Update LiteParser's serializeXML. (mathjax/MathJax-demos-node#58)
2 parents 65944ab + a4875e8 commit 96c1018

File tree

1 file changed

+53
-4
lines changed

1 file changed

+53
-4
lines changed

ts/adaptors/lite/Parser.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
9191
script: true
9292
};
9393

94+
public static XMLNS: {[name: string]: string} = {
95+
svg: 'http://www.w3.org/2000/svg',
96+
math: 'http://www.w3.org/1998/Math/MathML',
97+
html: 'http://www.w3.org/1999/xhtml'
98+
};
99+
94100
/**
95101
* @override
96102
*/
@@ -328,8 +334,8 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
328334
public serialize(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
329335
const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING;
330336
const tag = adaptor.kind(node);
331-
const attributes = adaptor.allAttributes(node).map(
332-
(x: AttributeData) => x.name + '="' + this.protectAttribute(x.value) + '"'
337+
const attributes = this.allAttributes(adaptor, node, xml).map(
338+
(x) => x.name + '="' + this.protectAttribute(x.value, xml) + '"'
333339
).join(' ');
334340
const content = this.serializeInner(adaptor, node, xml);
335341
const html =
@@ -341,6 +347,7 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
341347
/**
342348
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
343349
* @param {LiteElement} node The node whose innerHTML is needed
350+
* @param {boolean} xml True if XML rules should be used (e.g., self-closing tags)
344351
* @return {string} The serialized element (like innerHTML)
345352
*/
346353
public serializeInner(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
@@ -356,15 +363,57 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
356363
}).join('');
357364
}
358365

366+
/**
367+
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
368+
* @param {LiteElement} node The node to serialize
369+
* @param {boolean} xml True when producing XML, false for HTML
370+
* @return {AttributeData[]} The attribute list
371+
*/
372+
protected allAttributes(adaptor: LiteAdaptor, node: LiteElement, xml: boolean): AttributeData[] {
373+
let attributes = adaptor.allAttributes(node);
374+
//
375+
// If we aren't in XML mode, just use the attributes given
376+
//
377+
if (!xml) {
378+
return attributes;
379+
}
380+
//
381+
// Check that we know the namespace for the kind of node
382+
//
383+
const kind = adaptor.kind(node);
384+
const xmlns = (this.constructor as typeof LiteParser).XMLNS;
385+
if (!xmlns.hasOwnProperty(kind)) {
386+
return attributes;
387+
}
388+
//
389+
// Check for existance of xmlns attribute
390+
//
391+
for (const {name} of attributes) {
392+
if (name === 'xmlns') {
393+
return attributes;
394+
}
395+
}
396+
//
397+
// Add one of it is missing
398+
//
399+
attributes.push({name: 'xmlns', value: xmlns[kind]});
400+
return attributes;
401+
}
402+
359403
/**
360404
* @param {string} text The attribute value to be HTML escaped
405+
* @param {boolean} xml True if XML rules are to be used
361406
* @return {string} The string with " replaced by entities
362407
*/
363-
public protectAttribute(text: string): string {
408+
public protectAttribute(text: string, xml: boolean): string {
364409
if (typeof text !== 'string') {
365410
text = String(text);
366411
}
367-
return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
412+
text = text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
413+
if (xml) {
414+
text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
415+
}
416+
return text;
368417
}
369418

370419
/**

0 commit comments

Comments
 (0)