# LAB-5569: ODFDOM - Changing ODF documents using the new opensourced multi-tiered API

Expected Duration: 100 minutes
Contacts: Svante.Schubert Steffen Grund

Introduction | Exercise 0 | Exercise 1 | Exercise 2 | Exercise 3 | Exercise 4 | Summary
4. Introduction Steps to Follow Summary ## Exercise 1: Exploring the ODFDOM layers (20 minutes) The goal of this exercise is to get an impression of the ODFDOM layers following step by step instructions. ### Steps to Follow Step 1: Opening the Project If NetBeans is not already running, start it. Select File Menu Select New Project Select Category 'Java' and Project 'Java Application' Press 'Next' Figure-01: New Project: Choose Project In the next dialog, do the following Set 'Project Name' to OdfdomLayers Set 'Project Location' to '<lab_root>' - note for JavaOne attendees: this is correct as it is - just keep the default. Enter 'odfdom.example1.RunExample1' as main class. Press 'Finish' Figure-02: New Java Application: Name and Location We are adding some jar libraries to our project - for future usage. Right-click the OdfdomLayers project and choose 'Properties'. In the 'Libraries' category, click 'Add JAR/Folder'. Add the following libraries to the project: <lab_root>/resources/odfdom/jars/xercesImpl.jar <lab_root>/resources/odfdom/jars/odfdom.jar For JavaOne attendees, the libraries are here: /export/home/lab5569/odfdom/resources/odfdom/jars/xercesImpl.jar /export/home/lab5569/odfdom/resources/odfdom/jars/odfdom.jar Click "OK" afterwards. Figure-03: Add required libraries to the project After the project creation, the main class is automatically opened by NetBeans. When you enter the following code inside of the `main(...)` method, do not forget to set the `LAB_ROOT` variable. For JavaOne attendees, the line in the following code snippet is already correct. The second part of the exercise is commented at first since this project will be run twice.
           // For JavaOne the place for the project is this; change it for your machine
           private static final String LAB_ROOT = "/export/home/lab5569/odfdom/";
           private static final Logger LOG = Logger.getLogger(RunExample1.class.getName());

           /**
            *  Executes the first lab exercise.
            *
            * @param args the command line arguments
            */
           public static void main(String[] args) {
               try {
                   // 1st ODFDOM LAYER - PACKAGE / PHYSICAL LAYER:
                   // Creating an ODF package containing an image not shown in the text
                   firstExercicePart1();
               } catch (Exception ex) {
                   LOG.log(Level.SEVERE, "Something weired happened in the first part..", ex);
               }

       //        try {
       //            // 2nd ODFDOM LAYER - TYPED DOM / XML LAYER:
       //            // Creating an ODF Text document showing the image from the package
       //            firstExercicePart2();
       //        } catch (Exception ex) {
       //            LOG.log(Level.SEVERE, "Something weired happened in the second part..", ex);
       //        }
       //
       //        try {
       //            // 3rd ODFDOM LAYER - CONVENIENCE LAYER:
       //            // Quite similar to the previous DOM handling, as a DOC layer is always a child
       //            // of a DOM layer object therefore as well a DOM tree.
       //            //
       //            //
       //            // Two things are done for the user behind the scene:
       //            //
       //            // 1) The package handling to insert the image file
       //            //
       //            // 2) The default size is received from the image via AWT helper and
       //            // added to the attributes of the sourrounding draw:frame.
       //            firstExercicePart3();
       //        } catch (Exception ex) {
       //            LOG.log(Level.SEVERE, "Something weired happened in the third part..", ex);
       //        }
           }
5. Now implement the first exercise method. Notice that the output directory without path is the root of your current NetBeans project. The file is saved twice here with different extensions. With the .odt extension, you can open the file in OpenOffice.org, and with the .zip extension, the content can be viewed in NetBeans.
           /**
            * 1st ODFDOM LAYER - PACKAGE / PHYSICAL LAYER:
            * Creating an ODF package containing an image not shown in the text
            *
            * @throws java.lang.Exception
            */
           private static void firstExercicePart1() throws Exception {
               // ODF KNOW-HOW: One ODF Package is only a zipped container for arbitrary files of some document.
               OdfPackage pkg = OdfPackage.loadPackage(LAB_ROOT + "resources/e1-input.odt");
               // Inserting an image into the 'Pictures' directory within the ODF package.
               pkg.insert(new FileInputStream(LAB_ROOT + "resources/e1-01_DukeToEmbed.png"),
                       "Pictures/e1-01_DukeToEmbed.png");

               // Save the package with the picture; no path used here, will be stored in project root
               pkg.save("output_1_seems-empty.odt");
               // zip can be opened with NetBeans
               pkg.save("output_1_seems-empty.zip");

               // ODF-KNOW-HOW: Only images referenced from the text will be viewed in ODF.
               //              Therefore if the document is being opened (for instance with OpenOffice.org)
               //              The document appears to be empty.
               LOG.info("SUCCESS: You were able to save an ODF Package containing an image, which is not shown!");
           }
8. Press CTRL+S to save your file. Then press CTRL+SHIFT+I to fix the missing imports from the libraries. Your project should now be able to run. Press F6 for this. If it does not work, verify your code or ask a proctor. The result is shown in Figure-04. Activate the "Files" tab where the resulting document is displayed. NetBeans offers a simple way to browse into zip files: just click on the symbol before the file, then open the "Pictures" folder. You can open the .odt file in OpenOffice.org from here, too: click right on the document and select "Open With OpenOffice.org" Figure-04: Verify the correct document in Netbeans We implement the second exercise method. Please uncomment the execution of `firstExercisePart2();` in the `main(...)` method and implement the method like this:
           /**
            * 2nd ODFDOM LAYER - TYPED DOM / XML LAYER
            * Creating an ODF Text document showing the image from the package
            *
            * @throws java.lang.Exception
            */
           private static void firstExercicePart2() throws Exception {
               // ODF-KNOW-HOW: An ODF Package contains one or more ODF Documents.
               //               The ODF XML elements part of an ODF Document.
               // Load the ODF Package as an ODF Document.
               OdfDocument odfDoc = OdfDocument.loadDocument("output_1_seems-empty.odt");

               // Get the ODF XML content as DOM tree representation.
               OdfFileDom odfContent = odfDoc.getContentDom();

               // ODF KNOW-HOW: The element name of a paragraph is <text:p>
               // Receiving the first paragraph  "//text:p[1]" (using XPath functionality from JDK).
               XPath xpath = getXPathForODF();
               OdfParagraphElement para = (OdfParagraphElement) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE);

               // ODF KNOW-HOW: An image consists always of a <draw:frame> parent and an embedded <draw:image> child.
               // Create the <draw:frame> ODF element.
               OdfFrameElement odfFrame = (OdfFrameElement) OdfElementFactory.createOdfElement(odfContent,
               OdfFrame.ELEMENT_NAME);

               // Add the created frame to the earlier found first paragraph.
               para.appendChild(odfFrame);

               // create the <draw:image> ODF element viewing the previous (Part1 )inserted image
               OdfImageElement odfImage = (OdfImageElement) OdfElementFactory.createOdfElement(odfContent,
               OdfImage.ELEMENT_NAME);

               // Add the created image to the earlier created frame.
               odfFrame.appendChild(odfImage);

               // setting the xlink:href attribute
               odfImage.setHref(new OdfAnyURI("Pictures/e1-01_DukeToEmbed.png"));

               // Save the document; no path used here, will be stored in project root
               odfDoc.save("output_2_image-visible-small.odt");
               // zip can be opened with NetBeans
               odfDoc.save("output_2_image-visible-small.zip");
               LOG.info("SUCCESS: You were able to save an ODF Document again, now showing the earlier added image (small)!!");

           }
9. For the second exercise method to work, we need some helper. This is the helper function:
           private static XPath mXPath;

           private static XPath getXPathForODF() {
               if (mXPath == null) {
                   // W3C XPath initialization (i.e. JDK5 functionality)  -
                   // XPath is the path within the XML file
                   mXPath = XPathFactory.newInstance().newXPath();
                   mXPath.setNamespaceContext(new OdfNamespace());
               }
               return mXPath;
           }
12. Again press CTRL+S to save your file, followed by CTRL+SHIFT+I to fix the missing imports. This time you will be asked for correct classes. Figure-05 shows the correct imports. Figure-05: Correct imports for the used classes Your project should again be able to run. Press F6 for this. If it does not work, verify your code or ask a proctor. The result is shown in Figure-06. This time we use OpenOffice.org to verify: Open OpenOffice.org and click on "File - Open". Browse to your NetBeans project and open the file "e1-output-2.odt": Figure-06: Image is visiable, but small In the last layer, the convenient layer ODFDOM adds enhanced functionality and eases the developer's life. We implement the third exercise method. Please uncomment the execution of `firstExercisePart3();` in the `main(...)` method and implement the method like this:
          /**
             * 3rd ODFDOM LAYER - CONVENIENCE LAYER:
             * Quite similar to the previous DOM handling, as a DOC layer is always a child
             * of a DOM layer object therefore as well a DOM tree.
             *
             *
             * Two things are done for the user behind the scene:
             *
             * 1) The package handling to insert the image file
             *
             * 2) The default size is received from the image via AWT helper and
             * added to the attributes of the sourrounding draw:frame.
             *
             * @throws java.lang.Exception
             */
            private static void firstExercicePart3() throws Exception {

                OdfTextDocument odfText = OdfTextDocument.createTextDocument();
                // Get the ODF XML content as DOM tree representation.
                OdfFileDom odfContent = odfText.getContentDom();

                // ODF KNOW-HOW: The element name of a paragraph is <text:p>
                // Receiving the first paragraph  "//text:p[1]" (using XPath functionality from JDK).
                XPath xpath = getXPathForODF();
                OdfParagraph para = (OdfParagraph) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE);

                // ODF KNOW-HOW: An image consists always of a <draw:frame> parent and an embedded <draw:image> child.
                // Create the <draw:frame> ODF element.
                OdfFrame odfFrame = (OdfFrame) OdfElementFactory.createOdfElement(odfContent, OdfFrame.ELEMENT_NAME);

                // Add the created frame to the earlier found first paragraph.
                para.appendChild(odfFrame);

                // create the <draw:image> ODF element to view the similar image file
                OdfImage odfImage = (OdfImage) OdfElementFactory.createOdfElement(odfContent, OdfImage.ELEMENT_NAME);

                // Add the created image to the earlier created frame.
                odfFrame.appendChild(odfImage);

                // NOTE: Loading the image (relativ to <LABROOT>/solution/solution1
                // Adding the image to the package, getting the default
                // size via AWT helper and setting the size at the draw:frame parent.
                odfImage.insertImage(new URI("../../odfdom/resources/e1-01_DukeToEmbed.png"));

                // Save the document; no path used here, will be stored in project root
                odfText.save("output_3_image-visible-big.odt");
                // zip can be opened with NetBeans
                odfText.save("output_3_image-visible-big.zip");
                LOG.info("SUCCESS: You were able to add an image into an ODF Text Document using the convenient API!!");

            }
15. Again press CTRL+S to save your file, followed by CTRL+SHIFT+I to fix the missing imports. Your project should again be able to run. Press F6 for this. If it does not work, verify your code or ask a proctor. The result is shown in Figure-07. This time we use OpenOffice.org to verify: Open OpenOffice.org and click on "File - Open". Browse to your NetBeans project and open the file "e1-output-3.odt": Figure-07: Image is visable with it's default size For troubleshooting, the complete example should look like this (with first example method enabled):
        /*
         * To change this template, choose Tools | Templates
         * and open the template in the editor.
         */

        package odfdom.example1;

        import java.io.FileInputStream;
        import java.net.URI;
        import java.util.logging.Level;
        import java.util.logging.Logger;
        import javax.xml.xpath.XPath;
        import javax.xml.xpath.XPathConstants;
        import javax.xml.xpath.XPathFactory;
        import org.odftoolkit.odfdom.doc.OdfDocument;
        import org.odftoolkit.odfdom.doc.OdfFileDom;
        import org.odftoolkit.odfdom.doc.OdfTextDocument;
        import org.odftoolkit.odfdom.doc.element.OdfElementFactory;
        import org.odftoolkit.odfdom.doc.element.draw.OdfFrame;
        import org.odftoolkit.odfdom.doc.element.draw.OdfImage;
        import org.odftoolkit.odfdom.doc.element.text.OdfParagraph;
        import org.odftoolkit.odfdom.dom.OdfNamespace;
        import org.odftoolkit.odfdom.dom.element.draw.OdfFrameElement;
        import org.odftoolkit.odfdom.dom.element.draw.OdfImageElement;
        import org.odftoolkit.odfdom.dom.element.text.OdfParagraphElement;
        import org.odftoolkit.odfdom.dom.type.OdfAnyURI;
        import org.odftoolkit.odfdom.pkg.OdfPackage;

        /**
         *
         * @author sg128468
         */
        public class RunExample1 {

            // For JavaOne the place for the project is this; change it for your machine
            private static final String LAB_ROOT = "/export/home/lab5569/odfdom/";
            private static final Logger LOG = Logger.getLogger(RunExample1.class.getName());

            /**
             * @param args the command line arguments
             */
            public static void main(String[] args) {
               try {
                    // 1st ODFDOM LAYER - PACKAGE / PHYSICAL LAYER:
                    // Creating an ODF package containing an image not shown in the text
                    firstExercicePart1();
                } catch (Exception ex) {
                    LOG.log(Level.SEVERE, "Something weired happened in the first part..", ex);
                }

                try {
                    // 2nd ODFDOM LAYER - TYPED DOM / XML LAYER:
                    // Creating an ODF Text document showing the image from the package
                    firstExercicePart2();
                } catch (Exception ex) {
                    LOG.log(Level.SEVERE, "Something weired happened in the second part..", ex);
                }

                try {
                    // 3rd ODFDOM LAYER - CONVENIENCE LAYER:
                    // Quite similar to the previous DOM handling, as a DOC layer is always a child
                    // of a DOM layer object therefore as well a DOM tree.
                    //
                    //
                    // Two things are done for the user behind the scene:
                    //
                    // 1) The package handling to insert the image file
                    //
                    // 2) The default size is received from the image via AWT helper and
                    // added to the attributes of the sourrounding draw:frame.
                    firstExercicePart3();
                } catch (Exception ex) {
                    LOG.log(Level.SEVERE, "Something weired happened in the third part..", ex);
                }
            }

            /**
             * 1st ODFDOM LAYER - PACKAGE / PHYSICAL LAYER:
             * Creating an ODF package containing an image not shown in the text
             *
             * @throws java.lang.Exception
             */
            private static void firstExercicePart1() throws Exception {
                // ODF KNOW-HOW: One ODF Package is only a zipped container for arbitrary files of some document.
                OdfPackage pkg = OdfPackage.loadPackage(LAB_ROOT + "resources/e1-input.odt");
                // Inserting an image into the 'Pictures' directory within the ODF package.
                pkg.insert(new FileInputStream(LAB_ROOT + "resources/e1-01_DukeToEmbed.png"),
                        "Pictures/e1-01_DukeToEmbed.png");

                // Save the package with the picture; no path used here, will be stored in project root
                pkg.save("output_1_seems-empty.odt");
                // zip can be opened with NetBeans
                pkg.save("output_1_seems-empty.zip");

                // ODF-KNOW-HOW: Only images referenced from the text will be viewed in ODF.
                //              Therefore if the document is being opened (for instance with OpenOffice.org)
                //              The document appears to be empty.
                LOG.info("SUCCESS: You were able to save an ODF Package containing an image, which is not shown!");
            }

            /**
             * 2nd ODFDOM LAYER - TYPED DOM / XML LAYER
             * Creating an ODF Text document showing the image from the package
             *
             * @throws java.lang.Exception
             */
            private static void firstExercicePart2() throws Exception {
                // ODF-KNOW-HOW: An ODF Package contains one or more ODF Documents.
                //               The ODF XML elements part of an ODF Document.
                // Load the ODF Package as an ODF Document.
                OdfDocument odfDoc = OdfDocument.loadDocument("output_1_seems-empty.odt");

                // Get the ODF XML content as DOM tree representation.
                OdfFileDom odfContent = odfDoc.getContentDom();

                // ODF KNOW-HOW: The element name of a paragraph is <text:p>
                // Receiving the first paragraph  "//text:p[1]" (using XPath functionality from JDK).
                XPath xpath = getXPathForODF();
                OdfParagraphElement para = (OdfParagraphElement) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE);

                // ODF KNOW-HOW: An image consists always of a <draw:frame> parent and an embedded <draw:image> child.
                // Create the <draw:frame> ODF element.
                OdfFrameElement odfFrame = (OdfFrameElement) OdfElementFactory.createOdfElement(odfContent,
                OdfFrame.ELEMENT_NAME);

                // Add the created frame to the earlier found first paragraph.
                para.appendChild(odfFrame);

                // create the <draw:image> ODF element viewing the previous (Part1 )inserted image
                OdfImageElement odfImage = (OdfImageElement) OdfElementFactory.createOdfElement(odfContent,
                OdfImage.ELEMENT_NAME);

                // Add the created image to the earlier created frame.
                odfFrame.appendChild(odfImage);

                // setting the xlink:href attribute
                odfImage.setHref(new OdfAnyURI("Pictures/e1-01_DukeToEmbed.png"));

                // Save the document; no path used here, will be stored in project root
                odfDoc.save("output_2_image-visible-small.odt");
                // zip can be opened with NetBeans
                odfDoc.save("output_2_image-visible-small.zip");
                LOG.info("SUCCESS: You were able to save an ODF Document again, now showing the earlier added image (small)!!");

            }

         /**
             * 3rd ODFDOM LAYER - CONVENIENCE LAYER:
             * Quite similar to the previous DOM handling, as a DOC layer is always a child
             * of a DOM layer object therefore as well a DOM tree.
             *
             *
             * Two things are done for the user behind the scene:
             *
             * 1) The package handling to insert the image file
             *
             * 2) The default size is received from the image via AWT helper and
             * added to the attributes of the sourrounding draw:frame.
             *
             * @throws java.lang.Exception
             */
            private static void firstExercicePart3() throws Exception {

                OdfTextDocument odfText = OdfTextDocument.createTextDocument();
                // Get the ODF XML content as DOM tree representation.
                OdfFileDom odfContent = odfText.getContentDom();
                // ODF KNOW-HOW: The element name of a paragraph is <text:p>
                // Receiving the first paragraph  "//text:p[1]" (using XPath functionality from JDK).
                XPath xpath = getXPathForODF();
                OdfParagraph para = (OdfParagraph) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE);

                // ODF KNOW-HOW: An image consists always of a <draw:frame> parent and an embedded <draw:image> child.
                // Create the <draw:frame> ODF element.
                OdfFrame odfFrame = (OdfFrame) OdfElementFactory.createOdfElement(odfContent, OdfFrame.ELEMENT_NAME);

                // Add the created frame to the earlier found first paragraph.
                para.appendChild(odfFrame);

                // create the <draw:image> ODF element to view the similar image file
                OdfImage odfImage = (OdfImage) OdfElementFactory.createOdfElement(odfContent, OdfImage.ELEMENT_NAME);

                // Add the created image to the earlier created frame.
                odfFrame.appendChild(odfImage);

                // NOTE: Loading the image (relativ to <LABROOT>/solution/solution1
                // Adding the image to the package, getting the default
                // size via AWT helper and setting the size at the draw:frame parent.
                odfImage.insertImage(new URI("../../odfdom/resources/e1-01_DukeToEmbed.png"));

                // Save the document; no path used here, will be stored in project root
                odfText.save("output_3_image-visible-big.odt");
                // zip can be opened with NetBeans
                odfText.save("output_3_image-visible-big.zip");
                LOG.info("SUCCESS: You were able to add an image into an ODF Text Document using the convenient API!!");

            }

            private static XPath mXPath;

            private static XPath getXPathForODF() {
                if (mXPath == null) {
                    // W3C XPath initialization (i.e. JDK5 functionality)  -
                    // XPath is the path within the XML file
                    mXPath = XPathFactory.newInstance().newXPath();
                    mXPath.setNamespaceContext(new OdfNamespace());
                }
                return mXPath;
            }

        }
### Summary In this exercise, you learned what the different layers of ODFDOM offer in regard of inserting an image file. Back to top Next exercise