Skip to content

Commit

Permalink
Merge pull request #1046 from mathjax/xml-fixes
Browse files Browse the repository at this point in the history
Update LiteParser's serializeXML.  (mathjax/MathJax-demos-node#58)
  • Loading branch information
dpvc authored Feb 6, 2024
2 parents 65944ab + a4875e8 commit 96c1018
Showing 1 changed file with 53 additions and 4 deletions.
57 changes: 53 additions & 4 deletions ts/adaptors/lite/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
script: true
};

public static XMLNS: {[name: string]: string} = {
svg: 'http://www.w3.org/2000/svg',
math: 'http://www.w3.org/1998/Math/MathML',
html: 'http://www.w3.org/1999/xhtml'
};

/**
* @override
*/
Expand Down Expand Up @@ -328,8 +334,8 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
public serialize(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING;
const tag = adaptor.kind(node);
const attributes = adaptor.allAttributes(node).map(
(x: AttributeData) => x.name + '="' + this.protectAttribute(x.value) + '"'
const attributes = this.allAttributes(adaptor, node, xml).map(
(x) => x.name + '="' + this.protectAttribute(x.value, xml) + '"'
).join(' ');
const content = this.serializeInner(adaptor, node, xml);
const html =
Expand All @@ -341,6 +347,7 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
/**
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
* @param {LiteElement} node The node whose innerHTML is needed
* @param {boolean} xml True if XML rules should be used (e.g., self-closing tags)
* @return {string} The serialized element (like innerHTML)
*/
public serializeInner(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
Expand All @@ -356,15 +363,57 @@ export class LiteParser implements MinDOMParser<LiteDocument> {
}).join('');
}

/**
* @param {LiteAdaptor} adaptor The adaptor for managing nodes
* @param {LiteElement} node The node to serialize
* @param {boolean} xml True when producing XML, false for HTML
* @return {AttributeData[]} The attribute list
*/
protected allAttributes(adaptor: LiteAdaptor, node: LiteElement, xml: boolean): AttributeData[] {
let attributes = adaptor.allAttributes(node);
//
// If we aren't in XML mode, just use the attributes given
//
if (!xml) {
return attributes;
}
//
// Check that we know the namespace for the kind of node
//
const kind = adaptor.kind(node);
const xmlns = (this.constructor as typeof LiteParser).XMLNS;
if (!xmlns.hasOwnProperty(kind)) {
return attributes;
}
//
// Check for existance of xmlns attribute
//
for (const {name} of attributes) {
if (name === 'xmlns') {
return attributes;
}
}
//
// Add one of it is missing
//
attributes.push({name: 'xmlns', value: xmlns[kind]});
return attributes;
}

/**
* @param {string} text The attribute value to be HTML escaped
* @param {boolean} xml True if XML rules are to be used
* @return {string} The string with " replaced by entities
*/
public protectAttribute(text: string): string {
public protectAttribute(text: string, xml: boolean): string {
if (typeof text !== 'string') {
text = String(text);
}
return text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
text = text.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
if (xml) {
text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
return text;
}

/**
Expand Down

0 comments on commit 96c1018

Please sign in to comment.