From 0f79d8184202c15918f686596bb253ac8205cddb Mon Sep 17 00:00:00 2001 From: ingalls Date: Thu, 26 Mar 2026 14:27:49 -0600 Subject: [PATCH 1/2] Normalize Boolean --- lib/parser-normalize.ts | 55 +++++++++++++++++++++++++++++++++++++++++ lib/parser.ts | 7 +++++- test/validation.test.ts | 18 ++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 lib/parser-normalize.ts diff --git a/lib/parser-normalize.ts b/lib/parser-normalize.ts new file mode 100644 index 0000000..b0924fe --- /dev/null +++ b/lib/parser-normalize.ts @@ -0,0 +1,55 @@ +export type ParsedAttributeVisitor = ( + attributeKey: string, + attributeValue: unknown, + attributes: Record, + path: string[] +) => void; + +export function visitElementAttributes( + input: unknown, + visitor: ParsedAttributeVisitor, + path: string[] = [] +): void { + if (Array.isArray(input)) { + for (const [index, value] of input.entries()) { + visitElementAttributes(value, visitor, [...path, String(index)]); + } + + return; + } + + if (!input || typeof input !== 'object') { + return; + } + + const record = input as Record; + for (const [key, value] of Object.entries(record)) { + if (key === '_attributes' && value && typeof value === 'object' && !Array.isArray(value)) { + const attributes = value as Record; + + for (const [attributeKey, attributeValue] of Object.entries(attributes)) { + visitor(attributeKey, attributeValue, attributes, [...path, key]); + visitElementAttributes(attributes[attributeKey], visitor, [...path, key, attributeKey]); + } + + continue; + } + + visitElementAttributes(value, visitor, [...path, key]); + } +} + +export function normalizeBooleanAttributeValues(input: unknown): void { + visitElementAttributes(input, (attributeKey, attributeValue, attributes) => { + if (typeof attributeValue !== 'string') { + return; + } + + const normalized = attributeValue.toLowerCase(); + if (normalized === 'true') { + attributes[attributeKey] = true; + } else if (normalized === 'false') { + attributes[attributeKey] = false; + } + }); +} \ No newline at end of file diff --git a/lib/parser.ts b/lib/parser.ts index 1bee90e..5145f01 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -15,6 +15,7 @@ import type { import { InputFeature, } from './types/feature.js'; +import { normalizeBooleanAttributeValues } from './parser-normalize.js'; import JSONCoT, { Detail } from './types/types.js' import CoT from './cot.js'; import type { CoTOptions } from './cot.js'; @@ -157,8 +158,11 @@ export class CoTParser { raw: Buffer | string, opts: CoTOptions = {} ): CoT { + const parsed = xml2js(String(raw), { compact: true }) as Static; + normalizeBooleanAttributeValues(parsed); + const cot = new CoT( - xml2js(String(raw), { compact: true }) as Static, + parsed, opts ); @@ -249,6 +253,7 @@ export class CoTParser { for (const key in msg.cotEvent.detail) { if (key === 'xmlDetail') { const parsed: any = xml2js(`${msg.cotEvent.detail.xmlDetail}`, { compact: true }); + normalizeBooleanAttributeValues(parsed); Object.assign(detail, parsed.detail); if (detail.metadata) { diff --git a/test/validation.test.ts b/test/validation.test.ts index d90f7c8..ab7a9cd 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -11,3 +11,21 @@ test('await CoTParser.from_xml - Invalid', async (t) => { t.end(); }); + +test('await CoTParser.from_xml - Case-insensitive boolean attributes', async (t) => { + const cot = await CoTParser.from_xml(` + + + + + + +`); + + t.equal(cot.raw.event.detail?.labels_on?._attributes?.value, false, 'boolean attributes are normalized before validation'); + + const feature = await CoTParser.to_geojson(cot); + t.equal(feature.properties.labels, false, 'normalized boolean attributes remain booleans in GeoJSON output'); + + t.end(); +}); From 0ef2f0587f049630b6625b231e4adf61f5bf6928 Mon Sep 17 00:00:00 2001 From: ingalls Date: Thu, 26 Mar 2026 14:35:57 -0600 Subject: [PATCH 2/2] Normalize boolean --- lib/parser-normalize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parser-normalize.ts b/lib/parser-normalize.ts index b0924fe..9725994 100644 --- a/lib/parser-normalize.ts +++ b/lib/parser-normalize.ts @@ -52,4 +52,4 @@ export function normalizeBooleanAttributeValues(input: unknown): void { attributes[attributeKey] = false; } }); -} \ No newline at end of file +}