2017-05-17 1 views
1

XML-Eingabeformat:Wie summiere ich entsprechende Werte?

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> 

ich verwendet habe cts:sum Abfrage die Anzahl Wert für verschiedenen Währungstyp hinzuzufügen. Währungs andere Werte als INR & USD als OTH modifizierte wie unten angegeben:

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

, die die folgende Ausgabe

120,56 INR

234,45

USD gibt

450,0 OTH

100,0 OTH

Nun, ich brauche die Werte zu summieren, die gleiche Währung Werte hat. Ich muss 450.0 + 100.0 hinzufügen, um die Gesamtmenge anderer Währungswerte zu erhalten.

Könnte jemand dabei helfen?

+0

Was ist Ihr genaues Eingabeformat? Ist es eine einzelne Zeichenfolge, XML-Daten oder etwas völlig anderes? Und wie sollte die Ausgabe aussehen? –

+0

Ist MarkLogic 9 eine Option? Wenn nicht, welche Version von MarkLogic? –

Antwort

2

distinct-values() kann ein sehr teurer Anruf sein.

Für Ihr Problem, Sie brauchen es auch nicht.

tun Nur 3 Abfragen - eine für INR, eine für USD, und die andere für cts:not-query(cts:element-value-query(xs:QName('CurrencyType'), ("INR","USD")))

2

Je nachdem, wie viele Dokumente „alle XML-Dateien“ ist, alle diese Dokumente und XPathing zum CurrencyType Laden und die Verwendung distinct-values() könnte teuer und langsam sein.

Stattdessen könnten Sie:

  1. eine eindeutige Liste von CurrencyType und Amount Werte für diese Dokumente erhalten die Ergebnisse als Karte mit cts:element-value-co-occurences() und zurück.
  2. Iterierte über jede der Map-Einträge und die CurrencyType normalisieren und die Summen auszudrucken alle der Amount Werte für die normalisierte CurrencyType Label aufaddieren
  3. dann.

(: 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, .), " ", .) 
) 
3

Wie Jim erwähnt und Mads, vermeiden distinct-values. Zumal cts:element-values ohnehin einen Bereichsindex benötigt. Ich würde auch vermeiden, cts:sum (die übrigens offiziell veraltet ist) zu verwenden, und stattdessen die leistungsfähigere cts:sum-aggregate verwenden. Ich würde Jims Ansatz betrachten, und so etwas wie:

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 
) 

Hinweis: cts:range-query ist neu in Marklogic 9. Sie stattdessen cts:element-range-query in älteren Versionen verwenden kann.

Sie obigen Code verkürzen könnte sich noch weiter, und buchstäblich zu tun, wie Jim schlägt vor:

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 
) 

Letztere keinen Entfernungs-Index auf CurrencyType erfordern würde, aber wenn Sie, dass als Facette ausgesetzt haben, haben Sie wahrscheinlich, dass jedenfalls.

HTH!

Verwandte Themen