]> source.dussan.org Git - poi.git/commitdiff
Fix for saving custom and extended OOXML properties
authorYegor Kozlov <yegor@apache.org>
Sun, 19 Jul 2009 18:26:36 +0000 (18:26 +0000)
committerYegor Kozlov <yegor@apache.org>
Sun, 19 Jul 2009 18:26:36 +0000 (18:26 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@795587 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/POIXMLDocument.java
src/ooxml/java/org/apache/poi/POIXMLProperties.java
src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java [new file with mode: 0755]

index 2af0bd1e9fbb30602aa367a190ec0a07c491db17..d9045f2be54d1ad774d1193bfea16730d738d64b 100644 (file)
@@ -33,7 +33,8 @@
 
     <changes>
         <release version="3.5-beta7" date="2009-??-??">
-           <action dev="POI-DEVELOPERS" type="fix">47535 - fixed WordExtractor to tolerate files with empty footnote block</action>
+           <action dev="POI-DEVELOPERS" type="fix">47540 - Fix for saving custom and extended OOXML properties</action>
+           <action dev="POI-DEVELOPERS" type="fix">47535 - Fixed WordExtractor to tolerate files with empty footnote block</action>
            <action dev="POI-DEVELOPERS" type="fix">47517 - Fixed ExtractorFactory to support .xltx and .dotx files</action>
            <action dev="POI-DEVELOPERS" type="add">45556 - Support for extraction of footnotes from docx files</action>
            <action dev="POI-DEVELOPERS" type="add">45555 - Support for extraction of endnotes from docx files</action>
diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkbookProperties.java
new file mode 100755 (executable)
index 0000000..0e00c7d
--- /dev/null
@@ -0,0 +1,75 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.usermodel.examples;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.POIXMLProperties;
+
+/**
+ *  How to set extended and custom properties
+ *
+ * @author Yegor Kozlov
+ */
+public class WorkbookProperties {
+
+    public static void main(String[]args) throws Exception {
+
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        workbook.createSheet("Workbook Properties");
+
+        POIXMLProperties props = workbook.getProperties();
+
+        /**
+         * Extended properties are a predefined set of metadata properties
+         * that are specifically applicable to Office Open XML documents.
+         * Extended properties consist of 24 simple properties and 3 complex properties stored in the
+         *  part targeted by the relationship of type
+         */
+        POIXMLProperties.ExtendedProperties ext =  props.getExtendedProperties();
+        ext.getUnderlyingProperties().setCompany("Apache Software Foundation");
+        ext.getUnderlyingProperties().setTemplate("XSSF");
+
+        /**
+         * Custom properties enable users to define custom metadata properties
+         * through a set of well-defined data types. For example, a custom
+         * OLE Editor property of type string can be defined as follows:
+         *
+         *  <property fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" pid="2" name="Editor">
+         *    <vt:lpwstr>John Smith</vt:lpwstr>
+         *  </property>
+         */
+        
+        POIXMLProperties.CustomProperties cust =  props.getCustomProperties();
+        org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty
+                property = cust.getUnderlyingProperties().addNewProperty();
+
+        property.setFmtid("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
+        property.setPid(2);
+        property.setName("Editor");
+        property.setLpwstr("John Smith");
+        
+        FileOutputStream out = new FileOutputStream("workbook.xlsx");
+        workbook.write(out);
+        out.close();
+
+    }
+
+
+}
\ No newline at end of file
index 03a9466d9de6d07d5f5be3bec56b8c016c3b468d..ace5d01986d22cb9e18522a659b3661f94836b4a 100644 (file)
@@ -157,9 +157,13 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart{
      * Get the document properties. This gives you access to the
      *  core ooxml properties, and the extended ooxml properties.
      */
-    public POIXMLProperties getProperties() throws OpenXML4JException, IOException, XmlException {
+    public POIXMLProperties getProperties() {
         if(properties == null) {
-            properties = new POIXMLProperties(pkg);
+            try {
+                properties = new POIXMLProperties(pkg);
+            } catch (Exception e){
+                throw new POIXMLException(e);
+            }
         }
         return properties;
     }
@@ -197,6 +201,9 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart{
         //force all children to commit their changes into the underlying OOXML Package
         onSave();
 
+        //save extended and custom properties
+        getProperties().commit();
+
         getPackage().save(stream);
     }
 
index 9729309bcd28c791fe7906d9900508fe78adbb7f..69661496688f072e2283b3d93bb687c687aa21a2 100644 (file)
 package org.apache.poi;
 
 import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.HashMap;
 
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.*;
 import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
 import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlOptions;
+import org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument;
 
 /**
  * Wrapper around the two different kinds of OOXML properties 
@@ -33,8 +38,22 @@ public class POIXMLProperties {
        private CoreProperties core;
        private ExtendedProperties ext;
        private CustomProperties cust;
-       
-       public POIXMLProperties(OPCPackage docPackage) throws IOException, OpenXML4JException, XmlException {
+
+    private PackagePart extPart;
+    private PackagePart custPart;
+
+
+    private static final org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument NEW_EXT_INSTANCE;
+    private static final org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument NEW_CUST_INSTANCE;
+    static {
+        NEW_EXT_INSTANCE = org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument.Factory.newInstance();
+        NEW_EXT_INSTANCE.addNewProperties();
+
+        NEW_CUST_INSTANCE = org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument.Factory.newInstance();
+        NEW_CUST_INSTANCE.addNewProperties();
+    }
+
+    public POIXMLProperties(OPCPackage docPackage) throws IOException, OpenXML4JException, XmlException {
                this.pkg = docPackage;
                
                // Core properties
@@ -44,24 +63,28 @@ public class POIXMLProperties {
                PackageRelationshipCollection extRel =
                        pkg.getRelationshipsByType(POIXMLDocument.EXTENDED_PROPERTIES_REL_TYPE);
                if(extRel.size() == 1) {
-                       org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument props = org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument.Factory.parse(
-                                       pkg.getPart( extRel.getRelationship(0) ).getInputStream()
+            extPart = pkg.getPart( extRel.getRelationship(0));
+            org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument props = org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument.Factory.parse(
+                        extPart.getInputStream()
                        );
                        ext = new ExtendedProperties(props);
                } else {
-                       ext = new ExtendedProperties(org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument.Factory.newInstance());
-               }
+            extPart = null;
+            ext = new ExtendedProperties((org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument)NEW_EXT_INSTANCE.copy());
+        }
                
                // Custom properties
                PackageRelationshipCollection custRel =
                        pkg.getRelationshipsByType(POIXMLDocument.CUSTOM_PROPERTIES_REL_TYPE);
                if(custRel.size() == 1) {
-                       org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument props = org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument.Factory.parse(
-                                       pkg.getPart( custRel.getRelationship(0) ).getInputStream()
+            custPart = pkg.getPart( custRel.getRelationship(0));
+            org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument props = org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument.Factory.parse(
+                                       custPart.getInputStream()
                        );
                        cust = new CustomProperties(props);
                } else {
-                       cust = new CustomProperties(org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument.Factory.newInstance());
+            custPart = null;
+            cust = new CustomProperties((org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument)NEW_CUST_INSTANCE.copy());
                }
        }
        
@@ -87,11 +110,44 @@ public class POIXMLProperties {
        }
        
        /**
-        * Writes out the ooxml properties into the supplied,
-        *  new Package
+        * Commit changes to the underlying OPC package
         */
-       public void write(OPCPackage pkg) {
-               // TODO
+       public void commit() throws IOException{
+
+        if(extPart == null && !NEW_EXT_INSTANCE.toString().equals(ext.props.toString())){
+            try {
+                PackagePartName prtname = PackagingURIHelper.createPartName("/docProps/app.xml");
+                pkg.addRelationship(prtname, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties");
+                extPart = pkg.createPart(prtname, "application/vnd.openxmlformats-officedocument.extended-properties+xml");
+            } catch (InvalidFormatException e){
+                throw new POIXMLException(e);
+            }
+        }
+        if(custPart == null && !NEW_CUST_INSTANCE.toString().equals(cust.props.toString())){
+            try {
+                PackagePartName prtname = PackagingURIHelper.createPartName("/docProps/custom.xml");
+                pkg.addRelationship(prtname, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties");
+                custPart = pkg.createPart(prtname, "application/vnd.openxmlformats-officedocument.custom-properties+xml");
+            } catch (InvalidFormatException e){
+                throw new POIXMLException(e);
+            }
+        }
+        if(extPart != null){
+            XmlOptions xmlOptions = new XmlOptions(POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
+
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", "vt");
+            xmlOptions.setSaveSuggestedPrefixes(map);
+
+            OutputStream out = extPart.getOutputStream();
+            ext.props.save(out, xmlOptions);
+            out.close();
+        }
+        if(custPart != null){
+            OutputStream out = custPart.getOutputStream();
+            cust.props.save(out, POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
+            out.close();
+        }
        }
        
        /**
@@ -122,10 +178,6 @@ public class POIXMLProperties {
                private org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument props;
                private ExtendedProperties(org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument props) {
                        this.props = props;
-                       
-                       if(props.getProperties() == null) {
-                               props.addNewProperties();
-                       }
                }
                
                public org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties getUnderlyingProperties() {
@@ -140,10 +192,6 @@ public class POIXMLProperties {
                private org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument props;
                private CustomProperties(org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument props) {
                        this.props = props;
-                       
-                       if(props.getProperties() == null) {
-                               props.addNewProperties();
-                       }
                }
                
                public org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties getUnderlyingProperties() {
diff --git a/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java b/src/ooxml/testcases/org/apache/poi/TestPOIXMLProperties.java
new file mode 100755 (executable)
index 0000000..4349600
--- /dev/null
@@ -0,0 +1,134 @@
+/* ====================================================================
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi;
+
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+
+import junit.framework.TestCase;
+
+/**
+ * Test setting extended and custom OOXML properties
+ */
+public class TestPOIXMLProperties extends TestCase {
+    public void testWorkbookExtendedProperties() throws Exception {
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        POIXMLProperties props = workbook.getProperties();
+        assertNotNull(props);
+
+        org.apache.poi.POIXMLProperties.ExtendedProperties properties =
+                props.getExtendedProperties();
+
+        org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties
+                ctProps = properties.getUnderlyingProperties();
+
+
+        String appVersion = "3.5 beta";
+        String application = "POI";
+
+        ctProps.setApplication(application);
+        ctProps.setAppVersion(appVersion);
+
+        ctProps = null;
+        properties = null;
+        props = null;
+
+        XSSFWorkbook newWorkbook =
+                XSSFTestDataSamples.writeOutAndReadBack(workbook);
+
+        assertTrue(workbook != newWorkbook);
+
+
+        POIXMLProperties newProps = newWorkbook.getProperties();
+        assertNotNull(newProps);
+        org.apache.poi.POIXMLProperties.ExtendedProperties newProperties =
+                newProps.getExtendedProperties();
+
+        org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties
+                newCtProps = newProperties.getUnderlyingProperties();
+
+        assertEquals(application, newCtProps.getApplication());
+        assertEquals(appVersion, newCtProps.getAppVersion());
+
+
+    }
+
+
+    public void testWorkbookCustomProperties() throws Exception {
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        POIXMLProperties props = workbook.getProperties();
+        assertNotNull(props);
+
+        org.apache.poi.POIXMLProperties.CustomProperties properties =
+                props.getCustomProperties();
+
+        org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties
+                ctProps = properties.getUnderlyingProperties();
+
+
+        org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty
+                property = ctProps.addNewProperty();
+
+
+        String fmtid =
+                "{A1A1A1A1A1A1A1A1-A1A1A1A1-A1A1A1A1-A1A1A1A1-A1A1A1A1A1A1A1A1}";
+        int pId = 1;
+        String name = "testProperty";
+        String stringValue = "testValue";
+
+
+        property.setFmtid(fmtid);
+        property.setPid(pId);
+        property.setName(name);
+        property.setBstr(stringValue);
+
+
+        property = null;
+        ctProps = null;
+        properties = null;
+        props = null;
+
+        XSSFWorkbook newWorkbook =
+                XSSFTestDataSamples.writeOutAndReadBack(workbook);
+
+        assertTrue(workbook != newWorkbook);
+
+
+        POIXMLProperties newProps = newWorkbook.getProperties();
+        assertNotNull(newProps);
+        org.apache.poi.POIXMLProperties.CustomProperties newProperties =
+                newProps.getCustomProperties();
+
+        org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties
+                newCtProps = newProperties.getUnderlyingProperties();
+
+        assertEquals(1, newCtProps.getPropertyArray().length);
+
+
+        org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty
+                newpProperty = newCtProps.getPropertyArray()[0];
+
+        assertEquals(fmtid, newpProperty.getFmtid());
+        assertEquals(pId, newpProperty.getPid());
+        assertEquals(name, newpProperty.getName());
+        assertEquals(stringValue, newpProperty.getBstr());
+
+
+    }
+}
\ No newline at end of file