Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.samples » cursor » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   distributed under the License is distributed on an "AS IS" BASIS,
   10    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11    *   Unless required by applicable law or agreed to in writing, software
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans.samples.cursor;
   17   
   18   import org.apache.xmlbeans;
   19   import org.apache.xmlbeans.samples.cursor.mixedcontent.DescriptionType;
   20   import org.apache.xmlbeans.samples.cursor.mixedcontent.InventoryDocument;
   21   import org.apache.xmlbeans.samples.cursor.mixedcontent.ItemType;
   22   
   23   import java.io.File;
   24   import java.io.IOException;
   25   import java.util.ArrayList;
   26   
   27   /**
   28    * <p>This sample illustrates how you can use an XML cursor
   29    * to manipulate the content of an element. Even though
   30    * working with strongly-typed XML (in which you are accessing
   31    * the XML through an API generated from schema) provides easy
   32    * access for getting and setting the entire value of an
   33    * element or attribute, it does not easily provide finer
   34    * grained access to an element's content. This sample
   35    * shows how you can use an XML cursor to "dive into" an
   36    * element's content, manipulating it on a character-by-
   37    * character level.</p>
   38    * <p/>
   39    * <p>The code in this sample is designed to look at the
   40    * description of each item in an inventory list, creating
   41    * a link wherever the description contains a reference
   42    * to another item in the inventory list. This alters the
   43    * &lt;description&gt; element so that it contains a mix of text and
   44    * link elements. Such an element is said to have "mixed
   45    * content."</p>
   46    * <p/>
   47    * This sample uses the schema defined in inventory.xsd.
   48    */
   49   public class MixedContent
   50   {
   51       /**
   52        * Receives an inventory XML instance and rewrites it so that items listed
   53        * in the inventory point to one another via &lt;link&gt; elements.
   54        *
   55        * @param args An array containing one argument: the path to an XML instance
   56        *             conforming to the schema in inventory.xsd.
   57        */
   58       public static void main(String[] args)
   59       {
   60           // Create an instance of this sample to work with.
   61           MixedContent thisSample = new MixedContent();
   62   
   63           // Create an schema type instance from the XML indicated by the path.
   64           InventoryDocument inventoryDoc = thisSample.parseXml(args[0]);
   65   
   66           // Print what was received.
   67           System.out.println("Received XML: \n\n" + inventoryDoc.toString());
   68   
   69           // Edit the XML, adding <link> elements to associate related items.
   70           InventoryDocument linkedResultDoc = thisSample.linkItems(inventoryDoc);
   71   
   72           // Print the updated XML.
   73           System.out.println("XML with linked items: \n\n" + linkedResultDoc.toString());
   74   
   75           // Validate the result.
   76           System.out.println("New XML is valid: " +
   77                   thisSample.validateXml(linkedResultDoc));
   78       }
   79   
   80       /**
   81        * <p>Creates "links" between items in an inventory list by inserting
   82        * a &lt;link&gt; element for each linked item. An XmlCursor
   83        * instance passes through each &lt;description&gt; element, looking
   84        * for text matching the name of an item.</p>
   85        *
   86        * @param inventoryDoc An XML document conforming to the schema in
   87        *                     inventory.xsd.
   88        */
   89       public InventoryDocument linkItems(InventoryDocument inventoryDoc)
   90       {
   91           // Retrieve the &lt;inventory&gt; element and get an array of
   92           // the &lt;item&gt; elements it contains.
   93           InventoryDocument.Inventory inventory = inventoryDoc.getInventory();
   94           ItemType[] items = inventory.getItemArray();
   95   
   96           // Loop through the &lt;item&gt; elements, examining the
   97           // description for each to see if another inventory item
   98           // is mentioned.
   99           for (int i = 0; i < items.length; i++)
  100           {
  101               // Get details about the current item, including
  102               // its length. This will be used to measure text
  103               // while exploring the description.
  104               String itemName = items[i].getName();
  105               String itemId = new Integer(items[i].getId()).toString();
  106               int itemCharCount = itemName.length();
  107   
  108               // Loop through the item descriptions, looking at each
  109               // for the name of the current item.
  110               for (int j = 0; j < items.length; j++)
  111               {
  112                   DescriptionType description = items[j].getDescription();
  113   
  114                   // Insert an XmlCursor instance and set it at
  115                   // the beginning of the <&lt;description&gt; element's text,
  116                   // just after the start tag.
  117                   XmlCursor cursor = description.newCursor();
  118                   cursor.toLastAttribute();
  119                   cursor.toNextToken();
  120   
  121                   // Get a String containing the characters to the
  122                   // immediate right of the cursor, up to the next
  123                   // token (in this case, the next element after
  124                   // the description element). Get the number of
  125                   // characters to the right of the cursor; this will
  126                   // be used to mark the distance the cursor should move
  127                   // before trying another item's description. Also,
  128                   // create a charCount variable to mark the cursor's
  129                   // current position.
  130                   String cursorChars = cursor.getChars();
  131                   int descCharCount = cursorChars.length();
  132                   int charCount = 0;
  133   
  134                   // As long at the cursor hasn't reached the end of the
  135                   // description text, check to see if the text to the
  136                   // cursor's immediate right matches the item name sought.
  137                   // If it does match, remove the text and create a link
  138                   // element to replace it.
  139                   while (charCount < descCharCount)
  140                   {
  141   
  142                       // A char array to hold the characters currently being
  143                       // checked.
  144                       char[] chars = new char[itemCharCount];
  145   
  146                       // Pass the char array with the getChars method. This
  147                       // method will find the chars from the cursor's
  148                       // immediate right to the char at itemCharCount (the
  149                       // length of the item name currently sought). The
  150                       // method's second argument indicates where in the char
  151                       // array the found text should begin -- in this case, at the
  152                       // beginning.
  153                       int charsReturned = cursor.getChars(chars, 0, itemCharCount);
  154   
  155                       // If the characters in chars match the item name, then
  156                       // make a link from the text.
  157                       if (new String(chars).equals(itemName))
  158                       {
  159                           // Remove the found item name.
  160                           cursor.removeChars(itemCharCount);
  161   
  162                           // Begin a new link element whose namespace is the
  163                           // same as the rest of the inventory document. The
  164                           // beginElement method creates a new element with the
  165                           // name specified around the current cursor.
  166                           cursor.beginElement("link",
  167                                   "http://xmlbeans.apache.org/samples/cursor/mixedcontent");
  168   
  169                           // Insert an id attribute and make its value the id of
  170                           // the item sought.
  171                           cursor.insertAttributeWithValue("id", itemId);
  172   
  173                           // Insert the item name as the element's value.
  174                           cursor.insertChars(itemName);
  175                       }
  176   
  177                       // Move on to the next character in the description.
  178                       cursor.toNextChar(1);
  179   
  180                       // Increment the counter tracking the cursor's position.
  181                       charCount++;
  182                   }
  183   
  184                   // Be sure to dispose of a cursor that's no longer needed.
  185                   // This allows it to be garbage collected.
  186                   cursor.dispose();
  187               }
  188           }
  189   
  190           // Return the edited document.
  191           return inventoryDoc;
  192       }
  193   
  194       /**
  195        * <p>Validates the XML, printing error messages when the XML is invalid. Note
  196        * that this method will properly validate any instance of a compiled schema
  197        * type because all of these types extend XmlObject.</p>
  198        *
  199        * <p>Note that in actual practice, you'll probably want to use an assertion
  200        * when validating if you want to ensure that your code doesn't pass along
  201        * invalid XML. This sample prints the generated XML whether or not it's
  202        * valid so that you can see the result in both cases.</p>
  203        *
  204        * @param xml The XML to validate.
  205        * @return <code>true</code> if the XML is valid; otherwise, <code>false</code>
  206        */
  207       public boolean validateXml(XmlObject xml)
  208       {
  209           boolean isXmlValid = false;
  210   
  211           // A collection instance to hold validation error messages.
  212           ArrayList validationMessages = new ArrayList();
  213   
  214           // Validate the XML, collecting messages.
  215           isXmlValid = xml.validate(
  216                   new XmlOptions().setErrorListener(validationMessages));
  217   
  218           // If the XML isn't valid, print the messages.
  219           if (!isXmlValid)
  220           {
  221               System.out.println("Invalid XML: ");
  222               for (int i = 0; i < validationMessages.size(); i++)
  223               {
  224                   XmlError error = (XmlError) validationMessages.get(i);
  225                   System.out.println(error.getMessage());
  226                   System.out.println(error.getObjectLocation());
  227               }
  228           }
  229           return isXmlValid;
  230       }
  231   
  232       /**
  233        * <p>Creates a File from the XML path provided in main arguments, then
  234        * parses the file's contents into a type generated from schema.</p>
  235        *
  236        * <p>Note that this work might have been done in main. Isolating it here
  237        * makes the code separately available from outside this class.</p>
  238        *
  239        * @param xmlFilePath A path to XML based on the schema in inventory.xsd.
  240        * @return An instance of a generated schema type that contains the parsed
  241        * XML.
  242        */
  243       public InventoryDocument parseXml(String xmlFilePath)
  244       {
  245           // Get the XML instance into a file using the path provided.
  246           File inventoryFile = new File(xmlFilePath);
  247   
  248           // Create an instance of a type generated from schema to hold the XML.
  249           InventoryDocument inventoryDoc = null;
  250           try
  251           {
  252               // Parse the instance into the type generated from the schema.
  253               inventoryDoc = InventoryDocument.Factory.parse(inventoryFile);
  254           } catch (XmlException e)
  255           {
  256               e.printStackTrace();
  257           } catch (IOException e)
  258           {
  259               e.printStackTrace();
  260           }
  261           return inventoryDoc;
  262       }
  263   }

Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.samples » cursor » [javadoc | source]