AEM - Make the rendered html prettier/more readable

victor_toledo_3

16-04-2020

 

Hello everyone,

does anyone know if there is a way to make the rendered html more readable?. I mean, properly tabulated and ordered.
I'm using sigthly and the markup of each component is well tabulated on the app code.
But I understand that the rendering engine is modifying that indentation and rendering an html that is not ordered and indenting.

an example

<html>
<head></head>
<body>
<div><span>
</span></div>
</body>
<footer>
<div>
</div>
</footer>
</html>

instead of something like this

 

<html>
    <head></head>
    <body>
        <div>
            <span></span>
        </div>
    </body>
    <footer>
        <div></div>
    </footer>
</html>

 

Is that posible without add an extra html processor or something similar to that?

Thanks in advance

Accepted Solutions (1)

Accepted Solutions (1)

victor_toledo_3

24-04-2020

Well finally i have a possible approach.

Thanks @Jörg_Hoh and @BrianKasingli for all your help!!
here is the filter that i created and seems to be working. And i would like to share the solution and know your opinions. 

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

@Component(immediate = true)
@Service(Filter.class)
@Properties({ @Property(name = "sling.filter.scope", value = "REQUEST"),
    @Property(name = "sling.filter.pattern", value = ".*\\.html"),
    @Property(name = "service.ranking", value = "700") })
public class HTMLFormatterFilter  extends SlingAllMethodsServlet implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // create a response wrapper to capture the original response
        CharResponseWrapper wrappedResponse = new CharResponseWrapper(
            (HttpServletResponse)response);

        chain.doFilter(request, wrappedResponse);

        // modify the response with the formatted html
        byte[] bytes = wrappedResponse.getByteArray();

        if (wrappedResponse.getContentType().contains("text/html")) {
            String out = new String(bytes);
            Document doc = Jsoup.parse(out);
            response.getOutputStream().write(doc.toString().getBytes());
        }
        else {
            response.getOutputStream().write(bytes);
        }
    }

    @Override
    public void destroy() {
        // Do nothing
    }

    private static class ByteArrayServletStream extends ServletOutputStream
    {
        ByteArrayOutputStream baos;

        ByteArrayServletStream(ByteArrayOutputStream baos)
        {
            this.baos = baos;
        }

        public void write(int param) throws IOException
        {
            baos.write(param);
        }
    }

    private static class ByteArrayPrintWriter
    {

        private ByteArrayOutputStream baos = new ByteArrayOutputStream();

        private PrintWriter pw = new PrintWriter(baos);

        private ServletOutputStream sos = new ByteArrayServletStream(baos);

        public PrintWriter getWriter()
        {
            return pw;
        }

        public ServletOutputStream getStream()
        {
            return sos;
        }

        byte[] toByteArray()
        {
            return baos.toByteArray();
        }
    }

    private static class CharResponseWrapper extends HttpServletResponseWrapper
    {
        private ByteArrayPrintWriter output;
        private boolean usingWriter;

        public CharResponseWrapper(HttpServletResponse response)
        {
            super(response);
            usingWriter = false;
            output = new ByteArrayPrintWriter();
        }

        public byte[] getByteArray()
        {
            return output.toByteArray();
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException
        {
            // will error out, if in use
            if (usingWriter) {
                super.getOutputStream();
            }
            usingWriter = true;
            return output.getStream();
        }

        @Override
        public PrintWriter getWriter() throws IOException
        {
            // will error out, if in use
            if (usingWriter) {
                super.getWriter();
            }
            usingWriter = true;
            return output.getWriter();
        }

        public String toString()
        {
            return output.toString();
        }
    }
}

 

Answers (2)

Answers (2)

BrianKasingli

MVP

18-04-2020

If you wish to pretty print CSS, JS, HTML you can utilise the JavaScript library, js-beautify. Although this solution requires customisation to your JavaScript logic.

Example Code:

let formattedHTML = window.jsbeautifier.beautify('your HTML,CSS,JS string');

Documentation can be found here for js-beautify https://www.npmjs.com/package/js-beautify

 

Jörg_Hoh

Employee

17-04-2020

Technically it's possible, but as the indentation is only relevant for a human (for better readability when debugging) and not for a machine/browser, why don't you reformat the HTML when you need it?