Skip to content
Snippets Groups Projects
Commit 8eb7ed67 authored by srosse's avatar srosse
Browse files

OO-1402: support <br/> and lists in the html to OpenXML converter

parent e487692a
No related branches found
No related tags found
No related merge requests found
......@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.Deque;
import java.util.List;
import org.olat.core.util.openxml.OpenXMLDocument.ListParagraph;
import org.olat.core.util.openxml.OpenXMLDocument.Style;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
......@@ -50,8 +51,9 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
private List<Node> content = new ArrayList<Node>();
private Deque<StyleStatus> styleStack = new ArrayDeque<StyleStatus>();
private Element currentParagraph;
private Table currentTable;
private Element currentParagraph;
private ListParagraph currentListParagraph;
public HTMLToOpenXMLHandler(OpenXMLDocument document, Element paragraph) {
this.factory = document;
......@@ -76,6 +78,18 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
return currentParagraph;
}
private Element getCurrentListParagraph(boolean create) {
if(create || currentParagraph == null) {
//flush the text
if(textBuffer != null) {
flushText();
addContent(currentParagraph);
}
currentParagraph = factory.createListParagraph(currentListParagraph);
}
return currentParagraph;
}
private void closeParagraph() {
flushText();
currentParagraph = addContent(currentParagraph);
......@@ -229,6 +243,8 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
styles = setTextPreferences(cssStyles);
}
styleStack.add(new StyleStatus(tag, styles));
} else if("br".equals(tag)) {
closeParagraph();
} else if("em".equalsIgnoreCase(tag)) {
flushText();
Style[] styles = setTextPreferences(Style.italic);
......@@ -249,6 +265,10 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
int colspan = OpenXMLUtils.getSpanAttribute("colspan", attributes);
int rowspan = OpenXMLUtils.getSpanAttribute("rowspan", attributes);
currentTable.addCellEl(colspan, rowspan);
} else if("ul".equals(tag) || "ol".equals(tag)) {
currentListParagraph = factory.createListParagraph();
} else if("li".equals(tag)) {
getCurrentListParagraph(true);
}
}
......@@ -282,6 +302,8 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
if(currentTable != null) {
content.add(currentTable.getTableEl());
}
currentTable = null;
currentParagraph = null;
} else if("td".equals(tag) || "th".equals(tag)) {
flushText();
currentParagraph = addContent(currentParagraph);
......@@ -292,6 +314,11 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
textBuffer = null;
latex = false;
currentParagraph = null;
} else if("ul".equals(tag) || "ol".equals(tag)) {
closeParagraph();
currentListParagraph = null;
} else if("li".equals(tag)) {
//do nothing
}
}
......@@ -452,6 +479,5 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
public void unDone() {
done = false;
}
}
}
\ No newline at end of file
......@@ -80,11 +80,13 @@ public class OpenXMLDocument {
private final OpenXMLStyles styles;
private int currentId = 4;
private int currentNumberingId = 0;
private String documentHeader;
private Map<File, DocReference> fileToImagesMap = new HashMap<File, DocReference>();
private List<Node> cursorStack = new ArrayList<Node>();
private List<HeaderReference> headers = new ArrayList<HeaderReference>();
private List<Node> cursorStack = new ArrayList<>();
private List<ListParagraph> numbering = new ArrayList<>();
private List<HeaderReference> headers = new ArrayList<>();
private VFSContainer mediaContainer;
......@@ -131,6 +133,10 @@ public class OpenXMLDocument {
return headers;
}
public Collection<ListParagraph> getNumbering() {
return numbering;
}
public Node getCursor() {
return cursorStack.get(cursorStack.size() - 1);
}
......@@ -639,6 +645,104 @@ public class OpenXMLDocument {
return cellEl;
}
public ListParagraph createListParagraph() {
int abstractNumberingId = currentNumberingId++;
int numberingId = currentNumberingId++;
ListParagraph lp = new ListParagraph(abstractNumberingId, numberingId);
numbering.add(lp);
return lp;
}
/*
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>One</w:t>
</w:r>
</w:p>
*/
public Element createListParagraph(ListParagraph def) {
Element paragraphEl = document.createElement("w:p");
Element listEl = (Element)paragraphEl.appendChild(document.createElement("w:pPr"));
Element pStyleEl = (Element)listEl.appendChild(document.createElement("w:pStyle"));
pStyleEl.setAttribute("w:val", "ListParagraph");
Element numberingEl = (Element)listEl.appendChild(document.createElement("w:numPr"));
Element ilvlEl = (Element)numberingEl.appendChild(document.createElement("w:ilvl"));
ilvlEl.setAttribute("w:val", "0");
Element numIdEl = (Element)numberingEl.appendChild(document.createElement("w:numId"));
numIdEl.setAttribute("w:val", Integer.toString(def.getNumId()));
return paragraphEl;
}
/*
<w:abstractNum w:abstractNumId="0">
<w:lvl w:ilvl="0">
<w:start w:val="1"/>
<w:numFmt w:val="bullet"/>
<w:lvlText w:val="o"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="720"
w:hanging="360"/>
</w:pPr>
<w:rPr>
<w:rFonts w:ascii="Symbol"
w:hAnsi="Symbol"
w:hint="default"/>
</w:rPr>
</w:lvl>
*/
public Element createAbstractNumbering(ListParagraph def, Document doc) {
Element numEl = doc.createElement("w:abstractNum");
numEl.setAttribute("w:abstractNumId", Integer.toString(def.getAbstractNumId()));
numEl.appendChild(createNumberingLevel(doc));
return numEl;
}
private Element createNumberingLevel(Document numberingDoc) {
Element levelEl = numberingDoc.createElement("w:lvl");
levelEl.setAttribute("w:ilvl", "0");
Element startEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:start"));
startEl.setAttribute("w:val", "1");
Element numFmtEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:numFmt"));
numFmtEl.setAttribute("w:val", "bullet");
Element lvlTextEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:lvlText"));
lvlTextEl.setAttribute("w:val", Character.toString((char)0xB7));//bullet
Element lvlJcEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:lvlJc"));
lvlJcEl.setAttribute("w:val", "left");
//pPr
Element pPrEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:pPr"));
Element indEl = (Element)pPrEl.appendChild(numberingDoc.createElement("w:ind"));
indEl.setAttribute("w:left", "720");
indEl.setAttribute("w:hanging", "360");
//rPr
Element rPrEl = (Element)levelEl.appendChild(numberingDoc.createElement("w:rPr"));
Element rFontsEl = (Element)rPrEl.appendChild(numberingDoc.createElement("w:rFonts"));
rFontsEl.setAttribute("w:ascii", "Symbol");
rFontsEl.setAttribute("w:hAnsi", "Symbol");
rFontsEl.setAttribute("w:hint", "default");
return levelEl;
}
/*
<w:num w:numId="1">
<w:abstractNumId w:val="0"/>
</w:num>
*/
public Element createNumbering(ListParagraph def, Document numberingDoc) {
Element numEl = numberingDoc.createElement("w:num");
numEl.setAttribute("w:numId", Integer.toString(def.getNumId()));
Element abstractNumEl = (Element)numEl.appendChild(numberingDoc.createElement("w:abstractNumId"));
abstractNumEl.setAttribute("w:val", Integer.toString(def.getAbstractNumId()));
return numEl;
}
/*
<w:shd w:val="solid" w:color="E9EAF2" w:fill="auto" />
*/
......@@ -992,4 +1096,23 @@ public class OpenXMLDocument {
return header;
}
}
public static class ListParagraph {
private final int abstractNumId;
private final int numId;
public ListParagraph(int abstractNumId, int numId) {
this.abstractNumId = abstractNumId;
this.numId = numId;
}
public int getAbstractNumId() {
return abstractNumId;
}
public int getNumId() {
return numId;
}
}
}
......@@ -24,6 +24,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
......@@ -31,9 +32,11 @@ import org.apache.commons.io.IOUtils;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.openxml.OpenXMLDocument.HeaderReference;
import org.olat.core.util.openxml.OpenXMLDocument.ListParagraph;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
......@@ -101,6 +104,12 @@ public class OpenXMLDocumentWriter {
//word/media
appendMedias(out, document);
//word/numbering
ZipEntry numberingDocument = new ZipEntry("word/numbering.xml");
out.putNextEntry(numberingDocument);
appendNumbering(out, document);
out.closeEntry();
//word/document.xml
ZipEntry wordDocument = new ZipEntry("word/document.xml");
out.putNextEntry(wordDocument);
......@@ -138,6 +147,28 @@ public class OpenXMLDocumentWriter {
}
}
private void appendNumbering(ZipOutputStream out, OpenXMLDocument document) {
try(InputStream in = OpenXMLDocumentWriter.class.getResourceAsStream("_resources/numbering.xml")) {
Collection<ListParagraph> numberingList = document.getNumbering();
if(numberingList != null && numberingList.size() > 0) {
Document numberingDoc = OpenXMLUtils.createDocument(in);
NodeList numberingElList = numberingDoc.getElementsByTagName("w:numbering");
Node numberingEl = numberingElList.item(0);
for(ListParagraph numberingItem : numberingList) {
Element abstractEl = document.createAbstractNumbering(numberingItem, numberingDoc);
numberingEl.appendChild(abstractEl);
Element numEl = document.createNumbering(numberingItem, numberingDoc);
numberingEl.appendChild(numEl);
}
OpenXMLUtils.writeTo(numberingDoc, out, false);
} else {
IOUtils.copy(in, out);
}
} catch (IOException e) {
log.error("", e);
}
}
private void appendPredefinedStyles(ZipOutputStream out, OpenXMLStyles styles) {
try(InputStream in = OpenXMLDocumentWriter.class.getResourceAsStream("_resources/styles.xml")) {
if(styles != null) {
......@@ -159,12 +190,13 @@ public class OpenXMLDocumentWriter {
/*
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/>
<Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>
<Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
<Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/>
<Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>
<Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
<Relationship Id="rId2" Type="http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects" Target="stylesWithEffects.xml"/>
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml" />
</Relationships>
*/
protected void createDocumentRelationships(OutputStream out, OpenXMLDocument document) {
......@@ -175,6 +207,8 @@ public class OpenXMLDocumentWriter {
addRelationship("rId1", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
"styles.xml", relationshipsEl, doc);
addRelationship("rId2", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
"numbering.xml", relationshipsEl, doc);
if(document != null) {
for(DocReference docRef:document.getImages()) {
......@@ -315,6 +349,7 @@ public class OpenXMLDocumentWriter {
createContentTypesOverride("/docProps/core.xml", CT_CORE_PROPERTIES, typesEl, doc);
createContentTypesOverride("/word/document.xml", CT_WORD_DOCUMENT, typesEl, doc);
createContentTypesOverride("/word/styles.xml", CT_STYLES, typesEl, doc);
createContentTypesOverride("/word/numbering.xml", CT_NUMBERING, typesEl, doc);
for(HeaderReference headerRef:document.getHeaders()) {
createContentTypesOverride("/word/" + headerRef.getFilename(), CT_HEADER, typesEl, doc);
......
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:numbering xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14"></w:numbering>
\ No newline at end of file
......@@ -365,6 +365,14 @@
<w:semiHidden />
<w:unhideWhenUsed />
</w:style>
<w:style w:type="paragraph" w:styleId="ListParagraph">
<w:name w:val="List Paragraph"/>
<w:basedOn w:val="Normal"/>
<w:pPr>
<w:ind w:left="720"/>
<w:contextualSpacing/>
</w:pPr>
</w:style>
<w:style w:type="character" w:customStyle="1" w:styleId="ooHeading1Zeichen">
<w:name w:val="Überschrift 1 Zeichen" />
<w:basedOn w:val="Absatzstandardschriftart" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment