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

    1   /*   Copyright 2009 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.cursor;
   17   
   18   import java.io.File;
   19   import java.io.IOException;
   20   import java.util.Comparator;
   21   
   22   import org.apache.xmlbeans.XmlCursor;
   23   import org.apache.xmlbeans.XmlException;
   24   import org.apache.xmlbeans.XmlObject;
   25   
   26   import javax.xml.namespace.QName;
   27   
   28   /**
   29    */
   30   public final class XmlSort
   31   {
   32       /**
   33        * Receives an XML element instance and sorts the children of this
   34        * element in lexicographical (by default) order.
   35        *
   36        * @param args An array in which the first item is a
   37        * path to the XML instance file and the second item (optional) is
   38        * an XPath inside the document identifying the element to be sorted
   39        */
   40       public static void main(String[] args)
   41       {
   42           if (args.length < 1 || args.length > 2)
   43           {
   44               System.out.println("    java XmlSort <XML_File> [<XPath>]");
   45               return;
   46           }
   47           File f = new File(args[0]);
   48           try
   49           {
   50               XmlObject docInstance = XmlObject.Factory.parse(f);
   51               XmlObject element = null;
   52               if (args.length > 1)
   53               {
   54                   String xpath = args[1];
   55                   XmlObject[] result = docInstance.selectPath(xpath);
   56                   if (result.length == 0)
   57                   {
   58                       System.out.println("ERROR: XPath \"" + xpath + "\" did not return any results");
   59                   }
   60                   else if (result.length > 1)
   61                   {
   62                       System.out.println("ERROR: XPath \"" + xpath + "\" returned more than one " +
   63                           "node (" + result.length + ")");
   64                   }
   65                   else
   66                       element = result[0];
   67               }
   68               else
   69               {
   70                   // Navigate to the root element
   71                   XmlCursor c = docInstance.newCursor();
   72                   c.toFirstChild();
   73                   element = c.getObject();
   74                   c.dispose();
   75               }
   76               if (element != null)
   77                   sort(element, new QNameComparator(QNameComparator.ASCENDING));
   78               System.out.println(docInstance.xmlText());
   79           }
   80           catch (IOException ioe)
   81           {
   82               System.out.println("ERROR: Could not open file: \"" + args[0] + "\": " +
   83                   ioe.getMessage());
   84           }
   85           catch (XmlException xe)
   86           {
   87               System.out.println("ERROR: Could not parse file: \"" + args[0] + "\": " +
   88                   xe.getMessage());
   89           }
   90       }
   91   
   92       /**
   93        * Sorts the children of <code>element</code> according to the order indicated by the
   94        * comparator.
   95        * @param element the element whose content is to be sorted. Only element children are sorted,
   96        * attributes are not touched. When elements are reordered, all the text, comments and PIs
   97        * follow the element that they come immediately after.
   98        * @param comp a comparator that is to be used when comparing the <code>QName</code>s of two
   99        * elements. See {@link org.apache.xmlbeans.samples.cursor.XmlSort.QNameComparator} for a simple
  100        * implementation that compares two elements based on the value of their QName, but more
  101        * complicated implementations are possible, for instance, ones that compare two elements based
  102        * on the value of a specifc attribute etc.
  103        * @throws IllegalArgumentException if the input <code>XmlObject</code> does not represent
  104        * an element
  105        */
  106       public static void sort(XmlObject element, Comparator comp)
  107       {
  108           XmlCursor headCursor = element.newCursor();
  109           if (!headCursor.isStart())
  110               throw new IllegalStateException("The element parameter must point to a STARTDOC");
  111           // We use insertion sort to minimize the number of swaps, because each swap means
  112           // moving a part of the document
  113           /* headCursor points to the beginning of the list of the already sorted items and
  114              listCursor points to the beginning of the list of unsorted items
  115              At the beginning, headCursor points to the first element and listCursor points to the
  116              second element. The algorithm ends when listCursor cannot be moved to the "next"
  117              element in the unsorted list, i.e. the unsorted list becomes empty */
  118           boolean moved = headCursor.toFirstChild();
  119           if (!moved)
  120           {
  121               // Cursor was not moved, which means that the given element has no children and
  122               // therefore there is nothing to sort
  123               return;
  124           }
  125           XmlCursor listCursor = headCursor.newCursor();
  126           boolean moreElements = listCursor.toNextSibling();
  127           while (moreElements)
  128           {
  129               moved = false;
  130               // While we can move the head of the unsorted list, it means that there are still
  131               // items (elements) that need to be sorted
  132               while (headCursor.comparePosition(listCursor) < 0)
  133               {
  134                   if (comp.compare(headCursor, listCursor) > 0)
  135                   {
  136                       // We have found the position in the sorted list, insert the element and the
  137                       // text following the element in the current position
  138                       /*
  139                        * Uncomment this code to cause the text before the element to move along
  140                        * with the element, rather than the text after the element. Notice that this
  141                        * is more difficult to do, because the cursor's "type" refers to the position
  142                        * to the right of the cursor, so to get the type of the token to the left, the
  143                        * cursor needs to be first moved to the left (previous token)
  144                        *
  145                       headCursor.toPrevToken();
  146                       while (headCursor.isComment() || headCursor.isProcinst() || headCursor.isText())
  147                           headCursor.toPrevToken();
  148                       headCursor.toNextToken();
  149                       listCursor.toPrevToken();
  150                       while (listCursor.isComment() || listCursor.isProcinst() || listCursor.isText())
  151                           listCursor.toPrevToken();
  152                       listCursor.toNextToken();
  153                       while (!listCursor.isStart())
  154                           listCursor.moveXml(headCursor);
  155                       listCursor.moveXml(headCursor);
  156                       */
  157                       // Move the element
  158                       listCursor.moveXml(headCursor);
  159                       // Move the text following the element
  160                       while (!listCursor.isStart() && !listCursor.isEnd())
  161                           listCursor.moveXml(headCursor);
  162                       moreElements = listCursor.isStart();
  163                       moved = true;
  164                       break;
  165                   }
  166                   headCursor.toNextSibling();
  167               }
  168               if (!moved)
  169               {
  170                   // Because during the move of a fragment of XML, the listCursor is also moved, in
  171                   // case we didn't need to move XML (the new element to be inserted happened to
  172                   // be the last one in order), we need to move this cursor
  173                   moreElements = listCursor.toNextSibling();
  174               }
  175               // Reposition the head of the sorted list
  176               headCursor.toParent();
  177               headCursor.toFirstChild();
  178           }
  179       }
  180   
  181       /**
  182        * Implements a <code>java.util.Comparator</code> for comparing <code>QName</code>values.
  183        * The namespace URIs are compared first and if they are equal, the local parts are compared.
  184        * <p/>
  185        * The constructor accepts an argument indicating whether the comparison order is the same as
  186        * the lexicographic order of the strings or the reverse.
  187        */
  188       public static final class QNameComparator implements Comparator
  189       {
  190           public static final int ASCENDING = 1;
  191           public static final int DESCENDING = 2;
  192   
  193           private int order;
  194   
  195           public QNameComparator(int order)
  196           {
  197               this.order = order;
  198               if (order != ASCENDING && order != DESCENDING)
  199                   throw new IllegalArgumentException("Please specify one of ASCENDING or DESCENDING "+
  200                       "comparison orders");
  201           }
  202   
  203           public int compare(Object o, Object o1)
  204           {
  205               XmlCursor cursor1 = (XmlCursor) o;
  206               XmlCursor cursor2 = (XmlCursor) o1;
  207               QName qname1 = cursor1.getName();
  208               QName qname2 = cursor2.getName();
  209               int qnameComparisonRes = qname1.getNamespaceURI().compareTo(qname2.getNamespaceURI());
  210               if (qnameComparisonRes == 0)
  211                   return order == ASCENDING ?
  212                       qname1.getLocalPart().compareTo(qname2.getLocalPart()) :
  213                       -qname1.getLocalPart().compareTo(qname2.getLocalPart());
  214               else
  215                   return order == ASCENDING ? qnameComparisonRes : -qnameComparisonRes;
  216           }
  217       }
  218   }
  219    

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