Xml.hx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * Copyright (c) 2005, The haXe Project Contributors
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * - Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * - Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  19. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  20. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  23. * DAMAGE.
  24. */
  25. import flash.xml.XML;
  26. import flash.xml.XMLList;
  27. enum XmlType {
  28. }
  29. @:core_api class Xml {
  30. public static var Element(default,null) : XmlType;
  31. public static var PCData(default,null) : XmlType;
  32. public static var CData(default,null) : XmlType;
  33. public static var Comment(default,null) : XmlType;
  34. public static var DocType(default,null) : XmlType;
  35. public static var Prolog(default,null) : XmlType;
  36. public static var Document(default,null) : XmlType;
  37. public var nodeType(default,null) : XmlType;
  38. public var nodeName(getNodeName,setNodeName) : String;
  39. public var nodeValue(getNodeValue,setNodeValue) : String;
  40. public var parent(getParent,null) : Xml;
  41. static var _map : flash.utils.Dictionary;
  42. var _node : flash.xml.XML;
  43. public static function parse( str : String ) : Xml {
  44. XML.ignoreWhitespace = false;
  45. XML.ignoreProcessingInstructions = false;
  46. XML.ignoreComments = false;
  47. var root = new flash.xml.XML("<__document>" + str + "</__document>");
  48. return wrap( root, Xml.Document );
  49. }
  50. private function new() : Void {}
  51. public static function createElement( name : String ) : Xml {
  52. return wrap( new flash.xml.XML("<"+name+"/>"), Xml.Element );
  53. }
  54. public static function createPCData( data : String ) : Xml {
  55. XML.ignoreWhitespace = false;
  56. return wrap( new flash.xml.XML(data), Xml.PCData );
  57. }
  58. public static function createCData( data : String ) : Xml {
  59. return wrap( new flash.xml.XML("<![CDATA[ "+data+" ]]>"), Xml.CData );
  60. }
  61. public static function createComment( data : String ) : Xml {
  62. XML.ignoreComments = false;
  63. return wrap( new flash.xml.XML("<!-- "+data+" -->"), Xml.Comment );
  64. }
  65. public static function createDocType( data : String ) : Xml {
  66. return wrap( new flash.xml.XML("<!DOCTYPE "+data+">"), Xml.DocType );
  67. }
  68. public static function createProlog( data : String ) : Xml {
  69. XML.ignoreProcessingInstructions = false;
  70. return wrap( new flash.xml.XML("<?"+data+"?>"), Xml.Prolog );
  71. }
  72. public static function createDocument() : Xml {
  73. return wrap( new flash.xml.XML("<__document/>"), Xml.Document );
  74. }
  75. private static function getNodeType( node : flash.xml.XML ) : XmlType {
  76. switch( node.nodeKind() ) {
  77. case "element":
  78. return Xml.Element;
  79. case "text":
  80. return Xml.PCData;
  81. case "processing-instruction":
  82. return Xml.Prolog;
  83. case "comment":
  84. return Xml.Comment;
  85. default :
  86. throw "unimplemented node type: " + node.nodeType;
  87. }
  88. return null;
  89. }
  90. private function getNodeName() : String {
  91. if( nodeType != Xml.Element )
  92. throw "bad nodeType";
  93. var ns = _node.namespace();
  94. return (ns.prefix == "") ? _node.localName() : ns.prefix+":"+_node.localName();
  95. }
  96. private function setNodeName( n : String ) : String {
  97. if( nodeType != Xml.Element )
  98. throw "bad nodeType";
  99. var ns = n.split(":");
  100. if( ns.length == 1 )
  101. _node.setLocalName(n);
  102. else {
  103. _node.setLocalName(ns[1]);
  104. _node.setNamespace(_node.namespace(ns[0]));
  105. }
  106. return n;
  107. }
  108. private function getNodeValue() : String {
  109. if( _node.hasComplexContent() )
  110. throw "bad nodeType";
  111. return _node.toString();
  112. }
  113. private function setNodeValue( v : String ) : String {
  114. if( _node.hasComplexContent() || _node.children() == null )
  115. throw "bad nodeType";
  116. var children = _node.children();
  117. untyped __delete__(children, Reflect.fields(children)[0]);
  118. _node.appendChild(new XML(v));
  119. return v;
  120. }
  121. private function getParent() :Xml {
  122. return wrap( _node.parent() );
  123. }
  124. private static function wrap( node : XML, ?type : XmlType ) : Xml {
  125. var map : Dynamic = _map;
  126. if( map == null ) {
  127. map = new flash.utils.Dictionary(true);
  128. _map = map;
  129. }
  130. var x = untyped map[node];
  131. if( x == null ) {
  132. x = new Xml();
  133. x._node = node;
  134. x.nodeType = (type != null) ? type : getNodeType( node );
  135. untyped map[node] = x;
  136. }
  137. return x;
  138. }
  139. private function wraps( xList : XMLList ) : Array<Xml> {
  140. var out = new Array<Xml>();
  141. for( i in 0...xList.length() )
  142. out.push( wrap(xList[i]) );
  143. return out;
  144. }
  145. function getAttribNS( ns : Array<String> ) : XMLList {
  146. return _node.attribute(new flash.utils.QName(_node.namespace(ns[0]).uri,ns[1]));
  147. }
  148. public function get( att : String ) : String {
  149. if( nodeType != Xml.Element )
  150. throw "bad nodeType";
  151. var ns = att.split(":");
  152. if( ns.length == 1 ) {
  153. if( !Reflect.hasField(_node,"@"+att) )
  154. return null;
  155. return Reflect.field(_node, "@"+att);
  156. }
  157. var a = getAttribNS(ns);
  158. return (a.length() == 0) ? null : a.toString();
  159. }
  160. public function set( att : String, value : String ) : Void {
  161. if( nodeType != Xml.Element )
  162. throw "bad nodeType";
  163. var ns = att.split(":");
  164. if( ns.length == 1 )
  165. Reflect.setField(_node, "@"+att, value);
  166. else {
  167. var a = getAttribNS(ns);
  168. untyped a[0] = value;
  169. }
  170. }
  171. public function remove( att : String ) : Void{
  172. if( nodeType != Xml.Element )
  173. throw "bad nodeType";
  174. var ns = att.split(":");
  175. if( ns.length == 1 )
  176. Reflect.deleteField(_node, "@"+att);
  177. else
  178. untyped __delete__(getAttribNS(ns),0);
  179. }
  180. public function exists( att : String ) : Bool {
  181. if( nodeType != Xml.Element )
  182. throw "bad nodeType";
  183. var ns = att.split(":");
  184. if( ns.length == 1 )
  185. return Reflect.hasField(_node, "@"+att);
  186. return getAttribNS(ns).length() > 0;
  187. }
  188. public function attributes() : Iterator<String> {
  189. if( nodeType != Xml.Element )
  190. throw "bad nodeType";
  191. var attributes :XMLList = _node.attributes();
  192. var names = Reflect.fields(attributes);
  193. var cur = 0;
  194. return {
  195. hasNext : function(){
  196. return cur < names.length;
  197. },
  198. next : function(){
  199. return attributes[Std.parseInt(names[cur++])].name();
  200. }
  201. }
  202. }
  203. public function iterator() : Iterator<Xml> {
  204. var children:XMLList = _node.children();
  205. if( children == null )
  206. throw "bad nodetype";
  207. var wrappers :Array<Xml> = wraps(children);
  208. var cur = 0;
  209. return {
  210. hasNext : function(){
  211. return cur < wrappers.length;
  212. },
  213. next : function(){
  214. return wrappers[cur++];
  215. }
  216. };
  217. }
  218. public function elements() : Iterator<Xml> {
  219. var elements:XMLList = _node.elements();
  220. if( elements == null )
  221. throw "bad nodetype";
  222. var wrappers :Array<Xml> = wraps(elements);
  223. var cur = 0;
  224. return {
  225. hasNext : function(){
  226. return cur < wrappers.length;
  227. },
  228. next : function(){
  229. return wrappers[cur++];
  230. }
  231. };
  232. }
  233. public function elementsNamed( name : String ) : Iterator<Xml> {
  234. var ns = name.split(":");
  235. var elements:XMLList;
  236. if( ns.length == 1 )
  237. elements = _node.elements(name);
  238. else
  239. elements = _node.elements();
  240. if( elements == null )
  241. throw "bad nodetype";
  242. var wrappers :Array<Xml> = wraps(elements);
  243. if( ns.length != 1 )
  244. for( w in wrappers.copy() )
  245. if( w._node.localName() != ns[1] || w._node.namespace().prefix != ns[0] )
  246. wrappers.remove(w);
  247. var cur = 0;
  248. return {
  249. hasNext : function(){
  250. return cur < wrappers.length;
  251. },
  252. next : function(){
  253. return wrappers[cur++];
  254. }
  255. };
  256. }
  257. public function firstChild() : Xml {
  258. var children:XMLList = _node.children();
  259. if( children == null )
  260. throw "bad nodetype";
  261. if( children.length() == 0 )
  262. return null;
  263. return wrap( children[0] );
  264. }
  265. public function firstElement() : Xml {
  266. var elements:XMLList = _node.elements();
  267. if( elements == null )
  268. throw "bad nodetype";
  269. if( elements.length() == 0 )
  270. return null;
  271. return wrap( elements[0] );
  272. }
  273. public function addChild( x : Xml ) : Void {
  274. var children:XMLList = _node.children();
  275. if( children == null )
  276. throw "bad nodetype";
  277. _node.appendChild(x._node);
  278. }
  279. public function removeChild( x : Xml ) : Bool {
  280. var children:XMLList = _node.children();
  281. if( children == null )
  282. throw "bad nodetype";
  283. if( _node != x._node.parent() )
  284. return false;
  285. var i = x._node.childIndex();
  286. untyped __delete__(children, Reflect.fields(children)[i]);
  287. return true;
  288. }
  289. public function insertChild( x : Xml, pos : Int ) : Void {
  290. var children:XMLList = _node.children();
  291. if( children == null )
  292. throw "bad nodetype";
  293. if( pos < children.length() )
  294. _node.insertChildBefore(children[pos], x._node);
  295. else
  296. _node.appendChild(x._node);
  297. }
  298. public function toString() : String {
  299. XML.prettyPrinting = false;
  300. if( nodeType == Xml.Document ) {
  301. var str = "";
  302. var c = _node.children();
  303. for( i in 0...c.length() )
  304. str += c[i].toXMLString();
  305. return str;
  306. }
  307. return _node.toXMLString();
  308. }
  309. static function __init__() : Void untyped {
  310. Element = "element";
  311. PCData = "pcdata";
  312. CData = "cdata";
  313. Comment = "comment";
  314. DocType = "doctype";
  315. Prolog = "prolog";
  316. Document = "document";
  317. }
  318. }