给出一个比较器:
public int compareTo(Person p1, Person p2)
{
    String val1 = StringUtils.isEmpty(p1.nickName) ? p1.name : p1.nickName;
    String val2 = StringUtils.isBlank(p2.nickName) ? p2.name : p2.nickName;
    return val1.compareTo(val2);
}我希望通过使用xpath查询的"order by“实现相同的结果(如果它超出了xpath的能力范围,则可以使用SQL2 )。有可能吗?
给定数据:
No. |  Name    | Nickname |
 1  |  Adam    | Hornet   |
 2. |  Adam    |          |
 3. |  Jack    | Legend   |排序后的数据:
No. | name | nickname
2.  | Adam | 
1.  | Adam | Hornet
3.  | Jack | Legend发布于 2014-04-01 22:04:52
在JCR-SQL2和XPath中都可以做到这一点。
标准JCR-SQL2
假设您有一个名为Person的节点类型,其中包含name和nickname字段,那么在JCR-sql2中实现接近预期结果的一种方法是:
SELECT p.name, p.nickname FROM Person AS p ORDER BY p.name ASC, p.nickname ASC但是我们可以更简单地编写这个查询,因为只有一个选择器(即,一个“表”),并且我们可以省略可选的ASC
SELECT name, nickname FROM Person ORDER BY name, nickname现在,严格地说,从这个查询中获得的结果将取决于实现,这是因为您在问题中描述了nickname字段如何为NULL,而JCR2.0规范没有指定排序如何处理null值。例如,它们应该出现在非空值之前还是之后?实现可以选择。
还有另一个棘手的问题。注意,我假设Person节点类型有一个name字段,而不是假设您将person的名字存储在节点的名称中。这是因为在JCR-SQL2中,您必须使用名为NODENAME或NODELOCALNAME的特殊函数来访问节点的名称。您可以直接在排序中使用它,但不幸的是,在查询结果中获取节点的名称没有在标准JCR-SQL2中定义。
因此,使用标准JCR-SQL2的以下查询将起作用:
SELECT nickname FROM Person ORDER BY NODELOCALNAME, nickname但是您必须从从结果中获得的javax.jcr.Node中获取节点的名称,而不是结果集中的一个值。严格地说,这既不昂贵也不困难;它只是改变了应用程序使用查询结果的方式。
ModeShape中的JCR-SQL2
一个JCR实现ModeShape使用许多additional features扩展了标准的JCR-SQL2语法。其中一个扩展是引入几个伪列,包括:
jcr:name是节点的替代namejcr:path是节点的pathmode:localName是节点的本地部分的替代namemode:depth求值为nodejcr:uuid的深度求值为javax.jcr.Node.getUUID()的结果
因此,您可以在排序和SELECT子句中使用jcr:name伪列:
SELECT jcr:name, nickname FROM Person ORDER BY jcr:name, nickname这些选项在ModeShape 3.x中可用。但是社区目前正在开发ModeShape 4.0 (目前是Alpha4.0),并且添加了另一个扩展:您可以指定是否在排序中使用nulls should come first or last。下面是前面查询的一个变体,展示了如何使用它:
SELECT name, nickname FROM Person ORDER BY name NULLS FIRST, nickname NULLS FIRST如果您的Person节点类型定义确保name属性是强制的(从不为null),则不需要在name列排序上指定NULLS FIRST (或NULLS LAST)。
下面是相同的查询,只是使用了jcr:name而不是name
SELECT jcr:name, nickname FROM Person ORDER BY jcr:name, nickname NULLS FIRST注意,我们不需要在jcr:name列上指定NULLS FIRST或NULLS LAST,因为每个节点都有一个名称,因此jcr:name永远不会为null。
标准JCR1.0 XPath
如果您使用的JCR实现仍然支持XPath (从技术上讲,它是JSR-170或JCR1.0的一部分,在JSR-283或JCR2.0中已被弃用),则还可以使用XPath:
//element(*, Person) order by @name ascending, @nickname ascending由于JCR1.0确实定义了jcr:name伪列,因此实际上可以很容易地使用节点的名称:
//element(*, Person) order by @jcr:name ascending, @nickname ascending还有一件事:SQL3.x或更高版本将用ModeShape -SQL2、XPath和JCR-SQL语言编写的查询解析到相同的抽象语法树中,然后执行它们。因此,最后一个JCR-SQL2查询和最后一个XPath查询在ModeShape中的处理方式是相同的。
发布于 2014-04-01 22:41:10
下面是你如何在你的比较器中使用任意代码来做这件事的草图。获取从执行普通查询获得的NodeIterator:
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.query.NodeIterator;
import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
. . .
Query query = queryManager.createQuery( /* query without any ordering specs */ );
QueryResult queryResult = query.execute();
NodeIterator nodeIterator = queryResult.getNodes();并将其传递给执行排序并返回另一个NodeIterator的方法
NodeIterator sortedNodes = sortMyWay(nodeIterator);
. . .
private NodeIterator sortMyWay(NodeIterator input) {
    ArrayList<Node> results = new ArrayList<Node>();
    while (input.hasNext()) {
        results.add(input.nextNode());
    }
    Collections.sort(results, new Comparator<Node>(){
        @Override
        public int compare(Node node1, Node node2) {
            String nickName1 = (node1.hasProperty("nickName") ? node1.getProperty("nickName").getString() : "");
            String nickName2 = (node2.hasProperty("nickName") ? node2.getProperty("nickName").getString() : "");
            return nickName1.compareTo(nickName2);
        }
    });
    return new NodeIteratorAdapter(results);
}像往常一样从sortedNodes.nextNode()检索结果。
根据需要在上述方法中添加异常处理,并根据需要在name属性中添加默认值。
https://stackoverflow.com/questions/22780347
复制相似问题