html转出String,这个用io流就可以实现,比较简单,就不贴代码。主要是如何将string转成json
parseHtml方法,并附上需要导入的包
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
/**
* 传入html数据转换成为Documentation对象返回
* @param htmlStr
* @return
*/
public static Documentation parseHtml(String htmlStr, Documentation documentation, Integer id) {
Document doc = Jsoup.parse(htmlStr);//解析HTML字符串返回一个Document实现
//进入了这里说明解析出的文档是一个有数据可显示的信息,创建Documentation对象在解析完成的时候返回到Contraller层中以便存入数据库
//获取所有的META信息
Elements mates = doc.select("META");
for (Element mate : mates) {
switch (mate.attr("NAME")) {
case "AUTHOR":
documentation.setAuthorUsername(mate.attr("CONTENT"));
break;
}
}
JSONArray jsonArray = new JSONArray(); //这个JSONArray封装最终结果
JSONObject object = null;
Elements children = doc.select("body").first().children(); //取出转换后的所有的body标签下的子元素
for (Element element : children) {
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("h1")) {
object = new JSONObject();
object.put("type", "h1"); //一级标题
object.put("data", element.text());
jsonArray.put(object);
}
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("h2")) {
object = new JSONObject();
object.put("type", "h2"); 二级标题
object.put("data", element.text());
jsonArray.put(object);
}
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("h3")) {
object = new JSONObject();
object.put("type", "h3"); //三级标题
object.put("data", element.text());
jsonArray.put(object);
}
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("ul")) { //解析无序列表
object = new JSONObject();
object.put("type", "ul");
Elements elements = element.select("li");
JSONArray liDatas = new JSONArray();
for (Element liElement : elements) {
JSONObject liObject = new JSONObject();
if (liElement.select("img").size() > 0) { //li标签下嵌套有图片
JSONObject jsonObject = new JSONObject();
liObject.put("data", imageParagraph(liElement.child(0), jsonObject, id));
} else {
liObject.put("data", liElement.text());
}
liObject.put("type", "li");
liDatas.put(liObject);
}
object.put("data", liDatas);
jsonArray.put(object);
}
//System.out.println("isOl:"+(!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("ol")));
//System.out.println("isTable:"+(!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("table")));
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("ol")) {//解析有序列表
object = new JSONObject();
object.put("type", "ol"); //有序列表标签
System.out.println("startElement:"+element.absUrl("start"));
System.out.println("startElementIsNotBlank:"+StringUtils.isNotBlank(element.attr("start")));
if (StringUtils.isNotBlank(element.attr("start"))) {
System.out.println("startNotBlank");
object.put("start", element.attr("start"));
}
//特殊情况ol有嵌套且ol属性在第二层ol标签里
if (element.children().size() == 1 && element.child(0).tagName().equalsIgnoreCase("ol") && StringUtils.isNotBlank(element.child(0).attr("start"))) {
object.put("start", element.child(0).attr("start"));
}
JSONArray liDatas = new JSONArray();
JSONObject liObject = null;
Elements elements = element.select("li");
if (elements.size() <= 1) {
Elements h1Elements = elements.first().getElementsByTag("h1");
if (null != h1Elements && h1Elements.size() > 0) { // 如果属于ol下的li中但是包含h1标签,则将其优先当作一级文档标签解析
object.put("type", "h1");
object.put("data", elements.text());
}
}
for (Element liElement : elements) {
liObject = new JSONObject();
if (liElement.select("img").size() > 0) { //li标签下嵌套有图片
JSONObject jsonObject = new JSONObject();
liObject.put("data", imageParagraph(liElement.child(0), jsonObject, id));
} else {
liObject.put("data", liElement.text());
}
liObject.put("type", "li");
liDatas.put(liObject);
}
object.put("data", liDatas);
jsonArray.put(object);
}
if (element.tagName().equalsIgnoreCase("P")) { //进入P标签解析下可能是文字可能是包裹的图片
object = new JSONObject();
if (!StringUtils.isBlank(element.text())) {
object.put("type", "paragraph"); //段落
object.put("align", element.attr("align"));
object.put("data", element.text());
if ("版权声明".equals(element.text())) {
object.put("type", "copyrightTitle"); //版权声明标题
}
if (element.text().trim().startsWith("Copyright")) {
object.put("type", "copyrightNotice"); //版权声明标题
documentation.setCopyright(element.text());
}
//段落内容不为空,但是段落标签中包含img子表情则会解析为段落图片混合的段落
if (element.select("img").size() > 0) {
object = imageParagraph(element, object, id);
}
} else {
Element imgElement = element.select("img").first();
if (null != imgElement) {
object.put("type", "img"); //图片
object.put("src", "/upload/" + id + "/" + imgElement.attr("src"));
object.put("align", imgElement.attr("align"));
object.put("width", imgElement.attr("width"));
object.put("height", imgElement.attr("height"));
object.put("border", imgElement.attr("border"));
}
}
if (!object.isNull("type") && without(object)) { //json对象中不为空则加入返回结构体中
jsonArray.put(object);
}
}
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("TABLE")) {
object = new JSONObject();
// //TODO 需求过滤掉版本修改表
// String theadText = element.select("tbody").first().select("tr").first().select("p").text();
// if (theadText.indexOf("日期") != -1 && theadText.indexOf("版本号") != -1) {
// continue;
// }
//放入专门解析table的函数中执行
object = filteringAndParseTableTag(element, object, id);
if (null != object) {
jsonArray.put(object);
}
}
if (!StringUtils.isBlank(element.text()) && element.tagName().equalsIgnoreCase("IMG")) {
object = new JSONObject();
object.put("type", "img"); //段落
object.put("data", "/upload/" + id + "/" + element.attr("SRC"));
jsonArray.put(object);
}
}
documentation.setContent(jsonArray.toString());
return documentation;
}
Documentation对象是将存json,并返回出去。id是指这个转成json的html页面的唯一id。具体情况具体使用
专门解析table的函数:
/**
* 过滤并解析Table标签
* //TODO 这个函数还有对表格单元格中嵌套表格的情况没有判断后面再进行分析
* table的内容需要细分,有1)table图文类型,2)API类型,3)代码示例类型(codeView),4)函数类型,5)普通的table类型
*
* @param element
*/
private static JSONObject filteringAndParseTableTag(Element element, JSONObject object, Integer id) {
//先判断是否是左右图结构
if (element.select("colgroup").size() > 0) {
//可能是图文或者是函数
Element colgroup = element.select("colgroup").first();
//System.out.println("col:" + colgroup.select("col").size() + "");
if (colgroup.select("col").size() == 2) {//可能是图文可能是简单表格结构
//TODO 这里后面要重构,判断接单表格类型和图文类型
Elements elements = element.select("tbody").first().select("tr").first().getElementsByTag("img");
if (null != elements && elements.size() > 0 && element.select("tr").size() == 1 && element.select("td").size() == 2) { //图文类型
return graphicType(element, object, id);
}
} else if (element.select("colgroup").size() == 1) { //代码实例类型colgroup为1,且tr只有两行(标题和代码实例)
if (element.select("tr").size() == 2 && element.select("tr").select("td").size() == 2 && element.select("img").size() == 0) {
return tableForCodeView(element, object);
}
}
String theadText = element.select("tbody").first().select("tr").first().select("p").text();
theadText = theadText.replaceAll(" ", "");
if (theadText.indexOf("原型") != -1 || theadText.indexOf("prototype") != -1) { //方法函数原型
return wholeTable(element, object, "Function", id);
}
//如果table标签不满如上述的任何一种,则进入table完全解析的方法中来
return wholeTable(element, object, id);
}
return null;
}
grahicType():
/**
* 构建图文表格信息
*
* @param element
* @param object
*/
public static JSONObject graphicType(Element element, JSONObject object, Integer id) {
//通过colgroup下col标签个数可以确定是只有2个的是图文类型,判断是哪种类型的图文边框
object.put("type", "Graphic");
if (element.attr("bordercolor").equals(Constants.NOTE_BORDERCOLOR)) {
object.put("className", "graphicBg1");
} else if (element.attr("bordercolor").equals(Constants.CAUTION_BORDERCOLOR)) {
object.put("className", "graphicBg2");
} else if (element.attr("bordercolor").equals(Constants.WARNING_BORDERCOLOR)) {
object.put("className", "graphicBg3");
}
//构建data结构体,该结构体是一个JSONArray
JSONArray tbodyArray = new JSONArray();
Elements tdElements = element.select("tbody").first().select("tr").first().select("td");
JSONObject tdObject = null;
for (Element td : tdElements) {
tdObject = new JSONObject();
if (td.getElementsByTag("img").size() > 0) {
tdObject.put("img", "/upload/" + id + "/" + td.getElementsByTag("img").first().attr("src"));
} else {
//帮助信息中的文字信息部分,首先会存在p标签..如果其中存在ol有序
Elements tdChildren = td.children();
JSONArray jsonArray = new JSONArray();
for (Element tdChild : tdChildren) {
if ("p".equalsIgnoreCase(tdChild.tagName())) {
JSONObject tdObject1 = new JSONObject();
tdObject1.put("type", "paragraph");
tdObject1.put("align", tdChild.attr("align"));
tdObject1.put("data", tdChild.text());
jsonArray.put(tdObject1);
}
if ("ul".equalsIgnoreCase(tdChild.tagName())) {
JSONObject tdObject2 = new JSONObject();
tdObject2.put("type", "ul"); //无序列表标签
JSONArray liDatas = new JSONArray();
Elements liElements = tdChild.select("li");
for (Element liElement : liElements) {
JSONObject liObject = new JSONObject();
liObject.put("type", "li");
liObject.put("data", liElement.text());
liDatas.put(liObject);
}
tdObject2.put("data", liDatas);
jsonArray.put(tdObject2);
}
if ("ol".equalsIgnoreCase(tdChild.tagName())) {
JSONObject tdObject3 = new JSONObject();
tdObject3.put("type", "ol"); //无序列表标签
JSONArray liDatas = new JSONArray();
Elements liElements = tdChild.select("li");
for (Element liElement : liElements) {
JSONObject liObject = new JSONObject();
liObject.put("type", "li");
liObject.put("data", liElement.text());
liDatas.put(liObject);
}
tdObject3.put("data", liDatas);
jsonArray.put(tdObject3);
}
tdObject.put("data", jsonArray);
}
}
tbodyArray.put(tdObject);
}
JSONObject dataObject = new JSONObject();
dataObject.put("tbody", tbodyArray);
object.put("data", dataObject);
return object;
}
wholeTable():
/**
* 完全解析一个表格元素
*
* @param element
* @param object
* @param type 设置解析的结果类型
* @return
*/
private static JSONObject wholeTable(Element element, JSONObject object, String type, Integer id) {
object.put("type", type);
JSONObject tdObject = null;
JSONArray tr = null;
JSONArray trs = new JSONArray();
//把element先解析tr标签,然后将tr标签循环,取出td节点数据
Elements elements = element.select("tbody").first().select(">tr");
for (Element trElement : elements) {
Elements tdElements = trElement.select(">td");
tr = new JSONArray();
for (Element tdElement : tdElements) {
//创建最里面的td对象
tdObject = new JSONObject();
int colspan = StringUtils.isBlank(tdElement.attr("colspan")) ? 1 : Integer.parseInt(tdElement.attr("colspan"));
int rowspan = StringUtils.isBlank(tdElement.attr("rowspan")) ? 1 : Integer.parseInt(tdElement.attr("rowspan"));
tdObject.put("row", rowspan);
tdObject.put("col", colspan);
tdObject.put("width", tdElement.attr("width")); //增加列宽属性
//解析td对象
if ((null != tdElement.children()) && (tdElement.children().size() > tdElement.select(">p").size())) {
//此处处理的都是td元素中都是不止是单纯文本的复杂类型
Elements tdElementChildren = tdElement.children();
JSONArray objects = new JSONArray();
for (Element tdElementChild : tdElementChildren) {
if ("p".equalsIgnoreCase(tdElementChild.tagName())) {
JSONObject tdObject1 = new JSONObject();
tdObject1.put("type", "paragraph");
tdObject1.put("align", tdElementChild.attr("align"));
tdObject1.put("data", tdElementChild.text());
objects.put(tdObject1);
}
if ("table".equalsIgnoreCase(tdElementChild.tagName())) {
JSONObject tdObject2 = new JSONObject();
tdObject2.put("type", "table");
tdObject2.put("data", normalTable(tdElementChild));
objects.put(tdObject2);
}
if ("ul".equalsIgnoreCase(tdElementChild.tagName())) {
JSONObject tdObject3 = new JSONObject();
tdObject3.put("type", "ul"); //无序列表标签
JSONArray liDatas = new JSONArray();
Elements liElements = tdElementChild.select("li");
for (Element liElement : liElements) {
JSONObject liObject = new JSONObject();
liObject.put("type", "li");
liObject.put("data", liElement.text());
liDatas.put(liObject);
}
tdObject3.put("data", liDatas);
objects.put(tdObject3);
}
System.out.println("tableOl"+("ol".equalsIgnoreCase(tdElementChild.tagName())));
if ("ol".equalsIgnoreCase(tdElementChild.tagName())) {//解析有序列表
JSONObject tdObject4 = new JSONObject();
tdObject4.put("type", "ol"); //有序列表标签
System.out.println("start:"+tdElementChild.attr("start"));
if (StringUtils.isNotBlank(tdElementChild.attr("start"))) {
//System.out.println("startNotBlank:"+tdElementChild.attr("start"));
tdObject4.put("start", tdElementChild.attr("start"));
}
//特殊情况ol有嵌套且ol属性在第二层ol标签里
if (tdElementChild.children().size() == 1 && tdElementChild.child(0).tagName().equalsIgnoreCase("ol") && StringUtils.isNotBlank(tdElementChild.child(0).attr("start"))) {
tdObject4.put("start", tdElementChild.child(0).attr("start"));
}
//判断列表的类型,eg:1,2,3 or a,b,c
System.out.println("type:"+tdElementChild.attr("type"));
if(StringUtils.isNoneBlank(tdElementChild.attr("type")))
{
//System.out.println("type:"+tdElementChild.attr("type"));
tdObject4.put("oltype", tdElementChild.attr("type"));
}
JSONArray liDatas = new JSONArray();
Elements liElements = tdElementChild.select("li");
for (Element liElement : liElements) {
JSONObject liObject = new JSONObject();
liObject.put("type", "li");
liObject.put("data", liElement.text());
liDatas.put(liObject);
}
tdObject4.put("data", liDatas);
objects.put(tdObject4);
}
tdObject.put("text", objects);
}
} else if (tdElement.children().select("img").size() > 0) {
//处理表格中嵌套有图片的情况
Elements tdElementChildren = tdElement.children();
JSONArray objects = new JSONArray();
for (Element tdElementChild : tdElementChildren) {
if (tdElementChild.children().select("img").size() > 0) {
JSONObject imgObject;
JSONObject textObject;
JSONArray jsonImageParagraph = new JSONArray();
String paragraph = tdElementChild.html();
Elements imgElements = tdElementChild.select("img");
int i = 0;
for (Element imgElement : imgElements) {
imgObject = new JSONObject();
textObject = new JSONObject();
String[] str = paragraph.split(imgElement.toString(), 2);
String firstHalf = str[0];
textObject.put("type", "paragraph"); //段落
textObject.put("data", firstHalf);
imgObject.put("type", "img"); //图片
imgObject.put("src", "/upload/" + id + "/" + imgElement.attr("src"));
imgObject.put("align", imgElement.attr("align"));
imgObject.put("width", imgElement.attr("width"));
imgObject.put("height", imgElement.attr("height"));
imgObject.put("border", imgElement.attr("border"));
i++;
if (str.length > 1) {
paragraph = str[1];
}
jsonImageParagraph.put(textObject);
jsonImageParagraph.put(imgObject);
if (imgElements.size() == i && StringUtils.isNotBlank(str[1])) { //遍历到最后一次时,添加图片后面的文字
JSONObject textObject2 = new JSONObject();
textObject2.put("type", "paragraph");
textObject2.put("data", str[1]);
jsonImageParagraph.put(textObject2);
}
}
objects.put(jsonImageParagraph);
}
if ("p".equalsIgnoreCase(tdElementChild.tagName()) && tdElementChild.children().size() == 0) {
JSONObject tdObject1 = new JSONObject();
tdObject1.put("type", "paragraph");
tdObject1.put("align", tdElementChild.attr("align"));
tdObject1.put("data", tdElementChild.text());
objects.put(tdObject1);
}
tdObject.put("text", objects);
}
} else {
tdObject.put("text", tdElement.text());
}
tr.put(tdObject);
}
trs.put(tr);
}
object.put("data", trs);
return object;
}
wholeTable()三参:
/**
* 完全解析一个table元素
*
* @param element
* @param object
* @return
*/
private static JSONObject wholeTable(Element element, JSONObject object, Integer id) {
return wholeTable(element, object, "table", id);
}
normalTable():
/**
* 构建一个普通表格
*
* @return
*/
public static JSONArray normalTable(Element element) {
JSONArray tr = null;
JSONArray trs = new JSONArray();
//把element先解析tr标签,然后将tr标签循环,取出td节点数据
Elements elements = element.select("tr");
for (Element trElement : elements) {
Elements tdElements = trElement.select("td");
tr = new JSONArray();
for (Element tdElement : tdElements) {
//创建最里面的td对象
JSONObject tdObject = new JSONObject();
int colspan = StringUtils.isBlank(tdElement.attr("colspan")) ? 1 : Integer.parseInt(tdElement.attr("colspan"));
int rowspan = StringUtils.isBlank(tdElement.attr("rowspan")) ? 1 : Integer.parseInt(tdElement.attr("rowspan"));
tdObject.put("text", tdElement.text());
tdObject.put("row", rowspan);
tdObject.put("col", colspan);
tdObject.put("width", tdElement.attr("width")); //增加列宽属性
tr.put(tdObject);
}
trs.put(tr);
}
return trs;
}
tableForCodeView():
/**
* 构建codeView表格数据
*
* @param element
* @param object
*/
public static JSONObject tableForCodeView(Element element, JSONObject object) {
//通过colgroup下col标签个数可以确定是只有2个的是图文类型,判断是哪种类型的图文边框
object.put("type", "CodeView");
object.put("title", element.select("tr").first().text());
Elements elements = element.select("tr").get(1).getElementsByTag("p");
StringBuffer buffer = new StringBuffer("");
for (Element pElement : elements) {
buffer.append(pElement.text()).append("\n ");
}
object.put("data", buffer.toString());
return object;
}
imageParagraph():
/**
* 构建图文段落
*
* @param element
* @param object
* @return
*/
public static JSONObject imageParagraph(Element element, JSONObject object, Integer id) {
if (StringUtils.isBlank(element.html())) {
return null;
}
JSONArray jsonImageParagraph = new JSONArray();
JSONObject imgObject = null;
JSONObject textObject = null;
String paragraph = element.html();
//通过标签可以判断是一个有内容的包含图片的段落,将它的type定义为imageParagraph
object.put("type", "imageParagraph");
Elements imgElements = element.select("img");
int i = 0;
for (Element imgElement : imgElements) {
imgObject = new JSONObject();
textObject = new JSONObject();
String[] str = paragraph.split(imgElement.toString(), 2);
String firstHalf = str[0];
textObject.put("type", "paragraph"); //段落
textObject.put("data", firstHalf);
imgObject.put("type", "img"); //图片
imgObject.put("src", "/upload/" + id + "/" + imgElement.attr("src"));
imgObject.put("align", imgElement.attr("align"));
imgObject.put("width", imgElement.attr("width"));
imgObject.put("height", imgElement.attr("height"));
imgObject.put("border", imgElement.attr("border"));
i++;
if (str.length > 1) {
paragraph = str[1];
}
jsonImageParagraph.put(textObject);
jsonImageParagraph.put(imgObject);
if (imgElements.size() == i && StringUtils.isNotBlank(str[1])) { //遍历到最后一次时,添加图片后面的文字
JSONObject textObject2 = new JSONObject();
textObject2.put("type", "paragraph");
textObject2.put("data", str[1]);
jsonImageParagraph.put(textObject2);
}
}
object.put("data", jsonImageParagraph);
return object;
}
without():
/**
* 过滤出段落中不需要的信息
*
* @param object
* @return 如果对应的字段中包含不需要的字段则返回true, 反之则返回false
*/
private static boolean without(JSONObject object) {
if ("paragraph".equals(object.get("type").toString())) {
String data = object.get("data").toString();
if ("修改记录".equals(data) || "目录".equals(data) || "图表目录".equals(data)) {
return false;
}
}
return true;
}
Documentation:
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 文档信息实体对象
* 2016年11月15日-下午2:00:10
*/
@Data
public class Documentation implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id; //文档信息主键
private Integer authorId; //文档作者(0为上传文档)
private String authorUsername; //文档作者名称
private Integer catid; //文档类型
private String pageTitle; //文档标题
private String content; //文档内容
private String languageType; //语言类型
private String tag; //文章标签
private String digest; //文档摘要或介绍
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date addTime; //文档添加时间,可做编辑时间
private Integer status; // 文档类型(0:删除,1:正常,2:等待转换)
private String catidName;// 分类名称
private String logoPath; //文章logo地址
private String copyright;// 版权声明信息
private String dataType;// 数据类型
private Integer editorId; //编辑者ID
private Integer lock; //是否锁定,0:未锁定,1:已锁定
private Integer fileType;//文件类型,0:word;1:pdf
private String text;//html对应纯文本
}
jackson和lombok依赖,如果觉得lombok使用麻烦,直接用set() get()实体类字段也可:
com.fasterxml.jackson.core
jackson-core
2.7.4
com.fasterxml.jackson.core
jackson-databind
2.7.4
com.fasterxml.jackson.core
jackson-annotations
2.7.0
org.projectlombok
lombok
1.16.10
Constants:
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class Constants {
public static final String SESSION_USER = "USER";
public static final String COOKIE_NAME = "Authorize"; //设置Cookie名称
public static final Long PROVIDER_TYPE = 1l;// 字典主表运营商类型
public static final String NOTE_BORDERCOLOR = "#000080";// 标识图文结构的表格NOTE类型
public static final String CAUTION_BORDERCOLOR = "#ff0000";// 标识图文结构的表格CAUTION类型
public static final String WARNING_BORDERCOLOR = "#ff0000";// 标识图文结构的表格WARNING类型
public static final int PAGE_SIZE = 15;// 分页
public static final String SEARCH_FULL_TEXT = "fullText";// 搜索类型全文
public static final String SEARCH_TITLE = "title";// 标题
public static final String SEARCH_DOCUMENT = "document";// 文档
public static final String SEARCH_LABEL = "label";// 标签
public static final String SORT_ASC = "ASC";
public static final String SORT_DESC = "DESC";
public static final int STATUS_DELETE = 0; //删除状态
public static final int STATUS_SUCCESS = 1; //文档转换成功状态(转换成功)
public static final int STATUS_WAITING_FOR_CONVERSION = 2; //文档等待转换
public static final int STATUS_CONVERT_FAILED = 0; //文档转换失败
public static Map documentationMap = new HashMap<>();
//根据openoffice转换出来的html,目前只存在这两种id
public static final String chartCatalogDivId1="内容目录2";//图表目录id
public static final String chartCatalogDivId2="插图目录1";//图表目录id
public static final String chartCatalogDivId3="插图目录2";//图表目录id
public static final String CatalogDivId="内容目录1";//目录id
public static final String HtmlToPdf="waitConvertHtml";//默认待转换的html名称
public static final int RESPONSE_UNACCREDITED = 401;
public static final int RESPONSE_TOHOME = 402; //跳转到首页
public static final String API_TYPE = "api";
}
HtmlString转json需要判断逻辑比较复杂,代码直接复制即可。
希望可以帮到你