All files / src/web/flowable/roundTrip xmlSerializationHelpers.ts

88% Statements 44/50
67.85% Branches 38/56
100% Functions 14/14
87.5% Lines 42/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112        187x 184x     3x 1x     2x 1x     1x       1x       6767x         1202x       179x 179x       6766x       1201x 1201x 2815x   1201x 1201x       2897x 6811x   2897x 2897x   2897x 1517x     1380x 179x     1201x       112x 112x 112x           142x 112x     30x       30x 27x     3x 3x                     330x       3039x 3039x 2897x     142x  
import type { Element as XmlElement, Node as XmlNode } from '@xmldom/xmldom';
import { escapeXml, escapeXmlText, serializer } from './xmlUtils';
 
function serializeInlineNode(node: XmlNode): string {
	if (node.nodeType === node.TEXT_NODE) {
		return escapeXmlText(node.nodeValue || '');
	}
 
	if (node.nodeType === node.CDATA_SECTION_NODE) {
		return `<![CDATA[${node.nodeValue || ''}]]>`;
	}
 
	if (node.nodeType === node.COMMENT_NODE) {
		return `<!--${node.nodeValue || ''}-->`;
	}
 
	Iif (node.nodeType === node.PROCESSING_INSTRUCTION_NODE) {
		return `<?${node.nodeName} ${node.nodeValue || ''}?>`;
	}
 
	return serializer.serializeToString(node);
}
 
function isMixedContentNode(node: XmlNode): boolean {
	return (node.nodeType === node.TEXT_NODE && (node.nodeValue || '').trim().length > 0)
		|| (node.nodeType === node.CDATA_SECTION_NODE && (node.nodeValue || '').length > 0);
}
 
function hasMixedContent(childNodes: XmlNode[]): boolean {
	return childNodes.some(isMixedContentNode);
}
 
function serializeInlineElement(element: XmlElement, attributes: string, childNodes: XmlNode[], indent: string): string {
	const content = childNodes.map(serializeInlineNode).join('');
	return `${indent}<${element.tagName}${attributes}>${content}</${element.tagName}>\n`;
}
 
function getBlockChildNodes(childNodes: XmlNode[]): XmlNode[] {
	return childNodes.filter((child) => child.nodeType !== child.TEXT_NODE || (child.textContent || '').trim().length > 0);
}
 
function serializeBlockElement(element: XmlElement, attributes: string, childNodes: XmlNode[], depth: number, indent: string): string {
	let result = `${indent}<${element.tagName}${attributes}>\n`;
	for (const child of childNodes) {
		result += serializeXmlNode(child, depth + 1);
	}
	result += `${indent}</${element.tagName}>\n`;
	return result;
}
 
function serializeElementNode(element: XmlElement, depth: number, indent: string): string {
	const attributes = Array.from(element.attributes)
		.map((attribute) => ` ${attribute.name}="${escapeXml(attribute.value)}"`)
		.join('');
	const rawChildNodes = Array.from(element.childNodes);
	const hasElementChildren = rawChildNodes.some((child) => child.nodeType === child.ELEMENT_NODE);
 
	if (!hasElementChildren && rawChildNodes.length === 0) {
		return `${indent}<${element.tagName}${attributes}/>\n`;
	}
 
	if (!hasElementChildren || hasMixedContent(rawChildNodes)) {
		return serializeInlineElement(element, attributes, rawChildNodes, indent);
	}
 
	return serializeBlockElement(element, attributes, getBlockChildNodes(rawChildNodes), depth, indent);
}
 
function serializeTextNode(node: XmlNode, indent: string): string {
	const value = node.nodeValue || '';
	Eif (value.trim().length === 0) {
		return '';
	}
	return `${indent}${escapeXmlText(value)}\n`;
}
 
function serializeNonElementNode(node: XmlNode, indent: string): string {
	if (node.nodeType === node.TEXT_NODE) {
		return serializeTextNode(node, indent);
	}
 
	Iif (node.nodeType === node.CDATA_SECTION_NODE) {
		return `${indent}<![CDATA[${node.nodeValue || ''}]]>\n`;
	}
 
	if (node.nodeType === node.COMMENT_NODE) {
		return `${indent}<!--${node.nodeValue || ''}-->\n`;
	}
 
	Eif (node.nodeType === node.PROCESSING_INSTRUCTION_NODE) {
		return `${indent}<?${node.nodeName} ${node.nodeValue || ''}?>\n`;
	}
 
	if (node.nodeType === node.DOCUMENT_TYPE_NODE) {
		return `${serializer.serializeToString(node)}\n`;
	}
 
	return '';
}
 
export function isXmlDeclarationNode(node: XmlNode): boolean {
	return node.nodeType === node.PROCESSING_INSTRUCTION_NODE && node.nodeName.toLowerCase() === 'xml';
}
 
export function serializeXmlNode(node: XmlNode, depth: number): string {
	const indent = '  '.repeat(depth);
	if (node.nodeType === node.ELEMENT_NODE) {
		return serializeElementNode(node as XmlElement, depth, indent);
	}
 
	return serializeNonElementNode(node, indent);
}