【问题标题】:Saxon XdmNode.axisIterator() on "." nodeSaxon XdmNode.axisIterator() on "."节点
【发布时间】:2017-10-29 11:50:19
【问题描述】:

我有一个 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()));

但我觉得这件事可能会在以后咬我。

有没有更好的方法来做到这一点?

更新:假设我有 XPath "/Order/Dates/Date" 并希望按日期顺序恢复节点。所以我的 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()))?

更新 #3: 现在我提出的解决方法不起作用。这很奇怪,因为父节点确实将该节点作为子节点。

【问题讨论】:

  • 对不起,我没有理解这个问题。什么是 ”。”这里?此方法没有任何焦点或上下文项的概念。您能否更清楚地解释一下输入文档是什么,您想要实现什么,您编写了什么代码,以及它是如何失败的?
  • @MichaelKay - 我刚刚添加了一个更新。如果我需要更多,请告诉我。
  • 对不起,我还是不明白。当您使用 Java 迭代器导航树时,您将 Java 变量绑定到节点:不涉及 XPath 上下文,也没有“.”的概念。
  • @MichaelKay - 我在我的问题中添加了更多信息。这够了吗?

标签: java saxon


【解决方案1】:

如果 sortKey 以“.”形式给出,您可以使用 XdmNode.getStringValue() 提取两个节点的字符串值,然后使用与子节点相同的启发式逻辑比较字符串值。

或者,为什么不使用 XPath 引擎本身来评估排序键,而不是尝试自己解释它?

构造一个类似的表达式

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

对两个节点进行评估,并使用XdmAtomicValue.getUnderlyingValue().getSchemaComparable().compare()比较结果

类似这样的东西(未经测试):

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);

但是,我认为最好不要以这种方式混合 Java 和 XPath,而是在单个 XQuery 表达式中完成整个事情。

【讨论】:

  • 我应该把它放在哪里/放在哪里?那是我运行的后续查询吗?我从什么对象运行它?
猜你喜欢
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多