namespace Infrastructure.StockData; /// /// SEIBro getXrcStkStatInfo(주식관련사채 행사대상 주식정보) 응답 파서 — 순수 C#. 공용 SeibroXml envelope 입력. /// ⚠️ 실샘플 fixture 가 result="0"(0행)이라 필드 매핑을 라이브로 검증하지 못했다 — 주식.md 스펙 기준으로 구현했으며 /// 운영 첫 수집 시 로그로 필드명(대소문자 포함)을 확인해야 한다. SeibroXml 은 대소문자 무시라 명칭만 맞으면 매핑된다. /// 자연키(BOND_ISIN, XRC_STK_ISIN) 중 하나라도 없으면 건너뛴다. /// public static class SeibroXrcStkStatParser { public sealed record Row( string BondIsin, string? BondSecnNm, string? BondKindNm, string XrcStkIsin, string? StkSecnNm, string? WrtbIsin, string? WrtbSecnNm, decimal? XrcRatio, decimal? XrcPrice, int? SetaccEndtermLimitDays, int? NewstkAllocDdBfLimitDays, string? DmanLimitRsnContent ); public static IReadOnlyList Parse(SeibroXml.Envelope envelope) { var rows = new List(); foreach (var fields in envelope.Rows) { var bondIsin = SeibroXml.GetOrNull(fields, "BOND_ISIN")?.Trim(); var xrcStkIsin = SeibroXml.GetOrNull(fields, "XRC_STK_ISIN")?.Trim(); if (string.IsNullOrEmpty(bondIsin) || string.IsNullOrEmpty(xrcStkIsin)) { continue; } rows.Add(new Row( bondIsin, SeibroXml.GetOrNull(fields, "BOND_SECN_NM")?.Trim(), SeibroXml.GetOrNull(fields, "BOND_KIND_NM")?.Trim(), xrcStkIsin, SeibroXml.GetOrNull(fields, "STK_SECN_NM")?.Trim(), SeibroXml.GetOrNull(fields, "WRTB_ISIN")?.Trim(), SeibroXml.GetOrNull(fields, "WRTB_SECN_NM")?.Trim(), SeibroFieldParse.Decimal(SeibroXml.GetOrNull(fields, "XRC_RATIO")), SeibroFieldParse.Decimal(SeibroXml.GetOrNull(fields, "XRC_PRICE")), SeibroFieldParse.Int(SeibroXml.GetOrNull(fields, "SETACC_ENDTERM_LIMIT_DAYS")), SeibroFieldParse.Int(SeibroXml.GetOrNull(fields, "NEWSTK_ALOC_DD_BF_LIMIT_DAYS")), SeibroXml.GetOrNull(fields, "DMAN_LIMIT_RSN_CONTENT")?.Trim() )); } return rows; } }