Skip to content

xs:choice: Choice with maxOccurs > 1 #2815

@igarashitm

Description

@igarashitm

Goal: When dragging a collection choice wrapper node to a collection target field, auto-generate for-each wrapping choose/when/otherwise.

A collection choice is xs:choice with maxOccurs > 1. When the choice wrapper node (not an individual member) is dragged onto a target, the system needs to handle both the collection aspect (for-each) and the choice aspect (choose/when/otherwise).

The DnD UX on choice member nodes is addressed separately by #3167

Blocked by: #2856 (MappingPairService)


Prerequisite: verify layer icon

DocumentService.isCollectionField() already checks maxOccurs regardless of wrapperKind, so collection choice wrappers should automatically show the layer icon. Verify this works — no code change expected.


DnD scenarios (wrapper node only)

# Source Target Expected Behavior Notes
S1 Collection choice wrapper Non-collection field choose/when/otherwise only Same as non-collection choice. "Only source is collection → regular mapping" rule. No change needed
S2 Collection choice wrapper Collection field for-each wrapping choose/when/otherwise New behavior. Both sides are collections → auto for-each. Inside the loop, choose handles type discrimination

Target side: dropping onto a collection choice wrapper always errors out ("Cannot map to an unselected choice") — existing validation, no change needed.


Decision flow

Source collection choice wrapper → Target field
  │
  ├─ Is target a collection field?
  │   NO  → choose/when/otherwise only (S1, same as today)
  │   YES ↓
  │
  ├─ canUseCopyOf(choiceField, targetField)
  │   → always false (__choice__ wrapper never FQN-matches a real field)
  │
  └─ Create ForEachItem, then createChooseFromChoice() inside it (S2)

Expected XSLT output (S2)

<xsl:for-each select="/ns0:Source/{choice-path}">
  <TargetElement>
    <xsl:choose>
      <xsl:when test="member1">
        <xsl:value-of select="member1"/>
      </xsl:when>
      <xsl:when test="member2">
        <xsl:value-of select="member2"/>
      </xsl:when>
      <xsl:otherwise/>
    </xsl:choose>
  </TargetElement>
</xsl:for-each>

Changes

MappingActionService.engageMapping() (packages/ui/src/services/visualization/mapping-action.service.ts):

  • When source is an unselected ChoiceFieldNodeData AND isCollectionField(sourceField) AND target is a collection field (S2):
    • Create ForEachItem first
    • Then generate ChooseItem with when/otherwise inside it (reuse createChooseFromChoice() logic)

Verification

  • Collection choice wrapper shows layer icon
  • S2: DnD wrapper → collection target creates for-each wrapping choose/when/otherwise
  • S1: Non-collection target still gets only choose/when/otherwise (no regression)
  • Target wrapper still blocked by validation (no regression)
  • XSLT generation correct for nested for-eachchoose
  • Round-trip: generated XSLT can be deserialized back to mapping tree

Testing

  • Add test cases in mapping-action.service.choice.test.ts for S2 scenario
  • Verify existing choice mapping tests still pass (S1 regression)
  • Verify XSLT serialization/deserialization for the nested structure

Metadata

Metadata

Assignees

Labels

DataMapperAll issues related to the DataMappernever-staleMarks an issue to stay always open and not stale.subtask

Type

No type

Projects

Status

In Review

Relationships

None yet

Development

No branches or pull requests

Issue actions