I am configuring an API to send an email using the content of a publication as the body of the email. The text editor used for the publication save the text in HTML so I needed to convert the result into plain text. There are other questions that have gave me a solution, but I would like to keep from the original text the bold text, italic and the links. So this is what I have:
This is bold text.
This is regular text.
This is italic.
This is a link.
Then in the script I have the following function:
function htmlToText(html){
//remove code brakes and tabs
html = html.replace(/\n/g, "");
html = html.replace(/\t/g, "");
//keep html brakes and tabs
html = html.replace(/<\/td>/g, "\t");
html = html.replace(/<\/table>/g, "\n");
html = html.replace(/<\/tr>/g, "\n");
html = html.replace(/<\/p>/g, "\n");
html = html.replace(/<\/div>/g, "\n");
html = html.replace(/<\/h>/g, "\n");
html = html.replace(/<br>/g, "\n"); html = html.replace(/<br( )*\/>/g, "\n");
html = html.replace(/<a.*href="(.*?)".*>(.*?)<\/a>/gi, " $2 (Link->$1) ");
//parse html into text
var dom = (new DOMParser()).parseFromString('<!doctype html><body>' + html, 'text/html');
return dom.body.textContent;
}
That gives me some plain text with nice line breaks, but I was wondering if I could get the bold, italic and links.
Thanks.
I had some time on my hands and played around. This is what I came up with:
const copy=document.createElement("div");
copy.innerHTML=container.innerHTML.replace(/\n/g," ").replace(/[\t\n]+/g,"");
const tags={B:["**","**",1], // [<prefix>, <postfix>, <sequence-number> ]
I:["*","*",2],
H2:["##","\n",3],
P:["\n","\n",4],
DIV:["","\n",5],
TD:["","\t",6]};
[...copy.querySelectorAll(Object.keys(tags).join(","))]
.sort((a,b)=>tags[a.tagName][2]-tags[b.tagName][2])
.forEach(e=>{
const [a,b]=tags[e.tagName];
e.innerHTML=(e.matches("TD:first-child") ? "\n": a) + e.innerHTML + b;
});
console.log(copy.textContent.replace(/^ */mg,""));
<div id="container">
<H2>Second level heading</H2>
<div><div>
A <b>first div</b> with a
<a href="abc.html">link (abc)</a> and a
<p>paragraph having itself another <a href="def.html">link (def)</a> in it.</p>
</div>
</div>
And here is some more <i>"lost" text</i> ...
<table>
<tr><td>one</td><td><b>two</b></td><td>three</td></tr>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>d</td><td>e</td><td>f</td></tr>
</table>
</div>
Instead of using regexp to "parse" the html I chose to actually treat it in a DOM way: I create a new div element (copy) into which I insert the original .innerHTML. For particular element types I then define some pre- and postfixes that should surround the original .innerHTML. These are stored in tags and applied on the freshly created div element.
This is done by selecting all of the "special" elements (as specified by the tags-keys) and processing them in a given sequential order. Afterwards I simply return the .textContent of the modified copy element.
Plain text cannot really render bold or italics text decoration. For this reason I used modifiers in the markdown style (*:italics, **:bold)