package cn.wangjiahang.record.util.html;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Created on 2022/10/23.
*
* @author jh.wang
*/
public class HtmlUtil implements StrPool {
private static final String startTag = "startTag";
private static final String aloneTagContent = "aloneTagContent";
private static final String style = "style";
private static final String clazz = "class";
private static final String content = "content";
private static final String extra = "extra";
//---------------------------------
public static HtmlStyle style() {
return new HtmlStyle(MapUtil.newHashMap());
}
//---------------------------------
public static class HtmlTag {
private final String tag;
private String template;
public HtmlTag(boolean nonStyle, String htmlOrTag) {
this.tag = htmlOrTag;
this.template = nonStyle ? htmlOrTag : tagTemplate(htmlOrTag, null, false);
}
public HtmlTag(String tag) {
this.tag = tag;
this.template = tagTemplate(tag, null, false);
}
public HtmlTag(String tag, String extra) {
this.tag = tag;
this.template = tagTemplate(tag, extra, false);
}
public HtmlTag(String tag, boolean aloneTag) {
this.tag = tag;
this.template = tagTemplate(tag, null, aloneTag);
}
public HtmlTag(String tag, String extra, boolean aloneTag) {
this.tag = tag;
this.template = tagTemplate(tag, extra, aloneTag);
}
private static String tagTemplate(String tag, String extra, boolean aloneTag) {
// <{startTag} style='{style}' class='{class}' {extra}{aloneTagContent}
return StrUtil.format("<{startTag} style='{style}' class='{class}' {extra}{aloneTagContent}",
MapUtil.builder(HtmlUtil.startTag, tag)
.put(HtmlUtil.extra, extra)
.put(HtmlUtil.aloneTagContent, aloneTag ? "/>" : String.format(">{content}</%s>", tag))
.build(),
false);
}
public HtmlTag appendContent(HtmlTag htmlTag) {
return appendContent(htmlTag.build());
}
public HtmlTag appendContent(String customTag, Consumer<HtmlTag> htmlTag) {
final HtmlTag custom = HtmlUtil.custom(customTag);
htmlTag.accept(custom);
return appendContent(custom);
}
public HtmlTag appendContent(String customTag, String customExtra, Consumer<HtmlTag> htmlTag) {
final HtmlTag custom = HtmlUtil.custom(customTag, customExtra);
htmlTag.accept(custom);
return appendContent(custom);
}
public HtmlTag appendContent(String content) {
this.template = StrUtil.format(this.template, MapUtil.builder(HtmlUtil.content, content + String.format("{%s}", HtmlUtil.content)).build());
return this;
}
public String content(HtmlTag htmlTag) {
return content(htmlTag.ignore());
}
public String content(String customTag, Consumer<HtmlTag> htmlTag) {
final HtmlTag custom = HtmlUtil.custom(customTag);
htmlTag.accept(custom);
return content(custom);
}
public String content(String customTag, String customExtra, Consumer<HtmlTag> htmlTag) {
final HtmlTag custom = HtmlUtil.custom(customTag, customExtra);
htmlTag.accept(custom);
return content(custom);
}
public String content(String content) {
this.template = StrUtil.format(this.template, MapUtil.builder(HtmlUtil.content, content).build());
return build();
}
public HtmlTag style(String style) {
this.template = StrUtil.format(this.template, MapUtil.builder(HtmlUtil.style, style).build());
return this;
}
public HtmlTag style(HtmlStyle htmlStyle) {
return style(htmlStyle.build());
}
public HtmlTag style(Consumer<HtmlStyle> htmlTag) {
final HtmlStyle htmlStyle = HtmlUtil.style();
htmlTag.accept(htmlStyle);
return style(htmlStyle);
}
public HtmlTag style(String name, String value) {
return style(MapUtil.builder(name, value).build());
}
public HtmlTag style(Map<String, String> mapStyle) {
return style(MapUtil.joinIgnoreNull(mapStyle, ";", ": "));
}
public HtmlTag clazz(String... clazz) {
this.template = StrUtil.format(this.template, MapUtil.builder(HtmlUtil.clazz, CollUtil.join(Convert.toList(String.class, clazz), " ")).build());
return this;
}
public HtmlTag clazz(List<String> clazzs) {
return clazz(CollUtil.join(clazzs, " "));
}
public HtmlTag extraTag(String extraTag, String value) {
return this.extraTag(MapUtil.builder(extraTag, value).build());
}
public HtmlTag extraTag(Map<String, String> value) {
for (Map.Entry<String, String> entry : value.entrySet()) {
entry.setValue(String.format("%s=\"%s\"", entry.getKey(), entry.getValue()));
}
this.template = StrUtil.format(this.template, value);
return this;
}
public HtmlTag extraTag(Consumer<Map<String, String>> htmlTag) {
final HashMap<String, String> map = MapUtil.newHashMap();
htmlTag.accept(map);
return extraTag(map);
}
private String ignore() {
String temp = this.template.replaceAll(" style='\\{style}'", "").replaceAll(" class='\\{class}'", "");
return ReUtil.replaceAll(temp, String.format("<%s.*?>", this.tag), str -> ReUtil.replaceAll(str.group(0), "(\\{[^\\}]+\\})", ""));
}
public String build() {
return ignore().replaceAll("\\{content}", "");
}
}
public static class HtmlStyle {
private final Map<String, String> styles;
private HtmlStyle(Map<String, String> styles) {
this.styles = styles;
}
public HtmlStyle append(String name, String value) {
styles.put(name, value);
return this;
}
public String build() {
return MapUtil.joinIgnoreNull(styles, ";", ": ");
}
}
//---------------------------------
public static HtmlTag custom(String tag) {
return new HtmlTag(tag);
}
public static HtmlTag custom(String tag, String extra) {
return new HtmlTag(tag, extra);
}
public static HtmlTag custom(String tag, boolean aloneTag) {
return new HtmlTag(tag, aloneTag);
}
public static HtmlTag custom(String tag, String extra, boolean aloneTag) {
return new HtmlTag(tag, extra, aloneTag);
}
public static HtmlTag custom(boolean nonStyle, String html, int repeatCount) {
return new HtmlTag(nonStyle, StrUtil.repeat(html, repeatCount));
}
public static HtmlTag div() {
return custom("div");
}
public static HtmlTag span() {
return custom("span");
}
public static HtmlTag p() {
return custom("p");
}
public static HtmlTag img() {
return custom("img", "{src} {alt} {width}", true);
}
public static HtmlTag H(int level) {
return custom(String.format("h%s", level));
}
public static HtmlTag br() {
return br(0);
}
public static HtmlTag br(int count) {
return custom(true, "<br>", count);
}
public static HtmlTag hr() {
return br(0);
}
public static HtmlTag hr(int count) {
return custom(true, "<hr>", count);
}
public static HtmlTag i() {
return custom("i");
}
public static HtmlTag a() {
return custom("a", "{href}");
}
public static HtmlTag table() {
return custom("table", "{width} {align} {height} {border}", false);
}
public static HtmlTag thead() {
return custom("thead");
}
public static HtmlTag tfoot() {
return custom("tfoot");
}
public static HtmlTag tbody() {
return custom("tbody");
}
public static HtmlTag tr() {
return custom("tr");
}
public static HtmlTag th() {
return custom("th");
}
public static HtmlTag td() {
return custom("td");
}
public static HtmlTag ul() {
return custom("ul");
}
public static HtmlTag ol() {
return custom("ol");
}
public static HtmlTag dl() {
return custom("dl");
}
public static HtmlTag li() {
return custom("li");
}
}
测试类
package cn.wangjiahang.record.util.html;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Console;
import org.junit.Test;
/**
* @author jh.wang
* @since 2022/10/30
*/
public class HtmlTest {
@Test
public void htmlBuildTest() {
StopWatch stopWatch = new StopWatch();
stopWatch.start("测试1");
final String build1 = HtmlUtil.custom("div").clazz("container", "kkk").style(HtmlUtil.style().append("color", "red")).build();
stopWatch.stop();
Console.log("{} 耗时:{} 内容:{}", stopWatch.getLastTaskName(), stopWatch.getTotalTimeMillis(), build1);
stopWatch.start("测试2");
final String build2 = HtmlUtil.div().style("position", "relative").appendContent(HtmlUtil.div().style("position: absolute; top: 0;right: 20;")).build();
stopWatch.stop();
Console.log("{} 耗时:{} 内容:{}", stopWatch.getLastTaskName(), stopWatch.getTotalTimeMillis(), build2);
stopWatch.start("测试3");
final String build3 = HtmlUtil.custom("div","{uu} {uu3}")
.style(htmlStyle -> {
htmlStyle.append("yy", "90").append("ll", "99");
}).extraTag(val -> {
val.put("uu", "88");
val.put("uu3", "88");
}).appendContent("div", "{src}", tag -> {
tag.extraTag("src", "http:xxx/de/de12").content("p", inner1 -> {
inner1.clazz("aaaa").appendContent("a", "{alt} {src}", inner2 -> {
inner2.extraTag("src", "111")
.extraTag("alt", "点击跳转")
.style(style -> style.append("color", "#666"));
});
});
})
.content("来来来来来绿绿绿绿绿绿绿绿绿绿绿绿绿");
stopWatch.stop();
Console.log("{} 耗时:{} 内容:{}", stopWatch.getLastTaskName(), stopWatch.getTotalTimeMillis(), build3);
stopWatch.start("测试4");
for (int i = 0; i < 100; i++) {
HtmlUtil.custom("div","{uu} {uu3}")
.style(htmlStyle -> {
htmlStyle.append("yy", "90").append("ll", "99");
}).extraTag(val -> {
val.put("uu", "88");
val.put("uu3", "88");
}).appendContent("div", "{src}", tag -> {
tag.extraTag("src", "http:xxx/de/de12").content("p", inner1 -> {
inner1.clazz("aaaa").appendContent("a", "{alt} {src}", inner2 -> {
inner2.extraTag("src", "111")
.extraTag("alt", "点击跳转")
.style(style -> style.append("color", "#666"));
});
});
})
.content("来来来来来绿绿绿绿绿绿绿绿绿绿绿绿绿");
}
stopWatch.stop();
Console.log("{} 耗时:{}", stopWatch.getLastTaskName(), stopWatch.getTotalTimeMillis());
}
}
// 测试1 耗时:68 内容:<div style='color: red' class='container kkk' ></div>
// 测试2 耗时:94 内容:<div style='position: relative' ><div style='position: absolute; top: 0;right: 20;' ></div></div>
// 测试3 耗时:98 内容:<div style='yy: 90;ll: 99' uu="88" uu3="88"><div src="http:xxx/de/de12"><p class='aaaa' ><a style='color: #666' alt="点击跳转" src="111"></a></p></div>来来来来来绿绿绿绿绿绿绿绿绿绿绿绿绿</div>
// 测试4 耗时:212