You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlbeans.apache.org by ra...@apache.org on 2009/02/04 01:59:29 UTC

svn commit: r740542 - in /xmlbeans/trunk/samples/XmlSort: ./ src/ src/org/ src/org/apache/ src/org/apache/xmlbeans/ src/org/apache/xmlbeans/samples/ src/org/apache/xmlbeans/samples/cursor/ xml/

Author: radup
Date: Wed Feb  4 00:59:29 2009
New Revision: 740542

URL: http://svn.apache.org/viewvc?rev=740542&view=rev
Log:
Added sample showing how to order a set of elements using XmlCursor.

Added:
    xmlbeans/trunk/samples/XmlSort/
    xmlbeans/trunk/samples/XmlSort/README.txt
    xmlbeans/trunk/samples/XmlSort/build.xml
    xmlbeans/trunk/samples/XmlSort/src/
    xmlbeans/trunk/samples/XmlSort/src/org/
    xmlbeans/trunk/samples/XmlSort/src/org/apache/
    xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/
    xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/
    xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/
    xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/XmlSort.java
    xmlbeans/trunk/samples/XmlSort/xml/
    xmlbeans/trunk/samples/XmlSort/xml/unsorted.xml

Added: xmlbeans/trunk/samples/XmlSort/README.txt
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/samples/XmlSort/README.txt?rev=740542&view=auto
==============================================================================
--- xmlbeans/trunk/samples/XmlSort/README.txt (added)
+++ xmlbeans/trunk/samples/XmlSort/README.txt Wed Feb  4 00:59:29 2009
@@ -0,0 +1,51 @@
+Sample: XmlSort
+Category: cursor sample
+Author: Radu Preotiuc-Pietro
+Last Updated: Feb. 3, 2009
+
+Versions:
+    xmlbeans-v2
+
+-----------------------------------------------------------------------------
+
+This is another practical sample on how to use XmlCursor. It sorts all the
+children elements of a given parent in (reverse) alphabetical order. It uses
+insertion sort to minimize the number of swaps (and because it is stable) and
+XmlCursor.moveXml() to perform the swaps.
+
+The algorithm works by conceptually separating the list of children into a
+sorted list and an unsorted list. Each list is represented by an XmlCursor
+positioned at the head of the list. At the beginning, the sorted list
+contains the first child and the unsorted list contains the rest of the
+children (if any). Then, each of the elements in the unsorted list is
+inserted in the already-sorted list in its appropriate place using the
+moveXml() method (the text following each element is then moved along with
+the element).
+
+To build this sample, call 'ant build' and to run it against the provided
+sample XML file, call 'ant run'.
+
+To run the sample from the command line using 'java', provide as the first
+parameter the name of the XML file to process and as the second argument
+(optional), an XPath pointing to the element whose children are to be sorted
+(by default, the children of the root element are sorted). The XPath must
+evaluate to an element and one element only, otherwise an error will be
+reported. The console output will mirror the input file, with the children
+of the given element sorted in ascending alphabetical order.
+
+This sample can also be used as a library routine by calling its main
+static method: XmlSort.sort(XmlObject, Comparator). The XmlObject whose
+children are to be sorted is passed directly as a parameter and the
+Comparator defines the order in which the elements are to be sorted. The
+parameters to the compare() method are two XmlCursors pointing to the
+two elements to be compared. The inner class XmlSort.QNameComparator
+implements comparison based on the QName of the elements (ascending or
+descending) but custom comparison methods (based for instance on the
+value of some attribute etc) can also be passed in.
+
+To try out this sample:
+
+1. Set XMLBEANS_HOME in your environment
+2. Ant must be on your PATH
+3. To compile the sample source, run "ant build"
+4. To execute the sample, run "ant run"

Added: xmlbeans/trunk/samples/XmlSort/build.xml
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/samples/XmlSort/build.xml?rev=740542&view=auto
==============================================================================
--- xmlbeans/trunk/samples/XmlSort/build.xml (added)
+++ xmlbeans/trunk/samples/XmlSort/build.xml Wed Feb  4 00:59:29 2009
@@ -0,0 +1,96 @@
+<!--
+Copyright 2004 The Apache Software Foundation
+
+Licensed 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.
+ -->
+<project name="XmlSort" default="build">
+
+    <property environment="env"/>
+
+    <path id="XmlSort.path">
+        <path refid="xmlbeans.path"/>
+        <pathelement path="build/classes"/>
+    </path>
+
+    <target name="init">
+        <property name="xmlbeans.home" value="${env.XMLBEANS_HOME}"/>
+        <echo message="xmlbeans.home: ${xmlbeans.home}"/>
+
+        <!-- check for xbean.jar from binary distribution -->
+        <available
+            property="xmlbeans.lib"
+            value="${xmlbeans.home}/lib"
+            file="${xmlbeans.home}/lib/xbean.jar" />
+
+        <!-- check for xbean.jar compiled from source -->
+        <available
+            property="xmlbeans.lib"
+            value="${xmlbeans.home}/build/lib"
+            file="${xmlbeans.home}/build/lib/xbean.jar" />
+
+        <fail message="Set XMLBEANS_HOME in your enviornment."
+            unless="xmlbeans.lib"/>
+
+        <echo message="xmlbeans.lib: ${xmlbeans.lib}"/>
+        <path id="xmlbeans.path">
+            <fileset dir="${xmlbeans.lib}" includes="*.jar"/>
+        </path>
+    </target>
+
+    <!-- ========================== clean ==== -->
+
+    <target name="clean">
+        <delete dir="build"/>
+    </target>
+
+    <!-- ========================== build ==== -->
+
+    <target name="build" depends="init,XmlSort.classes">
+    </target>
+
+    <target name="XmlSort.classes" depends="init">
+        <mkdir dir="build/classes"/>
+
+        <javac srcdir="src"
+            destdir="build/classes"
+            classpathref="XmlSort.path"
+            debug="on"
+            source="1.4"
+            />
+    </target>
+
+    <!-- ========================== run ==== -->
+
+    <target name="run" depends="init,build">
+        <echo message="============================== running XmlSort"/>
+        <java
+            classname="org.apache.xmlbeans.samples.cursor.XmlSort"
+            classpathref="XmlSort.path"
+            fork="true">
+            <arg line="xml/unsorted.xml"/>
+        </java>
+    </target>
+
+    <!-- ========================== test ==== -->
+
+    <target name="test" depends="init,build">
+        <echo message="============================== testing XmlSort"/>
+        <java
+            classname="org.apache.xmlbeans.samples.cursor.XmlSort"
+            classpathref="XmlSort.path"
+            fork="true">
+            <arg line="xml/unsorted.xml"/>
+        </java>
+    </target>
+
+</project>

Added: xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/XmlSort.java
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/XmlSort.java?rev=740542&view=auto
==============================================================================
--- xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/XmlSort.java (added)
+++ xmlbeans/trunk/samples/XmlSort/src/org/apache/xmlbeans/samples/cursor/XmlSort.java Wed Feb  4 00:59:29 2009
@@ -0,0 +1,219 @@
+/*   Copyright 2009 The Apache Software Foundation
+ *
+ *   Licensed 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.xmlbeans.samples.cursor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Comparator;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+
+import javax.xml.namespace.QName;
+
+/**
+ */
+public final class XmlSort
+{
+    /**
+     * Receives an XML element instance and sorts the children of this
+     * element in lexicographical (by default) order.
+     *
+     * @param args An array in which the first item is a
+     * path to the XML instance file and the second item (optional) is
+     * an XPath inside the document identifying the element to be sorted
+     */
+    public static void main(String[] args)
+    {
+        if (args.length < 1 || args.length > 2)
+        {
+            System.out.println("    java XmlSort <XML_File> [<XPath>]");
+            return;
+        }
+        File f = new File(args[0]);
+        try
+        {
+            XmlObject docInstance = XmlObject.Factory.parse(f);
+            XmlObject element = null;
+            if (args.length > 1)
+            {
+                String xpath = args[1];
+                XmlObject[] result = docInstance.selectPath(xpath);
+                if (result.length == 0)
+                {
+                    System.out.println("ERROR: XPath \"" + xpath + "\" did not return any results");
+                }
+                else if (result.length > 1)
+                {
+                    System.out.println("ERROR: XPath \"" + xpath + "\" returned more than one " +
+                        "node (" + result.length + ")");
+                }
+                else
+                    element = result[0];
+            }
+            else
+            {
+                // Navigate to the root element
+                XmlCursor c = docInstance.newCursor();
+                c.toFirstChild();
+                element = c.getObject();
+                c.dispose();
+            }
+            if (element != null)
+                sort(element, new QNameComparator(QNameComparator.ASCENDING));
+            System.out.println(docInstance.xmlText());
+        }
+        catch (IOException ioe)
+        {
+            System.out.println("ERROR: Could not open file: \"" + args[0] + "\": " +
+                ioe.getMessage());
+        }
+        catch (XmlException xe)
+        {
+            System.out.println("ERROR: Could not parse file: \"" + args[0] + "\": " +
+                xe.getMessage());
+        }
+    }
+
+    /**
+     * Sorts the children of <code>element</code> according to the order indicated by the
+     * comparator.
+     * @param element the element whose content is to be sorted. Only element children are sorted,
+     * attributes are not touched. When elements are reordered, all the text, comments and PIs
+     * follow the element that they come immediately after.
+     * @param comp a comparator that is to be used when comparing the <code>QName</code>s of two
+     * elements. See {@link org.apache.xmlbeans.samples.cursor.XmlSort.QNameComparator} for a simple
+     * implementation that compares two elements based on the value of their QName, but more
+     * complicated implementations are possible, for instance, ones that compare two elements based
+     * on the value of a specifc attribute etc.
+     * @throws IllegalArgumentException if the input <code>XmlObject</code> does not represent
+     * an element
+     */
+    public static void sort(XmlObject element, Comparator comp)
+    {
+        XmlCursor headCursor = element.newCursor();
+        if (!headCursor.isStart())
+            throw new IllegalStateException("The element parameter must point to a STARTDOC");
+        // We use insertion sort to minimize the number of swaps, because each swap means
+        // moving a part of the document
+        /* headCursor points to the beginning of the list of the already sorted items and
+           listCursor points to the beginning of the list of unsorted items
+           At the beginning, headCursor points to the first element and listCursor points to the
+           second element. The algorithm ends when listCursor cannot be moved to the "next"
+           element in the unsorted list, i.e. the unsorted list becomes empty */
+        boolean moved = headCursor.toFirstChild();
+        if (!moved)
+        {
+            // Cursor was not moved, which means that the given element has no children and
+            // therefore there is nothing to sort
+            return;
+        }
+        XmlCursor listCursor = headCursor.newCursor();
+        boolean moreElements = listCursor.toNextSibling();
+        while (moreElements)
+        {
+            moved = false;
+            // While we can move the head of the unsorted list, it means that there are still
+            // items (elements) that need to be sorted
+            while (headCursor.comparePosition(listCursor) < 0)
+            {
+                if (comp.compare(headCursor, listCursor) > 0)
+                {
+                    // We have found the position in the sorted list, insert the element and the
+                    // text following the element in the current position
+                    /*
+                     * Uncomment this code to cause the text before the element to move along
+                     * with the element, rather than the text after the element. Notice that this
+                     * is more difficult to do, because the cursor's "type" refers to the position
+                     * to the right of the cursor, so to get the type of the token to the left, the
+                     * cursor needs to be first moved to the left (previous token)
+                     *
+                    headCursor.toPrevToken();
+                    while (headCursor.isComment() || headCursor.isProcinst() || headCursor.isText())
+                        headCursor.toPrevToken();
+                    headCursor.toNextToken();
+                    listCursor.toPrevToken();
+                    while (listCursor.isComment() || listCursor.isProcinst() || listCursor.isText())
+                        listCursor.toPrevToken();
+                    listCursor.toNextToken();
+                    while (!listCursor.isStart())
+                        listCursor.moveXml(headCursor);
+                    listCursor.moveXml(headCursor);
+                    */
+                    // Move the element
+                    listCursor.moveXml(headCursor);
+                    // Move the text following the element
+                    while (!listCursor.isStart() && !listCursor.isEnd())
+                        listCursor.moveXml(headCursor);
+                    moreElements = listCursor.isStart();
+                    moved = true;
+                    break;
+                }
+                headCursor.toNextSibling();
+            }
+            if (!moved)
+            {
+                // Because during the move of a fragment of XML, the listCursor is also moved, in
+                // case we didn't need to move XML (the new element to be inserted happened to
+                // be the last one in order), we need to move this cursor
+                moreElements = listCursor.toNextSibling();
+            }
+            // Reposition the head of the sorted list
+            headCursor.toParent();
+            headCursor.toFirstChild();
+        }
+    }
+
+    /**
+     * Implements a <code>java.util.Comparator</code> for comparing <code>QName</code>values.
+     * The namespace URIs are compared first and if they are equal, the local parts are compared.
+     * <p/>
+     * The constructor accepts an argument indicating whether the comparison order is the same as
+     * the lexicographic order of the strings or the reverse.
+     */
+    public static final class QNameComparator implements Comparator
+    {
+        public static final int ASCENDING = 1;
+        public static final int DESCENDING = 2;
+
+        private int order;
+
+        public QNameComparator(int order)
+        {
+            this.order = order;
+            if (order != ASCENDING && order != DESCENDING)
+                throw new IllegalArgumentException("Please specify one of ASCENDING or DESCENDING "+
+                    "comparison orders");
+        }
+
+        public int compare(Object o, Object o1)
+        {
+            XmlCursor cursor1 = (XmlCursor) o;
+            XmlCursor cursor2 = (XmlCursor) o1;
+            QName qname1 = cursor1.getName();
+            QName qname2 = cursor2.getName();
+            int qnameComparisonRes = qname1.getNamespaceURI().compareTo(qname2.getNamespaceURI());
+            if (qnameComparisonRes == 0)
+                return order == ASCENDING ?
+                    qname1.getLocalPart().compareTo(qname2.getLocalPart()) :
+                    -qname1.getLocalPart().compareTo(qname2.getLocalPart());
+            else
+                return order == ASCENDING ? qnameComparisonRes : -qnameComparisonRes;
+        }
+    }
+}
+ 
\ No newline at end of file

Added: xmlbeans/trunk/samples/XmlSort/xml/unsorted.xml
URL: http://svn.apache.org/viewvc/xmlbeans/trunk/samples/XmlSort/xml/unsorted.xml?rev=740542&view=auto
==============================================================================
--- xmlbeans/trunk/samples/XmlSort/xml/unsorted.xml (added)
+++ xmlbeans/trunk/samples/XmlSort/xml/unsorted.xml Wed Feb  4 00:59:29 2009
@@ -0,0 +1,22 @@
+<!--
+Copyright 2004 The Apache Software Foundation
+
+Licensed 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.
+ -->
+<root>
+    <bravo>bravo</bravo>
+    <charlie>charlie1</charlie>
+    <alpha>alpha</alpha>
+    <delta>delta</delta>
+    <charlie>charlie2</charlie>
+</root>



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlbeans.apache.org
For additional commands, e-mail: commits-help@xmlbeans.apache.org