对原子值进行排序的 XPath 查询的语法是什么?

What is the syntax for a sorted XPath query on atomic values?

我正在尝试在我的 Java 代码中执行以下 select:

// initialized earlier
private XdmNode xmlDocument;
private XPathCompiler xPath;

// ... the code that's a problem:

XPathExecutable exec = xPath.compile("sort(distinct-values(/root/data/hasTransaction/element/hasAssets/element/associatedAttributes/element[(value != '') and (dataParamName != 'modelNomenclature')]/name), (), function($node) { $node/displaySeq })");
XPathSelector selector = exec.load();
selector.setContextItem(xmlDocument);
selector.evaluate();

调用 evaluate() 抛出异常:

net.sf.saxon.trans.XPathException: The required item type of the first operand of '/' is node(); the supplied value u"Model Name" is an atomic value

查询有什么问题?我知道 distinct-values() returns 原子值,但为什么对这些值进行排序时出现问题? $node 对原子值排序没有意义吗?但是 select (没有排序)是:

/root/data/hasTransaction/element/hasAssets/element/associatedAttributes/element[(value != '') and (dataParamName != 'modelNomenclature')]/name

/root/data/hasTransaction/element/hasAssets/element/associatedAttributes:

    <associatedAttributes>
      <element>
        <uom>N/A</uom>
        <name>Model Name</name>
        <dataParamName>modelName</dataParamName>
        <seq />
        <value>A17-230P1A</value>
        <displayLevel>0</displayLevel>
        <displaySeq>5</displaySeq>
        <displayLevelTitle />
        <displayName>Model Name</displayName>
        <dataGroup />
      </element>

所以(对我来说)这似乎是合乎逻辑的,因为它是“...[...]/name”,它可以在 displaySeq

上排序

“/”运算符需要 LHS 上的节点(不是原子值)(如错误消息所述)。

我认为,如果 element 个元素具有相同的 name 个子元素,那么您正在尝试将它们作为重复项消除,然后按 displaySeq 的值对它们进行排序。不幸的是 distinct-values() 只保留(原子)值,它失去了这些值从中派生的节点的知识。 (至少在原则上,具有相同 name 的两个元素可以具有不同的 displaySeq 值,因此不清楚您要保留哪个。

理想情况下,您会为此使用 XSLT 或 XQuery 分组,而不是不同的值。如果你必须使用 XPath,你可以考虑创建一个映射来进行重复数据删除:

let $index := map:merge(/root/data/hasTransaction/element/hasAssets
           /element/associatedAttributes/element[
             (value != '') and (dataParamName != 'modelNomenclature')
           ]!map{displaySeq : .}/name)
 return sort(map:for-each($index, function($k, $v){$v}), 
             (), function($node) { $node/displaySeq })

未测试。

也许

distinct-values(sort(/root/data/hasTransaction/element/hasAssets/element/associatedAttributes/element[(value != '') and (dataParamName != 'modelNomenclature')], (), function($node) { $node/displaySeq })!name)

给你正确的结果,它按 displaySeqelement 元素进行排序,然后选择 name 子元素并计算不同的元素。

你也可以写成

(/root/data/hasTransaction/element/hasAssets/element/associatedAttributes/element[(value != '') and (dataParamName != 'modelNomenclature')] => sort((), function($node) { $node/displaySeq })) ! name => distinct-values()