Skip to content

Commit 429b347

Browse files
committed
Update LiteParser's serializeXML to add xmlns attributes when needed, and protect attribute values better. (mathjax/MathJax-demos-node#58)
1 parent e798b22 commit 429b347

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

ts/adaptors/lite/Parser.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
328328
public serialize(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
329329
const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING;
330330
const tag = adaptor.kind(node);
331-
const attributes = adaptor.allAttributes(node).map(
332-
(x: AttributeData) => x.name + '="' + this.protectAttribute(x.value) + '"'
331+
const attributes = this.allAttributes(adaptor, node, xml).map(
332+
(x) => x.name + '="' + this.protectAttribute(x.value, xml) + '"'
333333
).join(' ');
334334
const content = this.serializeInner(adaptor, node, xml);
335335
const html =
@@ -341,6 +341,7 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
341341
/**
342342
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
343343
* @param {LiteElement} node The node whose innerHTML is needed
344+
* @param {boolean} xml True if XML rules should be used (e.g., self-closing tags)
344345
* @return {string} The serialized element (like innerHTML)
345346
*/
346347
public serializeInner(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
@@ -356,15 +357,54 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
356357
}).join('');
357358
}
358359

360+
/**
361+
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
362+
* @param {LiteElement} node The node to serialize
363+
* @param {boolean} xml True when producing XML, false for HTML
364+
* @return {AttributeData[]} The attribute list
365+
*/
366+
protected allAttributes(adaptor: LiteAdaptor, node: LiteElement, xml: boolean): AttributeData[] {
367+
let attributes = adaptor.allAttributes(node);
368+
const kind = adaptor.kind(node);
369+
if (!xml || (kind !== 'svg' && kind !== 'math' && kind !== 'html')) {
370+
return attributes;
371+
}
372+
//
373+
// Check for existance of xmlns attribute
374+
//
375+
for (const {name} of attributes) {
376+
if (name === 'xmlns') {
377+
return attributes;
378+
}
379+
}
380+
//
381+
// Add one of it is missing
382+
//
383+
attributes.push({
384+
name: 'xmlns',
385+
value: ({
386+
svg: 'http://www.w3.org/2000/svg',
387+
math: 'http://www.w3.org/1998/Math/MathML',
388+
html: 'http://www.w3.org/1999/xhtml'
389+
})[kind]
390+
});
391+
return attributes;
392+
}
393+
359394
/**
360395
* @param {string} text The attribute value to be HTML escaped
396+
* @param {boolean} xml True if XML rules are to be used
361397
* @return {string} The string with " replaced by entities
362398
*/
363-
public protectAttribute(text: string): string {
399+
public protectAttribute(text: string, xml: boolean): string {
364400
if (typeof text !== 'string') {
365401
text = String(text);
366402
}
367-
return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
403+
text = text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
404+
if (xml) {
405+
text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
406+
}
407+
return text;
368408
}
369409

370410
/**

0 commit comments

Comments
 (0)