Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.samples » anytype » [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    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans.samples.anytype;
   17   
   18   import org.apache.xmlbeans;
   19   import org.apache.xmlbeans.samples.any.ListOfStrings;
   20   import org.apache.xmlbeans.samples.any.RootDocument;
   21   import org.apache.xmlbeans.samples.any.StringelementDocument;
   22   import org.apache.xmlbeans.samples.any.RootDocument.Root.Arrayofany;
   23   import org.w3c.dom.Element;
   24   import org.w3c.dom.Node;
   25   import org.w3c.dom.NodeList;
   26   
   27   import java.io.File;
   28   import java.io.IOException;
   29   import java.util.ArrayList;
   30   import java.util.Iterator;
   31   
   32   import javax.xml.namespace.QName;
   33   
   34   /**
   35    * A sample that illustrates various ways to manipulate XML whose
   36    * schema defines elements as type xs:any. Unlike its treatment of
   37    * other schema types, XMLBeans does not generate accessors for the 
   38    * xs:any particle when compiling schema. Instead, your code 
   39    * handles instances of this type through any of several alternative 
   40    * means, including XPath queries, the selectChildren method, 
   41    * XmlCursor instances and the DOM API. This samples illustrates 
   42    * these alternative approaches.
   43    */
   44   public class Any
   45   {
   46       private static final String m_namespaceUri = "http://xmlbeans.apache.org/samples/any";
   47   
   48       /**
   49        * Receives <root> XML instance, executing methods that 
   50        * edit the received instance or create a new one.
   51        * 
   52        * @param args An array in which the first item is a
   53        * path to the XML instance file.
   54        */
   55       public static void main(String[] args)
   56       {
   57           Any thisSample = new Any();
   58           System.out.println("Running Any.buildDocFromScratch\n");
   59           thisSample.buildDocFromScratch();
   60           
   61           RootDocument rootDoc = (RootDocument)thisSample.parseXml(args[0]);
   62   
   63           System.out.println("Running Any.editExistingDocWithSelectChildren\n");
   64           thisSample.editExistingDocWithSelectChildren(rootDoc);
   65   
   66           System.out.println("Running Any.editExistingDocWithDOM\n");
   67           thisSample.editExistingDocWithDOM(rootDoc);
   68   
   69           System.out.println("Running Any.editExistingDocWithSelectPath\n");
   70           thisSample.editExistingDocWithSelectPath(rootDoc);
   71       }
   72   
   73       /**
   74        * Creates a new <root> document from scratch.
   75        * 
   76        * This method illustrates how you can use XmlCursor instances
   77        * to build XML that is defined in schema as xs:any.
   78        * 
   79        * @return <code>true</code> if the new document is valid;
   80        * otherwise, <code>false</code>.
   81        */
   82       public boolean buildDocFromScratch()
   83       {
   84           // Start by creating a <root> element that will contain
   85           // the children built by this method.
   86           RootDocument rootDoc = RootDocument.Factory.newInstance();
   87           RootDocument.Root root = rootDoc.addNewRoot();
   88           
   89           // Add the first element, <stringelement>.
   90           root.setStringelement("some text");
   91   
   92           // Create an XmlObject in which to build the second
   93           // element in the sequence, <anyfoo>. Here, the 
   94           // XmlObject instance is simply a kind of incubator
   95           // for the XML. Later the XML will be moved into the
   96           // document this code is building.
   97           XmlObject anyFoo = XmlObject.Factory.newInstance();
   98   
   99           // Add a cursor to do the work of building the XML.
  100           XmlCursor childCursor = anyFoo.newCursor();
  101           childCursor.toNextToken();
  102   
  103           // Add the element in the schema's namespace, then add
  104           // element content.
  105           childCursor.beginElement(new QName(m_namespaceUri, "anyfoo"));
  106           childCursor.insertChars("some text");
  107   
  108           // Move the cursor back to the new element's top, where 
  109           // it can grab the element's XML.
  110           childCursor.toStartDoc();
  111           childCursor.toNextToken();
  112   
  113           // Move the XML into the <root> document by moving it
  114           // from a position at one cursor to a position at
  115           // another.
  116           XmlCursor rootCursor = root.newCursor();
  117           rootCursor.toEndToken();
  118           childCursor.moveXml(rootCursor);
  119   
  120           // Add the fourth element, <arrayofany>, by building it
  121           // elsewhere, then moving the new XML into place under
  122           // <root>.
  123           Arrayofany arrayOfAny = root.addNewArrayofany();
  124           if (buildArrayOfAny(arrayOfAny) == null)
  125           {
  126               return false;
  127           }
  128   
  129           childCursor.dispose();
  130           rootCursor.dispose();
  131   
  132           // Print and validate the result.
  133           System.out.println("Output: The <root> document built from scratch.\n");
  134           System.out.println(rootDoc + "\n");
  135           return validateXml(rootDoc);
  136       }
  137       
  138       /**
  139        * Replaces the <anyfoo> element with an <anybar> element in the
  140        * incoming XML.
  141        * 
  142        * This method illustrates how you can use the XmlCursor.selectChildren
  143        * method to retrieve child elements whose type is defined as
  144        * xs:any in schema.
  145        * 
  146        * @param rootDoc An instance of the <root> XML document.
  147        * @return <code>true</code> if the editing XML is valid; 
  148        * otherwise, <code>false</code>.
  149        */
  150       public boolean editExistingDocWithSelectChildren(RootDocument rootDoc)
  151       {
  152           RootDocument.Root root = rootDoc.getRoot();
  153           
  154           // Select the <anyfoo> children of <root>.
  155           XmlObject[] stringElements =
  156               root.selectChildren(new QName(m_namespaceUri, "anyfoo"));
  157   
  158           // If the element is there, replace it with another element.
  159           if (stringElements.length > 0)
  160           {
  161               XmlCursor editCursor = stringElements[0].newCursor();
  162               editCursor.removeXml();
  163               editCursor.beginElement(new QName(m_namespaceUri, "anybar"));
  164               editCursor.insertChars("some other text");                
  165               editCursor.dispose();
  166           }
  167           System.out.println("Output: The <anyfoo> element has been replaced\n" +
  168           		"by an <anybar> element.\n");
  169           System.out.println(rootDoc + "\n");
  170           return validateXml(rootDoc);
  171       }
  172   
  173       /**
  174        * Adds a new <bar> element between the first and second
  175        * children of the <arrayofany> element.
  176        * 
  177        * This method illustrates how you can use DOM methods to 
  178        * retrieve and edit elements whose type is defined as
  179        * xs:any in schema.
  180        * 
  181        * @param rootDoc An instance of the <root> XML document.
  182        * @return <code>true</code> if the editing XML is valid; 
  183        * otherwise, <code>false</code>.
  184        */
  185       public boolean editExistingDocWithDOM(RootDocument rootDoc)
  186       {
  187           RootDocument.Root root = rootDoc.getRoot();
  188           
  189           // Get the DOM nodes for the <arrayofany> element's children.
  190           Node arrayOfAnyNode = root.getArrayofany().getDomNode();
  191   
  192           // You don't have get* accessors for any of the <arrayofany> 
  193           // element's children, so use DOM to identify the first
  194           // and second elements while looping through the child list.
  195           NodeList childList = arrayOfAnyNode.getChildNodes();
  196           Element firstElementChild = null;
  197           Element secondElementChild = null;
  198   
  199           // Find the first child element and make sure it's
  200           // <stringelement>.
  201           for (int i = 0; i < childList.getLength(); i++)
  202           {
  203               Node node = childList.item(i);
  204               if (node.getNodeType() == Node.ELEMENT_NODE)
  205               {
  206                   if (node.getLocalName().equals("stringelement"))
  207                   {
  208                       firstElementChild = (Element)node;                
  209                       break;
  210                   }
  211               }
  212           }
  213           if (firstElementChild == null) {return false;}
  214   
  215           // Find the second child element and make sure it's
  216           // <someelement>.
  217           Node node = firstElementChild.getNextSibling();
  218           do {
  219               if (node.getNodeType() == Node.ELEMENT_NODE)
  220               {
  221                   if (node.getLocalName().equals("someelement"))
  222                   {
  223                       secondElementChild = (Element)node;
  224                       break;
  225                   }
  226               }
  227               node = node.getNextSibling();
  228           } while (node != null);
  229           if (secondElementChild == null) {return false;}
  230           
  231           // Create and insert a new <bar> element.
  232           Element fooElement = 
  233               secondElementChild.getOwnerDocument().createElementNS("http://openuri.org","bar");
  234           Node valueNode = 
  235               fooElement.getOwnerDocument().createTextNode("some text");
  236           fooElement.appendChild(valueNode);
  237           arrayOfAnyNode.insertBefore(fooElement, secondElementChild);
  238           
  239           System.out.println("Output: <arrayofany> has a new <bar> child element.\n");
  240           System.out.println(rootDoc + "\n");
  241           return validateXml(rootDoc);        
  242       }
  243       
  244       /**
  245        * Edits incoming <root> XML to make the following changes: replace
  246        * <somelement> with its <stringlist> child; add a new <foo> 
  247        * element as the second child of <arrayofany>.
  248        * 
  249        * This method illustrates how you can use the selectPath method
  250        * to find an element defined as xs:any in schema, then use
  251        * XmlCursor instances to edit the XML.
  252        * 
  253        * @param rootDoc An instance of the <root> XML document.
  254        * @return <code>true</code> if the editing XML is valid; 
  255        * otherwise, <code>false</code>.
  256        */
  257       public boolean editExistingDocWithSelectPath(RootDocument rootDoc)
  258       {
  259           String namespaceDecl = "declare namespace any='" + 
  260           			m_namespaceUri + "'; ";
  261           XmlCursor selectionCursor = rootDoc.getRoot().getArrayofany().newCursor();
  262   
  263           // Save the cursor's position for later, then use XPath
  264           // and cursor movement to position the cursor at
  265           // the <stringlist> element.
  266           selectionCursor.push();
  267           selectionCursor.selectPath(namespaceDecl + 
  268                   "$this//any:someelement/any:stringlist");
  269           selectionCursor.toNextSelection();
  270   
  271           // Create a new cursor and move it to the selection
  272           // cursor's <someelement> parent. Moving the 
  273           // <stringlist> element to this position, displacing
  274           // the <someelement> downward, then removing the
  275           // <someelement> XML effectively replaces <someelement>
  276           // with <stringlist>.
  277           XmlCursor editCursor = selectionCursor.newCursor();
  278           editCursor.toParent();
  279           selectionCursor.moveXml(editCursor);
  280           editCursor.removeXml();
  281           editCursor.dispose();
  282   
  283           // Return the cursor to the <arrayofany> element so you 
  284           // can do more editing. Then move the cursor to the second 
  285           // child and insert a new element as second child.
  286           selectionCursor.pop();
  287           selectionCursor.toFirstChild();
  288           selectionCursor.toNextSibling();
  289           selectionCursor.beginElement("foo", "http://openuri.org");
  290           selectionCursor.insertChars("some text");
  291           selectionCursor.dispose();
  292   
  293           System.out.println("Output: <stringlist> has been promoted to replace \n" +
  294                   "<someelement>, and there's a new <foo> element.\n");
  295           System.out.println(rootDoc + "\n");
  296           return validateXml(rootDoc);        
  297       }
  298   
  299       /**
  300        * Like the code in the buildDocFromScratch method, this code
  301        * uses the XmlCursor to build XML piece by piece, building
  302        * out the Arrayofany instance it receives. 
  303        * 
  304        * @return A valid <arrayofany> element bound to an 
  305        * Arrrayofany instance.
  306        */
  307       private Arrayofany buildArrayOfAny(Arrayofany arrayOfAny)
  308       {
  309           // Create a simple <stringelement> and move it into place
  310           // under <arrayofany>.
  311           StringelementDocument stringElementDoc = 
  312               StringelementDocument.Factory.newInstance();        
  313           stringElementDoc.setStringelement("some text");
  314           XmlCursor childCursor = stringElementDoc.newCursor();
  315           childCursor.toFirstContentToken();
  316   
  317           // Add a cursor to mark the position at which the new child 
  318           // XML will be moved.
  319           XmlCursor arrayCursor = arrayOfAny.newCursor();
  320           arrayCursor.toNextToken();
  321           childCursor.moveXml(arrayCursor);        
  322           childCursor.dispose();
  323           
  324           // Create a <someelement> that contains a <stringlist>
  325           // child element, then get the XmlObject representing the new
  326           // <stringlist>. Note that the XmlCursor.beginElement method
  327           // leaves the cursor between START and END tokens -- where 
  328           // content can be placed.
  329           arrayCursor.beginElement("someelement", m_namespaceUri);
  330           arrayCursor.beginElement("stringlist", m_namespaceUri);
  331           arrayCursor.toPrevToken();
  332           XmlObject stringList = arrayCursor.getObject();
  333   
  334           // The cursor's no longer needed.
  335           arrayCursor.dispose();
  336   
  337           // Create the <stringlist> element's value and set it.
  338           ListOfStrings stringListValue = buildListOfStrings();
  339           if (stringListValue == null)
  340           {
  341               return null;
  342           }
  343           stringList.set(stringListValue);
  344   
  345           // Validate the new XML.
  346           if (!validateXml(arrayOfAny))
  347           {
  348               return null;
  349           }
  350   
  351           return arrayOfAny;
  352       }
  353       
  354       /**
  355        * Creates an instance of the ListOfStrings complex type defined
  356        * in the schema. The instance returned by this method can be 
  357        * inserted using either a set* operation or a cursor, as in 
  358        * {@link #buildArrayOfAny()}.
  359        * 
  360        * @return A valid instance of ListOfStrings.
  361        */
  362       private ListOfStrings buildListOfStrings()
  363       {
  364           // Create an instance of the ListOfStrings complex type.
  365           ListOfStrings stringList = ListOfStrings.Factory.newInstance();
  366           stringList.setId("001");
  367   
  368           // Add two children for the instance's root.
  369           XmlString stringElement = stringList.addNewStringelement();
  370           stringElement.setStringValue("string1");
  371           stringElement = stringList.addNewStringelement();
  372           stringElement.setStringValue("string2");
  373           
  374           // Validate the new XML.
  375           if (!validateXml(stringList))
  376           {
  377               return null;
  378           }
  379   
  380           return stringList;
  381       }
  382       
  383       /**
  384        * <p>Validates the XML, printing error messages when the XML is invalid. Note
  385        * that this method will properly validate any instance of a compiled schema
  386        * type because all of these types extend XmlObject.</p>
  387        *
  388        * <p>Note that in actual practice, you'll probably want to use an assertion
  389        * when validating if you want to ensure that your code doesn't pass along
  390        * invalid XML. This sample prints the generated XML whether or not it's
  391        * valid so that you can see the result in both cases.</p>
  392        *
  393        * @param xml The XML to validate.
  394        * @return <code>true</code> if the XML is valid; otherwise, <code>false</code>
  395        */
  396       public static boolean validateXml(XmlObject xml)
  397       {
  398           boolean isXmlValid = false;
  399   
  400           // A collection instance to hold validation error messages.
  401           ArrayList validationMessages = new ArrayList();
  402   
  403           // Validate the XML, collecting messages.
  404           isXmlValid = xml.validate(
  405                   new XmlOptions().setErrorListener(validationMessages));
  406   
  407           // If the XML isn't valid, print the messages.
  408           if (!isXmlValid)
  409           {
  410               printErrors(validationMessages);
  411           }
  412           return isXmlValid;
  413       }
  414       
  415       /**
  416        * Receives the collection containing errors found during
  417        * validation and print the errors to the console.
  418        * 
  419        * @param validationErrors The validation errors.
  420        */
  421       public static void printErrors(ArrayList validationErrors)
  422       {
  423           Iterator iter = validationErrors.iterator();
  424           while (iter.hasNext())
  425           {
  426               System.out.println(">> " + iter.next() + "\n");
  427           }
  428       }
  429   
  430       /**
  431        * <p>Creates a File from the XML path provided in main arguments, then
  432        * parses the file's contents into a type generated from schema.</p>
  433        * <p/>
  434        * <p>Note that this work might have been done in main. Isolating it here
  435        * makes the code separately available from outside this class.</p>
  436        *
  437        * @param xmlFilePath A path to XML based on the schema in inventory.xsd.
  438        * @return An instance of a generated schema type that contains the parsed
  439        *         XML.
  440        */
  441       public XmlObject parseXml(String xmlFilePath)
  442       {
  443           File xmlFile = new File(xmlFilePath);
  444           XmlObject xml = null;
  445           try
  446           {
  447               xml = XmlObject.Factory.parse(xmlFile);
  448           } catch (XmlException e)
  449           {
  450               e.printStackTrace();
  451           } catch (IOException e)
  452           {
  453               e.printStackTrace();
  454           }
  455           return xml;
  456       }
  457   }

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