我有一个XdmNode,我需要从描述子节点/属性的特定XPath获取第一个子节点/属性。所以我做了以下几点:
XdmSequenceIterator iter1 = ((XdmNode)node1).axisIterator(Axis.CHILD, new QName(subKey));
这适用于除“。”之外的所有内容的子键。对于那种情况,iter1.hasNext()返回false。
相反,对于这种情况,我可以执行以下操作:
XdmSequenceIterator iter1 = ((XdmNode)node1).axisIterator(Axis.PARENT, new QName(((XdmNode) node1).getNodeName().getLocalName()));
但是这让我觉得有些事情可能会让我在okole中咬人。
有更好的方法吗?
更新:说我有XPath“/订单/日期/日期”,并希望以日期顺序恢复节点。所以我的XPath选择让我获得节点列表。然后,我将这些返回的节点移动到它们的排序对于每个节点,我调用axisIterator()来获取值。该值是该节点“。”
更新#2: 目前为了对查询结果进行排序,我们将所有结果读入ArrayList,然后使用compare()方法调用sort,如下所示:
private void sortNodes(ArrayList<XdmItem> nodes, final String sortKey, final boolean sortIsAttr, boolean descending) {
Comparator comparator = new Comparator() {
public int compare(Object node1, Object node2) {
if (node1 instanceof XdmNode && node2 instanceof XdmNode) {
if (sortIsAttr) {
return ((XdmNode) node1).getAttributeValue(new QName(sortKey)).compareTo(((XdmNode) node2).getAttributeValue(new QName(sortKey)));
}
else {
XdmSequenceIterator iter1 = ((XdmNode)node1).axisIterator(Axis.CHILD, new QName(sortKey));
XdmSequenceIterator iter2 = ((XdmNode)node2).axisIterator(Axis.CHILD, new QName(sortKey));
if(iter1.hasNext() && iter2.hasNext()) {
String val1 = iter1.next().getStringValue();
String val2 = iter2.next().getStringValue();
if(parseableAsDouble(val1) && parseableAsDouble(val2)) {
Double val1Double = Double.parseDouble(val1);
Double val2Double = Double.parseDouble(val2);
return val1Double.compareTo(val2Double);
}
Date val1Date = parseAsDate(val1);
Date val2Date = parseAsDate(val2);
if(val1Date != null && val2 != null)
return val1Date.compareTo(val2Date);
return (val1.compareTo(val2));
}
return 0;
}
} else {
return ((XdmItem)node1).getStringValue().compareTo(((XdmItem) node2).getStringValue());
}
}
};
if(descending){
comparator = Collections.reverseOrder(comparator);
}
Collections.sort(nodes, comparator);
除非sortKey =“。”,否则上述工作很有效。那是因为 ”。”不是节点的子节点,它是节点。因此,为了使这项工作成为解决方案,对于这种情况,调用((XdmNode)node1).axisIterator(Axis.PARENT,new QName(((XdmNode)node1).getNodeName()。getLocalName()))?< / p>
更新#3: 而现在我提议的解决方法不起作用。这很奇怪,因为父母确实将该节点作为孩子。
答案 0 :(得分:0)
If the sortKey is given as ".", you can just extract the string value of both nodes using XdmNode.getStringValue() and then compare the string values using the same heuristic logic as you use for child nodes.
Alternatively, why not use the XPath engine itself to evaluate the sort key, rather than trying to interpret it yourself?
Construct an expression something like
let $x := string(" + subKey + ")
return if ($x castable as xs:double) then xs:double($x)
else if ($x castable as xs:date) then xs:date($x)
else $x
evaluate it for both nodes, and compare the results using XdmAtomicValue.getUnderlyingValue().getSchemaComparable().compare()
Something like this (untested):
private void sortNodes(ArrayList<XdmItem> nodes, final String sortKey, XPathCompiler xpc, boolean descending) {
final XPathExpression computeSortKey = xpc.compile(
"let $x := string('" + sortKey + "')
return if ($x castable as xs:double) then xs:double($x)
else if ($x castable as xs:date) then xs:date($x)
else $x");
Comparator comparator = new Comparator() {
public int compare(Object node1, Object node2) {
if (node1 instanceof XdmNode && node2 instanceof XdmNode) {
XPathSelector selector = computeSortKey.load();
selector.setContextItem(((XdmNode)node1);
XdmAtomicValue key1 = (XdmAtomicValue)selector.evaluateSingle();
selector.setContextItem(((XdmNode)node2);
XdmAtomicValue key2 = (XdmAtomicValue)selector.evaluateSingle();
return key1.getUnderlyingValue().getSchemaComparable().compare(
key2.getUnderlyingValue().getSchemaComparable());
} else {
return ((XdmItem)node1).getStringValue().compareTo(((XdmItem) node2).getStringValue());
}
}
};
if(descending){
comparator = Collections.reverseOrder(comparator);
}
Collections.sort(nodes, comparator);
However, I think it would probably be better not to mix Java and XPath in this way, but rather to do the whole thing in a single XQuery expression.