You can use HtmlUnit and Jsoup. You render the html page in the browser using HtmlUnit. Then you get the computed styles going through the elements thanks to HtmlUnit. Jsoup is just here to format the html output.
You can find here a simple implementation :
public final class CssInliner {
private static final Logger log = Logger.getLogger(CssInliner.class);
private CssInliner() {
}
public static CssInliner make() {
return new CssInliner();
}
/**
* Main method
*
* @param html html to inline
*
* @return inlined html
*/
public String inline(String html) throws IOException {
try (WebClient webClient = new WebClient()) {
HtmlPage htmlPage = getHtmlPage(webClient, html);
Window window = webClient.getCurrentWindow().getScriptableObject();
for (HtmlElement htmlElement : htmlPage.getHtmlElementDescendants()) {
applyComputedStyle(window, htmlElement);
}
return outputCleanHtml(htmlPage);
}
}
/**
* Output the HtmlUnit page to a clean html. Remove the old global style tag
* that we do not need anymore. This in order to simplify of the tests of the
* output.
*
* @param htmlPage
*
* @return
*/
private String outputCleanHtml(HtmlPage htmlPage) {
Document doc = Jsoup.parse(htmlPage.getDocumentElement().asXml());
Element globalStyleTag = doc.selectFirst("html style");
if (globalStyleTag != null) {
globalStyleTag.remove();
}
doc.outputSettings().syntax(Syntax.html);
return doc.html();
}
/**
* Modify the html elements by adding an style attribute to each element
*
* @param window
* @param htmlElement
*/
private void applyComputedStyle(Window window, HtmlElement htmlElement) {
HTMLElement pj = htmlElement.getScriptableObject();
ComputedCSSStyleDeclaration cssStyleDeclaration = window.getComputedStyle(pj, null);
Map<String, StyleElement> map = getStringStyleElementMap(cssStyleDeclaration);
// apply style element to html
if (!map.isEmpty()) {
htmlElement.writeStyleToElement(map);
}
}
private Map<String, StyleElement> getStringStyleElementMap(ComputedCSSStyleDeclaration cssStyleDeclaration) {
Map<String, StyleElement> map = new HashMap<>();
for (Definition definition : Definition.values()) {
String style = cssStyleDeclaration.getStyleAttribute(definition, false);
if (StringUtils.isNotBlank(style)) {
map.put(definition.getAttributeName(),
new StyleElement(definition.getAttributeName(),
style,
"",
SelectorSpecificity.DEFAULT_STYLE_ATTRIBUTE));
}
}
return map;
}
private HtmlPage getHtmlPage(WebClient webClient, String html) throws IOException {
URL url = new URL("http://tinubuinliner/" + Math.random());
StringWebResponse stringWebResponse = new StringWebResponse(html, url);
return HTMLParser.parseHtml(stringWebResponse, webClient.getCurrentWindow());
}
}