mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 21:06:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import definition = require("xml");
 | 
						|
import easysax = require("js-libs/easysax");
 | 
						|
 | 
						|
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 _prefix: string;
 | 
						|
    private _namespace: string;
 | 
						|
    private _elementName: string;
 | 
						|
    private _attributes: Object;
 | 
						|
    private _data: string;
 | 
						|
 | 
						|
    constructor(eventType: string, prefix?: string, namespace?: string, elementName?: string, attributes?: Object, data?: string) {
 | 
						|
        this._eventType = eventType;
 | 
						|
        this._prefix = prefix;
 | 
						|
        this._namespace = namespace;
 | 
						|
        this._elementName = elementName;
 | 
						|
        this._attributes = attributes;
 | 
						|
        this._data = data;
 | 
						|
    }
 | 
						|
 | 
						|
    public toString(): string {
 | 
						|
        return JSON.stringify({
 | 
						|
            eventType: this.eventType,
 | 
						|
            prefix: this.prefix,
 | 
						|
            namespace: this.namespace,
 | 
						|
            elementName: this.elementName,
 | 
						|
            attributes: this.attributes,
 | 
						|
            data: this.data
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    public get eventType(): string {
 | 
						|
        return this._eventType;
 | 
						|
    }
 | 
						|
 | 
						|
    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;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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: easysax.EasySAXParser;
 | 
						|
 | 
						|
    private _processNamespaces: boolean;
 | 
						|
    private _namespaceStack: Array<any>;
 | 
						|
 | 
						|
    constructor(onEvent: (event: definition.ParserEvent) => void, onError?: (error: Error) => void, processNamespaces?: boolean) {
 | 
						|
        this._processNamespaces = processNamespaces;
 | 
						|
        this._parser = new easysax.EasySAXParser();
 | 
						|
 | 
						|
        var that = this;
 | 
						|
        this._parser.on('startNode', function (elem, attr, uq, str, tagend) {
 | 
						|
            var attributes = attr();
 | 
						|
 | 
						|
            if (attributes === true) {//HACK: For some reason easysax returns the true literal when an element has no attributes.
 | 
						|
                attributes = undefined;
 | 
						|
            }
 | 
						|
 | 
						|
            if (attributes) {
 | 
						|
                var key;
 | 
						|
                for (key in attributes) {
 | 
						|
                    if (attributes.hasOwnProperty(key)) {
 | 
						|
                        // Convert entities such as > to >
 | 
						|
                        attributes[key] = XmlParser._dereferenceEntities(attributes[key]);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            var prefix = undefined;
 | 
						|
            var namespace = undefined;
 | 
						|
            var name = elem;
 | 
						|
 | 
						|
            if (that._processNamespaces) {
 | 
						|
                var stackEntry = XmlParser._getNamespacesStackEntry(attributes);    
 | 
						|
                that._namespaceStack.push(stackEntry);
 | 
						|
 | 
						|
                var resolved = that._resolveNamespace(name);
 | 
						|
                prefix = resolved.prefix;
 | 
						|
                namespace = resolved.namespace;
 | 
						|
                name = resolved.name;
 | 
						|
            }
 | 
						|
 | 
						|
            onEvent(new ParserEvent(ParserEventType.StartElement, prefix, namespace, name, attributes, undefined));
 | 
						|
        });
 | 
						|
 | 
						|
        this._parser.on('textNode', function (text, uq) {
 | 
						|
            var data = uq(text);// Decode entity references such as < and >
 | 
						|
            onEvent(new ParserEvent(ParserEventType.Text, undefined, undefined, undefined, undefined, data));
 | 
						|
        });
 | 
						|
 | 
						|
        this._parser.on('endNode', function (elem, uq, tagstart, str) {
 | 
						|
 | 
						|
            var prefix = undefined;
 | 
						|
            var namespace = undefined;
 | 
						|
            var name = elem;
 | 
						|
 | 
						|
            if (that._processNamespaces) {
 | 
						|
                var resolved = that._resolveNamespace(name);
 | 
						|
                prefix = resolved.prefix;
 | 
						|
                namespace = resolved.namespace;
 | 
						|
                name = resolved.name;
 | 
						|
            }
 | 
						|
 | 
						|
            onEvent(new ParserEvent(ParserEventType.EndElement, prefix, namespace, name, undefined, undefined));
 | 
						|
 | 
						|
            if (that._processNamespaces) {
 | 
						|
                that._namespaceStack.pop();
 | 
						|
            }
 | 
						|
        });
 | 
						|
 | 
						|
        this._parser.on('cdata', function (data) {
 | 
						|
            onEvent(new ParserEvent(ParserEventType.CDATA, undefined, undefined, undefined, undefined, data));
 | 
						|
        });
 | 
						|
 | 
						|
        this._parser.on('comment', function (text) {
 | 
						|
            onEvent(new ParserEvent(ParserEventType.Comment, undefined, undefined, undefined, undefined, text));
 | 
						|
        });
 | 
						|
 | 
						|
        if (onError) {
 | 
						|
            this._parser.on('error', function (msg) {
 | 
						|
                onError(new Error(msg));
 | 
						|
            });
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public parse(xmlString: string): void {
 | 
						|
        if (this._processNamespaces) {
 | 
						|
            this._namespaceStack = [];
 | 
						|
        }
 | 
						|
 | 
						|
        this._parser.parse(xmlString);
 | 
						|
    }
 | 
						|
 | 
						|
    private static _getNamespacesStackEntry(attributes: any): any {
 | 
						|
        var stackEntry = {};
 | 
						|
 | 
						|
        if (!attributes) {
 | 
						|
            return stackEntry;
 | 
						|
        }
 | 
						|
 | 
						|
        for (var key in attributes) {
 | 
						|
            if (!attributes.hasOwnProperty(key)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            var attributeName = <string>key;
 | 
						|
            if (attributeName.indexOf("xmlns") !== 0) {
 | 
						|
                // This is a normal attribute, so go on.
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            var 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; } {
 | 
						|
        var result: { prefix: string; namespace: string; name: string; } = { prefix: undefined, namespace: undefined, name: undefined }
 | 
						|
        result.prefix = "";
 | 
						|
        if (fullName.indexOf(":") !== -1) {
 | 
						|
            var split = fullName.split(":");
 | 
						|
            result.prefix = split[0];
 | 
						|
            result.name = split[1];
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            result.name = fullName;
 | 
						|
        }
 | 
						|
 | 
						|
        var i;
 | 
						|
        var stackEntry;
 | 
						|
        for (i = this._namespaceStack.length - 1; i >= 0; i--) {
 | 
						|
            stackEntry = this._namespaceStack[i];
 | 
						|
 | 
						|
            for (var 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) {
 | 
						|
            if (s.indexOf('<') !== -1) { 
 | 
						|
                s = s.replace(/</g, '<'); 
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (s.indexOf('>') !== -1) { 
 | 
						|
                s = s.replace(/>/g, '>'); 
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (s.indexOf('&') !== -1) { 
 | 
						|
                s = s.replace(/&/g, '&'); 
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (s.indexOf(''') !== -1) { 
 | 
						|
                s = s.replace(/'/g, "'"); 
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (s.indexOf('"') !== -1) { 
 | 
						|
                s = s.replace(/"/g, '"'); 
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        return s;
 | 
						|
    }
 | 
						|
} |