如何将相应的值相加?

时间:2017-05-17 09:05:28

标签: xquery marklogic

输入xml格式:

a.xml
<Global>
  <CurrencyType>INR</CurrencyType>
  <Amount>100.56</Amount>
</Global>

b.xml
<Global>
  <CurrencyType>USD</CurrencyType>
  <Amount>234.45</Amount>
</Global>

c.xml
<Global>
  <CurrencyType>INR</CurrencyType>
  <Amount>20</Amount>
</Global>

d.xml
<Global>
  <CurrencyType>EUR</CurrencyType>
  <Amount>450.0</Amount>
</Global>

e.xml
<Global>
  <CurrencyType>DIR</CurrencyType>
  <Amount>100.56</Amount>
</Global>

我使用cts:sum查询添加各种货币类型的金额值。除 INR&amp;之外的货币值美元被修改为 OTH ,如下所示:

let $doc := all the xml files 
for $currency in fn:distinct-values($doc//CurrencyType) 
let $tot := cts:sum(cts:element-values(xs:QName('Amount'),(),(),
                      cts:element-value-query(xs:QName('Currency'),$currency))) 
return  if($currency eq ('INR','USD'))  then concat($tot, " ", $currency)  
        else concat($tot, " ", 'OTH')

提供以下输出

  

120.56 INR

     

234.45 USD

     

450.0 OTH

     

100.0 OTH

现在,我需要总结具有相同货币值的值。我需要添加450.0 + 100.0才能获得其他货币值的总额。

有人可以为此提供帮助吗?

3 个答案:

答案 0 :(得分:3)

如Jim和Mads所述,请避免distinct-values。特别是因为cts:element-values无论如何都需要范围索引。我也避免使用cts:sum(顺便说一下,这是正式弃用的),而是使用性能更高的cts:sum-aggregate。我考虑过吉姆的方法,并做一些像:

let $currencies := cts:values(cts:element-reference(xs:QName("CurrencyType")))
let $explicit-currencies := $currencies[. = ("INR", "USD")]
let $other-currencies := $currencies[not(. = $explicit-currencies)]
return (
  for $c in $explicit-currencies
  let $sum := cts:sum-aggregate(
    cts:element-reference(xs:QName("Amount")),
    (),
    cts:range-query(cts:element-reference(xs:QName("CurrencyType")), "=", $c)
  )
  return $c || " " || $sum,

  let $other-sum := cts:sum-aggregate(
    cts:element-reference(xs:QName("Amount")),
    (),
    cts:range-query(cts:element-reference(xs:QName("CurrencyType")), "=", $other-currencies)
  )
  return "OTH" || " " || $other-sum
)

注意:cts:range-query是MarkLogic 9中的新功能。您可以在旧版本中使用cts:element-range-query

你可以进一步缩短上面的代码,并按照Jim的建议完成:

let $explicit-currencies := ("INR", "USD")
return (
  for $c in $explicit-currencies
  let $sum := cts:sum-aggregate(
    cts:element-reference(xs:QName("Amount")),
    (),
    cts:range-query(cts:element-reference(xs:QName("CurrencyType")), "=", $c)
  )
  return $c || " " || $sum,

  let $other-sum := cts:sum-aggregate(
    cts:element-reference(xs:QName("Amount")),
    (),
    cts:not-query(cts:element-value-query(xs:QName("CurrencyType"), $explicit-currencies))
  )
  return "OTH" || " " || $other-sum
)

后者不需要CurrencyType上的范围索引,但如果你将其暴露为方面,那么无论如何你可能都有。

HTH!

答案 1 :(得分:2)

distinct-values()可能是一个非常昂贵的电话。

对于您的问题,您也不需要它。

只做3个查询 - 一个用于INR,一个用于USD,另一个用于cts:not-query(cts:element-value-query(xs:QName('CurrencyType'), ("INR","USD")))

答案 2 :(得分:2)

取决于多少文档&#34;所有XML文件&#34;是,将所有这些文档和XPath加载到CurrencyType,使用distinct-values()可能既昂贵又缓慢。

相反,你可以:

  1. 使用CurrencyType获取这些文档的Amountcts:element-value-co-occurences()值的明确列表,并将结果作为地图返回。
  2. 迭代每个Map条目并规范化CurrencyType并将标准化Amount标签的所有CurrencyType值相加
  3. 然后打印出总数。
  4.  (: 1. obtain the CurrencyType and Amount values as a map :)
    let $currencyMap := cts:element-value-co-occurrences(
                          xs:QName("CurrencyType"), 
                          xs:QName("Amount"), 
                          "map", 
                          (:change this to a more specific query for "all the xml files" :)
                          cts:true-query())
    let $totalMap := map:map()
    return 
    ( 
      for $currency in map:keys($currencyMap)
     (: 2.a. normalize the labels :)
      let $label := 
          if ($currency = ('INR', 'USD')) then $currency 
          else "OTH"
      return
     (: 2.b. as we iterate through each CurrencyType, add it's Amount to the current total :)
        map:put($totalMap, $label, 
                sum((map:get($currencyMap, $currency), map:get($totalMap, $label))) ),
     (: 3. Print out the totals for the consolidated currency labels :) 
      map:keys($totalMap) ! concat(map:get($totalMap, .), " ", .)
    )