NativeXml.hx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright (C)2005-2017 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package flash;
  23. import flash.xml.XML;
  24. import flash.xml.XMLList;
  25. extern enum XmlType {
  26. }
  27. typedef NativeXml = Xml;
  28. class Xml {
  29. public static var Element(default,null) : XmlType;
  30. public static var PCData(default,null) : XmlType;
  31. public static var CData(default,null) : XmlType;
  32. public static var Comment(default,null) : XmlType;
  33. public static var DocType(default,null) : XmlType;
  34. public static var ProcessingInstruction(default,null) : XmlType;
  35. public static var Document(default,null) : XmlType;
  36. public var nodeType(default,null) : XmlType;
  37. public var nodeName(get,set) : String;
  38. public var nodeValue(get,set) : String;
  39. public var parent(get,null) : Xml;
  40. var _node : flash.xml.XML;
  41. public static function parse( str : String ) : Xml {
  42. XML.ignoreWhitespace = false;
  43. XML.ignoreProcessingInstructions = false;
  44. XML.ignoreComments = false;
  45. var prefix = "<__document";
  46. var root = null;
  47. while( root == null ) {
  48. try {
  49. root = new flash.xml.XML(prefix+">" + str + "</__document>");
  50. } catch( e : flash.errors.TypeError ) {
  51. // if we miss a namespace, let's add it !
  52. var r = ~/"([^"]+)"/; //"
  53. if( e.errorID == 1083 && r.match(e.message) ) {
  54. var ns = r.matched(1);
  55. prefix += " xmlns:" + ns + '="@' + ns + '"';
  56. } else
  57. throw e;
  58. }
  59. }
  60. return wrap( root, Xml.Document );
  61. }
  62. @:keep #if as3 @:hack public #end static function compare( a : Xml, b : Xml ) : Bool {
  63. return a == null ? b == null : (b == null ? false : a._node == b._node);
  64. }
  65. private function new() : Void {}
  66. public static function createElement( name : String ) : Xml {
  67. return wrap( new flash.xml.XML("<"+name+"/>"), Xml.Element );
  68. }
  69. public static function createPCData( data : String ) : Xml {
  70. XML.ignoreWhitespace = false;
  71. return wrap( new flash.xml.XML(data), Xml.PCData );
  72. }
  73. public static function createCData( data : String ) : Xml {
  74. return wrap( new flash.xml.XML("<![CDATA["+data+"]]>"), Xml.CData );
  75. }
  76. public static function createComment( data : String ) : Xml {
  77. XML.ignoreComments = false;
  78. return wrap( new flash.xml.XML("<!--"+data+"-->"), Xml.Comment );
  79. }
  80. public static function createDocType( data : String ) : Xml {
  81. return wrap( new flash.xml.XML("<!DOCTYPE "+data+">"), Xml.DocType );
  82. }
  83. public static function createProcessingInstruction( data : String ) : Xml {
  84. XML.ignoreProcessingInstructions = false;
  85. return wrap( new flash.xml.XML("<?"+data+"?>"), Xml.ProcessingInstruction );
  86. }
  87. public static function createDocument() : Xml {
  88. return wrap( new flash.xml.XML("<__document/>"), Xml.Document );
  89. }
  90. private static function getNodeType( node : flash.xml.XML ) : XmlType {
  91. switch( node.nodeKind() ) {
  92. case "element":
  93. return Xml.Element;
  94. case "text":
  95. return Xml.PCData;
  96. case "processing-instruction":
  97. return Xml.ProcessingInstruction;
  98. case "comment":
  99. return Xml.Comment;
  100. default :
  101. throw "unimplemented node type: " + node.nodeType;
  102. }
  103. }
  104. private function get_nodeName() : String {
  105. if( nodeType != Xml.Element )
  106. throw "bad nodeType";
  107. var ns = _node.namespace();
  108. return (ns.prefix == "") ? _node.localName() : ns.prefix+":"+_node.localName();
  109. }
  110. private function set_nodeName( n : String ) : String {
  111. if( nodeType != Xml.Element )
  112. throw "bad nodeType";
  113. var ns = n.split(":");
  114. if( ns.length == 1 )
  115. _node.setLocalName(n);
  116. else {
  117. _node.setLocalName(ns[1]);
  118. _node.setNamespace(_node.namespace(ns[0]));
  119. }
  120. return n;
  121. }
  122. private function get_nodeValue() : String {
  123. var nodeType = nodeType;
  124. if( nodeType == Xml.Element || nodeType == Xml.Document )
  125. throw "bad nodeType";
  126. if( nodeType == Xml.Comment )
  127. return _node.toString().substr(4,-7);
  128. return _node.toString();
  129. }
  130. private function set_nodeValue( v : String ) : String {
  131. var nodeType = nodeType;
  132. var x = null;
  133. if( nodeType == Xml.Element || nodeType == Xml.Document )
  134. throw "bad nodeType";
  135. else if( nodeType == Xml.PCData )
  136. x = createPCData(v);
  137. else if( nodeType == Xml.CData )
  138. x = createCData(v);
  139. else if( nodeType == Xml.Comment )
  140. x = createComment(v);
  141. else if( nodeType == Xml.DocType )
  142. x = createDocType(v);
  143. else
  144. x = createProcessingInstruction(v);
  145. var p = _node.parent();
  146. if( p != null ) {
  147. p.insertChildAfter(_node, x._node);
  148. var i = _node.childIndex();
  149. var children = p.children();
  150. untyped __delete__(children, Reflect.fields(children)[i]);
  151. }
  152. _node = x._node;
  153. return v;
  154. }
  155. private function get_parent() :Xml {
  156. var p = _node.parent();
  157. return p == null ? null : wrap( p );
  158. }
  159. private static function wrap( node : XML, ?type : XmlType ) : Xml {
  160. var x = new Xml();
  161. x._node = node;
  162. x.nodeType = (type != null) ? type : getNodeType( node );
  163. return x;
  164. }
  165. private function wraps( xList : XMLList ) : Array<Xml> {
  166. var out = new Array<Xml>();
  167. for( i in 0...xList.length() )
  168. out.push( wrap(xList[i]) );
  169. return out;
  170. }
  171. function getAttribNS( cur : XML, ns : Array<String> ) : XMLList {
  172. var n = cur.namespace(ns[0]);
  173. if( n == null ) {
  174. var parent = cur.parent();
  175. if( parent == null ) {
  176. n = new flash.utils.Namespace(ns[0], "@"+ns[0]);
  177. cur.addNamespace(n);
  178. } else
  179. return getAttribNS(parent, ns);
  180. }
  181. return _node.attribute(new flash.utils.QName(n,ns[1]));
  182. }
  183. public function get( att : String ) : String {
  184. if( nodeType != Xml.Element )
  185. throw "bad nodeType";
  186. var ns = att.split(":");
  187. if( ns[0] == "xmlns" ) {
  188. var n = _node.namespace((ns[1] == null) ? "" : ns[1]);
  189. return (n == null) ? null : n.uri;
  190. }
  191. if( ns.length == 1 ) {
  192. if( !Reflect.hasField(_node,"@"+att) )
  193. return null;
  194. return Reflect.field(_node, "@"+att);
  195. }
  196. var a = getAttribNS(_node,ns);
  197. return (a.length() == 0) ? null : a.toString();
  198. }
  199. public function set( att : String, value : String ) : Void {
  200. if( nodeType != Xml.Element )
  201. throw "bad nodeType";
  202. var ns = att.split(":");
  203. if( ns[0] == "xmlns" ) {
  204. var n = _node.namespace((ns[1] == null) ? "" : ns[1]);
  205. if( n != null )
  206. throw "Can't modify namespace";
  207. if( ns[1] == null )
  208. throw "Can't set default namespace";
  209. _node.addNamespace(new flash.utils.Namespace(ns[1], value));
  210. return;
  211. }
  212. if( ns.length == 1 )
  213. Reflect.setField(_node, "@"+att, value);
  214. else {
  215. var a = getAttribNS(_node,ns);
  216. untyped a[0] = value;
  217. }
  218. }
  219. public function remove( att : String ) : Void{
  220. if( nodeType != Xml.Element )
  221. throw "bad nodeType";
  222. var ns = att.split(":");
  223. if( ns.length == 1 )
  224. Reflect.deleteField(_node, "@"+att);
  225. else
  226. untyped __delete__(getAttribNS(_node,ns),0);
  227. }
  228. public function exists( att : String ) : Bool {
  229. if( nodeType != Xml.Element )
  230. throw "bad nodeType";
  231. var ns = att.split(":");
  232. if( ns[0] == "xmlns" )
  233. return _node.namespace((ns[1] == null) ? "" : ns[1]) != null;
  234. if( ns.length == 1 )
  235. return Reflect.hasField(_node, "@"+att);
  236. return getAttribNS(_node,ns).length() > 0;
  237. }
  238. public function attributes() : Iterator<String> {
  239. if( nodeType != Xml.Element )
  240. throw "bad nodeType";
  241. var attributes :XMLList = _node.attributes();
  242. var names = Reflect.fields(attributes);
  243. var cur = 0;
  244. var nss = _node.namespaceDeclarations();
  245. return {
  246. hasNext : function(){
  247. return cur < names.length + nss.length;
  248. },
  249. next : function() {
  250. if(cur<names.length){
  251. return attributes[Std.parseInt(names[cur++])].name();
  252. }else {
  253. var ns:flash.utils.Namespace = nss[cur++ - names.length];
  254. return "xmlns:"+ns.prefix;
  255. }
  256. }
  257. }
  258. }
  259. public function iterator() : Iterator<Xml> {
  260. if( nodeType != Xml.Element && nodeType != Xml.Document )
  261. throw "bad nodeType";
  262. var children:XMLList = _node.children();
  263. var wrappers :Array<Xml> = wraps(children);
  264. var cur = 0;
  265. return {
  266. hasNext : function(){
  267. return cur < wrappers.length;
  268. },
  269. next : function(){
  270. return wrappers[cur++];
  271. }
  272. };
  273. }
  274. public function elements() : Iterator<Xml> {
  275. if( nodeType != Xml.Element && nodeType != Xml.Document )
  276. throw "bad nodeType";
  277. var elements:XMLList = _node.elements();
  278. var wrappers :Array<Xml> = wraps(elements);
  279. var cur = 0;
  280. return {
  281. hasNext : function(){
  282. return cur < wrappers.length;
  283. },
  284. next : function(){
  285. return wrappers[cur++];
  286. }
  287. };
  288. }
  289. public function elementsNamed( name : String ) : Iterator<Xml> {
  290. if( nodeType != Xml.Element && nodeType != Xml.Document )
  291. throw "bad nodeType";
  292. var ns = name.split(":");
  293. var elements:XMLList;
  294. if( ns.length == 1 )
  295. elements = _node.elements(name);
  296. else
  297. elements = _node.elements();
  298. var wrappers :Array<Xml> = wraps(elements);
  299. if( ns.length != 1 )
  300. for( w in wrappers.copy() )
  301. if( w._node.localName() != ns[1] || w._node.namespace().prefix != ns[0] )
  302. wrappers.remove(w);
  303. var cur = 0;
  304. return {
  305. hasNext : function(){
  306. return cur < wrappers.length;
  307. },
  308. next : function(){
  309. return wrappers[cur++];
  310. }
  311. };
  312. }
  313. public function firstChild() : Xml {
  314. if( nodeType != Xml.Element && nodeType != Xml.Document )
  315. throw "bad nodeType";
  316. var children:XMLList = _node.children();
  317. if( children.length() == 0 )
  318. return null;
  319. return wrap( children[0] );
  320. }
  321. public function firstElement() : Xml {
  322. if( nodeType != Xml.Element && nodeType != Xml.Document )
  323. throw "bad nodeType";
  324. var elements:XMLList = _node.elements();
  325. if( elements.length() == 0 )
  326. return null;
  327. return wrap( elements[0] );
  328. }
  329. public function addChild( x : Xml ) : Void {
  330. if( nodeType != Xml.Element && nodeType != Xml.Document )
  331. throw "bad nodeType";
  332. if (x.parent != null)
  333. x.parent.removeChild(x);
  334. var children:XMLList = _node.children();
  335. _node.appendChild(x._node);
  336. }
  337. public function removeChild( x : Xml ) : Bool {
  338. if( nodeType != Xml.Element && nodeType != Xml.Document )
  339. throw "bad nodeType";
  340. var children:XMLList = _node.children();
  341. if( _node != x._node.parent() )
  342. return false;
  343. var i = x._node.childIndex();
  344. untyped __delete__(children, Reflect.fields(children)[i]);
  345. return true;
  346. }
  347. public function insertChild( x : Xml, pos : Int ) : Void {
  348. if( nodeType != Xml.Element && nodeType != Xml.Document )
  349. throw "bad nodeType";
  350. if (x.parent != null)
  351. x.parent.removeChild(x);
  352. var children:XMLList = _node.children();
  353. if( pos < children.length() )
  354. _node.insertChildBefore(children[pos], x._node);
  355. else
  356. _node.appendChild(x._node);
  357. }
  358. public function toString() : String {
  359. XML.prettyPrinting = false;
  360. if( nodeType == Xml.Document ) {
  361. var str = _node.toXMLString();
  362. // remove <__document xmlns....>STR</__document> wrapper
  363. str = str.substr(str.indexOf(">") + 1);
  364. str = str.substr(0, str.length - 13);
  365. return str;
  366. }
  367. return _node.toXMLString();
  368. }
  369. static function __init__() : Void untyped {
  370. Element = "element";
  371. PCData = "pcdata";
  372. CData = "cdata";
  373. Comment = "comment";
  374. DocType = "doctype";
  375. ProcessingInstruction = "processingInstruction";
  376. Document = "document";
  377. }
  378. }