问题
To sort a query in Saxon we first run the query:
XPathExecutable exe = xPath.compile(query);
XPathSelector selector = exe.load();
selector.setContextItem(xmlDocument);
XdmValue nodeSet = selector.evaluate();
// put the results in an array
ArrayList<XdmItem> nodes = new ArrayList<XdmItem>();
for (int i = 0; i < nodeSet.size(); i++)
nodes.add(nodeSet.itemAt(i));
// Sort the results
sortNodes(nodes, "RiskLevel", false, false);
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, iter2;
if (sortKey.equals(".")) {
iter1 = ((XdmNode) node1).axisIterator(Axis.SELF, new QName(((XdmNode) node1).getNodeName().getLocalName()));
iter2 = ((XdmNode) node2).axisIterator(Axis.SELF, new QName(((XdmNode) node2).getNodeName().getLocalName()));
} else if (sortKey.contains("/")){
// we get here when the sortKey is a descendant, but not direct child of the node, so we traverse down the tree to get there
String key = sortKey;
while (key.contains("/")) {
node1 = ((XdmNode) node1).axisIterator(Axis.CHILD, new QName(key.substring(0, key.indexOf("/")))).next();
node2 = ((XdmNode) node2).axisIterator(Axis.CHILD, new QName(key.substring(0, key.indexOf("/")))).next();
key = key.substring(key.indexOf("/") + 1);
}
iter1 = ((XdmNode) node1).axisIterator(Axis.CHILD, new QName(key));
iter2 = ((XdmNode) node2).axisIterator(Axis.CHILD, new QName(key));
} else {
iter1 = ((XdmNode) node1).axisIterator(Axis.CHILD, new QName(sortKey));
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 {
assert node1 != null && node2 != null;
return ((XdmItem)node1).getStringValue().compareTo(((XdmItem) node2).getStringValue());
}
}
};
if (descending)
comparator = Collections.reverseOrder(comparator);
Collections.sort(nodes, comparator);
}
The problem is for the following XML (nodeSet.toString():
<Securities xmlns="http://www.windward.net">
<RiskLevel>4</RiskLevel>
The code:
iter1 = ((XdmNode) node1).axisIterator(Axis.CHILD, new QName(sortKey));
iter2 = ((XdmNode) node2).axisIterator(Axis.CHILD, new QName(sortKey));
}
if(iter1.hasNext() && iter2.hasNext()) {
returns false on both hasNext() calls.
First question, is this the beast way to do this? If not, what is a better approach?
Second question, if this is the best way, why do the iterators return false ofr hasNext()?
回答1:
Why don't you use XQuery to do the sorting? Generate and compile the query
'declare variable $nodes external;
for $n in $nodes order by $n/' + sortkey + ' return $n'
and then compile and execute this query, binding $nodes
to your nodeSet
obtained from the first query.
I would think that the reason your code is failing is that the elements are in a namespace, and when you construct a QName to hold the sort key, you are constructing a no-namespace QName.
来源:https://stackoverflow.com/questions/54738705/trying-to-sort-a-node-set-from-saxon