diff --git a/CHANGES.txt b/CHANGES.txt index 1b5aaf91e5..16556bfc19 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,12 +1,15 @@ Release 4.2.0 - unreleased + * The docx parser wraps OMML equations (m:oMath) in ; their + text was previously emitted as unmarked body text (TIKA-4968). + * The docx parser links REF, PAGEREF and NOTEREF fields, and in-document HYPERLINK \l fields, to their bookmarks (). Fields are now tracked as a stack, so a field nested in a HYPERLINK field no longer ends the enclosing link early. Simple fields (w:fldSimple) are now parsed as well, so HYPERLINK, INCLUDEPICTURE and similar fields written that way are linked or reported like their complex-field equivalents (TIKA-4967). - + * The docx parser now applies bold and italics set by a run's character style (e.g. Word's built-in Strong and Emphasis), following basedOn chains; previously only direct formatting was emitted. The new OfficeParserConfig option diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/FormattingTagManager.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/FormattingTagManager.java index 8717b524aa..9c77492064 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/FormattingTagManager.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/FormattingTagManager.java @@ -44,8 +44,9 @@ class FormattingTagManager { private final XHTMLContentHandler xhtml; - // Outermost to innermost: hyperlink > span > bold > italic > strike > underline + // Outermost to innermost: hyperlink > math > span > bold > italic > strike > underline private String currentHyperlink = null; + private boolean isMath = false; private String currentSpanClass = null; private boolean wrapperHyperlinkActive = false; private boolean isBold = false; @@ -123,7 +124,7 @@ void applyFormatting(RunProperties runProperties, String spanClass) throws SAXEx } if (!Objects.equals(spanClass, currentSpanClass)) { - closeInlineTags(); + closeStyledTags(); if (spanClass != null) { xhtml.startElement("span", "class", spanClass); } @@ -195,6 +196,27 @@ void applyFormatting(RunProperties runProperties, String spanClass) throws SAXEx } } + /** + * Opens {@code } for an OMML equation. A hyperlink change inside + * the equation closes it. + */ + void openMath() throws SAXException { + if (isMath) { + return; + } + closeStyledTags(); + xhtml.startElement("span", "class", "math"); + isMath = true; + } + + void closeMath() throws SAXException { + if (isMath) { + closeStyledTags(); + xhtml.endElement("span"); + isMath = false; + } + } + /** * Closes all currently open tags in proper nesting order. */ @@ -208,6 +230,11 @@ void closeAll() throws SAXException { } private void closeInlineTags() throws SAXException { + closeStyledTags(); + closeMath(); + } + + private void closeStyledTags() throws SAXException { closeFormattingTags(); if (currentSpanClass != null) { xhtml.endElement("span"); diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLTikaBodyPartHandler.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLTikaBodyPartHandler.java index 7df2342fda..f849f92d70 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLTikaBodyPartHandler.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLTikaBodyPartHandler.java @@ -168,6 +168,16 @@ public void hyperlinkEnd() throws SAXException { formattingTags.closeHyperlink(); } + @Override + public void startMath() throws SAXException { + formattingTags.openMath(); + } + + @Override + public void endMath() throws SAXException { + formattingTags.closeMath(); + } + @Override public void startParagraph(ParagraphProperties paragraphProperties) throws SAXException { diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLWordAndPowerPointTextHandler.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLWordAndPowerPointTextHandler.java index 281c2ed186..569b4065ae 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLWordAndPowerPointTextHandler.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLWordAndPowerPointTextHandler.java @@ -99,6 +99,9 @@ public class OOXMLWordAndPowerPointTextHandler extends DefaultHandler { "http://schemas.openxmlformats.org/drawingml/2006/main"; private final static String V_NS = "urn:schemas-microsoft-com:vml"; private final static String C_NS = "http://schemas.openxmlformats.org/drawingml/2006/chart"; + private final static String M_NS = + "http://schemas.openxmlformats.org/officeDocument/2006/math"; + private final static String O_MATH = "oMath"; private final static String OFFICE_DOC_RELATIONSHIP_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; private final static char[] TAB_CHAR = new char[]{'\t'}; @@ -178,6 +181,7 @@ public class OOXMLWordAndPowerPointTextHandler extends DefaultHandler { private final Deque fieldStack = new ArrayDeque<>(); private int hyperlinkElementDepth = 0; private boolean inInstrText = false; + private int mathDepth = 0; private EditType editType = EditType.NONE; @@ -273,6 +277,10 @@ public void startElement(String uri, String localName, String qName, Attributes //yes, I know, likely premature optimization... if (RPR.equals(localName)) { inRPr = true; + } else if (O_MATH.equals(localName) && M_NS.equals(uri)) { + if (mathDepth++ == 0) { + bodyContentsHandler.startMath(); + } } else if (R.equals(localName)) { inR = true; } else if (T.equals(localName)) { @@ -554,6 +562,10 @@ public void endElement(String uri, String localName, String qName) throws SAXExc return; } else if (RPR.equals(localName)) { inRPr = false; + } else if (O_MATH.equals(localName) && M_NS.equals(uri)) { + if (mathDepth > 0 && --mathDepth == 0) { + bodyContentsHandler.endMath(); + } } else if (R.equals(localName)) { handleEndOfRun(); } else if (T.equals(localName)) { diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFBodyContentsHandler.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFBodyContentsHandler.java index a9eb400e98..401b0e720f 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFBodyContentsHandler.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFBodyContentsHandler.java @@ -46,6 +46,15 @@ default void fieldCodeHyperlinkStart(String link) throws SAXException { void hyperlinkEnd() throws SAXException; + /** + * Called at the start of an OMML equation ({@code m:oMath}); its runs follow. + */ + default void startMath() throws SAXException { + } + + default void endMath() throws SAXException { + } + void startParagraph(ParagraphProperties paragraphProperties) throws SAXException; void endParagraph() throws SAXException; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java index 80590ec5e4..03ba3d3b3c 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java @@ -145,6 +145,14 @@ public void testMissingText() throws Exception { assertContains("Rich_text_in_cell", xmlResult.xml); } + @Test + public void testOmmlMath() throws Exception { + String xml = getXML("testWORD_omml.docx").xml; + assertContains("

area A=πrr2 done

", xml); + assertContains("

x+y

", xml); + assertContains("

bold z after

", xml); + } + @Test public void testBoldHyperlink() throws Exception { String xml = getXML("testWORD_boldHyperlink.docx").xml; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testWORD_omml.docx b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testWORD_omml.docx new file mode 100644 index 0000000000..bde754a670 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testWORD_omml.docx differ