From 57c4509faabf7025bc52ecfe90684512b2cf01a4 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 11 Jan 2012 14:02:40 +0000 Subject: [PATCH] Fix bug #52449 - Support writing XWPF documents with glossaries (plus fix some indenting) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1230045 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../poi/xwpf/usermodel/XWPFDocument.java | 15 ++++ .../poi/xwpf/usermodel/XWPFRelation.java | 6 ++ .../poi/xwpf/usermodel/XWPFSettings.java | 3 + .../apache/poi/xwpf/usermodel/XWPFStyles.java | 71 +++++++++--------- .../poi/xwpf/usermodel/TestXWPFStyles.java | 16 +++- test-data/document/52449.docx | Bin 0 -> 18854 bytes 7 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 test-data/document/52449.docx diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 139408242d..38c7666b96 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 52449 - Support writing XWPF documents with glossaries (Glossaries are not yet supported, but can now be written out again without changes) 52446 - Handle files which have been truncated by a few bytes in NPropertyTable 52438 - Update CellDateFormatter to handle times without seconds 52389 - Support ?/? as well as #/# fractions, and tighten DataFormatter rules for fraction matching diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index 6b4423ba8d..4cb412931e 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -188,6 +189,20 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { picData.onDocumentRead(); registerPackagePictureData(picData); pictures.add(picData); + } else if (relation.equals(XWPFRelation.GLOSSARY_DOCUMENT.getRelation())) { + // We don't currently process the glossary itself + // Until we do, we do need to load the glossary child parts of it + for (POIXMLDocumentPart gp : p.getRelations()) { + // Trigger the onDocumentRead for all the child parts + // Otherwise we'll hit issues on Styles, Settings etc on save + try { + Method onDocumentRead = gp.getClass().getDeclaredMethod("onDocumentRead"); + onDocumentRead.setAccessible(true); + onDocumentRead.invoke(gp); + } catch(Exception e) { + throw new POIXMLException(e); + } + } } } initHyperlinks(); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java index 9f7ef404c6..89524de671 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java @@ -58,6 +58,12 @@ public final class XWPFRelation extends POIXMLRelation { "/word/document.xml", null ); + public static final XWPFRelation GLOSSARY_DOCUMENT = new XWPFRelation( + "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument", + "/word/glossary/document.xml", + null + ); public static final XWPFRelation NUMBERING = new XWPFRelation( "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java index 84b9fdf66c..5471fde0cb 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java @@ -149,6 +149,9 @@ public class XWPFSettings extends POIXMLDocumentPart { @Override protected void commit() throws IOException { + if (ctSettings == null) { + throw new IllegalStateException("Unable to write out settings that were never read in!"); + } XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); xmlOptions.setSaveSyntheticDocumentElement(new QName(CTSettings.type.getName().getNamespaceURI(), "settings")); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java index f45d113ca5..35a0c6027e 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java @@ -70,41 +70,44 @@ public class XWPFStyles extends POIXMLDocumentPart{ public XWPFStyles() { } - /** - * Read document - */ - @Override - protected void onDocumentRead ()throws IOException{ - StylesDocument stylesDoc; - try { - InputStream is = getPackagePart().getInputStream(); - stylesDoc = StylesDocument.Factory.parse(is); - ctStyles = stylesDoc.getStyles(); - latentStyles = new XWPFLatentStyles(ctStyles.getLatentStyles(), this); - - } catch (XmlException e) { - throw new POIXMLException(); - } - //get any Style - for(CTStyle style : ctStyles.getStyleList()) { - listStyle.add(new XWPFStyle(style, this)); - } - } + /** + * Read document + */ + @Override + protected void onDocumentRead() throws IOException{ + StylesDocument stylesDoc; + try { + InputStream is = getPackagePart().getInputStream(); + stylesDoc = StylesDocument.Factory.parse(is); + ctStyles = stylesDoc.getStyles(); + latentStyles = new XWPFLatentStyles(ctStyles.getLatentStyles(), this); + } catch (XmlException e) { + throw new POIXMLException("Unable to read styles", e); + } + + // Build up all the style objects + for(CTStyle style : ctStyles.getStyleList()) { + listStyle.add(new XWPFStyle(style, this)); + } + } - @Override - protected void commit() throws IOException { - XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); - xmlOptions.setSaveSyntheticDocumentElement(new QName(CTStyles.type.getName().getNamespaceURI(), "styles")); - Map map = new HashMap(); - map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); - map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); - xmlOptions.setSaveSuggestedPrefixes(map); - PackagePart part = getPackagePart(); - OutputStream out = part.getOutputStream(); - ctStyles.save(out, xmlOptions); - out.close(); - } - + @Override + protected void commit() throws IOException { + if (ctStyles == null) { + throw new IllegalStateException("Unable to write out styles that were never read in!"); + } + + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName(CTStyles.type.getName().getNamespaceURI(), "styles")); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + xmlOptions.setSaveSuggestedPrefixes(map); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + ctStyles.save(out, xmlOptions); + out.close(); + } /** * Sets the ctStyles diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java index 156e1b5802..3c13504cdf 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java @@ -68,8 +68,18 @@ public class TestXWPFStyles extends TestCase { assertTrue(styles.styleExist(strStyleName)); } -// protected void tearDown() throws Exception { -// super.tearDown(); -// } + /** + * Bug #52449 - We should be able to write a file containing + * both regular and glossary styles without error + */ + public void test52449() throws Exception { + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("52449.docx"); + XWPFStyles styles = doc.getStyles(); + assertNotNull(styles); + + XWPFDocument docIn = XWPFTestDataSamples.writeOutAndReadBack(doc); + styles = docIn.getStyles(); + assertNotNull(styles); + } } diff --git a/test-data/document/52449.docx b/test-data/document/52449.docx new file mode 100644 index 0000000000000000000000000000000000000000..f294b85dbd1995ed67c68f83ac2295df477d9943 GIT binary patch literal 18854 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 Ln(