瀏覽代碼

add back old Xml implementations as target.NativeXml for cpp, flash, neko and php (see #3910)

Simon Krajewski 10 年之前
父節點
當前提交
b7cca6dcbb
共有 8 個文件被更改,包括 1668 次插入8 次删除
  1. 11 0
      genas3.ml
  2. 2 2
      gencpp.ml
  3. 18 5
      genswf9.ml
  4. 1 1
      matcher.ml
  5. 424 0
      std/cpp/NativeXml.hx
  6. 421 0
      std/flash/NativeXml.hx
  7. 427 0
      std/neko/NativeXml.hx
  8. 364 0
      std/php/NativeXml.hx

+ 11 - 0
genas3.ml

@@ -54,6 +54,14 @@ let is_var_field f =
 	| _ ->
 	| _ ->
 		false
 		false
 
 
+let is_special_compare e1 e2 =
+	match e1.eexpr, e2.eexpr with
+	| TConst TNull, _  | _ , TConst TNull -> None
+	| _ ->
+	match follow e1.etype, follow e2.etype with
+	| TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c
+	| _ -> None
+
 let protect name =
 let protect name =
 	match name with
 	match name with
 	| "Error" | "Namespace" -> "_" ^ name
 	| "Error" | "Namespace" -> "_" ^ name
@@ -578,6 +586,9 @@ and gen_expr ctx e =
 		spr ctx "[";
 		spr ctx "[";
 		gen_value ctx e2;
 		gen_value ctx e2;
 		spr ctx "]";
 		spr ctx "]";
+	| TBinop (Ast.OpEq,e1,e2) when (match is_special_compare e1 e2 with Some c -> true | None -> false) ->
+		let c = match is_special_compare e1 e2 with Some c -> c | None -> assert false in
+		gen_expr ctx (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic e.epos,FDynamic "compare")) t_dynamic e.epos,[e1;e2])) ctx.inf.com.basic.tbool e.epos);
 	(* what is this used for? *)
 	(* what is this used for? *)
 (* 	| TBinop (op,{ eexpr = TField (e1,s) },e2) ->
 (* 	| TBinop (op,{ eexpr = TField (e1,s) },e2) ->
 		gen_value_op ctx e1;
 		gen_value_op ctx e1;

+ 2 - 2
gencpp.ml

@@ -264,7 +264,7 @@ let include_class_header = function
 
 
 let is_cpp_class = function
 let is_cpp_class = function
    | ("cpp"::_ , _)  -> true
    | ("cpp"::_ , _)  -> true
-   | ( [] , "Xml" )  -> true
+   | ( ["cpp"] , "Xml" )  -> true
    | ( [] , "EReg" )  -> true
    | ( [] , "EReg" )  -> true
    | ( ["haxe"] , "Log" )  -> true
    | ( ["haxe"] , "Log" )  -> true
    | _ -> false;;
    | _ -> false;;
@@ -4587,7 +4587,7 @@ let cppia_op_info = function
    | IaNoMain -> ("NOMAIN", 76)
    | IaNoMain -> ("NOMAIN", 76)
    | IaResources -> ("RESOURCES", 77)
    | IaResources -> ("RESOURCES", 77)
    | IaReso -> ("RESO", 78)
    | IaReso -> ("RESO", 78)
- 
+
 
 
 	| IaBinOp OpAdd -> ("+", 101)
 	| IaBinOp OpAdd -> ("+", 101)
 	| IaBinOp OpMult -> ("*", 102)
 	| IaBinOp OpMult -> ("*", 102)

+ 18 - 5
genswf9.ml

@@ -120,6 +120,14 @@ let tid (x : 'a index) : int = Obj.magic x
 let ethis = mk (TConst TThis) (mk_mono()) null_pos
 let ethis = mk (TConst TThis) (mk_mono()) null_pos
 let dynamic_prop = HMMultiNameLate [HNPublic (Some "")]
 let dynamic_prop = HMMultiNameLate [HNPublic (Some "")]
 
 
+let is_special_compare e1 e2 =
+	match e1.eexpr, e2.eexpr with
+	| TConst TNull, _  | _ , TConst TNull -> None
+	| _ ->
+	match follow e1.etype, follow e2.etype with
+	| TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c
+	| _ -> None
+
 let write ctx op =
 let write ctx op =
 	DynArray.add ctx.code op;
 	DynArray.add ctx.code op;
 	ctx.infos.ipos <- ctx.infos.ipos + 1;
 	ctx.infos.ipos <- ctx.infos.ipos + 1;
@@ -227,7 +235,7 @@ let rec type_id ctx t =
 		type_path ctx ([],"Function")
 		type_path ctx ([],"Function")
 	| TType ({ t_path = ([],"UInt") as path },_) ->
 	| TType ({ t_path = ([],"UInt") as path },_) ->
 		type_path ctx path
 		type_path ctx path
-	| TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
 		HMPath ([],"String")
 		HMPath ([],"String")
 	| TEnum (e,_) ->
 	| TEnum (e,_) ->
 		let rec loop = function
 		let rec loop = function
@@ -259,7 +267,7 @@ let classify ctx t =
 		KBool
 		KBool
 	| TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) ->
 	| TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) ->
 		KDynamic
 		KDynamic
-	| TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
 		KType (HMPath ([],"String"))
 		KType (HMPath ([],"String"))
 	| TEnum (e,_) ->
 	| TEnum (e,_) ->
 		let rec loop = function
 		let rec loop = function
@@ -1602,7 +1610,12 @@ and gen_binop ctx retval op e1 e2 t p =
 		write ctx (HOp o)
 		write ctx (HOp o)
 	in
 	in
 	let gen_eq() =
 	let gen_eq() =
-		gen_op A3OEq
+		match is_special_compare e1 e2 with
+		| None ->
+			gen_op A3OEq
+		| Some c ->
+			let f = FStatic (c,try PMap.find "compare" c.cl_statics with Not_found -> assert false) in
+			gen_expr ctx true (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic p,f)) t_dynamic p,[e1;e2])) ctx.com.basic.tbool p);
 	in
 	in
 	match op with
 	match op with
 	| OpAssign ->
 	| OpAssign ->
@@ -1709,8 +1722,8 @@ and jump_expr_gen ctx e jif jfun =
 			jfun (if jif then t else f)
 			jfun (if jif then t else f)
 		in
 		in
 		(match op with
 		(match op with
-		| OpEq -> j J3Eq J3Neq
-		| OpNotEq -> j J3Neq J3Eq
+		| OpEq when is_special_compare e1 e2 = None -> j J3Eq J3Neq
+		| OpNotEq when is_special_compare e1 e2 = None -> j J3Neq J3Eq
 		| OpGt -> j J3Gt J3NotGt
 		| OpGt -> j J3Gt J3NotGt
 		| OpGte -> j J3Gte J3NotGte
 		| OpGte -> j J3Gte J3NotGte
 		| OpLt -> j J3Lt J3NotLt
 		| OpLt -> j J3Lt J3NotLt

+ 1 - 1
matcher.ml

@@ -1163,7 +1163,7 @@ let match_expr ctx e cases def with_type p =
 			let e = type_expr ctx e Value in
 			let e = type_expr ctx e Value in
 			begin match follow e.etype with
 			begin match follow e.etype with
 			(* TODO: get rid of the XmlType check *)
 			(* TODO: get rid of the XmlType check *)
-			| TEnum(en,_) when (en.e_path = ([],"XmlType")) || Meta.has Meta.FakeEnum en.e_meta ->
+			| TEnum(en,_) when (match en.e_path with (["neko" | "php" | "flash" | "cpp"],"XmlType") -> true | _ -> Meta.has Meta.FakeEnum en.e_meta) ->
 				raise Exit
 				raise Exit
 			| TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) ->
 			| TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) ->
 				raise Exit;
 				raise Exit;

+ 424 - 0
std/cpp/NativeXml.hx

@@ -0,0 +1,424 @@
+/*
+ * Copyright (C)2005-2012 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 cpp;
+
+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;
+
+
+	private var _nodeName : String;
+	private var _nodeValue : String;
+	private var _attributes : Dynamic<String>;
+	private var _children : Array<Xml>;
+	private var _parent : Xml;
+
+	function new() : Void {
+	}
+
+	private static var _parse = cpp.Lib.load("std","parse_xml",2);
+
+	@:analyzer(ignore) public static function parse( str : String ) : Xml {
+		var x = new Xml();
+		x._children = new Array();
+		var parser = {
+			cur : x,
+			xml : function(name,att) {
+				var x = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.Element;
+				x._nodeName = new String(name);
+				x._attributes = att;
+				x._children = new Array();
+				untyped {
+					var i = 0;
+					__this__.cur.addChild(x);
+					__this__.cur = x;
+				}
+			},
+			cdata : function(text) {
+				var x = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.CData;
+				x._nodeValue = new String(text);
+				untyped __this__.cur.addChild(x);
+			},
+			pcdata : function(text) {
+				var x = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.PCData;
+				x._nodeValue = new String(text);
+				untyped __this__.cur.addChild(x);
+			},
+			comment : function(text:String) {
+				var x = new Xml();
+				x._parent = untyped __this__.cur;
+				if( untyped text.cca(0) == 63 ) {
+					x.nodeType = Xml.ProcessingInstruction;
+					text = new String(text);
+					text = text.substr(1, text.length - 2);
+				} else {
+					x.nodeType = Xml.Comment;
+					text = new String(text);
+				}
+				x._nodeValue = text;
+				untyped __this__.cur.addChild(x);
+			},
+			doctype : function(text) {
+				var x = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.DocType;
+				x._nodeValue = (new String(text)).substr(1);
+				var p : Xml = untyped __this__.cur;
+				p.addChild(x);
+			},
+			done : function() {
+				untyped __this__.cur = __this__.cur._parent;
+			}
+		};
+		untyped _parse(str,parser);
+		x.nodeType = Xml.Document;
+		return x;
+	}
+
+
+	public static function createElement( name : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Element;
+		r._nodeName = name;
+		r._attributes = null;
+		r._children = new Array();
+		return r;
+	}
+
+	public static function createPCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.PCData;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.CData;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createComment( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Comment;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createDocType( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.DocType;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createProcessingInstruction( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.ProcessingInstruction;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createDocument() : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Document;
+		r._children = new Array();
+		return r;
+	}
+
+	public var nodeType(default,null) : XmlType;
+
+	public var nodeName(get,set) : String;
+
+	public var nodeValue(get,set) : String;
+
+
+	private function get_nodeName() : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName;
+	}
+
+	private function set_nodeName( n : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName = n;
+	}
+
+	private function get_nodeValue() : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue;
+	}
+
+	private function set_nodeValue( v : String ) : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue = v;
+	}
+
+	public var parent(get,null) : Xml;
+	private function get_parent() : Xml {
+		return _parent;
+	}
+
+	public function get( att : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.field( _attributes, att );
+	}
+
+	public function set( att : String, value : String ) : Void {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		if (_attributes==null)
+			_attributes = {};
+		Reflect.setField (_attributes, att, value );
+		return null;
+	}
+
+	public function remove( att : String ) : Void{
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		Reflect.deleteField( _attributes, att );
+		return null;
+	}
+
+	public function exists( att : String ) : Bool {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.hasField( _attributes, att );
+	}
+
+	public function attributes() : Iterator<String> {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.fields( _attributes ).iterator();
+	}
+
+	public function iterator() : Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+      return untyped _children.iterator();
+	}
+
+
+	@:analyzer(ignore) public function elements(): Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+      var children = _children;
+		return untyped {
+			cur: 0,
+			hasNext : function() {
+				var k:Int = __this__.cur;
+				var l = children.length;
+				while( k < l ) {
+					if( children[k].nodeType == Xml.Element )
+						break;
+					k += 1;
+				}
+				__this__.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = __this__.cur;
+				var l = children.length;
+				while( k < l ) {
+					var n = children[k];
+					k += 1;
+					if( n.nodeType == Xml.Element ) {
+						__this__.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	@:analyzer(ignore) public function elementsNamed( name : String ) : Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+      var children = _children;
+		return untyped {
+			cur: 0,
+			hasNext : function() {
+				var k = __this__.cur;
+				var l = children.length;
+				while( k < l ) {
+					var n = children[k];
+					if( n.nodeType == Xml.Element && n._nodeName == name )
+						break;
+					k++;
+				}
+				__this__.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = __this__.cur;
+				var l = children.length;
+				while( k < l ) {
+					var n = children[k];
+					k++;
+					if( n.nodeType == Xml.Element && n._nodeName == name ) {
+						__this__.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	public function firstChild() : Xml {
+		if( _children == null )
+			throw "bad nodetype";
+		return _children[0];
+	}
+
+	public function firstElement() : Xml {
+		if( _children == null )
+			throw "bad nodetype";
+		for( cur in 0..._children.length ) {
+			var n:Xml = _children[cur];
+			if( n.nodeType == Xml.Element )
+				return n;
+		}
+		return null;
+	}
+
+   public function addChild( x : Xml ) : Void {
+		if( _children == null )
+			throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.push( x );
+		return null;
+	}
+
+   public function removeChild( x : Xml ) : Bool {
+		if( _children == null )
+			throw "bad nodetype";
+		var b = _children.remove( x );
+		if( b ) x._parent = null;
+		return b;
+	}
+
+	public function insertChild( x : Xml, pos : Int ) : Void {
+		if( _children == null )
+			throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.insert( pos, x );
+		return null;
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		toStringRec(s);
+		return s.toString();
+	}
+
+	private function toStringRec(s: StringBuf) : Void {
+		switch( nodeType ) {
+		case Xml.Document:
+			for( x in _children )
+				x.toStringRec(s);
+		case Xml.Element:
+			s.addChar("<".code);
+			s.add(_nodeName);
+			for( k in Reflect.fields(_attributes) ) {
+				s.addChar(" ".code);
+				s.add(k);
+				s.addChar("=".code);
+				s.addChar("\"".code);
+				s.add(Reflect.field(_attributes,k));
+				s.addChar("\"".code);
+			}
+			if( _children.length == 0 ) {
+				s.addChar("/".code);
+				s.addChar(">".code);
+				return;
+			}
+			s.addChar(">".code);
+			for( x in _children )
+				x.toStringRec(s);
+			s.addChar("<".code);
+			s.addChar("/".code);
+			s.add(_nodeName);
+			s.addChar(">".code);
+		case Xml.PCData:
+			s.add(StringTools.htmlEscape(_nodeValue));
+		case Xml.CData:
+			s.add("<![CDATA[");
+			s.add(_nodeValue);
+			s.add("]]>");
+		case Xml.Comment:
+			s.add("<!--");
+			s.add(_nodeValue);
+			s.add("-->");
+		case Xml.DocType:
+			s.add("<!DOCTYPE ");
+			s.add(_nodeValue);
+			s.add(">");
+		case Xml.ProcessingInstruction:
+			s.add("<?");
+			s.add(_nodeValue);
+			s.add("?>");
+		}
+	}
+
+	static function __init__() : Void untyped {
+		PCData = Type.createEnum(XmlType,"__");
+		Element = Type.createEnum(XmlType,"__");
+		CData =  Type.createEnum(XmlType,"__");
+		Comment = Type.createEnum(XmlType,"__");
+		DocType = Type.createEnum(XmlType,"__");
+		ProcessingInstruction =  Type.createEnum(XmlType,"__");
+		Document = Type.createEnum(XmlType,"__");
+		__global__.__hxcpp_enum_force(PCData , "pcdata", 0);
+		__global__.__hxcpp_enum_force(Element , "element", 1);
+		__global__.__hxcpp_enum_force(CData , "cdata", 2);
+		__global__.__hxcpp_enum_force(Comment , "comment", 3);
+		__global__.__hxcpp_enum_force(DocType , "doctype", 4);
+		__global__.__hxcpp_enum_force(ProcessingInstruction , "processingInstruction", 5);
+		__global__.__hxcpp_enum_force(Document , "document", 6);
+	}
+
+}

+ 421 - 0
std/flash/NativeXml.hx

@@ -0,0 +1,421 @@
+/*
+ * Copyright (C)2005-2012 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 #if as3 @:hack public #end 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";
+	}
+
+
+}

+ 427 - 0
std/neko/NativeXml.hx

@@ -0,0 +1,427 @@
+/*
+ * Copyright (C)2005-2012 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 neko;
+
+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 nodeName(get,set) : String;
+	public var nodeValue(get,set) : String;
+	public var parent(get,null) : Xml;
+	public var nodeType(default,null) : XmlType;
+
+	private var _nodeName : String;
+	private var _nodeValue : String;
+	private var _attributes : Dynamic<String>;
+	private var _children : Array<Xml>;
+	private var _parent : Xml;
+
+	private function new() : Void {
+	}
+
+	private static var _parse = neko.Lib.load("std","parse_xml",2);
+
+	public static function parse( str : String ) : Xml {
+		var x = new Xml();
+		x._children = new Array();
+		var parser = {
+			cur : x,
+			add : function(x:Dynamic) {
+				untyped __this__.cur._children.push(x);
+			},
+			xml : function(name,att) {
+				var x : Dynamic = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.Element;
+				x._nodeName = new String(name);
+				x._attributes = att;
+				x._children = new Array();
+				untyped {
+					var f = __dollar__objfields(att);
+					var i = 0;
+					var l = __dollar__asize(f);
+					while( i < l ) {
+						__dollar__objset(att,f[i], new String(__dollar__objget(att,f[i]))) ;
+						i++;
+					}
+					__this__.add(x);
+					__this__.cur = x;
+				}
+			},
+			cdata : function(text) {
+				var x : Dynamic = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.CData;
+				x._nodeValue = new String(text);
+				untyped __this__.add(x);
+			},
+			pcdata : function(text) {
+				var x : Dynamic = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.PCData;
+				x._nodeValue = new String(text);
+				untyped __this__.add(x);
+			},
+			comment : function(text) {
+				var x : Dynamic = new Xml();
+				x._parent = untyped __this__.cur;
+				if( untyped __dollar__sget(text,0) == 63 ) {
+					x.nodeType = Xml.ProcessingInstruction;
+					text = new String(text);
+					text = text.substr(1,text.length - 2);
+				} else {
+					x.nodeType = Xml.Comment;
+					text = new String(text);
+				}
+				x._nodeValue = text;
+				untyped __this__.add(x);
+			},
+			doctype : function(text) {
+				var x : Dynamic = new Xml();
+				x._parent = untyped __this__.cur;
+				x.nodeType = Xml.DocType;
+				x._nodeValue = new String(text).substr(1);
+				var p : Xml = untyped __this__.cur;
+				p.addChild(x);
+			},
+			done : function() {
+				untyped __this__.cur = __this__.cur._parent;
+			}
+		};
+		untyped _parse(str.__s,parser);
+		x.nodeType = Xml.Document;
+		return x;
+	}
+
+
+	public static function createElement( name : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Element;
+		r._nodeName = name;
+		r._attributes = untyped __dollar__new(null);
+		r._children = new Array();
+		return r;
+	}
+
+	public static function createPCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.PCData;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.CData;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createComment( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Comment;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createDocType( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.DocType;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createProcessingInstruction( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.ProcessingInstruction;
+		r._nodeValue = data;
+		return r;
+	}
+
+	public static function createDocument() : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Document;
+		r._children = new Array();
+		return r;
+	}
+
+	private function get_nodeName() : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName;
+	}
+
+	private function set_nodeName( n : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName = n;
+	}
+
+	private function get_nodeValue() : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue;
+	}
+
+	private function set_nodeValue( v : String ) : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue = v;
+	}
+
+	private function get_parent() : Xml {
+		return _parent;
+	}
+
+	public function get( att : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.field( _attributes, att );
+	}
+
+	public function set( att : String, value : String ) : Void {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		Reflect.setField (_attributes, att, value );
+	}
+
+	public function remove( att : String ) : Void{
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		Reflect.deleteField( _attributes, att );
+	}
+
+	public function exists( att : String ) : Bool {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.hasField( _attributes, att );
+	}
+
+	public function attributes() : Iterator<String> {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return Reflect.fields( _attributes ).iterator();
+	}
+
+	public function iterator() : Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function(){
+				return __this__.cur < __this__.x.length;
+			},
+			next : function(){
+				return __this__.x[__this__.cur++];
+			}
+		}
+	}
+
+
+	public function elements() : Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function() {
+				var k = __this__.cur;
+				var l = __this__.x.length;
+				while( k < l ) {
+					if( __this__.x[k].nodeType == Xml.Element )
+						break;
+					k += 1;
+				}
+				__this__.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = __this__.cur;
+				var l = __this__.x.length;
+				while( k < l ) {
+					var n = __this__.x[k];
+					k += 1;
+					if( n.nodeType == Xml.Element ) {
+						__this__.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	public function elementsNamed( name : String ) : Iterator<Xml> {
+		if( _children == null )
+			throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function() {
+				var k = __this__.cur;
+				var l = __this__.x.length;
+				while( k < l ) {
+					var n = __this__.x[k];
+					if( n.nodeType == Xml.Element && n._nodeName == name )
+						break;
+					k++;
+				}
+				__this__.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = __this__.cur;
+				var l = __this__.x.length;
+				while( k < l ) {
+					var n = __this__.x[k];
+					k++;
+					if( n.nodeType == Xml.Element && n._nodeName == name ) {
+						__this__.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	public function firstChild() : Xml {
+		if( _children == null )
+			throw "bad nodetype";
+		return _children[0];
+	}
+
+	public function firstElement() : Xml {
+		if( _children == null )
+			throw "bad nodetype";
+		for( cur in 0..._children.length ) {
+			var n = _children[cur];
+			if( n.nodeType == Xml.Element )
+				return n;
+		}
+		return null;
+	}
+
+	public function addChild( x : Xml ) : Void {
+		if( _children == null )
+			throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.push( x );
+	}
+
+	public function removeChild( x : Xml ) : Bool {
+		if( _children == null )
+			throw "bad nodetype";
+		var b = _children.remove( x );
+		if( b ) x._parent = null;
+		return b;
+	}
+
+	public function insertChild( x : Xml, pos : Int ) : Void {
+		if( _children == null )
+			throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.insert( pos, x );
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		toStringRec(s);
+		return s.toString();
+	}
+
+	function toStringRec(s: StringBuf) : Void {
+		switch( nodeType ) {
+		case Xml.Document:
+			for( x in _children )
+				x.toStringRec(s);
+		case Xml.Element:
+			s.addChar("<".code);
+			s.add(_nodeName);
+			for( k in Reflect.fields(_attributes) ) {
+				s.addChar(" ".code);
+				s.add(k);
+				s.addChar("=".code);
+				s.addChar("\"".code);
+				s.add(Reflect.field(_attributes,k));
+				s.addChar("\"".code);
+			}
+			if( _children.length == 0 ) {
+				s.addChar("/".code);
+				s.addChar(">".code);
+				return;
+			}
+			s.addChar(">".code);
+			for( x in _children )
+				x.toStringRec(s);
+			s.addChar("<".code);
+			s.addChar("/".code);
+			s.add(_nodeName);
+			s.addChar(">".code);
+		case Xml.PCData:
+			s.add(StringTools.htmlEscape(_nodeValue));
+		case Xml.CData:
+			s.add("<![CDATA[");
+			s.add(_nodeValue);
+			s.add("]]>");
+		case Xml.Comment:
+			s.add("<!--");
+			s.add(_nodeValue);
+			s.add("-->");
+		case Xml.DocType:
+			s.add("<!DOCTYPE ");
+			s.add(_nodeValue);
+			s.add(">");
+		case Xml.ProcessingInstruction:
+			s.add("<?");
+			s.add(_nodeValue);
+			s.add("?>");
+		}
+	}
+
+	static function __init__() : Void untyped {
+		Xml.Element = "element";
+		Xml.PCData = "pcdata";
+		Xml.CData = "cdata";
+		Xml.Comment = "comment";
+		Xml.DocType = "doctype";
+		Xml.ProcessingInstruction = "processingInstruction";
+		Xml.Document = "document";
+	}
+
+}

+ 364 - 0
std/php/NativeXml.hx

@@ -0,0 +1,364 @@
+/*
+ * Copyright (C)2005-2012 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 php;
+
+import php.Lib;
+
+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 _nodeName : String;
+	var _nodeValue : String;
+	var _attributes : haxe.ds.StringMap<String>;
+	var _children : Array<Xml>;
+	var _parent : Xml;
+	var _fromCustomParser:Bool;
+
+	private static var build : Xml;
+	private static function __start_element_handler(parser : Dynamic, name : String, attribs : ArrayAccess<String>) : Void {
+		var node = createElement(name);
+		untyped __php__("foreach($attribs as $k => $v) $node->set($k, $v)");
+		build.addChild(node);
+		build = node;
+	}
+
+	private static function __end_element_handler(parser : Dynamic, name : String) : Void {
+		build = build.parent;
+	}
+
+	private static function __decodeattr(value : String) : String
+	{
+		return untyped __call__("str_replace", "'", '&apos;', __call__("htmlspecialchars", value, __php__('ENT_COMPAT'), 'UTF-8'));
+	}
+
+	private static function __decodeent(value : String) : String
+	{
+		return untyped __call__("str_replace", "'", '&apos;', __call__("htmlentities", value, __php__('ENT_COMPAT'), 'UTF-8'));
+	}
+
+	private static function __character_data_handler(parser : Dynamic, data : String) : Void {
+		var d = __decodeent(data);
+		if ((untyped __call__("strlen", data) == 1 && d != data) || d == data) {
+			var last = build._children[build._children.length - 1];
+			if (null != last && last.nodeType == Xml.PCData)
+			{
+				last.nodeValue += d;
+			} else
+				build.addChild(createPCData(d));
+		} else {
+			build.addChild(createCData(data));
+		}
+	}
+
+	private static function __default_handler(parser : Dynamic, data : String) : Void {
+		//On some PHP setups (seems to happen when libexpat is used) we may get called for such "entities" although character_data will correctly be called afterward.
+		if(data == "<![CDATA[")
+			return;
+		if(data == "]]>")
+			return;
+		if ("<!--" == data.substr(0, 4))
+			build.addChild(createComment(data.substr(4, data.length-7)));
+		else
+			build.addChild(createPCData(data));
+	}
+
+	static var reHeader = ~/\s*(?:<\?(.+?)\?>)?(?:<!DOCTYPE ([^>]+)>)?/mi;
+
+	public static function parse( str : String ) : Xml {
+		build = createDocument();
+		var xml_parser = untyped __call__("xml_parser_create");
+		untyped __call__("xml_set_element_handler", xml_parser, __start_element_handler, __end_element_handler);
+		untyped __call__("xml_set_character_data_handler", xml_parser, __character_data_handler);
+		untyped __call__("xml_set_default_handler", xml_parser, __default_handler);
+		untyped __call__("xml_parser_set_option", xml_parser, __php__("XML_OPTION_CASE_FOLDING"), 0);
+		untyped __call__("xml_parser_set_option", xml_parser, __php__("XML_OPTION_SKIP_WHITE"), 0);
+
+		reHeader.match(str);
+
+		str = "<doc>"+reHeader.matchedRight()+"</doc>";
+
+		if(1 != untyped __call__("xml_parse", xml_parser, str, true)) {
+			throw "Xml parse error ("+untyped __call__("xml_error_string", __call__("xml_get_error_code", xml_parser)) + ") line #" + __call__("xml_get_current_line_number", xml_parser);
+		}
+
+		untyped __call__("xml_parser_free", xml_parser);
+
+		build = build._children[0];
+		build._parent = null;
+		build._nodeName = null;
+		build.nodeType = Document;
+
+		var doctype = reHeader.matched(2);
+		if (null != doctype)
+			build.insertChild(createDocType(doctype), 0);
+
+		var ProcessingInstruction = reHeader.matched(1);
+		if (null != ProcessingInstruction)
+			build.insertChild(createProcessingInstruction(ProcessingInstruction), 0);
+
+		return build;
+	}
+
+	private function new(fromCustomParser:Bool = false) : Void {
+		_fromCustomParser = fromCustomParser;
+	}
+
+	@:allow(haxe.xml.Parser)
+	static function createPCDataFromCustomParser( data : String ) : Xml {
+		var r = new Xml(true);
+		r.nodeType = Xml.PCData;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createElement( name : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Element;
+		r._children = new Array();
+		r._attributes = new haxe.ds.StringMap();
+		r.set_nodeName( name );
+		return r;
+	}
+
+	public static function createPCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.PCData;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createCData( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.CData;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createComment( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Comment;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createDocType( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.DocType;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createProcessingInstruction( data : String ) : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.ProcessingInstruction;
+		r.set_nodeValue( data );
+		return r;
+	}
+
+	public static function createDocument() : Xml {
+		var r = new Xml();
+		r.nodeType = Xml.Document;
+		r._children = new Array();
+		return r;
+	}
+
+	private function get_nodeName() : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName;
+	}
+
+	private function set_nodeName( n : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName = n;
+	}
+
+	private function get_nodeValue() : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue;
+	}
+
+	private function set_nodeValue( v : String ) : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue = v;
+	}
+
+	private inline function get_parent() : Xml {
+		return _parent;
+	}
+
+	public function get( att : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.get( att );
+	}
+
+	// TODO: check correct transform function
+	@:ifFeature("Xml.parse")
+	public function set( att : String, value : String ) : Void {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		_attributes.set( att, __decodeattr(value) );
+	}
+
+	public function remove( att : String ) : Void{
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		_attributes.remove( att );
+	}
+
+	public function exists( att : String ) : Bool {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.exists( att );
+	}
+
+	public function attributes() : Iterator<String> {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.keys();
+	}
+
+	public function iterator() : Iterator<Xml> {
+		if( _children == null ) throw "bad nodetype";
+		return _children.iterator();
+	}
+
+	public function elements() : Iterator<Xml> {
+		if( _children == null ) throw "bad nodetype";
+		return Lambda.filter(_children, function(child) return child.nodeType == Xml.Element).iterator();
+	}
+
+	public function elementsNamed( name : String ) : Iterator<Xml> {
+		if( _children == null ) throw "bad nodetype";
+		return Lambda.filter(_children, function(child) return child.nodeType == Xml.Element && child.nodeName == name).iterator();
+	}
+
+	public function firstChild() : Xml {
+		if( _children == null ) throw "bad nodetype";
+		if( _children.length == 0 ) return null;
+		return _children[0];
+	}
+
+	public function firstElement() : Xml {
+		if( _children == null ) throw "bad nodetype";
+		for (child in _children)
+			if (child.nodeType == Xml.Element)
+				return child;
+		return null;
+	}
+
+	public function addChild( x : Xml ) : Void {
+		if( _children == null ) throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.push( x );
+	}
+
+	public function removeChild( x : Xml ) : Bool {
+		if( _children == null ) throw "bad nodetype";
+		var b = _children.remove( x );
+		if( b )
+			x._parent = null;
+		return b;
+	}
+
+	public function insertChild( x : Xml, pos : Int ) : Void {
+		if( _children == null ) throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.insert( pos, x );
+	}
+
+	public function toString() : String {
+		if( nodeType == Xml.PCData )
+			return _fromCustomParser ? StringTools.htmlEscape(_nodeValue) : _nodeValue;
+
+		var s = "";
+
+		if( nodeType == Xml.Element ) {
+			s += "<";
+			s += _nodeName;
+			for( k in _attributes.keys() ){
+				s += " ";
+				s += k;
+				s += "=\""; // \"
+				s += _attributes.get(k);
+				s += "\""; // \"
+			}
+			if( _children.length == 0 ) {
+				s += "/>";
+				return s;
+			}
+			s += ">";
+		} else if( nodeType == Xml.CData )
+			return "<![CDATA["+_nodeValue+"]]>";
+		else if( nodeType == Xml.Comment )
+			return "<!--"+_nodeValue+"-->";
+		else if( nodeType == Xml.DocType )
+			return "<!DOCTYPE "+_nodeValue+">";
+		else if ( nodeType == Xml.ProcessingInstruction )
+			return "<?"+_nodeValue+"?>";
+
+
+		for( x in iterator() )
+			s += x.toString();
+
+		if( nodeType == Xml.Element ) {
+			s += "</";
+			s += _nodeName;
+			s += ">";
+		}
+		return s;
+	}
+
+	static function __init__() : Void untyped {
+		Xml.Element = "element";
+		Xml.PCData = "pcdata";
+		Xml.CData = "cdata";
+		Xml.Comment = "comment";
+		Xml.DocType = "doctype";
+		Xml.ProcessingInstruction = "processingInstruction";
+		Xml.Document = "document";
+	}
+
+}