При преобразовании текста HTML никогда не следует переходить на HTML
, используя только строковые методы.XML
, а также HTML
являются языками разметки.Их содержание - разметка, а не только простой текст.Разметка должна быть пройдена, чтобы получить все отдельные узлы вместе со значениями из нее.Этот процесс обхода никогда не бывает тривиальным, поэтому существуют специальные библиотеки.Глубоко внутри этих библиотек также необходимо использовать строковые методы, но они обернуты в полезные методы для обхода разметки.
Для обхода можно использовать, например, HTML
jsoup .Особенно NodeTraversor с использованием NodeVisitor полезен для обхода HTML
.
В моем примере создается ParagraphNodeVisitor
, который реализует NodeVisitor
.Этот интерфейс запрашивает метод public void head(Node node, int depth)
, который вызывается каждый раз, когда NodeTraversor
находится в начале узла, и public void tail(Node node, int depth)
, который вызывается каждый раз, когда NodeTraversor
находится в хвостовой части узла.В этих методах может быть реализован процесс обработки отдельных узлов.В нашем случае основная часть процесса заключается в том, нужен ли нам новый XWPFRun
и какие настройки нужны для этого запуска.
Пример:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.jsoup.select.NodeVisitor;
import org.jsoup.select.NodeTraversor;
public class HTMLtoDOCX {
private XWPFDocument document;
public HTMLtoDOCX(String html, String docxPath) throws Exception {
this.document = new XWPFDocument();
XWPFParagraph paragraph = null;
Document htmlDocument = Jsoup.parse(html);
Elements htmlParagraphs = htmlDocument.select("p");
for(Element htmlParagraph : htmlParagraphs) {
System.out.println(htmlParagraph);
paragraph = document.createParagraph();
createParagraphFromHTML(paragraph, htmlParagraph);
}
FileOutputStream out = new FileOutputStream(docxPath);
document.write(out);
out.close();
document.close();
}
void createParagraphFromHTML(XWPFParagraph paragraph, Element htmlParagraph) {
ParagraphNodeVisitor nodeVisitor = new ParagraphNodeVisitor(paragraph);
NodeTraversor.traverse(nodeVisitor, htmlParagraph);
}
private class ParagraphNodeVisitor implements NodeVisitor {
String nodeName;
boolean needNewRun;
boolean isItalic;
boolean isBold;
boolean isUnderlined;
int fontSize;
String fontColor;
XWPFParagraph paragraph;
XWPFRun run;
ParagraphNodeVisitor(XWPFParagraph paragraph) {
this.paragraph = paragraph;
this.run = paragraph.createRun();
this.nodeName = "";
this.needNewRun = false;
this.isItalic = false;
this.isBold = false;
this.isUnderlined = false;
this.fontSize = 11;
this.fontColor = "000000";
}
@Override
public void head(Node node, int depth) {
nodeName = node.nodeName();
System.out.println("Start "+nodeName+": " + node);
needNewRun = false;
if ("#text".equals(nodeName)) {
run.setText(((TextNode)node).text());
needNewRun = true; //after setting the text in the run a new run is needed
} else if ("i".equals(nodeName)) {
isItalic = true;
} else if ("b".equals(nodeName)) {
isBold = true;
} else if ("u".equals(nodeName)) {
isUnderlined = true;
} else if ("br".equals(nodeName)) {
run.addBreak();
} else if ("font".equals(nodeName)) {
fontColor = (!"".equals(node.attr("color")))?node.attr("color").substring(1):"000000";
fontSize = (!"".equals(node.attr("size")))?Integer.parseInt(node.attr("size")):11;
}
if (needNewRun) run = paragraph.createRun();
needNewRun = false;
run.setItalic(isItalic);
run.setBold(isBold);
if (isUnderlined) run.setUnderline(UnderlinePatterns.SINGLE); else run.setUnderline(UnderlinePatterns.NONE);
run.setColor(fontColor); run.setFontSize(fontSize);
}
@Override
public void tail(Node node, int depth) {
nodeName = node.nodeName();
System.out.println("End "+nodeName);
if ("i".equals(nodeName)) {
isItalic = false;
} else if ("b".equals(nodeName)) {
isBold = false;
} else if ("u".equals(nodeName)) {
isUnderlined = false;
} else if ("font".equals(nodeName)) {
fontColor = "000000";
fontSize = 11;
}
if (needNewRun) run = paragraph.createRun();
needNewRun = false;
run.setItalic(isItalic);
run.setBold(isBold);
if (isUnderlined) run.setUnderline(UnderlinePatterns.SINGLE); else run.setUnderline(UnderlinePatterns.NONE);
run.setColor(fontColor); run.setFontSize(fontSize);
}
}
public static void main(String[] args) throws Exception {
String html =
"<p><font size='32' color='#0000FF'><b>First paragraph.</font></b><br/>Just like a heading</p>"
+"<p>This is my text <i>which now is in italic <b>but also in bold</b> depending on its <u>importance</u></i>.<br/>Now a <b><i><u>new</u></i></b> line starts <i>within <b>the same</b> paragraph</i>.</p>"
+"<p><b>Last <u>paragraph <i>comes</u> here</b> finally</i>.</p>"
+"<p>But yet <u><i><b>another</i></u></b> paragraph having <i><font size='22' color='#FF0000'>special <u>font</u> settings</font></i>. Now default font again.</p>";
HTMLtoDOCX htmlToDOCX = new HTMLtoDOCX(html, "./CreateWordParagraphFromHTML.docx");
}
}
Результат:
Отказ от ответственности: Это рабочий проект, показывающий принцип.Он не полностью готов и не готов для использования в продуктивной среде.