Explorar o código

improved xml support for Comment,Prolog,DocType
replace flash9 Xml implementation with native parser (and supported namespaces for nodes & attributes)

Nicolas Cannasse %!s(int64=15) %!d(string=hai) anos
pai
achega
b2353240b7

+ 1 - 0
doc/CHANGES.txt

@@ -26,6 +26,7 @@
 	flash9 : added @:bind support
 	flash9 : added @:bind support
 	all : fixed StringTools.hex with negative numbers
 	all : fixed StringTools.hex with negative numbers
 	flash9 : fixed Type.typeof(1<<28) was TFloat
 	flash9 : fixed Type.typeof(1<<28) was TFloat
+	flash9 : use flash.XML parser for Xml class implementation
 
 
 2010-01-09: 2.05
 2010-01-09: 2.05
 	js : added js.Scroll
 	js : added js.Scroll

+ 44 - 24
std/cpp/CppXml__.hx

@@ -84,10 +84,11 @@ class CppXml__ {
 				x._parent = untyped this.cur;
 				x._parent = untyped this.cur;
 				if( untyped text.cca(0) == 63 ) {
 				if( untyped text.cca(0) == 63 ) {
 					x.nodeType = Xml.Prolog;
 					x.nodeType = Xml.Prolog;
-					text = "<"+new String(text)+">";
+					text = new String(text);
+					text = text.substr(1, text.length - 2);
 				} else {
 				} else {
 					x.nodeType = Xml.Comment;
 					x.nodeType = Xml.Comment;
-					text = "<!--"+new String(text)+"-->";
+					text = new String(text);
 				}
 				}
 				x._nodeValue = text;
 				x._nodeValue = text;
 				untyped this.cur.addChild(x);
 				untyped this.cur.addChild(x);
@@ -96,7 +97,7 @@ class CppXml__ {
 				var x = new CppXml__();
 				var x = new CppXml__();
 				x._parent = untyped this.cur;
 				x._parent = untyped this.cur;
 				x.nodeType = Xml.DocType;
 				x.nodeType = Xml.DocType;
-				x._nodeValue = "<!DOCTYPE"+new String(text)+">";
+				x._nodeValue = (new String(text)).substr(1);
 				untyped this.cur.addChild(x);
 				untyped this.cur.addChild(x);
 			},
 			},
 			done : function() {
 			done : function() {
@@ -362,39 +363,58 @@ class CppXml__ {
 	}
 	}
 
 
 	public function toString() {
 	public function toString() {
-		if( nodeType == Xml.PCData )
-			return _nodeValue;
-		if( nodeType == Xml.CData )
-			return "<![CDATA["+_nodeValue+"]]>";
-		if( nodeType == Xml.Comment || nodeType == Xml.DocType || nodeType == Xml.Prolog )
-			return _nodeValue;
-
 		var s = new StringBuf();
 		var s = new StringBuf();
+		toStringRec(s);
+		return s.toString();
+	}
 
 
-		if( nodeType == Xml.Element ) {
-			s.add("<");
+	public function toStringRec(s: StringBuf) {
+		switch( nodeType ) {
+		case Xml.Document:
+			for( x in _children )
+				x.toStringRec(s);
+		case Xml.Element:
+			s.addChar("<".code);
 			s.add(_nodeName);
 			s.add(_nodeName);
 			for( k in Reflect.fields(_attributes) ) {
 			for( k in Reflect.fields(_attributes) ) {
-				s.add(" ");
+				s.addChar(" ".code);
 				s.add(k);
 				s.add(k);
-				s.add("=\"");
+				s.addChar("=".code);
+				s.addChar("\"".code);
 				s.add(Reflect.field(_attributes,k));
 				s.add(Reflect.field(_attributes,k));
-				s.add("\"");
+				s.addChar("\"".code);
 			}
 			}
 			if( _children.length == 0 ) {
 			if( _children.length == 0 ) {
-				s.add("/>");
-				return s.toString();
+				s.addChar("/".code);
+				s.addChar(">".code);
+				return;
 			}
 			}
-			s.add(">");
-		}
-		for( x in iterator() )
-			s.add(x);
-		if( nodeType == Xml.Element ) {
-			s.add("</");
+			s.addChar(">".code);
+			for( x in _children )
+				x.toStringRec(s);
+			s.addChar("<".code);
+			s.addChar("/".code);
 			s.add(_nodeName);
 			s.add(_nodeName);
+			s.addChar(">".code);
+		case Xml.PCData:
+			s.add(_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(">");
 			s.add(">");
+		case Xml.Prolog:
+			s.add("<?");
+			s.add(_nodeValue);
+			s.add("?>");
 		}
 		}
-		return s.toString();
 	}
 	}
 
 
 	static function __init__() : Void {
 	static function __init__() : Void {

+ 2 - 1
std/flash/FlashXml__.hx

@@ -277,9 +277,10 @@ class FlashXml__ {
 				s += c.toString();
 				s += c.toString();
 			return s;
 			return s;
 		}
 		}
+		// only works for toplevel elements
 		if( nodeType == Xml.CData )
 		if( nodeType == Xml.CData )
 			return "<![CDATA["+__x[untyped "nodeValue"]+"]]>";
 			return "<![CDATA["+__x[untyped "nodeValue"]+"]]>";
-		return __x.toString();
+		return __x.toString().split(" />").join("/>");
 	}
 	}
 
 
 
 

+ 347 - 439
std/flash9/FlashXml__.hx

@@ -1,439 +1,347 @@
-/*
- * Copyright (c) 2005, The haXe Project Contributors
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   - Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   - Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- */
-package flash;
-import Xml;
-
-class FlashXml__ {
-
-	static var enode = ~/^<([a-zA-Z0-9:_-]+)/;
-	static var ecdata = ~/^<!\[CDATA\[/i;
-	static var edoctype = ~/^<!DOCTYPE/i;
-	static var eend = ~/^<\/([a-zA-Z0-9:_-]+)>/;
-	static var epcdata = ~/^[^<]+/;
-	static var ecomment = ~/^<!--/;
-	static var eprolog = ~/^<\?[^\?]+\?>/;
-
-	static var eattribute = ~/^\s*([a-zA-Z0-9:_-]+)\s*=\s*(['"])([^\2]*?)\2/; //"
-	static var eclose = ~/^[ \r\n\t]*(>|(\/>))/;
-	static var ecdata_end = ~/\]\]>/;
-	static var edoctype_elt = ~/[\[|\]>]/;
-	static var ecomment_end = ~/-->/;
-
-	public static var Element : String;
-	public static var PCData : String;
-	public static var CData : String;
-	public static var Comment : String;
-	public static var DocType : String;
-	public static var Prolog : String;
-	public static var Document : String;
-
-	public var nodeType(default,null) : XmlType;
-	public var nodeName(getNodeName,setNodeName) : String;
-	public var nodeValue(getNodeValue,setNodeValue) : String;
-	public var parent(getParent,null) : FlashXml__;
-
-	var _nodeName : String;
-	var _nodeValue : String;
-	var _attributes : Hash<String>;
-	var _children : Array<FlashXml__>;
-	var _parent : FlashXml__;
-
-	public static function parse( str : String ) : FlashXml__ {
-		var rules = [enode,epcdata,eend,ecdata,edoctype,ecomment,eprolog];
-		var nrules = rules.length;
-		var current = createDocument();
-		var stack = new List();
-		var line = 1;
-		while( str.length > 0 ) {
-			var i = 0;
-			while( i < nrules ) {
-				var r = rules[i];
-				if( r.match(str) ) {
-					switch( i ) {
-					case 0: // Node
-						var x = createElement(r.matched(1));
-						current.addChild(x);
-						str = r.matchedRight();
-						while( eattribute.match(str) ) {
-							x.set(eattribute.matched(1),eattribute.matched(3));
-							str = eattribute.matchedRight();
-						}
-						if( !eclose.match(str) ) {
-							i = nrules;
-							break;
-						}
-						if( eclose.matched(1) == ">" ) {
-							stack.push(current);
-							current = x;
-						}
-						str = eclose.matchedRight();
-					case 1: // PCData
-						var text = r.matched(0);
-						var p = 0;
-						while(true) {
-							p = text.indexOf("\n",p);
-							if( p < 0 ) break;
-							line++;
-							p++;
-						}
-						var x = createPCData(text);
-						current.addChild(x);
-						str = r.matchedRight();
-					case 2: // End Node
-						if( current._children != null && current._children.length == 0 ) {
-							var e = createPCData("");
-							current.addChild(e);
-						}
-						if( r.matched(1) != current._nodeName || stack.isEmpty() ) {
-							i = nrules;
-							break;
-						}
-						current = stack.pop();
-						str = r.matchedRight();
-					case 3: // CData
-						str = r.matchedRight();
-						if( !ecdata_end.match(str) )
-							throw "End of CDATA section not found";
-						var x = createCData(ecdata_end.matchedLeft());
-						current.addChild(x);
-						str = ecdata_end.matchedRight();
-					case 4: // DocType
-						var pos = 0;
-						var count = 0;
-						var old = str;
-						while( true ) {
-							if( !edoctype_elt.match(str) )
-								throw "End of DOCTYPE section not found";
-							var p = edoctype_elt.matchedPos();
-							pos += p.pos + p.len;
-							str = edoctype_elt.matchedRight();
-							switch( edoctype_elt.matched(0) ) {
-							case "[": count++;
-							case "]": count--; if( count < 0 ) throw "Invalid ] found in DOCTYPE declaration";
-							default:
-								if( count == 0 )
-									break;
-							}
-						}
-						var x = createDocType(old.substr(0,pos));
-						current.addChild(x);
-					case 5: // Comment
-						if( !ecomment_end.match(str) )
-							throw "Unclosed Comment";
-						var p = ecomment_end.matchedPos();
-						var x = createComment(str.substr(0,p.pos+p.len));
-						current.addChild(x);
-						str = ecomment_end.matchedRight();
-					case 6: // Prolog
-						var x = createProlog(r.matched(0));
-						current.addChild(x);
-						str = r.matchedRight();
-					}
-					break;
-				}
-				i += 1;
-			}
-			if( i == nrules ) {
-				if( str.length > 10 )
-					throw ("Xml parse error : Unexpected "+str.substr(0,10)+"... line "+line);
-				else
-					throw ("Xml parse error : Unexpected "+str);
-			}
-		}
-		if( !stack.isEmpty() )
-			throw "Xml parse error : Unclosed "+stack.last().nodeName;
-		return current;
-	}
-
-	private function new(){
-	}
-
-	public static function createElement( name : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.Element;
-		r._children = new Array();
-		r._attributes = new Hash();
-		r.setNodeName( name );
-		return r;
-	}
-
-	public static function createPCData( data : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.PCData;
-		r.setNodeValue( data );
-		return r;
-	}
-
-	public static function createCData( data : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.CData;
-		r.setNodeValue( data );
-		return r;
-	}
-
-	public static function createComment( data : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.Comment;
-		r.setNodeValue( data );
-		return r;
-	}
-
-	public static function createDocType( data : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.DocType;
-		r.setNodeValue( data );
-		return r;
-	}
-
-	public static function createProlog( data : String ) : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.Prolog;
-		r.setNodeValue( data );
-		return r;
-	}
-
-	public static function createDocument() : FlashXml__ {
-		var r = new FlashXml__();
-		r.nodeType = Xml.Document;
-		r._children = new Array();
-		return r;
-	}
-
-	private function getNodeName() : String {
-		if( nodeType != Xml.Element )
-			throw "bad nodeType";
-		return _nodeName;
-	}
-
-	private function setNodeName( n : String ) : String {
-		if( nodeType != Xml.Element )
-			throw "bad nodeType";
-		return _nodeName = n;
-	}
-
-	private function getNodeValue() : String {
-		if( nodeType == Xml.Element || nodeType == Xml.Document )
-			throw "bad nodeType";
-		return _nodeValue;
-	}
-
-	private function setNodeValue( v : String ) : String {
-		if( nodeType == Xml.Element || nodeType == Xml.Document )
-			throw "bad nodeType";
-		return _nodeValue = v;
-	}
-
-	private function getParent() {
-		return _parent;
-	}
-
-	public function get( att : String ) : String {
-		if( nodeType != Xml.Element )
-			throw "bad nodeType";
-		return _attributes.get( att );
-	}
-
-	public function set( att : String, value : String ) : Void {
-		if( nodeType != Xml.Element )
-			throw "bad nodeType";
-		_attributes.set( att, 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(){
-		if( _children == null ) throw "bad nodetype";
-		var cur = 0;
-		var x = _children;
-		return {
-			hasNext : function(){
-				return cur < x.length;
-			},
-			next : function(){
-				return x[cur++];
-			}
-		}
-	}
-
-	public function elements(){
-		if( _children == null ) throw "bad nodetype";
-		var cur = 0;
-		var x = _children;
-		return {
-			hasNext : function() {
-				var k = cur;
-				var l = x.length;
-				while( k < l ) {
-					if( x[k].nodeType == Xml.Element )
-						break;
-					k += 1;
-				}
-				cur = k;
-				return k < l;
-			},
-			next : function() {
-				var k = cur;
-				var l = x.length;
-				while( k < l ) {
-					var n = x[k];
-					k += 1;
-					if( n.nodeType == Xml.Element ) {
-						cur = k;
-						return n;
-					}
-				}
-				return null;
-			}
-		}
-	}
-
-	public function elementsNamed( name : String ) {
-		if( _children == null ) throw "bad nodetype";
-		var cur = 0;
-		var x = _children;
-		return {
-			hasNext : function() {
-				var k = cur;
-				var l = x.length;
-				while( k < l ) {
-					var n = x[k];
-					if( n.nodeType == Xml.Element && n._nodeName == name )
-						break;
-					k++;
-				}
-				cur = k;
-				return k < l;
-			},
-			next : function() {
-				var k = cur;
-				var l = x.length;
-				while( k < l ) {
-					var n = x[k];
-					k++;
-					if( n.nodeType == Xml.Element && n._nodeName == name ) {
-						cur = k;
-						return n;
-					}
-				}
-				return null;
-			}
-		}
-	}
-
-	public function firstChild() : FlashXml__ {
-		if( _children == null ) throw "bad nodetype";
-		return _children[0];
-	}
-
-	public function firstElement() : FlashXml__ {
-		if( _children == null ) throw "bad nodetype";
-		var cur = 0;
-		var l = _children.length;
-		while( cur < l ) {
-			var n = _children[cur];
-			if( n.nodeType == Xml.Element )
-				return n;
-			cur++;
-		}
-		return null;
-	}
-
-	public function addChild( x : FlashXml__ ) : 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 : FlashXml__ ) : Bool {
-		if( _children == null ) throw "bad nodetype";
-		var b = _children.remove( x );
-		if( b )
-			x._parent = null;
-		return b;
-	}
-
-	public function insertChild( x : FlashXml__, 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() {
-		if( nodeType == Xml.PCData )
-			return _nodeValue;
-		if( nodeType == Xml.CData )
-			return "<![CDATA["+_nodeValue+"]]>";
-		if( nodeType == Xml.Comment || nodeType == Xml.DocType || nodeType == Xml.Prolog )
-			return _nodeValue;
-
-		var s = new StringBuf();
-
-		if( nodeType == Xml.Element ) {
-			s.add("<");
-			s.add(_nodeName);
-			for( k in _attributes.keys() ){
-				s.add(" ");
-				s.add(k);
-				s.add("=\"");
-				s.add(_attributes.get(k));
-				s.add("\"");
-			}
-			if( _children.length == 0 ) {
-				s.add("/>");
-				return s.toString();
-			}
-			s.add(">");
-		}
-
-		for( x in iterator() )
-			s.add(x.toString());
-
-		if( nodeType == Xml.Element ) {
-			s.add("</");
-			s.add(_nodeName);
-			s.add(">");
-		}
-		return s.toString();
-	}
-
-}
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package flash;
+
+import Xml;
+import flash.xml.XML;
+import flash.xml.XMLList;
+
+class FlashXml__ {
+
+	public static var Element : String;
+	public static var PCData : String;
+	public static var CData : String;
+	public static var Comment : String;
+	public static var DocType : String;
+	public static var Prolog : String;
+	public static var Document : String;
+
+	public var nodeType(default,null) : XmlType;
+	public var nodeName(getNodeName,setNodeName) : String;
+	public var nodeValue(getNodeValue,setNodeValue) : String;
+	public var parent(getParent,null) : FlashXml__;
+
+	public static var _map : flash.utils.Dictionary;
+	var _node : flash.xml.XML;
+
+	public static function parse( str : String ) : FlashXml__ {
+		XML.ignoreWhitespace = false;
+		XML.ignoreProcessingInstructions = false;
+		XML.ignoreComments = false;
+		var root = new flash.xml.XML("<__document>" + str + "</__document>");
+		return wrap( root, Xml.Document );
+	}
+
+	private function new() {}
+
+	public static function createElement( name : String ) : FlashXml__ {
+		return wrap( new flash.xml.XML("<"+name+"/>"), Xml.Element );
+	}
+
+	public static function createPCData( data : String ) : FlashXml__ {
+		XML.ignoreWhitespace = false;
+		return wrap( new flash.xml.XML(data), Xml.PCData );
+	}
+
+	public static function createCData( data : String ) : FlashXml__ {
+		return wrap( new flash.xml.XML("<![CDATA[ "+data+" ]]>"), Xml.CData );
+	}
+
+	public static function createComment( data : String ) : FlashXml__ {
+		XML.ignoreComments = false;
+		return wrap( new flash.xml.XML("<!-- "+data+" -->"), Xml.Comment );
+	}
+
+	public static function createDocType( data : String ) : FlashXml__ {
+		return wrap( new flash.xml.XML("<!DOCTYPE "+data+">"), Xml.DocType );
+	}
+
+	public static function createProlog( data : String ) : FlashXml__ {
+		XML.ignoreProcessingInstructions = false;
+		return wrap( new flash.xml.XML("<?"+data+"?>"), Xml.Prolog );
+	}
+
+	public static function createDocument() : FlashXml__ {
+		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.Prolog;
+		case "comment":
+			return Xml.Comment;
+		default :
+			throw "unimplemented node type: " + node.nodeType;
+		}
+		return null;
+	}
+
+	private function getNodeName() : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		var ns = _node.namespace();
+		return (ns.prefix == "") ? _node.localName() : ns.prefix+":"+_node.localName();
+	}
+
+	private function setNodeName( 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 getNodeValue() : String {
+		if( _node.hasComplexContent() )
+			throw "bad nodeType";
+		return _node.toString();
+	}
+
+	private function setNodeValue( v : String ) : String {
+		if( _node.hasComplexContent() || _node.children() == null )
+			throw "bad nodeType";
+		var children = _node.children();
+		untyped __delete__(children, Reflect.fields(children)[0]);
+		_node.appendChild(new XML(v));
+		return v;
+	}
+
+	private function getParent() :FlashXml__ {
+		return wrap( _node.parent() );
+	}
+
+	private static function wrap( node : XML, ?type : XmlType ) : FlashXml__ {
+		var map : Dynamic = _map;
+		if( map == null ) {
+			map = new flash.utils.Dictionary(true);
+			_map = map;
+		}
+		var x = untyped map[node];
+		if( x == null ) {
+			x = new FlashXml__();
+			x._node = node;
+			x.nodeType = (type != null) ? type : getNodeType( node );
+			untyped map[node] = x;
+		}
+		return x;
+	}
+
+	private function wraps( xList : XMLList ) : Array<FlashXml__> {
+		var out = new Array<FlashXml__>();
+		for( i in 0...xList.length() )
+			out.push( wrap(xList[i]) );
+		return out;
+	}
+
+	function getAttribNS( ns : Array<String> ) {
+		return _node.attribute(new flash.utils.QName(_node.namespace(ns[0]).uri,ns[1]));
+	}
+
+	public function get( att : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		var ns = att.split(":");
+		if( ns.length == 1 ) {
+			if( !Reflect.hasField(_node,"@"+att) )
+				return null;
+			return Reflect.field(_node, "@"+att);
+		}
+		var a = getAttribNS(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.length == 1 )
+			Reflect.setField(_node, "@"+att, value);
+		else {
+			var a = getAttribNS(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(ns),0);
+	}
+
+	public function exists( att : String ) : Bool {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		var ns = att.split(":");
+		if( ns.length == 1 )
+			return Reflect.hasField(_node, "@"+att);
+		return getAttribNS(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;
+		return {
+			hasNext : function(){
+				return cur < names.length;
+			},
+			next : function(){
+				return attributes[Std.parseInt(names[cur++])].name();
+			}
+		}
+	}
+
+	public function iterator() {
+		var children:XMLList = _node.children();
+		if( children == null )
+			throw "bad nodetype";
+		var wrappers :Array<FlashXml__> = wraps(children);
+		var cur = 0;
+		return {
+			hasNext : function(){
+				return cur < wrappers.length;
+			},
+			next : function(){
+				return wrappers[cur++];
+			}
+		};
+	}
+
+	public function elements() {
+		var elements:XMLList = _node.elements();
+		if( elements == null )
+			throw "bad nodetype";
+		var wrappers :Array<FlashXml__> = wraps(elements);
+		var cur = 0;
+		return {
+			hasNext : function(){
+				return cur < wrappers.length;
+			},
+			next : function(){
+				return wrappers[cur++];
+			}
+		};
+	}
+
+	public function elementsNamed( name : String ) {
+		var ns = name.split(":");
+		var elements:XMLList;
+		if( ns.length == 1 )
+			elements = _node.elements(name);
+		else
+			elements = _node.elements();
+		if( elements == null )
+			throw "bad nodetype";
+		var wrappers :Array<FlashXml__> = 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() : FlashXml__ {
+		var children:XMLList = _node.children();
+		if( children == null )
+			throw "bad nodetype";
+		if( children.length() == 0 )
+			return null;
+		return wrap( children[0] );
+	}
+
+	public function firstElement() : FlashXml__ {
+		var elements:XMLList = _node.elements();
+		if( elements == null )
+			throw "bad nodetype";
+		if( elements.length() == 0 )
+			return null;
+		return wrap( elements[0] );
+	}
+
+	public function addChild( x : FlashXml__ ) : Void {
+		var children:XMLList = _node.children();
+		if( children == null )
+			throw "bad nodetype";
+		_node.appendChild(x._node);
+	}
+
+	public function removeChild( x : FlashXml__ ) : Bool {
+		var children:XMLList = _node.children();
+		if( children == null )
+			throw "bad nodetype";
+		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 : FlashXml__, pos : Int ) : Void {
+		var children:XMLList = _node.children();
+		if( children == null )
+			throw "bad nodetype";
+		if( pos < children.length() )
+			_node.insertChildBefore(children[pos], x._node);
+		else
+			_node.appendChild(x._node);
+	}
+
+	public function toString() {
+		XML.prettyPrinting = false;
+		if( nodeType == Xml.Document ) {
+			var str = "";
+			var c = _node.children();
+			for( i in 0...c.length() )
+				str += c[i].toXMLString();
+			return str;
+		}
+		return _node.toXMLString();
+	}
+
+}

+ 1 - 2
std/flash9/utils/QName.hx

@@ -3,6 +3,5 @@ package flash.utils;
 extern class QName {
 extern class QName {
 	var localName(default,null) : String;
 	var localName(default,null) : String;
 	var uri(default,null) : String;
 	var uri(default,null) : String;
-	// p1 can be Namespace or QName (without localName)
-	public function new( p1 : Dynamic, ?localName : QName ) : Void;
+	public function new( p1 : Dynamic, ?localName : Dynamic ) : Void;
 }
 }

+ 1 - 1
std/flash9/xml/XML.hx

@@ -22,7 +22,7 @@ extern class XML implements Dynamic<XMLList> {
 	function length() : Int;
 	function length() : Int;
 	function localName() : Dynamic;
 	function localName() : Dynamic;
 	function name() : Dynamic;
 	function name() : Dynamic;
-	function namespace(?prefix : Dynamic) : Void;
+	function namespace(?prefix : String) : flash.utils.Namespace;
 	function namespaceDeclarations() : Array<Dynamic>;
 	function namespaceDeclarations() : Array<Dynamic>;
 	function nodeKind() : String;
 	function nodeKind() : String;
 	function normalize() : XML;
 	function normalize() : XML;

+ 11 - 7
std/js/JsXml__.hx

@@ -29,7 +29,7 @@ class JsXml__ {
 
 
 	static var enode = ~/^<([a-zA-Z0-9:_-]+)/;
 	static var enode = ~/^<([a-zA-Z0-9:_-]+)/;
 	static var ecdata = ~/^<!\[CDATA\[/i;
 	static var ecdata = ~/^<!\[CDATA\[/i;
-	static var edoctype = ~/^<!DOCTYPE/i;
+	static var edoctype = ~/^<!DOCTYPE /i;
 	static var eend = ~/^<\/([a-zA-Z0-9:_-]+)>/;
 	static var eend = ~/^<\/([a-zA-Z0-9:_-]+)>/;
 	static var epcdata = ~/^[^<]+/;
 	static var epcdata = ~/^[^<]+/;
 	static var ecomment = ~/^<!--/;
 	static var ecomment = ~/^<!--/;
@@ -121,17 +121,18 @@ class JsXml__ {
 									break;
 									break;
 							}
 							}
 						}
 						}
-						var x = Xml.createDocType(old.substr(0,pos));
+						var x = Xml.createDocType(old.substr(10,pos-11));
 						current.addChild(x);
 						current.addChild(x);
 					case 5: // Comment
 					case 5: // Comment
 						if( !ecomment_end.match(str) )
 						if( !ecomment_end.match(str) )
 							throw "Unclosed Comment";
 							throw "Unclosed Comment";
 						var p = ecomment_end.matchedPos();
 						var p = ecomment_end.matchedPos();
-						var x = Xml.createComment(str.substr(0,p.pos+p.len));
+						var x = Xml.createComment(str.substr(4,p.pos+p.len-7));
 						current.addChild(x);
 						current.addChild(x);
 						str = ecomment_end.matchedRight();
 						str = ecomment_end.matchedRight();
 					case 6: // Prolog
 					case 6: // Prolog
-						var x = Xml.createProlog(r.matched(0));
+						var prolog = r.matched(0);
+						var x = Xml.createProlog(prolog.substr(2,prolog.length - 4));
 						current.addChild(x);
 						current.addChild(x);
 						str = r.matchedRight();
 						str = r.matchedRight();
 					}
 					}
@@ -387,9 +388,12 @@ class JsXml__ {
 			return _nodeValue;
 			return _nodeValue;
 		if( nodeType == Xml.CData )
 		if( nodeType == Xml.CData )
 			return "<![CDATA["+_nodeValue+"]]>";
 			return "<![CDATA["+_nodeValue+"]]>";
-		if( nodeType == Xml.Comment || nodeType == Xml.DocType || nodeType == Xml.Prolog )
-			return _nodeValue;
-
+		if( nodeType == Xml.Comment )
+			return "<!--"+_nodeValue+"-->";
+		if( nodeType == Xml.DocType )
+			return "<!DOCTYPE "+_nodeValue+">";
+		if( nodeType == Xml.Prolog )
+			return "<?"+_nodeValue+"?>";
 		var s = new StringBuf();
 		var s = new StringBuf();
 
 
 		if( nodeType == Xml.Element ) {
 		if( nodeType == Xml.Element ) {

+ 15 - 4
std/neko/NekoXml__.hx

@@ -88,10 +88,11 @@ class NekoXml__ {
 				x._parent = untyped this.cur;
 				x._parent = untyped this.cur;
 				if( untyped __dollar__sget(text,0) == 63 ) {
 				if( untyped __dollar__sget(text,0) == 63 ) {
 					x.nodeType = Xml.Prolog;
 					x.nodeType = Xml.Prolog;
-					text = "<"+new String(text)+">";
+					text = new String(text);
+					text = text.substr(1,text.length - 2);
 				} else {
 				} else {
 					x.nodeType = Xml.Comment;
 					x.nodeType = Xml.Comment;
-					text = "<!--"+new String(text)+"-->";
+					text = new String(text);
 				}
 				}
 				x._nodeValue = text;
 				x._nodeValue = text;
 				untyped this.cur.addChild(x);
 				untyped this.cur.addChild(x);
@@ -100,7 +101,7 @@ class NekoXml__ {
 				var x : Dynamic = new NekoXml__();
 				var x : Dynamic = new NekoXml__();
 				x._parent = untyped this.cur;
 				x._parent = untyped this.cur;
 				x.nodeType = Xml.DocType;
 				x.nodeType = Xml.DocType;
-				x._nodeValue = "<!DOCTYPE"+new String(text)+">";
+				x._nodeValue = new String(text).substr(1);
 				untyped this.cur.addChild(x);
 				untyped this.cur.addChild(x);
 			},
 			},
 			done : function() {
 			done : function() {
@@ -386,8 +387,18 @@ class NekoXml__ {
 			s.add("<![CDATA[");
 			s.add("<![CDATA[");
 			s.add(_nodeValue);
 			s.add(_nodeValue);
 			s.add("]]>");
 			s.add("]]>");
-		case Xml.Comment, Xml.DocType, Xml.Prolog:
+		case Xml.Comment:
+			s.add("<!--");
 			s.add(_nodeValue);
 			s.add(_nodeValue);
+			s.add("-->");
+		case Xml.DocType:
+			s.add("<!DOCTYPE ");
+			s.add(_nodeValue);
+			s.add(">");
+		case Xml.Prolog:
+			s.add("<?");
+			s.add(_nodeValue);
+			s.add("?>");
 		}
 		}
 	}
 	}
 
 

+ 2 - 2
tests/unit/Test.hx

@@ -155,10 +155,10 @@ class Test #if swf_mark implements mt.Protect #end #if as3 implements haxe.Publi
 	static function main() {
 	static function main() {
 		#if neko
 		#if neko
 		if( neko.Web.isModNeko )
 		if( neko.Web.isModNeko )
-			neko.Lib.print("<pre>");
+			neko.Web.setHeader("Content-Type","text/plain");
 		#elseif php
 		#elseif php
 		if( php.Web.isModNeko )
 		if( php.Web.isModNeko )
-			php.Lib.print("<pre>");
+			php.Web.setHeader("Content-Type","text/plain");
 		#end
 		#end
 		resetTimer();
 		resetTimer();
 		trace("START");
 		trace("START");

+ 6 - 1
tests/unit/TestSerialize.hx

@@ -8,9 +8,14 @@ class TestSerialize extends Test {
 
 
 	function test() {
 	function test() {
 		// basic types
 		// basic types
-		for( v in [null,true,false,0,1,1506,-0xABCDEF,12.3,-1e10,Math.POSITIVE_INFINITY,Math.NEGATIVE_INFINITY,"hello","éé","\r\n","\n","   ",""] )
+		for( v in [null,true,false,0,1,1506,-0xABCDEF,12.3,-1e10,"hello","éé","\r\n","\n","   ",""] )
 			eq( id(v), v );
 			eq( id(v), v );
+
 		t( Math.isNaN(id(Math.NaN)) );
 		t( Math.isNaN(id(Math.NaN)) );
+		t( id(Math.POSITIVE_INFINITY) > 0 );
+		f( id(Math.NEGATIVE_INFINITY) > 0 );
+		f( Math.isFinite(id(Math.POSITIVE_INFINITY)) );
+		f( Math.isFinite(id(Math.NEGATIVE_INFINITY)) );
 
 
 		// array/list
 		// array/list
 		doTestCollection([]);
 		doTestCollection([]);

+ 160 - 1
tests/unit/TestXML.hx

@@ -2,14 +2,173 @@ package unit;
 
 
 class TestXML extends Test {
 class TestXML extends Test {
 
 
-	function textXML() {
+	function checkExc( x : Xml, ?pos ) {
+		exc( function() x.nodeName, pos );
+		exc( function() x.nodeValue, pos );
+		exc( function() x.attributes(), pos );
+		exc( function() x.get("att"), pos );
+		exc( function() x.exists("att"), pos );
+	}
+
+	function testBasic() {
 		var x = Xml.parse('<a href="hello">World<b/></a>');
 		var x = Xml.parse('<a href="hello">World<b/></a>');
+
+		eq( x.nodeType, Xml.Document );
+		checkExc(x);
+
+		x = x.firstChild();
+		eq( x.nodeType, Xml.Element );
+
+		// nodeName
 		eq( x.nodeName, "a" );
 		eq( x.nodeName, "a" );
+		x.nodeName = "b";
+		eq( x.nodeName, "b" );
+		eq( x.toString(), '<b href="hello">World<b/></b>');
+
+		// attributes
 		eq( x.get("href"), "hello" );
 		eq( x.get("href"), "hello" );
 		eq( x.get("other"), null );
 		eq( x.get("other"), null );
+		eq( x.exists("href"), true );
+		eq( x.exists("other"), false );
+		eq( Lambda.array({ iterator : x.attributes }).join("#"), "href" );
+		x.remove("href");
+		eq( Lambda.array({ iterator : x.attributes }).join("#"), "" );
+		eq( x.toString(), '<b>World<b/></b>');
+
+		// children
 		eq( x.firstChild().nodeValue, "World" );
 		eq( x.firstChild().nodeValue, "World" );
+		eq( x.firstElement().nodeName, "b" );
 
 
+		// errors
 		exc( function() Xml.parse("<node>") );
 		exc( function() Xml.parse("<node>") );
 	}
 	}
 
 
+	function testFormat() {
+		#if flash8
+		// flash8 does not parse CDATA sections as PCDATA...
+		eq( Xml.parse("<a><b><c/> <d/> \n <e/><![CDATA[<x>]]></b></a>").toString(), "<a><b><c/> <d/> \n <e/>&lt;x&gt;</b></a>" );
+		#else
+		eq( Xml.parse("<a><b><c/> <d/> \n <e/><![CDATA[<x>]]></b></a>").toString(), "<a><b><c/> <d/> \n <e/><![CDATA[<x>]]></b></a>" );
+		#end
+		#if flash8
+		eq( Xml.parse('"').toString(), '&quot;' ); // flash8 has bad habits of escaping entities
+		#else
+		eq( Xml.parse('"').toString(), '"' );
+		#end
+		#if flash8
+		eq( Xml.parse('&quot; &lt; &gt;').toString(), '&amp;quot; &amp;lt; &amp;gt;' ); // flash8 has bad habits of escaping entities
+		#elseif flash9
+		eq( Xml.parse('&quot; &lt; &gt;').toString(), '" &lt; &gt;' ); // some entities are resolved but not escaped on printing
+		#else
+		eq( Xml.parse('&quot; &lt; &gt;').toString(), '&quot; &lt; &gt;' );
+		#end
+	}
+
+	function testComplex() {
+		// this is showing some quirks with flash XML parser
+
+		var header = '<?some header?>';
+		var doctype = '<!DOCTYPE Doctype infos>';
+		var comment = '<!--Comment-->';
+		var xml = '<html><body><![CDATA[<a href="CDATA"/>&lt;]]></body></html>';
+
+		#if flash8
+		// flash8 can't parse header
+		header = '';
+		#end
+
+		var x = Xml.parse(header + doctype + comment + xml);
+
+		#if flash8
+		// cdata is parsed as pcdata in flash8
+		xml = '<html><body>&lt;a href=&quot;CDATA&quot;/&gt;&lt;</body></html>';
+		#end
+
+		#if flash
+		// doctype is well parsed but is not present in the parsed Xml (both f8 and f9)
+		doctype = '';
+		#end
+
+		#if flash8
+		// comments are well parsed but are not present in the parsed Xml
+		comment = '';
+		#end
+
+		eq( x.toString(), header + doctype + comment + xml);
+	}
+
+	function testWhitespaces() {
+		// whitespaces
+		var x = Xml.parse('<a> </a><b></b> \n <c/>');
+
+		var childs = Lambda.array(x);
+
+		eq( childs.length, 4 );
+
+		var d = childs[2];
+		eq( d.nodeType, Xml.PCData );
+		eq( d.nodeValue, " \n " );
+
+		var el = x.elements();
+		var a = el.next();
+		eq( a.firstChild().nodeValue, " ");
+		var b = el.next();
+		#if flash
+		eq( b.firstChild(), null);
+		eq( x.toString().split("\n").join("\\n"), '<a> </a><b/> \\n <c/>' );
+		#else
+		eq( b.firstChild().nodeValue, "");
+		eq( x.toString().split("\n").join("\\n"), '<a> </a><b></b> \\n <c/>' );
+		#end
+		var c = el.next();
+		eq( c.firstChild(), null);
+	}
+
+	function testCreate() {
+		eq( Xml.createDocument().toString(), "");
+		eq( Xml.createPCData("Hello").toString(), "Hello" );
+		#if flash8
+
+		// too hard for him
+
+		#elseif flash9
+		// flash9 printer love to include additional whitespaces
+		eq( Xml.createCData("<x>").toString(), "<![CDATA[ <x> ]]>" );
+		eq( Xml.createComment("Hello").toString(), "<!-- Hello -->" );
+		eq( Xml.createProlog("XHTML").toString(), "<?XHTML ?>");
+		// doctype is parsed but not printed
+		eq( Xml.createDocType("XHTML").toString(), "" );
+		#else
+		eq( Xml.createCData("<x>").toString(), "<![CDATA[<x>]]>" );
+		eq( Xml.createComment("Hello").toString(), "<!--Hello-->" );
+		eq( Xml.createDocType("XHTML").toString(), "<!DOCTYPE XHTML>" );
+		eq( Xml.createProlog("XHTML").toString(), "<?XHTML?>");
+		#end
+	}
+
+	function testNS() {
+		var x = Xml.parse('<xhtml:br xmlns:xhtml="http://www.w3.org/1999/xhtml" xhtml:alt="test"><hello/></xhtml:br>').firstChild();
+		eq( x.nodeType, Xml.Element );
+		eq( x.nodeName, "xhtml:br" );
+		t( x.exists("xhtml:alt") );
+		eq( x.get("xhtml:alt"), "test" );
+		eq( x.get("xhtml:other"), null );
+		x.set("xhtml:alt", "bye" );
+		eq( x.get("xhtml:alt"), "bye" );
+
+		var h = x.firstElement();
+		eq( h.nodeName, "hello" );
+		h.nodeName = "em";
+		eq( h.nodeName, "em" );
+
+		eq( Lambda.count({ iterator : callback(x.elementsNamed,"em") }), 1 );
+
+		h.nodeName = "xhtml:em";
+
+		eq( Lambda.count({ iterator : callback(x.elementsNamed,"xhtml:em") }), 1 );
+		eq( Lambda.count({ iterator : callback(x.elementsNamed,"em") }), 0 );
+
+		eq( h.nodeName, "xhtml:em" );
+	}
+
 }
 }

+ 0 - 1
tests/unit/unit.hxp

@@ -70,7 +70,6 @@
     <file path="MySubClass.hx" />
     <file path="MySubClass.hx" />
     <file path="RemotingApi.hx" />
     <file path="RemotingApi.hx" />
     <file path="RemotingServer.hx" />
     <file path="RemotingServer.hx" />
-    <file path="Run.hx" />
     <file path="RunCpp.hx" />
     <file path="RunCpp.hx" />
     <file path="Test.hx" />
     <file path="Test.hx" />
     <file path="TestBasetypes.hx" />
     <file path="TestBasetypes.hx" />