mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 12:58:38 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			600 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			600 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
// TODO: Delete `nativescript-core/xml/xml.js` from source control after
 | 
						|
// https://github.com/NativeScript/nativescript-dev-webpack/issues/932
 | 
						|
 | 
						|
import * as definition from '.';
 | 
						|
import { EasySAXParser } from '../js-libs/easysax';
 | 
						|
 | 
						|
/**
 | 
						|
 * Defines a position within string, in line and column form.
 | 
						|
 */
 | 
						|
export interface Position {
 | 
						|
	/**
 | 
						|
	 * The line number. The first line is at index 1.
 | 
						|
	 */
 | 
						|
	line: number;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * The column number. The first character is at index 1.
 | 
						|
	 */
 | 
						|
	column: number;
 | 
						|
}
 | 
						|
 | 
						|
export class ParserEventType implements definition.ParserEventType {
 | 
						|
	static StartElement = 'StartElement';
 | 
						|
	static EndElement = 'EndElement';
 | 
						|
	static Text = 'Text';
 | 
						|
	static CDATA = 'CDATA';
 | 
						|
	static Comment = 'Comment';
 | 
						|
}
 | 
						|
 | 
						|
export class ParserEvent implements definition.ParserEvent {
 | 
						|
	private _eventType: string;
 | 
						|
	private _position: Position;
 | 
						|
	private _prefix: string;
 | 
						|
	private _namespace: string;
 | 
						|
	private _elementName: string;
 | 
						|
	private _attributes: Object;
 | 
						|
	private _data: string;
 | 
						|
 | 
						|
	constructor(eventType: string, position: Position, prefix?: string, namespace?: string, elementName?: string, attributes?: Object, data?: string) {
 | 
						|
		this._eventType = eventType;
 | 
						|
		this._position = position;
 | 
						|
		this._prefix = prefix;
 | 
						|
		this._namespace = namespace;
 | 
						|
		this._elementName = elementName;
 | 
						|
		this._attributes = attributes;
 | 
						|
		this._data = data;
 | 
						|
	}
 | 
						|
 | 
						|
	public toString(): string {
 | 
						|
		return JSON.stringify({
 | 
						|
			eventType: this.eventType,
 | 
						|
			position: this.position,
 | 
						|
			prefix: this.prefix,
 | 
						|
			namespace: this.namespace,
 | 
						|
			elementName: this.elementName,
 | 
						|
			attributes: this.attributes,
 | 
						|
			data: this.data,
 | 
						|
		});
 | 
						|
	}
 | 
						|
 | 
						|
	public get eventType(): string {
 | 
						|
		return this._eventType;
 | 
						|
	}
 | 
						|
 | 
						|
	public get position(): Position {
 | 
						|
		return this._position;
 | 
						|
	}
 | 
						|
 | 
						|
	public get prefix(): string {
 | 
						|
		return this._prefix;
 | 
						|
	}
 | 
						|
 | 
						|
	public get namespace(): string {
 | 
						|
		return this._namespace;
 | 
						|
	}
 | 
						|
 | 
						|
	public get elementName(): string {
 | 
						|
		return this._elementName;
 | 
						|
	}
 | 
						|
 | 
						|
	public get attributes(): Object {
 | 
						|
		return this._attributes;
 | 
						|
	}
 | 
						|
 | 
						|
	public get data(): string {
 | 
						|
		return this._data;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
let _ampCodes;
 | 
						|
const _entitySearchRegEx = /&#(\d+);|&#x([0123456789abcdef]+);|&(\w+);/gi;
 | 
						|
 | 
						|
function _generateAmpMap(): any {
 | 
						|
	const objCodes = {
 | 
						|
		Tab: 9,
 | 
						|
		NewLine: 10,
 | 
						|
		excl: 33,
 | 
						|
		quot: 34,
 | 
						|
		QUOT: 34,
 | 
						|
		num: 35,
 | 
						|
		dollar: 36,
 | 
						|
		percent: 37,
 | 
						|
		amp: 38,
 | 
						|
		AMP: 38,
 | 
						|
		apos: 39,
 | 
						|
		lpar: 40,
 | 
						|
		rpar: 41,
 | 
						|
		ast: 42,
 | 
						|
		midast: 42,
 | 
						|
		plus: 43,
 | 
						|
		comma: 44,
 | 
						|
		period: 46,
 | 
						|
		sol: 47,
 | 
						|
		colon: 58,
 | 
						|
		semi: 59,
 | 
						|
		lt: 60,
 | 
						|
		LT: 60,
 | 
						|
		equals: 61,
 | 
						|
		gt: 62,
 | 
						|
		GT: 62,
 | 
						|
		quest: 63,
 | 
						|
		commat: 64,
 | 
						|
		lsqb: 91,
 | 
						|
		lbrack: 91,
 | 
						|
		bsol: 92,
 | 
						|
		rsqb: 92,
 | 
						|
		rbrack: 92,
 | 
						|
		Hat: 94,
 | 
						|
		lowbar: 95,
 | 
						|
		grave: 96,
 | 
						|
		DiacriticalGrave: 96,
 | 
						|
		lcub: 123,
 | 
						|
		lbrace: 123,
 | 
						|
		verbar: 124,
 | 
						|
		vert: 124,
 | 
						|
		VerticalLine: 124,
 | 
						|
		rcub: 125,
 | 
						|
		rbrace: 125,
 | 
						|
		nbsp: 160,
 | 
						|
		iexcl: 161,
 | 
						|
		cent: 162,
 | 
						|
		pound: 163,
 | 
						|
		curren: 164,
 | 
						|
		yen: 165,
 | 
						|
		brvbar: 166,
 | 
						|
		brkbar: 166,
 | 
						|
		sect: 167,
 | 
						|
		uml: 168,
 | 
						|
		copy: 169,
 | 
						|
		ordf: 170,
 | 
						|
		laquo: 171,
 | 
						|
		not: 172,
 | 
						|
		shy: 173,
 | 
						|
		reg: 174,
 | 
						|
		macr: 175,
 | 
						|
		hibar: 175,
 | 
						|
		deg: 176,
 | 
						|
		plusmn: 177,
 | 
						|
		sup2: 178,
 | 
						|
		sup3: 179,
 | 
						|
		acute: 180,
 | 
						|
		micro: 181,
 | 
						|
		para: 182,
 | 
						|
		middot: 183,
 | 
						|
		cedil: 184,
 | 
						|
		sup1: 185,
 | 
						|
		ordm: 186,
 | 
						|
		raquo: 187,
 | 
						|
		frac14: 188,
 | 
						|
		frac12: 189,
 | 
						|
		frac34: 190,
 | 
						|
		iquest: 191,
 | 
						|
		Agrave: 192,
 | 
						|
		Aacute: 193,
 | 
						|
		Acirc: 194,
 | 
						|
		Atilde: 195,
 | 
						|
		Auml: 196,
 | 
						|
		Aring: 197,
 | 
						|
		AElig: 198,
 | 
						|
		Ccedil: 199,
 | 
						|
		Egrave: 200,
 | 
						|
		Eacute: 201,
 | 
						|
		Ecirc: 202,
 | 
						|
		Euml: 203,
 | 
						|
		Igrave: 204,
 | 
						|
		Iacute: 205,
 | 
						|
		Icirc: 206,
 | 
						|
		Iuml: 207,
 | 
						|
		ETH: 208,
 | 
						|
		Dstrok: 208,
 | 
						|
		Ntilde: 209,
 | 
						|
		Ograve: 210,
 | 
						|
		Oacute: 211,
 | 
						|
		Ocirc: 212,
 | 
						|
		Otilde: 213,
 | 
						|
		Ouml: 214,
 | 
						|
		times: 215,
 | 
						|
		Oslash: 216,
 | 
						|
		Ugrave: 217,
 | 
						|
		Uacute: 218,
 | 
						|
		Ucirc: 219,
 | 
						|
		Uuml: 220,
 | 
						|
		Yacute: 221,
 | 
						|
		THORN: 222,
 | 
						|
		szlig: 223,
 | 
						|
		agrave: 224,
 | 
						|
		aacute: 225,
 | 
						|
		acirc: 226,
 | 
						|
		atilde: 227,
 | 
						|
		auml: 228,
 | 
						|
		aring: 229,
 | 
						|
		aelig: 230,
 | 
						|
		ccedil: 231,
 | 
						|
		egrave: 232,
 | 
						|
		eacute: 233,
 | 
						|
		ecirc: 234,
 | 
						|
		euml: 235,
 | 
						|
		igrave: 236,
 | 
						|
		iacute: 237,
 | 
						|
		icirc: 238,
 | 
						|
		iuml: 239,
 | 
						|
		eth: 240,
 | 
						|
		ntilde: 241,
 | 
						|
		ograve: 242,
 | 
						|
		oacute: 243,
 | 
						|
		ocirc: 244,
 | 
						|
		otilde: 245,
 | 
						|
		ouml: 246,
 | 
						|
		divide: 247,
 | 
						|
		oslash: 248,
 | 
						|
		ugrave: 249,
 | 
						|
		uacute: 250,
 | 
						|
		ucirc: 251,
 | 
						|
		uuml: 252,
 | 
						|
		yacute: 253,
 | 
						|
		thorn: 254,
 | 
						|
		yuml: 255,
 | 
						|
		fnof: 402,
 | 
						|
		imped: 437,
 | 
						|
		gacute: 501,
 | 
						|
		jmath: 567,
 | 
						|
		circ: 710,
 | 
						|
		caron: 711,
 | 
						|
		Hacek: 711,
 | 
						|
		breve: 728,
 | 
						|
		Breve: 728,
 | 
						|
		dot: 729,
 | 
						|
		DiacriticalDot: 729,
 | 
						|
		ring: 730,
 | 
						|
		ogon: 731,
 | 
						|
		tilde: 732,
 | 
						|
		DiacriticalTilde: 732,
 | 
						|
		dblac: 733,
 | 
						|
		DiacriticalDoubleAcute: 733,
 | 
						|
		DownBreve: 785,
 | 
						|
		UnderBar: 818,
 | 
						|
		Alpha: 913,
 | 
						|
		Beta: 914,
 | 
						|
		Gamma: 915,
 | 
						|
		Delta: 916,
 | 
						|
		Epsilon: 917,
 | 
						|
		Zeta: 918,
 | 
						|
		Eta: 919,
 | 
						|
		Theta: 920,
 | 
						|
		Iota: 921,
 | 
						|
		Kappa: 922,
 | 
						|
		Lambda: 923,
 | 
						|
		Mu: 924,
 | 
						|
		Nu: 925,
 | 
						|
		Xi: 926,
 | 
						|
		Omicron: 927,
 | 
						|
		Pi: 928,
 | 
						|
		Rho: 929 /* 930 is not real */,
 | 
						|
		Sigma: 931,
 | 
						|
		Tau: 932,
 | 
						|
		Upsilon: 933,
 | 
						|
		Phi: 934,
 | 
						|
		Chi: 935,
 | 
						|
		Psi: 936,
 | 
						|
		Omega: 937,
 | 
						|
		alpha: 945,
 | 
						|
		beta: 946,
 | 
						|
		gamma: 947,
 | 
						|
		delta: 948,
 | 
						|
		epsilon: 949,
 | 
						|
		epsiv: 949,
 | 
						|
		varepsilon: 949,
 | 
						|
		zeta: 950,
 | 
						|
		eta: 951,
 | 
						|
		theta: 952,
 | 
						|
		iota: 953,
 | 
						|
		kappa: 954,
 | 
						|
		lambda: 955,
 | 
						|
		mu: 956,
 | 
						|
		nu: 957,
 | 
						|
		xi: 958,
 | 
						|
		omicron: 959,
 | 
						|
		pi: 960,
 | 
						|
		rho: 961,
 | 
						|
		sigmaf: 962,
 | 
						|
		sigmav: 962,
 | 
						|
		varsigma: 962,
 | 
						|
		sigma: 963,
 | 
						|
		tau: 964,
 | 
						|
		upsilon: 965,
 | 
						|
		phi: 966,
 | 
						|
		chi: 967,
 | 
						|
		psi: 968,
 | 
						|
		omega: 969,
 | 
						|
		thetav: 977,
 | 
						|
		vartheta: 977,
 | 
						|
		thetasym: 977,
 | 
						|
		Upsi: 978,
 | 
						|
		upsih: 978,
 | 
						|
		straightphi: 981,
 | 
						|
		piv: 982,
 | 
						|
		varpi: 982,
 | 
						|
		Gammad: 988,
 | 
						|
		gammad: 989,
 | 
						|
		digamma: 989,
 | 
						|
		kappav: 1008,
 | 
						|
		varkappa: 1008,
 | 
						|
		rhov: 1009,
 | 
						|
		varrho: 1009,
 | 
						|
		epsi: 1013,
 | 
						|
		straightepsilon: 1013,
 | 
						|
		bepsi: 1014,
 | 
						|
		backepsilon: 1014,
 | 
						|
		/* Skipped Codes 1015 - 1119 */ euro: 8364,
 | 
						|
		trade: 8482,
 | 
						|
		TRADE: 8482,
 | 
						|
		forall: 8704,
 | 
						|
		part: 8706,
 | 
						|
		larr: 8592,
 | 
						|
		rarr: 8593,
 | 
						|
		hyphen: 8208,
 | 
						|
		dash: 8208,
 | 
						|
		ndash: 8211,
 | 
						|
		mdash: 8212,
 | 
						|
		horbar: 8213,
 | 
						|
		Vert: 8214,
 | 
						|
		Verbar: 8214,
 | 
						|
		lsquo: 8216,
 | 
						|
		OpenCurlyQuote: 8216,
 | 
						|
		rsquo: 8217,
 | 
						|
		rsquor: 8217,
 | 
						|
		CloseCurlyQuote: 8217,
 | 
						|
		lsquor: 8218,
 | 
						|
		sbquo: 8218,
 | 
						|
		ldquo: 8220,
 | 
						|
		OpenCurlyDoubleQuote: 8220,
 | 
						|
		rdquo: 8221,
 | 
						|
		rdquor: 8221,
 | 
						|
		CloseCurlyDoubleQuote: 8221,
 | 
						|
		ldquor: 8222,
 | 
						|
		bdquo: 8222,
 | 
						|
		dagger: 8224,
 | 
						|
		Dagger: 8225,
 | 
						|
		ddagger: 8225,
 | 
						|
		bull: 8226,
 | 
						|
		bullet: 8226,
 | 
						|
		nldr: 8229,
 | 
						|
		hellip: 8230,
 | 
						|
		mldr: 8230,
 | 
						|
		hybull: 8259,
 | 
						|
		tdot: 8411,
 | 
						|
		TripleDot: 8411,
 | 
						|
		DotDot: 8412,
 | 
						|
		star: 9734,
 | 
						|
		phone: 9742,
 | 
						|
		spades: 9824,
 | 
						|
		clubs: 9827,
 | 
						|
		hearts: 9829,
 | 
						|
		diams: 9830,
 | 
						|
		female: 9792,
 | 
						|
		male: 9794,
 | 
						|
		check: 10003,
 | 
						|
		checkmark: 10003,
 | 
						|
		cross: 10007,
 | 
						|
		VerticalSeparator: 10072,
 | 
						|
		EmptySmallSquare: 9723,
 | 
						|
		FilledSmallSquare: 9724,
 | 
						|
		starf: 9733,
 | 
						|
		bigstar: 9733,
 | 
						|
		square: 9633,
 | 
						|
		squ: 9633,
 | 
						|
		Square: 9633,
 | 
						|
	};
 | 
						|
	const ampCodes = new Map();
 | 
						|
	for (const key in objCodes) {
 | 
						|
		if (objCodes.hasOwnProperty(key)) {
 | 
						|
			ampCodes.set(key, objCodes[key]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return ampCodes;
 | 
						|
}
 | 
						|
 | 
						|
// android-specific implementation, which pre-populates the map to get it saved into the heap blob
 | 
						|
if (global.__snapshot) {
 | 
						|
	_ampCodes = _generateAmpMap();
 | 
						|
}
 | 
						|
 | 
						|
function _HandleAmpEntities(found: string, decimalValue: string, hexValue: string, wordValue: string): string {
 | 
						|
	if (wordValue) {
 | 
						|
		if (!_ampCodes) {
 | 
						|
			_ampCodes = _generateAmpMap();
 | 
						|
		}
 | 
						|
		const res = _ampCodes.get(wordValue);
 | 
						|
		if (res) {
 | 
						|
			return String.fromCodePoint(res);
 | 
						|
		}
 | 
						|
 | 
						|
		// Invalid word; so we just return it
 | 
						|
		return found;
 | 
						|
	}
 | 
						|
	if (decimalValue) {
 | 
						|
		return String.fromCodePoint(parseInt(decimalValue, 10));
 | 
						|
	}
 | 
						|
 | 
						|
	return String.fromCodePoint(parseInt(hexValue, 16));
 | 
						|
}
 | 
						|
 | 
						|
export class XmlParser implements definition.XmlParser {
 | 
						|
	//TODO: Add option to configure whether the parser should report ignorable whitespace, i.e. document formatting whitespace.
 | 
						|
	private _parser: EasySAXParser;
 | 
						|
 | 
						|
	private _processNamespaces: boolean;
 | 
						|
	private _namespaceStack: Array<any>;
 | 
						|
 | 
						|
	constructor(onEvent: (event: definition.ParserEvent) => void, onError?: (error: Error, position: Position) => void, processNamespaces?: boolean) {
 | 
						|
		this._processNamespaces = processNamespaces;
 | 
						|
		this._parser = new EasySAXParser();
 | 
						|
 | 
						|
		const that = this;
 | 
						|
		this._parser.on('startNode', function (elem, attr, uq, tagend, str, pos) {
 | 
						|
			let attributes = attr();
 | 
						|
 | 
						|
			if (attributes === true) {
 | 
						|
				//HACK: For some reason easysax returns the true literal when an element has no attributes.
 | 
						|
				attributes = undefined;
 | 
						|
			}
 | 
						|
 | 
						|
			if (attributes) {
 | 
						|
				for (const key in attributes) {
 | 
						|
					if (attributes.hasOwnProperty(key)) {
 | 
						|
						// Convert entities such as > to >
 | 
						|
						attributes[key] = XmlParser._dereferenceEntities(attributes[key]);
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			let prefix = undefined;
 | 
						|
			let namespace = undefined;
 | 
						|
			let name = elem;
 | 
						|
 | 
						|
			if (that._processNamespaces) {
 | 
						|
				const stackEntry = XmlParser._getNamespacesStackEntry(attributes);
 | 
						|
				that._namespaceStack.push(stackEntry);
 | 
						|
 | 
						|
				const resolved = that._resolveNamespace(name);
 | 
						|
				prefix = resolved.prefix;
 | 
						|
				namespace = resolved.namespace;
 | 
						|
				name = resolved.name;
 | 
						|
			}
 | 
						|
 | 
						|
			onEvent(new ParserEvent(ParserEventType.StartElement, pos(), prefix, namespace, name, attributes, undefined));
 | 
						|
		});
 | 
						|
 | 
						|
		this._parser.on('textNode', function (text, uq, pos) {
 | 
						|
			const data = uq(XmlParser._dereferenceEntities(text)); // Decode entity references such as < and >
 | 
						|
			onEvent(new ParserEvent(ParserEventType.Text, pos(), undefined, undefined, undefined, undefined, data));
 | 
						|
		});
 | 
						|
 | 
						|
		this._parser.on('endNode', function (elem, uq, tagstart, str, pos) {
 | 
						|
			let prefix = undefined;
 | 
						|
			let namespace = undefined;
 | 
						|
			let name = elem;
 | 
						|
 | 
						|
			if (that._processNamespaces) {
 | 
						|
				const resolved = that._resolveNamespace(name);
 | 
						|
				prefix = resolved.prefix;
 | 
						|
				namespace = resolved.namespace;
 | 
						|
				name = resolved.name;
 | 
						|
			}
 | 
						|
 | 
						|
			onEvent(new ParserEvent(ParserEventType.EndElement, pos(), prefix, namespace, name, undefined, undefined));
 | 
						|
 | 
						|
			if (that._processNamespaces) {
 | 
						|
				that._namespaceStack.pop();
 | 
						|
			}
 | 
						|
		});
 | 
						|
 | 
						|
		this._parser.on('cdata', function (data, res, pos) {
 | 
						|
			onEvent(new ParserEvent(ParserEventType.CDATA, pos(), undefined, undefined, undefined, undefined, data));
 | 
						|
		});
 | 
						|
 | 
						|
		this._parser.on('comment', function (text, uq, pos) {
 | 
						|
			onEvent(new ParserEvent(ParserEventType.Comment, pos(), undefined, undefined, undefined, undefined, text));
 | 
						|
		});
 | 
						|
 | 
						|
		if (onError) {
 | 
						|
			this._parser.on('error', function (msg, pos) {
 | 
						|
				onError(new Error(msg), pos());
 | 
						|
			});
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public get angularSyntax(): boolean {
 | 
						|
		return this._parser.angularSyntax;
 | 
						|
	}
 | 
						|
 | 
						|
	public set angularSyntax(value: boolean) {
 | 
						|
		this._parser.angularSyntax = value;
 | 
						|
	}
 | 
						|
 | 
						|
	public parse(xmlString: string): void {
 | 
						|
		if (this._processNamespaces) {
 | 
						|
			this._namespaceStack = [];
 | 
						|
		}
 | 
						|
 | 
						|
		this._parser.parse(xmlString);
 | 
						|
	}
 | 
						|
 | 
						|
	private static _getNamespacesStackEntry(attributes: any): any {
 | 
						|
		const stackEntry = {};
 | 
						|
 | 
						|
		if (!attributes) {
 | 
						|
			return stackEntry;
 | 
						|
		}
 | 
						|
 | 
						|
		let attributeName;
 | 
						|
		let namespacePrefix;
 | 
						|
		for (const key in attributes) {
 | 
						|
			if (!attributes.hasOwnProperty(key)) {
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			attributeName = <string>key;
 | 
						|
			if (attributeName.indexOf('xmlns') !== 0) {
 | 
						|
				// This is a normal attribute, so go on.
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			namespacePrefix = '';
 | 
						|
			if (attributeName.indexOf(':') !== -1) {
 | 
						|
				namespacePrefix = attributeName.split(':')[1];
 | 
						|
			}
 | 
						|
 | 
						|
			stackEntry[namespacePrefix] = attributes[key];
 | 
						|
		}
 | 
						|
 | 
						|
		return stackEntry;
 | 
						|
	}
 | 
						|
 | 
						|
	private _resolveNamespace(fullName: string): { prefix: string; namespace: string; name: string } {
 | 
						|
		const result: { prefix: string; namespace: string; name: string } = {
 | 
						|
			prefix: undefined,
 | 
						|
			namespace: undefined,
 | 
						|
			name: undefined,
 | 
						|
		};
 | 
						|
		result.prefix = '';
 | 
						|
		if (fullName.indexOf(':') !== -1) {
 | 
						|
			const split = fullName.split(':');
 | 
						|
			result.prefix = split[0];
 | 
						|
			result.name = split[1];
 | 
						|
		} else {
 | 
						|
			result.name = fullName;
 | 
						|
		}
 | 
						|
 | 
						|
		let stackEntry;
 | 
						|
		for (let i = this._namespaceStack.length - 1; i >= 0; i--) {
 | 
						|
			stackEntry = this._namespaceStack[i];
 | 
						|
 | 
						|
			for (const key in stackEntry) {
 | 
						|
				if (!stackEntry.hasOwnProperty(key)) {
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				if (result.prefix === key) {
 | 
						|
					result.namespace = stackEntry[key];
 | 
						|
 | 
						|
					return result;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
 | 
						|
	private static _dereferenceEntities(s: string): string {
 | 
						|
		s = String(s);
 | 
						|
		if (s.length > 3 && s.indexOf('&') !== -1) {
 | 
						|
			s = s.replace(_entitySearchRegEx, _HandleAmpEntities);
 | 
						|
		}
 | 
						|
 | 
						|
		return s;
 | 
						|
	}
 | 
						|
}
 |