Your achievements

Level 1

0% to

Level 2

Tip /
Sign in

Sign in to Community

to gain points, level up, and earn exciting badges like the new
Bedrock Mission!

Learn more

View all

Sign in to view all badges

SOLVED

AEM - Make the rendered html prettier/more readable

victor_toledo_3
Level 3
Level 3

 

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

1 Accepted Solution
victor_toledo_3
Correct answer by
Level 3
Level 3

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();
        }
    }
}

 

View solution in original post

4 Replies
Jörg_Hoh
Employee
Employee

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?

victor_toledo_3
Level 3
Level 3
Hi @Jörg_Hoh, yes i know, this is a client requirement, they want to have a "better" html for debugging propose and compare with their Front End code. I just trying to test some posible solution and see if it makes sense or we will have a performance decrease
Jörg_Hoh
Employee
Employee
I guess that's it is possible, but I've never done that, also I don't know a good library for it. If you have found one, I would try to implement it in the rewriter pipeline (as the last rewriter). The performance impact is probably negligible (depends on the performance of that library).
victor_toledo_3
Level 3
Level 3
Hi @Jörg_Hoh, And how could I make it last in the rewriter pipeline, perhaps with a java filter? Briankasingli shared me this one https://mkyong.com/java/java-pretty-print-html
Jörg_Hoh
Employee
Employee
What you can do: Implement a filter, capture the complete output in a string and then apply the reformatting. Just be sure that you do that only for HTML; also it breaks the streaming approach of the result (sending the response to the browser starts when the last byte of the response has been created).
BrianKasingli
Community Advisor
Community Advisor

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

 

victor_toledo_3
Level 3
Level 3
Hi @BrianKasingli, thanks for your response. But i would like to it on the render process and not add an extra process on the client side.
victor_toledo_3
Level 3
Level 3
I will try with that lib and see the results, thank you very much!
victor_toledo_3
Correct answer by
Level 3
Level 3

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();
        }
    }
}

 

View solution in original post