I am working with the blob API in the latest Chrome and would like to have the following XML DOM added to a new empty object URL:
<root>
<Title>
<H1>A Title</H1>
<H2>A Subtitle</H2>
Some text or other elements<BR/>
</Title>
</root>
This piece of XML is selected by the user with their mouse from a content editable DIV. Then I convert that selection into an XML DOM like so:
var n_parser = new DOMParser; //new parser
var small_xml_string = "<root>" + window.getSelection().toString() + "</root>"; //add a root node
var small_xml_obj = n_parser.parseFromString(small_xml_string.replace(/\n/g, ""), "text/xml"); //convert user selection to string then to an XML DOM while removing some expected newlines below the selection
The DOMParser however fails to convert any nodes to XML that would have any HTML tags in them, resulting in the following DOM:
<root>
</Title>
</root>
I've tried escaping the the HTML entities but the parser still behaves the same. This was the code I created to try and deal with entities:
var unencoded_title =
small_xml_string.toString().substring(
small_xml_string.toString().indexOf("<Title>") + 7,
small_xml_string.toString().indexOf("</Title>")
);//Find the string between the title tags
var encoded_title_lt = unencoded_title.replace(/</g, "<");//replace the "<" with "<"
var encoded_title = encoded_title_lt.replace(/>/g, ">");//replace the ">" with ">"
xml_dom.getElementsByTagName("Title")[0].childNodes[0].nodeValue = encoded_title //Add the encoded string to the node, replacing what's there
Note that "xml_dom" is a ready DOM that looks like this:
<root>
<Title>Example
</Title>
</root>
The resulting DOM though is exactly the same as if I'd passed the HTML tags in. Users will be adding HTML tags like line breaks and superscript to the input. How can I process HTML tags in the user input, ready to pass to the blob api?
Your issue is in getSelection().toString() this will return the text content of the actual selection. What you want is Range.cloneContents(), which gets a copy of the DOM structure:
document.querySelector("button").onclick = evt => {
const sel = getSelection();
const range = sel.rangeCount && sel.getRangeAt(0);
const content = range.cloneContents?.();
const xml = new DOMParser().parseFromString(`<root>
<Title/>
</root>`, "text/xml");
xml.querySelector("Title").append(content||"");
console.log(new XMLSerializer().serializeToString(xml));
};
Select the content below:
<H1>A Title</H1>
<H2>A Subtitle</H2>
Some text or other elements<BR/>
<button>log</button>