diff --git a/ts/adaptors/HTMLAdaptor.ts b/ts/adaptors/HTMLAdaptor.ts
index d2d0f6cb6..d6e8794b3 100644
--- a/ts/adaptors/HTMLAdaptor.ts
+++ b/ts/adaptors/HTMLAdaptor.ts
@@ -113,13 +113,22 @@ export interface MinText {
/**
* The minimum fields needed for a DOMParser
*
- * @template N The HTMLElement node class
- * @template T The Text node class
+ * @template D The Document class
*/
export interface MinDOMParser {
parseFromString(text: string, format?: string): D;
}
+/*****************************************************************/
+/**
+ * The minimum fields needed for a DOMParser
+ *
+ * @template N The HTMLElement node class
+ */
+export interface MinXMLSerializer {
+ serializeToString(node: N): string;
+}
+
/*****************************************************************/
/**
* The minimum fields needed for a Window
@@ -132,6 +141,9 @@ export interface MinWindow {
DOMParser: {
new(): MinDOMParser
};
+ XMLSerializer: {
+ new(): MinXMLSerializer;
+ };
NodeList: any;
HTMLCollection: any;
HTMLElement: any;
@@ -399,6 +411,11 @@ AbstractDOMAdaptor implements MinHTMLAdaptor {
return node.outerHTML;
}
+ public serializeXML(node: N) {
+ const serializer = new this.window.XMLSerializer();
+ return serializer.serializeToString(node) as string;
+ }
+
/**
* @override
*/
diff --git a/ts/adaptors/browserAdaptor.ts b/ts/adaptors/browserAdaptor.ts
index 3be113bb1..b86a914a9 100644
--- a/ts/adaptors/browserAdaptor.ts
+++ b/ts/adaptors/browserAdaptor.ts
@@ -30,6 +30,7 @@ declare global {
interface Window {
Document: typeof Document;
DOMParser: typeof DOMParser;
+ XMLSerializer: typeof XMLSerializer;
HTMLElement: typeof HTMLElement;
HTMLCollection: typeof HTMLCollection;
NodeList: typeof NodeList;
diff --git a/ts/adaptors/lite/Parser.ts b/ts/adaptors/lite/Parser.ts
index 90ac57310..e47412f85 100644
--- a/ts/adaptors/lite/Parser.ts
+++ b/ts/adaptors/lite/Parser.ts
@@ -345,18 +345,20 @@ export class LiteParser implements MinDOMParser {
/**
* @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 {string} The serialized element (like outerHTML)
*/
- public serialize(adaptor: LiteAdaptor, node: LiteElement): string {
+ public serialize(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING;
const CDATA = (this.constructor as typeof LiteParser).CDATA_ATTR;
const tag = adaptor.kind(node);
const attributes = adaptor.allAttributes(node).map(
(x: AttributeData) => x.name + '="' + (CDATA[x.name] ? x.value : this.protectAttribute(x.value)) + '"'
).join(' ');
+ const content = this.serializeInner(adaptor, node, xml);
const html =
- '<' + tag + (attributes ? ' ' + attributes : '') + '>'
- + (SELF_CLOSING[tag] ? '' : adaptor.innerHTML(node) + '' + tag + '>');
+ '<' + tag + (attributes ? ' ' + attributes : '')
+ + (content && !SELF_CLOSING[tag] ? `>${content}${tag}>` : xml ? '/>' : '>');
return html;
}
@@ -365,7 +367,7 @@ export class LiteParser implements MinDOMParser {
* @param {LiteElement} node The node whose innerHTML is needed
* @return {string} The serialized element (like innerHTML)
*/
- public serializeInner(adaptor: LiteAdaptor, node: LiteElement): string {
+ public serializeInner(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string {
const PCDATA = (this.constructor as typeof LiteParser).PCDATA;
if (PCDATA.hasOwnProperty(node.kind)) {
return adaptor.childNodes(node).map(x => adaptor.value(x)).join('');
@@ -374,7 +376,7 @@ export class LiteParser implements MinDOMParser {
const kind = adaptor.kind(x);
return (kind === '#text' ? this.protectHTML(adaptor.value(x)) :
kind === '#comment' ? (x as LiteComment).value :
- this.serialize(adaptor, x as LiteElement));
+ this.serialize(adaptor, x as LiteElement, xml));
}).join('');
}
diff --git a/ts/adaptors/liteAdaptor.ts b/ts/adaptors/liteAdaptor.ts
index ed02de3af..ed828f1ff 100644
--- a/ts/adaptors/liteAdaptor.ts
+++ b/ts/adaptors/liteAdaptor.ts
@@ -463,6 +463,13 @@ export class LiteAdaptor extends AbstractDOMAdaptor {
*/
outerHTML(node: N): string;
+ /**
+ * @param {N} node The HTML node whose serialized string is to be obtained
+ * @return {string} The serialized node and its content
+ */
+ serializeXML(node: N): string;
+
/**
* @param {N} node The HTML node whose attribute is to be set
* @param {string|number} name The name of the attribute to set
@@ -558,6 +564,11 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor
*/
public abstract outerHTML(node: N): string;
+ /**
+ * @override
+ */
+ public abstract serializeXML(node: N): string;
+
/**
* @override
*/
diff --git a/ts/core/MmlTree/MmlNode.ts b/ts/core/MmlTree/MmlNode.ts
index 46d88963c..8bdda1168 100644
--- a/ts/core/MmlTree/MmlNode.ts
+++ b/ts/core/MmlTree/MmlNode.ts
@@ -1231,7 +1231,7 @@ export class XMLNode extends AbstractMmlEmptyNode {
* @return {string} The serialized XML content
*/
public getSerializedXML(): string {
- return this.adaptor.outerHTML(this.xml);
+ return this.adaptor.serializeXML(this.xml);
}
/**