XHTML Output
RichTextEditor saves HTML— there is no XHTML mode built in. When a publishing pipeline needs stricter markup you convert on the way out, and the browser does almost all of it: parse as HTML, serialise as XML. This page runs that conversion live and re-parses the result as XML to prove it is well-formed.
Edit here and watch the XHTML below update.
Void elements are the interesting part — a line break,
an image
, and an
unquoted-attribute link.
- List item
XHTML produced from the saved HTML
Loading…
The converter
function htmlToXHTML(html) {
// Parse as HTML (forgiving), serialise as XML (strict). The browser does
// the hard part: void elements come back self-closed, attribute values are
// quoted, and tag names are lower-cased.
const doc = new DOMParser().parseFromString(html, "text/html");
const xml = new XMLSerializer().serializeToString(doc.body);
return xml
// Drop the wrapper the serialiser adds around body.
.replace(/^<body[^>]*>/, "").replace(/<\/body>$/, "")
// XHTML wants a space before the self-closing slash.
.replace(/([^ ])\/>/g, "$1 />")
.trim();
}
// XHTML only accepts five named entities, so anything else must be numeric.
function toNumericEntities(s) {
return s.replace(/&(?!(?:amp|lt|gt|quot|apos|#\d+|#x[0-9a-f]+);)([a-z]+);/gi,
(m, name) => {
const el = document.createElement("textarea");
el.innerHTML = m;
const ch = el.value;
return ch.length === 1 ? "&#" + ch.charCodeAt(0) + ";" : m;
});
}
const xhtml = toNumericEntities(htmlToXHTML(editor.getHTMLCode()));Two details the serialiser will not do for you: XHTML recognises only five named entities, so everything else has to become numeric, and if you are emitting a full document you still need the XML declaration and an xmlns on the root element.