419 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C)2005-2019 Haxe Foundation
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | |
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  * DEALINGS IN THE SOFTWARE.
 | |
|  */
 | |
| 
 | |
| package flash;
 | |
| 
 | |
| import flash.xml.XML;
 | |
| import flash.xml.XMLList;
 | |
| 
 | |
| extern enum XmlType {}
 | |
| typedef NativeXml = Xml;
 | |
| 
 | |
| class Xml {
 | |
| 	public static var Element(default, null):XmlType;
 | |
| 	public static var PCData(default, null):XmlType;
 | |
| 	public static var CData(default, null):XmlType;
 | |
| 	public static var Comment(default, null):XmlType;
 | |
| 	public static var DocType(default, null):XmlType;
 | |
| 	public static var ProcessingInstruction(default, null):XmlType;
 | |
| 	public static var Document(default, null):XmlType;
 | |
| 
 | |
| 	public var nodeType(default, null):XmlType;
 | |
| 	public var nodeName(get, set):String;
 | |
| 	public var nodeValue(get, set):String;
 | |
| 	public var parent(get, null):Xml;
 | |
| 
 | |
| 	var _node:flash.xml.XML;
 | |
| 
 | |
| 	public static function parse(str:String):Xml {
 | |
| 		XML.ignoreWhitespace = false;
 | |
| 		XML.ignoreProcessingInstructions = false;
 | |
| 		XML.ignoreComments = false;
 | |
| 		var prefix = "<__document";
 | |
| 		var root = null;
 | |
| 		while (root == null) {
 | |
| 			try {
 | |
| 				root = new flash.xml.XML(prefix + ">" + str + "</__document>");
 | |
| 			} catch (e:flash.errors.TypeError) {
 | |
| 				// if we miss a namespace, let's add it !
 | |
| 				var r = ~/"([^"]+)"/; // "
 | |
| 				if (e.errorID == 1083 && r.match(e.message)) {
 | |
| 					var ns = r.matched(1);
 | |
| 					prefix += " xmlns:" + ns + '="@' + ns + '"';
 | |
| 				} else
 | |
| 					throw e;
 | |
| 			}
 | |
| 		}
 | |
| 		return wrap(root, Xml.Document);
 | |
| 	}
 | |
| 
 | |
| 	@:keep static function compare(a:Xml, b:Xml):Bool {
 | |
| 		return a == null ? b == null : (b == null ? false : a._node == b._node);
 | |
| 	}
 | |
| 
 | |
| 	private function new():Void {}
 | |
| 
 | |
| 	public static function createElement(name:String):Xml {
 | |
| 		return wrap(new flash.xml.XML("<" + name + "/>"), Xml.Element);
 | |
| 	}
 | |
| 
 | |
| 	public static function createPCData(data:String):Xml {
 | |
| 		XML.ignoreWhitespace = false;
 | |
| 		return wrap(new flash.xml.XML(data), Xml.PCData);
 | |
| 	}
 | |
| 
 | |
| 	public static function createCData(data:String):Xml {
 | |
| 		return wrap(new flash.xml.XML("<![CDATA[" + data + "]]>"), Xml.CData);
 | |
| 	}
 | |
| 
 | |
| 	public static function createComment(data:String):Xml {
 | |
| 		XML.ignoreComments = false;
 | |
| 		return wrap(new flash.xml.XML("<!--" + data + "-->"), Xml.Comment);
 | |
| 	}
 | |
| 
 | |
| 	public static function createDocType(data:String):Xml {
 | |
| 		return wrap(new flash.xml.XML("<!DOCTYPE " + data + ">"), Xml.DocType);
 | |
| 	}
 | |
| 
 | |
| 	public static function createProcessingInstruction(data:String):Xml {
 | |
| 		XML.ignoreProcessingInstructions = false;
 | |
| 		return wrap(new flash.xml.XML("<?" + data + "?>"), Xml.ProcessingInstruction);
 | |
| 	}
 | |
| 
 | |
| 	public static function createDocument():Xml {
 | |
| 		return wrap(new flash.xml.XML("<__document/>"), Xml.Document);
 | |
| 	}
 | |
| 
 | |
| 	private static function getNodeType(node:flash.xml.XML):XmlType {
 | |
| 		switch (node.nodeKind()) {
 | |
| 			case "element":
 | |
| 				return Xml.Element;
 | |
| 			case "text":
 | |
| 				return Xml.PCData;
 | |
| 			case "processing-instruction":
 | |
| 				return Xml.ProcessingInstruction;
 | |
| 			case "comment":
 | |
| 				return Xml.Comment;
 | |
| 			default:
 | |
| 				throw "unimplemented node type: " + node.nodeType;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private function get_nodeName():String {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = _node.namespace();
 | |
| 		return (ns.prefix == "") ? _node.localName() : ns.prefix + ":" + _node.localName();
 | |
| 	}
 | |
| 
 | |
| 	private function set_nodeName(n:String):String {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = n.split(":");
 | |
| 		if (ns.length == 1)
 | |
| 			_node.setLocalName(n);
 | |
| 		else {
 | |
| 			_node.setLocalName(ns[1]);
 | |
| 			_node.setNamespace(_node.namespace(ns[0]));
 | |
| 		}
 | |
| 		return n;
 | |
| 	}
 | |
| 
 | |
| 	private function get_nodeValue():String {
 | |
| 		var nodeType = nodeType;
 | |
| 		if (nodeType == Xml.Element || nodeType == Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		if (nodeType == Xml.Comment)
 | |
| 			return _node.toString().substr(4, -7);
 | |
| 		return _node.toString();
 | |
| 	}
 | |
| 
 | |
| 	private function set_nodeValue(v:String):String {
 | |
| 		var nodeType = nodeType;
 | |
| 		var x = null;
 | |
| 		if (nodeType == Xml.Element || nodeType == Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		else if (nodeType == Xml.PCData)
 | |
| 			x = createPCData(v);
 | |
| 		else if (nodeType == Xml.CData)
 | |
| 			x = createCData(v);
 | |
| 		else if (nodeType == Xml.Comment)
 | |
| 			x = createComment(v);
 | |
| 		else if (nodeType == Xml.DocType)
 | |
| 			x = createDocType(v);
 | |
| 		else
 | |
| 			x = createProcessingInstruction(v);
 | |
| 		var p = _node.parent();
 | |
| 		if (p != null) {
 | |
| 			p.insertChildAfter(_node, x._node);
 | |
| 			var i = _node.childIndex();
 | |
| 			var children = p.children();
 | |
| 			untyped __delete__(children, Reflect.fields(children)[i]);
 | |
| 		}
 | |
| 		_node = x._node;
 | |
| 		return v;
 | |
| 	}
 | |
| 
 | |
| 	private function get_parent():Xml {
 | |
| 		var p = _node.parent();
 | |
| 		return p == null ? null : wrap(p);
 | |
| 	}
 | |
| 
 | |
| 	private static function wrap(node:XML, ?type:XmlType):Xml {
 | |
| 		var x = new Xml();
 | |
| 		x._node = node;
 | |
| 		x.nodeType = (type != null) ? type : getNodeType(node);
 | |
| 		return x;
 | |
| 	}
 | |
| 
 | |
| 	private function wraps(xList:XMLList):Array<Xml> {
 | |
| 		var out = new Array<Xml>();
 | |
| 		for (i in 0...xList.length())
 | |
| 			out.push(wrap(xList[i]));
 | |
| 		return out;
 | |
| 	}
 | |
| 
 | |
| 	function getAttribNS(cur:XML, ns:Array<String>):XMLList {
 | |
| 		var n = cur.namespace(ns[0]);
 | |
| 		if (n == null) {
 | |
| 			var parent = cur.parent();
 | |
| 			if (parent == null) {
 | |
| 				n = new flash.utils.Namespace(ns[0], "@" + ns[0]);
 | |
| 				cur.addNamespace(n);
 | |
| 			} else
 | |
| 				return getAttribNS(parent, ns);
 | |
| 		}
 | |
| 		return _node.attribute(new flash.utils.QName(n, ns[1]));
 | |
| 	}
 | |
| 
 | |
| 	public function get(att:String):String {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = att.split(":");
 | |
| 		if (ns[0] == "xmlns") {
 | |
| 			var n = _node.namespace((ns[1] == null) ? "" : ns[1]);
 | |
| 			return (n == null) ? null : n.uri;
 | |
| 		}
 | |
| 		if (ns.length == 1) {
 | |
| 			if (!Reflect.hasField(_node, "@" + att))
 | |
| 				return null;
 | |
| 			return Reflect.field(_node, "@" + att);
 | |
| 		}
 | |
| 		var a = getAttribNS(_node, ns);
 | |
| 		return (a.length() == 0) ? null : a.toString();
 | |
| 	}
 | |
| 
 | |
| 	public function set(att:String, value:String):Void {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = att.split(":");
 | |
| 		if (ns[0] == "xmlns") {
 | |
| 			var n = _node.namespace((ns[1] == null) ? "" : ns[1]);
 | |
| 			if (n != null)
 | |
| 				throw "Can't modify namespace";
 | |
| 			if (ns[1] == null)
 | |
| 				throw "Can't set default namespace";
 | |
| 			_node.addNamespace(new flash.utils.Namespace(ns[1], value));
 | |
| 			return;
 | |
| 		}
 | |
| 		if (ns.length == 1)
 | |
| 			Reflect.setField(_node, "@" + att, value);
 | |
| 		else {
 | |
| 			var a = getAttribNS(_node, ns);
 | |
| 			untyped a[0] = value;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function remove(att:String):Void {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = att.split(":");
 | |
| 		if (ns.length == 1)
 | |
| 			Reflect.deleteField(_node, "@" + att);
 | |
| 		else
 | |
| 			untyped __delete__(getAttribNS(_node, ns), 0);
 | |
| 	}
 | |
| 
 | |
| 	public function exists(att:String):Bool {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = att.split(":");
 | |
| 		if (ns[0] == "xmlns")
 | |
| 			return _node.namespace((ns[1] == null) ? "" : ns[1]) != null;
 | |
| 		if (ns.length == 1)
 | |
| 			return Reflect.hasField(_node, "@" + att);
 | |
| 		return getAttribNS(_node, ns).length() > 0;
 | |
| 	}
 | |
| 
 | |
| 	public function attributes():Iterator<String> {
 | |
| 		if (nodeType != Xml.Element)
 | |
| 			throw "bad nodeType";
 | |
| 		var attributes:XMLList = _node.attributes();
 | |
| 		var names = Reflect.fields(attributes);
 | |
| 		var cur = 0;
 | |
| 		var nss = _node.namespaceDeclarations();
 | |
| 		return {
 | |
| 			hasNext: function() {
 | |
| 				return cur < names.length + nss.length;
 | |
| 			},
 | |
| 			next: function() {
 | |
| 				if (cur < names.length) {
 | |
| 					return attributes[Std.parseInt(names[cur++])].name();
 | |
| 				} else {
 | |
| 					var ns:flash.utils.Namespace = nss[cur++ - names.length];
 | |
| 					return "xmlns:" + ns.prefix;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function iterator():Iterator<Xml> {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var children:XMLList = _node.children();
 | |
| 		var wrappers:Array<Xml> = wraps(children);
 | |
| 		var cur = 0;
 | |
| 		return {
 | |
| 			hasNext: function() {
 | |
| 				return cur < wrappers.length;
 | |
| 			},
 | |
| 			next: function() {
 | |
| 				return wrappers[cur++];
 | |
| 			}
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	public function elements():Iterator<Xml> {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var elements:XMLList = _node.elements();
 | |
| 		var wrappers:Array<Xml> = wraps(elements);
 | |
| 		var cur = 0;
 | |
| 		return {
 | |
| 			hasNext: function() {
 | |
| 				return cur < wrappers.length;
 | |
| 			},
 | |
| 			next: function() {
 | |
| 				return wrappers[cur++];
 | |
| 			}
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	public function elementsNamed(name:String):Iterator<Xml> {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var ns = name.split(":");
 | |
| 		var elements:XMLList;
 | |
| 		if (ns.length == 1)
 | |
| 			elements = _node.elements(name);
 | |
| 		else
 | |
| 			elements = _node.elements();
 | |
| 		var wrappers:Array<Xml> = wraps(elements);
 | |
| 		if (ns.length != 1)
 | |
| 			for (w in wrappers.copy())
 | |
| 				if (w._node.localName() != ns[1] || w._node.namespace().prefix != ns[0])
 | |
| 					wrappers.remove(w);
 | |
| 		var cur = 0;
 | |
| 		return {
 | |
| 			hasNext: function() {
 | |
| 				return cur < wrappers.length;
 | |
| 			},
 | |
| 			next: function() {
 | |
| 				return wrappers[cur++];
 | |
| 			}
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	public function firstChild():Xml {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var children:XMLList = _node.children();
 | |
| 		if (children.length() == 0)
 | |
| 			return null;
 | |
| 		return wrap(children[0]);
 | |
| 	}
 | |
| 
 | |
| 	public function firstElement():Xml {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var elements:XMLList = _node.elements();
 | |
| 		if (elements.length() == 0)
 | |
| 			return null;
 | |
| 		return wrap(elements[0]);
 | |
| 	}
 | |
| 
 | |
| 	public function addChild(x:Xml):Void {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		if (x.parent != null)
 | |
| 			x.parent.removeChild(x);
 | |
| 		var children:XMLList = _node.children();
 | |
| 		_node.appendChild(x._node);
 | |
| 	}
 | |
| 
 | |
| 	public function removeChild(x:Xml):Bool {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		var children:XMLList = _node.children();
 | |
| 		if (_node != x._node.parent())
 | |
| 			return false;
 | |
| 		var i = x._node.childIndex();
 | |
| 		untyped __delete__(children, Reflect.fields(children)[i]);
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	public function insertChild(x:Xml, pos:Int):Void {
 | |
| 		if (nodeType != Xml.Element && nodeType != Xml.Document)
 | |
| 			throw "bad nodeType";
 | |
| 		if (x.parent != null)
 | |
| 			x.parent.removeChild(x);
 | |
| 		var children:XMLList = _node.children();
 | |
| 		if (pos < children.length())
 | |
| 			_node.insertChildBefore(children[pos], x._node);
 | |
| 		else
 | |
| 			_node.appendChild(x._node);
 | |
| 	}
 | |
| 
 | |
| 	public function toString():String {
 | |
| 		XML.prettyPrinting = false;
 | |
| 		if (nodeType == Xml.Document) {
 | |
| 			var str = _node.toXMLString();
 | |
| 			// remove <__document xmlns....>STR</__document> wrapper
 | |
| 			str = str.substr(str.indexOf(">") + 1);
 | |
| 			str = str.substr(0, str.length - 13);
 | |
| 			return str;
 | |
| 		}
 | |
| 		return _node.toXMLString();
 | |
| 	}
 | |
| 
 | |
| 	static function __init__():Void
 | |
| 		untyped {
 | |
| 			Element = "element";
 | |
| 			PCData = "pcdata";
 | |
| 			CData = "cdata";
 | |
| 			Comment = "comment";
 | |
| 			DocType = "doctype";
 | |
| 			ProcessingInstruction = "processingInstruction";
 | |
| 			Document = "document";
 | |
| 		}
 | |
| }
 |