Misha Moroshko
Misha Moroshko

Reputation: 171459

How to correct indentation in HTML string?

Given a string like this:

' \n <div id="a">\n <span class="b">\n<span>Hello</span>\n\n\n</span> <input type="text">\n  \n</div>\n '

I'd like to format it like this:

<div id="a">
  <span class="b">
    <span>Hello</span>
  </span>
  <input type="text">
</div>

i.e. the result should be: (assume 2 spaces for indentation)

'<div id="a">\n  <span class="b">\n    <span>\n      Hello\n    </span>\n  </span>\n  <input type="text">\n</div>'

What's the most elegant way to achieve this? Is there an established way to do that?

Note:

Upvotes: 23

Views: 25852

Answers (3)

dfsq
dfsq

Reputation: 193301

Here is a simple recursive function I wrote, which I think might help you to achieve what you are after.

function process(str) {

    var div = document.createElement('div');
    div.innerHTML = str.trim();

    return format(div, 0).innerHTML;
}

function format(node, level) {

    var indentBefore = new Array(level++ + 1).join('  '),
        indentAfter  = new Array(level - 1).join('  '),
        textNode;

    for (var i = 0; i < node.children.length; i++) {

        textNode = document.createTextNode('\n' + indentBefore);
        node.insertBefore(textNode, node.children[i]);

        format(node.children[i], level);

        if (node.lastElementChild == node.children[i]) {
            textNode = document.createTextNode('\n' + indentAfter);
            node.appendChild(textNode);
        }
    }

    return node;
}

Then you would use it like this:

process(str);

Here is a demo:

var str = '<div id="a"><span class="b"><span>Hello</span></span><input type="text"><p><b>b <i>italic</i></b></p></div>';

function process(str) {
  var div = document.createElement('div');
  div.innerHTML = str.trim();

  return format(div, 0).innerHTML;
}

function format(node, level) {
  var indentBefore = new Array(level++ + 1).join('  '),
    indentAfter = new Array(level - 1).join('  '),
    textNode;

  for (var i = 0; i < node.children.length; i++) {
    textNode = document.createTextNode('\n' + indentBefore);
    node.insertBefore(textNode, node.children[i]);

    format(node.children[i], level);

    if (node.lastElementChild == node.children[i]) {
      textNode = document.createTextNode('\n' + indentAfter);
      node.appendChild(textNode);
    }
  }

  return node;
}

document.querySelector('#out').innerText = process(str);
<pre id="out"></pre>

Demo: http://jsfiddle.net/1gf07wap/

Upvotes: 45

rafaelcastrocouto
rafaelcastrocouto

Reputation: 12161

Since there are lots of complains about js-beautify, I'm posting this alternative:

GIT: https://github.com/maxogden/commonjs-html-prettyprinter

DEMO: http://requirebin.com/?gist=45056f6a9b306a14ea3d

CODE:

var htmlmodule = require('html');
var str = ' \n <div id="a">\n <span class="b"><span>Hello</span></span><input type="text">\n  \n</div>\n ';
var pretty = htmlmodule.prettyPrint(str);

IF this does not work as you intend to, I recommend parsing the HTML string... for this job you can use this xmldom parseFromString... it's really simple.

Upvotes: 1

parchment
parchment

Reputation: 4002

The js-beautify tool can work with html, and has an api. It's probably the easiest way to do what you want.

After installing it with node:

var beautify_html = require('js-beautify').html;

result = beautify_html(htmlstring);

To use it in a browser, you need to include all the beautify*.js scripts in this directory and use window.html_beautify.

DEMO

Upvotes: 6

Related Questions