jstrachan 2002/11/27 11:22:42 Modified: jelly/src/java/org/apache/commons/jelly/tags/xml SetTag.java XPathComparator.java SortTag.java ForEachTag.java jelly/src/test/org/apache/commons/jelly/xml suite.jelly Log: Patch to Jason's XPath sorting implementation that uses XPaths numerical functions instead of taking a Java Class to perform conversions. So to sort by the foo attribute you could use @foo for textual sorting or for numeric sorting... number(@foo) Revision Changes Path 1.11 +5 -15 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/SetTag.java Index: SetTag.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/SetTag.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- SetTag.java 27 Nov 2002 17:21:16 -0000 1.10 +++ SetTag.java 27 Nov 2002 19:22:41 -0000 1.11 @@ -150,14 +150,4 @@ if (xpCmp == null) xpCmp = new XPathComparator(); xpCmp.setDescending(descending); } - - /** - * Set the data type to convert nodes being sorted on into before sorting. - * This should be the name of a class that commons.beanutils knows how to convert strings - * into. - */ - public void setSortDataType(String sortType) throws ClassNotFoundException { - if (xpCmp == null) xpCmp = new XPathComparator(); - xpCmp.setType(Class.forName(sortType)); - } } 1.2 +23 -67 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/XPathComparator.java Index: XPathComparator.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/XPathComparator.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- XPathComparator.java 27 Nov 2002 17:21:16 -0000 1.1 +++ XPathComparator.java 27 Nov 2002 19:22:41 -0000 1.2 @@ -62,6 +62,7 @@ package org.apache.commons.jelly.tags.xml; import java.util.Comparator; +import java.util.List; import org.dom4j.Node; @@ -85,9 +86,6 @@ /** The xpath to use to extract value from nodes to compare */ private XPath xpath = null; - /** If set then the value extracted will be cast into this type and compared. */ - private Class type = null; - /** Sort descending or ascending */ private boolean descending = false; @@ -100,12 +98,6 @@ this.descending = descending; } - public XPathComparator(XPath xpath, Class type, boolean descending) { - this.xpath = xpath; - this.type = type; - this.descending = descending; - } - public void setXpath(XPath xpath) { this.xpath = xpath; } @@ -114,10 +106,6 @@ return xpath; } - public void setType(Class type) { - this.type = type; - } - public void setDescending(boolean descending) { this.descending = descending; } @@ -131,43 +119,16 @@ // apply the xpaths. not using stringValueOf since I don't // want all of the child nodes appended to the strings - Node val1 = (Node)xpath.selectSingleNode(n1); - Node val2 = (Node)xpath.selectSingleNode(n2); + Object val1 = xpath.evaluate(n1); + Object val2 = xpath.evaluate(n2); // return if null if (val1 == null || val2 == null) { return val1 == null ? (val2 == null ? 1 : -1) : 1; } - // these are what will be compared - Comparable c1, c2; - - // extract the string values - String s1 = val1.getText(); - String s2 = val2.getText(); - - // if type is set convert to it and compare - // if it is not set try to infer types - if (type != null) { - c1 = (Comparable)ConvertUtils.convert(s1, type); - c2 = (Comparable)ConvertUtils.convert(s2, type); - } else { - // check if numeric type - if (isNumeric(s1) && isNumeric(s2)) { - // if either is a double, cast to doubles - if (isDouble(s1) || isDouble(s2)) { - c1 = (Double)ConvertUtils.convert(s1, Double.class); - c2 = (Double)ConvertUtils.convert(s2, Double.class); - } else { - c1 = (Integer)ConvertUtils.convert(s1, Integer.class); - c2 = (Integer)ConvertUtils.convert(s2, Integer.class); - } - } else { - // nope, leave as strings - c1 = s1; - c2 = s2; - } - } + Comparable c1 = getComparableValue(val1); + Comparable c2 = getComparableValue(val2); // compare descending or ascending if (!descending) { @@ -184,32 +145,27 @@ } /** - * Check to see if a string is a number. Negative and decimals supported. - * @param str String to check - * @return True if the string is numeric. Empty strings are not numeric. + * Turns the XPath result value into a Comparable object. */ - private static final boolean isNumeric(String str) { - final int strLen = str.length(); - // empty strings are not numbers - if (strLen == 0) return false; - // start at pos 1 if the 1st char is '-' to support negatives - final int startPos = (str.charAt(0) == '-') ? 1 : 0; - if (startPos == strLen) return false; - for (int i=startPos;i<strLen;i++) { - char ch = str.charAt(i); - if ((ch < '0' || ch > '9') && (ch != '.')) { - return false; + protected Comparable getComparableValue(Object value) { + if (value instanceof List) { + List list = (List) value; + if (list.isEmpty()) { + value = ""; + } + value = list.get(0); + if (value == null) { + value = ""; } } - - return true; - } - - /** - * Check to see if the number has a period. - */ - private static final boolean isDouble(String str) { - return str.indexOf(".") != -1; + if (value instanceof Comparable) { + return (Comparable) value; + } + else if (value instanceof Node) { + Node node = (Node) value; + return node.getStringValue(); + } + return value.toString(); } /** 1.2 +0 -10 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/SortTag.java Index: SortTag.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/SortTag.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- SortTag.java 27 Nov 2002 17:21:16 -0000 1.1 +++ SortTag.java 27 Nov 2002 19:22:41 -0000 1.2 @@ -114,14 +114,4 @@ if (xpCmp == null) xpCmp = new XPathComparator(); xpCmp.setDescending(descending); } - - /** - * Set the data type to convert nodes being sorted on into before sorting. This - * should be the name of a class that commons.beanutils knows how to convert strings - * into. - */ - public void setSortDataType(String sortType) throws ClassNotFoundException { - if (xpCmp == null) xpCmp = new XPathComparator(); - xpCmp.setType(Class.forName(sortType)); - } } 1.12 +5 -15 jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/ForEachTag.java Index: ForEachTag.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/tags/xml/ForEachTag.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- ForEachTag.java 27 Nov 2002 17:21:16 -0000 1.11 +++ ForEachTag.java 27 Nov 2002 19:22:41 -0000 1.12 @@ -155,14 +155,4 @@ if (xpCmp == null) xpCmp = new XPathComparator(); xpCmp.setDescending(descending); } - - /** - * Set the data type to convert nodes being sorted on into before sorting. This - * should be the name of a class that commons.beanutils knows how to convert strings - * into. - */ - public void setSortDataType(String sortType) throws ClassNotFoundException { - if (xpCmp == null) xpCmp = new XPathComparator(); - xpCmp.setType(Class.forName(sortType)); - } } 1.5 +16 -14 jakarta-commons-sandbox/jelly/src/test/org/apache/commons/jelly/xml/suite.jelly Index: suite.jelly =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/jelly/src/test/org/apache/commons/jelly/xml/suite.jelly,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- suite.jelly 27 Nov 2002 17:21:16 -0000 1.4 +++ suite.jelly 27 Nov 2002 19:22:42 -0000 1.5 @@ -28,13 +28,15 @@ </test:case> <test:case name="testBadElementAndAttribute"> - - <j:catch var="ex"> - <x:element name="foo"> - some text - <x:attribute name="x">1234</x:attribute> - </x:element> - </j:catch> + + <log:info> + <j:catch var="ex"> + <x:element name="foo"> + some text + <x:attribute name="x">1234</x:attribute> + </x:element> + </j:catch> + </log:info> <test:assert test="${ex != null}"> We should have created an exception as some text is output before the attributes @@ -59,7 +61,7 @@ <test:assert test="${ex != null}">We should have created an exception</test:assert> - The exception was: ${ex.message} + <log:info>The exception was: ${ex.message}</log:info> </test:case> <!-- test the use of namespaces with XPath --> @@ -118,7 +120,7 @@ <!-- test ascending --> <j:set var="result" value=""/> - <x:forEach select="$nums/a/b" var="x" sort="@v"> + <x:forEach select="$nums/a/b" var="x" sort="number(@v)"> <x:set var="num" select="$x/@v"/> <j:set var="result" value="${result} ${num.get(0).getText()}"/> </x:forEach> @@ -127,7 +129,7 @@ <!-- test descending --> <j:set var="result" value=""/> - <x:forEach select="$nums/a/b" var="x" sort="@v" descending="true"> + <x:forEach select="$nums/a/b" var="x" sort="number(@v)" descending="true"> <x:set var="num" select="$x/@v"/> <j:set var="result" value="${result} ${num.get(0).getText()}"/> </x:forEach> @@ -136,7 +138,7 @@ <!-- test deeper nesting --> <j:set var="result" value=""/> - <x:forEach select="$deeper/a/b" var="x" sort="c/d"> + <x:forEach select="$deeper/a/b" var="x" sort="number(c/d/text())"> <j:set var="result" value="${result} ${x.getStringValue()}"/> </x:forEach> @@ -144,7 +146,7 @@ <!-- test sort as strings --> <j:set var="result" value=""/> - <x:forEach select="$nums/a/b" var="x" sort="@v" sortDataType="java.lang.String"> + <x:forEach select="$nums/a/b" var="x" sort="@v"> <x:set var="num" select="$x/@v"/> <j:set var="result" value="${result} ${num.get(0).getText()}"/> </x:forEach> @@ -153,7 +155,7 @@ <!-- test x:set with sort --> <j:set var="result" value=""/> - <x:set var="rset" select="$nums/a/b" sort="@v"/> + <x:set var="rset" select="$nums/a/b" sort="number(@v)"/> <j:forEach var="num" items="${rset.iterator()}"> <j:set var="result" value="${result} ${num.attributeValue('v')}"/> </j:forEach> @@ -163,7 +165,7 @@ <!-- test x:set with sort --> <j:set var="result" value=""/> <x:set var="rset" select="$nums/a/b"/> - <x:sort list="${rset}" sort="@v"/> + <x:sort list="${rset}" sort="number(@v)"/> <j:forEach var="num" items="${rset.iterator()}"> <j:set var="result" value="${result} ${num.attributeValue('v')}"/> </j:forEach>
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>