/* * Copyright (C)2005-2017 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 + ""); } 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(""), Xml.CData ); } public static function createComment( data : String ) : Xml { XML.ignoreComments = false; return wrap( new flash.xml.XML(""), Xml.Comment ); } public static function createDocType( data : String ) : Xml { return wrap( new flash.xml.XML(""), Xml.DocType ); } public static function createProcessingInstruction( data : String ) : Xml { XML.ignoreProcessingInstructions = false; return wrap( new flash.xml.XML(""), 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 { var out = new Array(); for( i in 0...xList.length() ) out.push( wrap(xList[i]) ); return out; } function getAttribNS( cur : XML, ns : Array ) : 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 { 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 { if( nodeType != Xml.Element && nodeType != Xml.Document ) throw "bad nodeType"; var children:XMLList = _node.children(); var wrappers :Array = wraps(children); var cur = 0; return { hasNext : function(){ return cur < wrappers.length; }, next : function(){ return wrappers[cur++]; } }; } public function elements() : Iterator { if( nodeType != Xml.Element && nodeType != Xml.Document ) throw "bad nodeType"; var elements:XMLList = _node.elements(); var wrappers :Array = wraps(elements); var cur = 0; return { hasNext : function(){ return cur < wrappers.length; }, next : function(){ return wrappers[cur++]; } }; } public function elementsNamed( name : String ) : Iterator { 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 = 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 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"; } }