forked from LeenkxTeam/LNXSDK
419 lines
12 KiB
Haxe
419 lines
12 KiB
Haxe
/*
|
|
* Copyright (C)2005-2019 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 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";
|
|
}
|
|
}
|