lit-xml
Version:
Burning your XML documents to the ground? Yes please. In the mean time, let's use lit-xml.
78 lines (70 loc) • 2.37 kB
text/typescript
import { XmlFragment } from './xml-fragment';
import { LitXmlOptions } from './lit-xml-options';
import { X2jOptions, XmlBuilderOptions, XMLParser, XMLBuilder } from 'fast-xml-parser';
export function valueToString(value: unknown): string {
if (value instanceof XmlFragment) {
return value.toStringRaw();
}
if (value === null) {
return 'null';
}
if (value === undefined) {
return '';
}
if (isJsonSerializable(value)) {
return sanitize(value.toJSON());
}
if (Array.isArray(value)) {
return value.map(valueToString).join('');
}
// eslint-disable-next-line
return sanitize((value as any).toString());
}
function isJsonSerializable(value: unknown): value is { toJSON(): string } {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return Boolean(value) && typeof (value as any).toJSON === 'function';
}
const fastXmlOptions: Partial<XmlBuilderOptions & X2jOptions> = {
attributeNamePrefix: '',
attributesGroupName: '$attr', //default is 'false'
textNodeName: '#text',
ignoreAttributes: false,
removeNSPrefix: false,
allowBooleanAttributes: false,
suppressBooleanAttributes: false,
parseTagValue: true,
parseAttributeValue: false,
trimValues: true,
cdataPropName: '__cdata', //default is 'false'
suppressEmptyNode: true,
};
export function format(xml: string, { format, indent }: Pick<LitXmlOptions, 'format' | 'indent'>): string {
if (format) {
const indentBy = new Array(indent).fill(' ').join('');
const xmlAsJson: unknown = new XMLParser(fastXmlOptions).parse(xml, fastXmlOptions);
return new XMLBuilder({ ...fastXmlOptions, format, indentBy }).build(xmlAsJson) as string;
} else {
return xml;
}
}
const XML_ESCAPE_MAP = Object.freeze({
['&']: '&',
["'"]: ''',
['"']: '"',
['<']: '<',
['>']: '>',
});
const XML_SPECIAL_CHAR_REGEX = new RegExp(`([${Object.keys(XML_ESCAPE_MAP).join('')}])`, 'g');
/**
* Escapes XML characters
* " => "
* ' => '
* < => <
* > => >
* & => &
* @see https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents#answer-1091953
* @param text the input text to be escaped
*/
export function sanitize(text: string) {
return text.replace(XML_SPECIAL_CHAR_REGEX, (_match, char: keyof typeof XML_ESCAPE_MAP) => XML_ESCAPE_MAP[char]);
}