给出一个比较器:
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查询(或SQL2,如果它超出xpath的功能)使用“order by”获得相同的结果。有可能吗?
鉴于数据:
No. | Name | Nickname |
1 | Adam | Hornet |
2. | Adam | |
3. | Jack | Legend |
排序数据:
No. | name | nickname
2. | Adam |
1. | Adam | Hornet
3. | Jack | Legend
答案 0 :(得分:0)
您可以在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,而JCR 2.0规范未指定如何排序处理NULL
值。例如,它们应该出现在非空值之前还是之后?实现可以选择。
还有另一个棘手的问题。请注意,我假设Person
节点类型具有name
字段,而不是假设您将该人的名称存储在节点名称中。那是因为在JCR-SQL2中,您必须使用名为NODENAME
或NODELOCALNAME
的特殊函数来访问节点的名称。您可以直接在排序中使用它,但遗憾的是,在标准JCR-SQL2中未定义查询结果中的节点名称。
因此,使用标准JCR-SQL2的以下查询将起作用:
SELECT nickname FROM Person ORDER BY NODELOCALNAME, nickname
但您必须从结果中获取的javax.jcr.Node
中获取节点的名称,而不是结果集中的某个值。严格来说,这既不昂贵也不困难;它只是改变了应用程序使用查询结果的方式。
ModeShape中的JCR-SQL2
一个JCR实现ModeShape扩展了标准JCR-SQL2语法,其数量为additional features。其中一个扩展是引入几个伪列,包括:
jcr:name
是节点名称的替身jcr:path
是节点路径的替身mode:localName
是节点名称mode:depth
评估节点的深度jcr: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(目前在Alpha中),并且还添加了一个扩展名:您可以指定排序中是否nulls should come first or last。以下是早期查询的变体,显示了如何使用它:
SELECT name, nickname FROM Person ORDER BY name NULLS FIRST, nickname NULLS FIRST
如果你是Person
节点类型定义确保name
属性是必需的(永远不为null),则不需要指定NULLS FIRST
(或{{1}在NULLS LAST
列排序。
除了name
而不是jcr:name
:
name
请注意,我们不需要在SELECT jcr:name, nickname FROM Person ORDER BY jcr:name, nickname NULLS FIRST
列上指定NULLS FIRST
或NULLS LAST
,因为每个节点都有一个名称,因此jcr:name
永远不会为空。
标准JCR 1.0 XPath
如果您正在使用仍支持XPath的JCR实现(技术上已指定为JSR-170或JCR 1.0的一部分,并且在JSR-283或JCR 2.0中已弃用),您还可以使用XPath:
jcr:name
由于JCR 1.0确实定义了//element(*, Person) order by @name ascending, @nickname ascending
伪列,因此您可以非常轻松地使用节点名称:
jcr:name
还有一件事:ModeShape 3.x或更高版本将用JCR-SQL2,XPath和JCR-SQL编写的查询解析到同一个抽象语法树中,然后执行它们。因此,最后一个JCR-SQL2查询和最后一个XPath查询将在ModeShape中以相同方式处理。
答案 1 :(得分:0)
以下是比较器中如何使用任意代码执行此操作的草图。获取执行普通查询时获得的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
属性添加默认值。