export interface BlfEntry { id: string; blfNo: number; blfType: string; blfTypeId: string; value: string; } const BLF_TAG = //]*)(?:\s*\/>|>([\s\S]*?)<\/BLF>)/gi; function attr(attrs: string, name: string): string { const match = attrs.match(new RegExp(`\\b${name}="([^"]*)"`, "i")); return match?.[1] ?? ""; } export function parseBlfs(xml: string | undefined | null): BlfEntry[] { if (!xml) { return []; } const entries: BlfEntry[] = []; for (const match of xml.matchAll(BLF_TAG)) { const attrs = match[1] ?? ""; const blfNo = Number.parseInt(attr(attrs, "BLFNo"), 10); if (!Number.isFinite(blfNo)) { continue; } entries.push({ id: attr(attrs, "ID") || "-1", blfNo, blfType: attr(attrs, "BLFType") || "BLF", blfTypeId: attr(attrs, "BLFTypeID") || "0", value: (match[2] ?? "").trim(), }); } return entries; } function escapeXml(value: string): string { return value .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } export function serializeBlfs(entries: BlfEntry[]): string { const sorted = [...entries].sort((a, b) => a.blfNo - b.blfNo); const inner = sorted .map((entry) => { const attrs = `ID="${escapeXml(entry.id)}" BLFNo="${entry.blfNo}" BLFType="${escapeXml(entry.blfType)}" BLFTypeID="${escapeXml(entry.blfTypeId)}"`; if (entry.value === "") { return ``; } return `${escapeXml(entry.value)}`; }) .join(""); return `${inner}`; } export function blfsEqual(a: string | undefined | null, b: string): boolean { return serializeBlfs(parseBlfs(a)) === serializeBlfs(parseBlfs(b)); }