Literale in Entitäten wiederverwenden

Problem

Ein Literal (litA) soll mit einem mehrfach vorhandenen weiteren Literal (litB) in einer Entität zusammenfügt werden, wobei für jedes litB eine Entität erstellt wird.

Eingabe

{litA: wertA, litB: wertB, litB: wertC}

Erwartete Ausabe

{entAB {litA: wertA, litB: wertB} entAB {litA: wertA, litB: wertC}}

Lösung

<entity name="entAB" flushWith="litB" reset="true">
    <combine name="litA" value="${litA}" flushWith="litB">
        <data source="litA"/>
    </combine>
    <data source="litB" name="litB"/>
</entity>

litA wird in einem combine-collector “gespeichert”, der in diesem Fall wie ein Cache benutzt werden kann. Wichtig ist, dass der collector zur gleichen Zeit weitergeleitet wird wie die ihn umgebende entity, da ansonsten der in ihm aggregierte Wert nur einmal (nämlich wenn er das erste Mal gefüllt ist) “geflusht” wird.

Analoges gilt für concat.

Bemerkungen

Generalisierung

Sollte im obigen Beispiel das Literal litA im Datensatz nach litB ausgelesen werden, muss auch die Reihenfolge der Ausgabe geändert werden. s. dazu das Rezept “Ordnung von Literalen ändern”

Inkorrekte Lösungsansätze

Direktes Auslesen des Literals

<entity name="entAB" flushWith="litB" reset="true">
    <data source="litA"/>
    <data source="litB" name="litB"/>
</entity>

Ausgabe:

{entAB {litA: wertA, litB: wertB} entAB {litB: wertC}}

Da das Feld litA vor litB ausgelesen und im entity-Block nach der Verarbeitung des ersten litB geflusht wird, steht es zum Zeitpunkt des zweiten litB nicht mehr zur Verfügung.

Entität nicht zurücksetzen

<entity name="entAB" flushWith="litB" reset="false">
    <combine name="litA" value="${litA}" flushWith="litB">
        <data source="litA"/>
    </combine>
    <data source="litB" name="litB"/>
</entity>

Ausgabe:

{entAB {litA: wertA, litB: wertB} entAB {litA: wertA, litB: wertB, litB: wertC}}

Nicht möglich, da so alle Werte in entity gesammelt werden. Allerdings würde diese Strategie beispielsweise für combine funktionieren, da in diesem Fall Werte mit gleichem Feldnamen überschrieben werden.

Rekursives Zugreifen auf litA

<data source="litA" name="@loop"/>
<entity name="entAB" flushWith="litB" reset="false">
    <data source="@loop" name="litA"/>
    <data source="litB" name="litB"/>
</entity>

Ausgabe:

{entAB {litA: wertA, litB: wertB} entAB {litB: wertC}}

Zwar ist der Wert von litA über die ganze restliche Prozessierungszeit des Records im Cache gespeichert, doch kann pro Zugriffsort nur einmal über ihn iteriert werden.