2

给定一个比较器:

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
4

2 回答 2

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属性添加默认值。

于 2014-04-01T14:41:10.050 回答
0

您可以在 JCR-SQL2 和 XPath 中执行此操作。

标准 JCR-SQL2

假设您有一个名为Personwithnamenickname字段的节点类型,那么在 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字段如何为空,并且 JCR 2.0 规范没有指定排序如何处理NULL值。例如,它们应该出现在非空值之前还是之后?实施可以选择。

还有一个棘手的问题。请注意,我假设Person节点类型有一个name字段,而不是假设您将人名存储在节点名称中。这是因为在 JCR-SQL2 中,您必须使用名为NODENAMEor的特殊函数来访问节点的名称NODELOCALNAME。您可以直接在排序中使用它,但不幸的是,在标准 JCR-SQL2 中没有定义在查询结果中获取节点的名称。

因此,使用标准 JCR-SQL2 的以下查询将起作用:

SELECT nickname FROM Person ORDER BY NODELOCALNAME, nickname

但是您必须javax.jcr.Node从结果中获取节点的名称,而不是结果集中的值之一。严格来说,这既不贵也不难;它只是改变了您的应用程序使用查询结果的方式。

ModeShape 中的 JCR-SQL2

一种 JCR 实现 ModeShape 扩展了标准 JCR-SQL2 语法,增加了许多附加功能。其中一个扩展是引入几个伪列,包括:

  • jcr:name是节点名称的替代
  • jcr:path是节点路径的替身
  • mode:localName是节点名称的本地部分的替代
  • mode:depth计算节点的深度
  • jcr:uuid评估结果为javax.jcr.Node.getUUID()

因此,您可以jcr:name在排序和 SELECT 子句中使用伪列:

SELECT jcr:name, nickname FROM Person ORDER BY jcr:name, nickname

这些选项在 ModeShape 3.x 中可用。但是社区目前正在开发 ModeShape 4.0(目前处于 Alpha 阶段),并且添加了一个扩展:您可以指定空值在排序中应该排在第一位还是排在最后。这是早期查询的一个变体,展示了如何使用它:

SELECT name, nickname FROM Person ORDER BY name NULLS FIRST, nickname NULLS FIRST

如果您的Person节点类型定义确保该name属性是强制性的(从不为空),则不需要在列排序上指定NULLS FIRST(or NULLS LAST) 。name

这是相同的查询,除了 withjcr:name而不是name

SELECT jcr:name, nickname FROM Person ORDER BY jcr:name, nickname NULLS FIRST

请注意,我们不需要在列上指定NULLS FIRST或,因为每个节点都有一个名称,因此永远不会为空。NULLS LASTjcr:namejcr:name

标准 JCR 1.0 XPath

如果您使用的 JCR 实现仍然支持 XPath(在技术上被指定为 JSR-170 或 JCR 1.0 的一部分,并且在 JSR-283 或 JCR 2.0 中已弃用),您还可以使用 XPath:

//element(*, Person) order by @name ascending, @nickname ascending

由于 JCR 1.0 确实定义了jcr:name伪列,因此您实际上可以很容易地使用节点的名称:

//element(*, Person) order by @jcr:name ascending, @nickname ascending

还有一件事:ModeShape 3.x 或更高版本将用 JCR-SQL2、XPath 和 JCR-SQL 编写的查询解析为相同的抽象语法树,然后执行它们。因此,最后一个 JCR-SQL2 查询和最后一个 XPath 查询在 ModeShape 中的处理方式相同。

于 2014-04-01T14:04:52.120 回答