private FxSingle parseLeg(
     XmlElement legEl, FpmlDocument document, TradeInfo.Builder tradeInfoBuilder) {
   // supported elements:
   // 'exchangedCurrency1/paymentAmount'
   // 'exchangedCurrency2/paymentAmount'
   // 'valueDate'
   // ignored elements:
   // 'dealtCurrency?'
   // 'exchangeRate'
   // rejected elements:
   // 'nonDeliverableSettlement?'
   // 'currency1ValueDate'
   // 'currency2ValueDate'
   document.validateNotPresent(legEl, "currency1ValueDate");
   document.validateNotPresent(legEl, "currency2ValueDate");
   document.validateNotPresent(legEl, "nonDeliverableSettlement");
   XmlElement curr1El = legEl.getChild("exchangedCurrency1");
   XmlElement curr2El = legEl.getChild("exchangedCurrency2");
   // pay/receive and counterparty
   PayReceive curr1PayReceive = document.parsePayerReceiver(curr1El, tradeInfoBuilder);
   PayReceive curr2PayReceive = document.parsePayerReceiver(curr2El, tradeInfoBuilder);
   if (curr1PayReceive == curr2PayReceive) {
     throw new FpmlParseException(
         "FX single leg currencies must not have same Pay/Receive direction");
   }
   // amount
   CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount"));
   CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount"));
   if (curr1PayReceive == PayReceive.PAY) {
     curr1Amount = curr1Amount.negative();
     curr2Amount = curr2Amount.positive();
   } else {
     curr1Amount = curr1Amount.positive();
     curr2Amount = curr2Amount.negative();
   }
   // payment date
   LocalDate valueDate = document.parseDate(legEl.getChild("valueDate"));
   // result
   return FxSingle.of(curr1Amount, curr2Amount, valueDate);
 }
 // -------------------------------------------------------------------------
 @Override
 public Trade parseTrade(XmlElement tradeEl, FpmlDocument document) {
   // supported elements:
   // 'nearLeg'
   // 'farLeg'
   TradeInfo.Builder tradeInfoBuilder = document.parseTradeInfo(tradeEl);
   XmlElement fxEl = tradeEl.getChild("fxSwap");
   FxSingle nearLeg = parseLeg(fxEl.getChild("nearLeg"), document, tradeInfoBuilder);
   FxSingle farLeg = parseLeg(fxEl.getChild("farLeg"), document, tradeInfoBuilder);
   return FxSwapTrade.builder()
       .tradeInfo(tradeInfoBuilder.build())
       .product(FxSwap.of(nearLeg, farLeg))
       .build();
 }