summaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/xmlimplsrc/org')
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java367
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java381
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java734
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java280
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java606
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java765
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java469
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java812
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java125
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java869
-rw-r--r--trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java445
11 files changed, 5853 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java
new file mode 100644
index 0000000..a4cf585
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/Namespace.java
@@ -0,0 +1,367 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+
+/**
+ * Class Namespace
+ *
+ */
+class Namespace extends IdScriptableObject
+{
+ static final long serialVersionUID = -5765755238131301744L;
+
+ private static final Object NAMESPACE_TAG = new Object();
+
+ private Namespace prototype;
+ private XmlNode.Namespace ns;
+
+ private Namespace() {
+ }
+
+ static Namespace create(Scriptable scope, Namespace prototype, XmlNode.Namespace namespace) {
+ Namespace rv = new Namespace();
+ rv.setParentScope(scope);
+ rv.prototype = prototype;
+ rv.setPrototype(prototype);
+ rv.ns = namespace;
+ return rv;
+ }
+
+ final XmlNode.Namespace getDelegate() {
+ return ns;
+ }
+
+ public void exportAsJSClass(boolean sealed) {
+ exportAsJSClass(MAX_PROTOTYPE_ID, this.getParentScope(), sealed);
+ }
+
+ public String uri() {
+ return ns.getUri();
+ }
+
+ public String prefix() {
+ return ns.getPrefix();
+ }
+
+ public String toString() {
+ return uri();
+ }
+
+ public String toLocaleString() {
+ return toString();
+ }
+
+ private boolean equals(Namespace n) {
+ return uri().equals(n.uri());
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Namespace)) return false;
+ return equals((Namespace)obj);
+ }
+
+ protected Object equivalentValues(Object value) {
+ if (!(value instanceof Namespace)) return Scriptable.NOT_FOUND;
+ boolean result = equals((Namespace)value);
+ return result ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public String getClassName() {
+ return "Namespace";
+ }
+
+ public Object getDefaultValue(Class hint) {
+ return uri();
+ }
+
+// #string_id_map#
+ private static final int
+ Id_prefix = 1,
+ Id_uri = 2,
+ MAX_INSTANCE_ID = 2;
+
+ protected int getMaxInstanceId()
+ {
+ return super.getMaxInstanceId() + MAX_INSTANCE_ID;
+ }
+
+ protected int findInstanceIdInfo(String s)
+ {
+ int id;
+// #generated# Last update: 2007-08-20 08:23:22 EDT
+ L0: { id = 0; String X = null;
+ int s_length = s.length();
+ if (s_length==3) { X="uri";id=Id_uri; }
+ else if (s_length==6) { X="prefix";id=Id_prefix; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+
+ if (id == 0) return super.findInstanceIdInfo(s);
+
+ int attr;
+ switch (id) {
+ case Id_prefix:
+ case Id_uri:
+ attr = PERMANENT | READONLY;
+ break;
+ default: throw new IllegalStateException();
+ }
+ return instanceIdInfo(attr, super.getMaxInstanceId() + id);
+ }
+// #/string_id_map#
+
+ protected String getInstanceIdName(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_prefix: return "prefix";
+ case Id_uri: return "uri";
+ }
+ return super.getInstanceIdName(id);
+ }
+
+ protected Object getInstanceIdValue(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_prefix:
+ if (ns.getPrefix() == null) return Undefined.instance;
+ return ns.getPrefix();
+ case Id_uri:
+ return ns.getUri();
+ }
+ return super.getInstanceIdValue(id);
+ }
+
+
+// #string_id_map#
+ private static final int
+ Id_constructor = 1,
+ Id_toString = 2,
+ Id_toSource = 3,
+ MAX_PROTOTYPE_ID = 3;
+
+ protected int findPrototypeId(String s)
+ {
+ int id;
+// #generated# Last update: 2007-08-20 08:23:22 EDT
+ L0: { id = 0; String X = null; int c;
+ int s_length = s.length();
+ if (s_length==8) {
+ c=s.charAt(3);
+ if (c=='o') { X="toSource";id=Id_toSource; }
+ else if (c=='t') { X="toString";id=Id_toString; }
+ }
+ else if (s_length==11) { X="constructor";id=Id_constructor; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+ return id;
+ }
+// #/string_id_map#
+
+ protected void initPrototypeId(int id)
+ {
+ String s;
+ int arity;
+ switch (id) {
+ case Id_constructor: arity=2; s="constructor"; break;
+ case Id_toString: arity=0; s="toString"; break;
+ case Id_toSource: arity=0; s="toSource"; break;
+ default: throw new IllegalArgumentException(String.valueOf(id));
+ }
+ initPrototypeMethod(NAMESPACE_TAG, id, s, arity);
+ }
+
+ public Object execIdCall(IdFunctionObject f,
+ Context cx,
+ Scriptable scope,
+ Scriptable thisObj,
+ Object[] args)
+ {
+ if (!f.hasTag(NAMESPACE_TAG)) {
+ return super.execIdCall(f, cx, scope, thisObj, args);
+ }
+ int id = f.methodId();
+ switch (id) {
+ case Id_constructor:
+ return jsConstructor(cx, (thisObj == null), args);
+ case Id_toString:
+ return realThis(thisObj, f).toString();
+ case Id_toSource:
+ return realThis(thisObj, f).js_toSource();
+ }
+ throw new IllegalArgumentException(String.valueOf(id));
+ }
+
+ private Namespace realThis(Scriptable thisObj, IdFunctionObject f) {
+ if(!(thisObj instanceof Namespace))
+ throw incompatibleCallError(f);
+ return (Namespace)thisObj;
+ }
+
+ Namespace newNamespace(String uri) {
+ Namespace prototype = (this.prototype == null) ? this : this.prototype;
+ return create( this.getParentScope(), prototype, XmlNode.Namespace.create(uri) );
+ }
+
+ Namespace newNamespace(String prefix, String uri) {
+ if (prefix == null) return newNamespace(uri);
+ Namespace prototype = (this.prototype == null) ? this : this.prototype;
+ return create( this.getParentScope(), prototype, XmlNode.Namespace.create(prefix, uri) );
+ }
+
+ Namespace constructNamespace(Object uriValue) {
+ String prefix;
+ String uri;
+
+ if (uriValue instanceof Namespace) {
+ Namespace ns = (Namespace)uriValue;
+ prefix = ns.prefix();
+ uri = ns.uri();
+ } else if (uriValue instanceof QName) {
+ QName qname = (QName)uriValue;
+ uri = qname.uri();
+ if (uri != null) {
+ // TODO Is there a way to push this back into QName so that we can make prefix() private?
+ prefix = qname.prefix();
+ } else {
+ uri = qname.toString();
+ prefix = null;
+ }
+ } else {
+ uri = ScriptRuntime.toString(uriValue);
+ prefix = (uri.length() == 0) ? "" : null;
+ }
+
+ return newNamespace(prefix, uri);
+ }
+
+ Namespace castToNamespace(Object namespaceObj) {
+ if (namespaceObj instanceof Namespace) {
+ return (Namespace)namespaceObj;
+ }
+ return constructNamespace(namespaceObj);
+ }
+
+ private Namespace constructNamespace(Object prefixValue, Object uriValue) {
+ String prefix;
+ String uri;
+
+ if (uriValue instanceof QName) {
+ QName qname = (QName)uriValue;
+ uri = qname.uri();
+ if (uri == null) {
+ uri = qname.toString();
+ }
+ } else {
+ uri = ScriptRuntime.toString(uriValue);
+ }
+
+ if (uri.length() == 0) {
+ if (prefixValue == Undefined.instance) {
+ prefix = "";
+ } else {
+ prefix = ScriptRuntime.toString(prefixValue);
+ if (prefix.length() != 0) {
+ throw ScriptRuntime.typeError(
+ "Illegal prefix '"+prefix+"' for 'no namespace'.");
+ }
+ }
+ } else if (prefixValue == Undefined.instance) {
+ prefix = "";
+ } else if (!XMLName.accept(prefixValue)) {
+ prefix = "";
+ } else {
+ prefix = ScriptRuntime.toString(prefixValue);
+ }
+
+ return newNamespace(prefix, uri);
+ }
+
+ private Namespace constructNamespace() {
+ return newNamespace("", "");
+ }
+
+ private Object jsConstructor(Context cx, boolean inNewExpr, Object[] args)
+ {
+ if (!inNewExpr && args.length == 1) {
+ return castToNamespace(args[0]);
+ }
+
+ if (args.length == 0) {
+ return constructNamespace();
+ } else if (args.length == 1) {
+ return constructNamespace(args[0]);
+ } else {
+ return constructNamespace(args[0], args[1]);
+ }
+ }
+
+ private String js_toSource()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append('(');
+ toSourceImpl(ns.getPrefix(), ns.getUri(), sb);
+ sb.append(')');
+ return sb.toString();
+ }
+
+ static void toSourceImpl(String prefix, String uri, StringBuffer sb)
+ {
+ sb.append("new Namespace(");
+ if (uri.length() == 0) {
+ if (!"".equals(prefix)) throw new IllegalArgumentException(prefix);
+ } else {
+ sb.append('\'');
+ if (prefix != null) {
+ sb.append(ScriptRuntime.escapeString(prefix, '\''));
+ sb.append("', '");
+ }
+ sb.append(ScriptRuntime.escapeString(uri, '\''));
+ sb.append('\'');
+ }
+ sb.append(')');
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java
new file mode 100644
index 0000000..90a18cb
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/QName.java
@@ -0,0 +1,381 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+
+/**
+ * Class QName
+ *
+ */
+final class QName extends IdScriptableObject
+{
+ static final long serialVersionUID = 416745167693026750L;
+
+ private static final Object QNAME_TAG = new Object();
+
+ private XMLLibImpl lib;
+
+ private QName prototype;
+
+ private XmlNode.QName delegate;
+
+ private QName() {
+ }
+
+ static QName create(XMLLibImpl lib, Scriptable scope, QName prototype, XmlNode.QName delegate) {
+ QName rv = new QName();
+ rv.lib = lib;
+ rv.setParentScope(scope);
+ rv.prototype = prototype;
+ rv.setPrototype(prototype);
+ rv.delegate = delegate;
+ return rv;
+ }
+
+// /** @deprecated */
+// static QName create(XMLLibImpl lib, XmlNode.QName nodeQname) {
+// return create(lib, lib.globalScope(), lib.qnamePrototype(), nodeQname);
+// }
+
+ void exportAsJSClass(boolean sealed) {
+ exportAsJSClass(MAX_PROTOTYPE_ID, getParentScope(), sealed);
+ }
+
+ public String toString() {
+ // ECMA357 13.3.4.2
+ if (delegate.getNamespace() == null) {
+ return "*::" + localName();
+ } else if (delegate.getNamespace().isGlobal()) {
+ // leave as empty
+ return localName();
+ } else {
+ return uri() + "::" + localName();
+ }
+ }
+
+ public String localName() {
+ if (delegate.getLocalName() == null) return "*";
+ return delegate.getLocalName();
+ }
+
+ /**
+ @deprecated
+
+ This property is supposed to be invisible and I think we can make it private at some point, though Namespace
+ might need it
+ */
+ String prefix() {
+ if (delegate.getNamespace() == null) return null;
+ return delegate.getNamespace().getPrefix();
+ }
+
+ String uri() {
+ if (delegate.getNamespace() == null) return null;
+ return delegate.getNamespace().getUri();
+ }
+
+ /** @deprecated */
+ final XmlNode.QName toNodeQname() {
+ return delegate;
+ }
+
+ final XmlNode.QName getDelegate() {
+ return delegate;
+ }
+
+ public boolean equals(Object obj) {
+ if(!(obj instanceof QName)) return false;
+ return equals((QName)obj);
+ }
+
+ protected Object equivalentValues(Object value)
+ {
+ if(!(value instanceof QName)) return Scriptable.NOT_FOUND;
+ boolean result = equals((QName)value);
+ return result ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ private boolean equals(QName q) {
+ return this.delegate.isEqualTo(q.delegate);
+ }
+
+ public String getClassName() {
+ return "QName";
+ }
+
+ public Object getDefaultValue(Class hint) {
+ return toString();
+ }
+
+// #string_id_map#
+ private static final int
+ Id_localName = 1,
+ Id_uri = 2,
+ MAX_INSTANCE_ID = 2;
+
+ protected int getMaxInstanceId()
+ {
+ return super.getMaxInstanceId() + MAX_INSTANCE_ID;
+ }
+
+ protected int findInstanceIdInfo(String s)
+ {
+ int id;
+// #generated# Last update: 2007-08-20 08:21:41 EDT
+ L0: { id = 0; String X = null;
+ int s_length = s.length();
+ if (s_length==3) { X="uri";id=Id_uri; }
+ else if (s_length==9) { X="localName";id=Id_localName; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+
+ if (id == 0) return super.findInstanceIdInfo(s);
+
+ int attr;
+ switch (id) {
+ case Id_localName:
+ case Id_uri:
+ attr = PERMANENT | READONLY;
+ break;
+ default: throw new IllegalStateException();
+ }
+ return instanceIdInfo(attr, super.getMaxInstanceId() + id);
+ }
+// #/string_id_map#
+
+ protected String getInstanceIdName(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_localName: return "localName";
+ case Id_uri: return "uri";
+ }
+ return super.getInstanceIdName(id);
+ }
+
+ protected Object getInstanceIdValue(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_localName: return localName();
+ case Id_uri: return uri();
+ }
+ return super.getInstanceIdValue(id);
+ }
+
+// #string_id_map#
+ private static final int
+ Id_constructor = 1,
+ Id_toString = 2,
+ Id_toSource = 3,
+ MAX_PROTOTYPE_ID = 3;
+
+ protected int findPrototypeId(String s)
+ {
+ int id;
+// #generated# Last update: 2007-08-20 08:21:41 EDT
+ L0: { id = 0; String X = null; int c;
+ int s_length = s.length();
+ if (s_length==8) {
+ c=s.charAt(3);
+ if (c=='o') { X="toSource";id=Id_toSource; }
+ else if (c=='t') { X="toString";id=Id_toString; }
+ }
+ else if (s_length==11) { X="constructor";id=Id_constructor; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+ return id;
+ }
+// #/string_id_map#
+
+ protected void initPrototypeId(int id)
+ {
+ String s;
+ int arity;
+ switch (id) {
+ case Id_constructor: arity=2; s="constructor"; break;
+ case Id_toString: arity=0; s="toString"; break;
+ case Id_toSource: arity=0; s="toSource"; break;
+ default: throw new IllegalArgumentException(String.valueOf(id));
+ }
+ initPrototypeMethod(QNAME_TAG, id, s, arity);
+ }
+
+ public Object execIdCall(IdFunctionObject f,
+ Context cx,
+ Scriptable scope,
+ Scriptable thisObj,
+ Object[] args)
+ {
+ if (!f.hasTag(QNAME_TAG)) {
+ return super.execIdCall(f, cx, scope, thisObj, args);
+ }
+ int id = f.methodId();
+ switch (id) {
+ case Id_constructor:
+ return jsConstructor(cx, (thisObj == null), args);
+ case Id_toString:
+ return realThis(thisObj, f).toString();
+ case Id_toSource:
+ return realThis(thisObj, f).js_toSource();
+ }
+ throw new IllegalArgumentException(String.valueOf(id));
+ }
+
+ private QName realThis(Scriptable thisObj, IdFunctionObject f)
+ {
+ if(!(thisObj instanceof QName))
+ throw incompatibleCallError(f);
+ return (QName)thisObj;
+ }
+
+ QName newQName(XMLLibImpl lib, String q_uri, String q_localName, String q_prefix) {
+ QName prototype = this.prototype;
+ if (prototype == null) {
+ prototype = this;
+ }
+ XmlNode.Namespace ns = null;
+ if (q_prefix != null) {
+ ns = XmlNode.Namespace.create(q_uri, q_prefix);
+ } else if (q_uri != null) {
+ ns = XmlNode.Namespace.create(q_uri);
+ } else {
+ ns = null;
+ }
+ if (q_localName != null && q_localName.equals("*")) q_localName = null;
+ return create(lib, this.getParentScope(), prototype, XmlNode.QName.create(ns, q_localName));
+ }
+
+ // See ECMA357 13.3.2
+ QName constructQName(XMLLibImpl lib, Context cx, Object namespace, Object name) {
+ String nameString = null;
+ if (name instanceof QName) {
+ if (namespace == Undefined.instance) {
+ return (QName)name;
+ } else {
+ nameString = ((QName)name).localName();
+ }
+ }
+ if (name == Undefined.instance) {
+ nameString = "";
+ } else {
+ nameString = ScriptRuntime.toString(name);
+ }
+
+ if (namespace == Undefined.instance) {
+ if ("*".equals(nameString)) {
+ namespace = null;
+ } else {
+ namespace = lib.getDefaultNamespace(cx);
+ }
+ }
+ Namespace namespaceNamespace = null;
+ if (namespace == null) {
+ // leave as null
+ } else if (namespace instanceof Namespace) {
+ namespaceNamespace = (Namespace)namespace;
+ } else {
+ namespaceNamespace = lib.newNamespace(ScriptRuntime.toString(namespace));
+ }
+ String q_localName = nameString;
+ String q_uri;
+ String q_prefix;
+ if (namespace == null) {
+ q_uri = null;
+ q_prefix = null; // corresponds to undefined; see QName class
+ } else {
+ q_uri = namespaceNamespace.uri();
+ q_prefix = namespaceNamespace.prefix();
+ }
+ return newQName(lib, q_uri, q_localName, q_prefix);
+ }
+
+ QName constructQName(XMLLibImpl lib, Context cx, Object nameValue) {
+ return constructQName(lib, cx, Undefined.instance, nameValue);
+ }
+
+ QName castToQName(XMLLibImpl lib, Context cx, Object qnameValue) {
+ if (qnameValue instanceof QName) {
+ return (QName)qnameValue;
+ }
+ return constructQName(lib, cx, qnameValue);
+ }
+
+ private Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) {
+ // See ECMA357 13.3.2
+ if (!inNewExpr && args.length == 1) {
+ return castToQName(lib, cx, args[0]);
+ }
+ if (args.length == 0) {
+ return constructQName(lib, cx, Undefined.instance);
+ } else if (args.length == 1) {
+ return constructQName(lib, cx, args[0]);
+ } else {
+ return constructQName(lib, cx, args[0], args[1]);
+ }
+ }
+
+ private String js_toSource() {
+ StringBuffer sb = new StringBuffer();
+ sb.append('(');
+ toSourceImpl(uri(), localName(), prefix(), sb);
+ sb.append(')');
+ return sb.toString();
+ }
+
+ private static void toSourceImpl(String uri, String localName, String prefix, StringBuffer sb) {
+ sb.append("new QName(");
+ if (uri == null && prefix == null) {
+ if (!"*".equals(localName)) {
+ sb.append("null, ");
+ }
+ } else {
+ Namespace.toSourceImpl(prefix, uri, sb);
+ sb.append(", ");
+ }
+ sb.append('\'');
+ sb.append(ScriptRuntime.escapeString(localName, '\''));
+ sb.append("')");
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java
new file mode 100644
index 0000000..090ae1a
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XML.java
@@ -0,0 +1,734 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.XMLObject;
+
+class XML extends XMLObjectImpl {
+ static final long serialVersionUID = -630969919086449092L;
+
+ private XmlNode node;
+
+ XML(XMLLibImpl lib, Scriptable scope, XMLObject prototype, XmlNode node) {
+ super(lib, scope, prototype);
+ initialize(node);
+ }
+
+ void initialize(XmlNode node) {
+ this.node = node;
+ this.node.setXml(this);
+ }
+
+ final XML getXML() {
+ return this;
+ }
+
+ void replaceWith(XML value) {
+ // We use the underlying document structure if the node is not
+ // "standalone," but we need to just replace the XmlNode instance
+ // otherwise
+ if (this.node.parent() != null || false) {
+ this.node.replaceWith(value.node);
+ } else {
+ this.initialize(value.node);
+ }
+ }
+
+ /** @deprecated I would love to encapsulate this somehow. */
+ XML makeXmlFromString(XMLName name, String value) {
+ try {
+ return newTextElementXML(this.node, name.toQname(), value.toString());
+ } catch(Exception e) {
+ throw ScriptRuntime.typeError(e.getMessage());
+ }
+ }
+
+ /** @deprecated Rename this, at the very least. But it's not clear it's even necessary */
+ XmlNode getAnnotation() {
+ return node;
+ }
+
+ //
+ // Methods from ScriptableObject
+ //
+
+ // TODO Either cross-reference this next comment with the specification or delete it and change the behavior
+ // The comment: XML[0] should return this, all other indexes are Undefined
+ public Object get(int index, Scriptable start) {
+ if (index == 0) {
+ return this;
+ } else {
+ return Scriptable.NOT_FOUND;
+ }
+ }
+
+ public boolean has(int index, Scriptable start) {
+ return (index == 0);
+ }
+
+ public void put(int index, Scriptable start, Object value) {
+ // TODO Clarify the following comment and add a reference to the spec
+ // The comment: Spec says assignment to indexed XML object should return type error
+ throw ScriptRuntime.typeError("Assignment to indexed XML is not allowed");
+ }
+
+ public Object[] getIds() {
+ if (isPrototype()) {
+ return new Object[0];
+ } else {
+ return new Object[] { new Integer(0) };
+ }
+ }
+
+ // TODO This is how I found it but I am not sure it makes sense
+ public void delete(int index) {
+ if (index == 0) {
+ this.remove();
+ }
+ }
+
+ //
+ // Methods from XMLObjectImpl
+ //
+
+ boolean hasXMLProperty(XMLName xmlName) {
+ if (isPrototype()) {
+ return getMethod(xmlName.localName()) != NOT_FOUND;
+ } else {
+ return (getPropertyList(xmlName).length() > 0) || (getMethod(xmlName.localName()) != NOT_FOUND);
+ }
+ }
+
+ Object getXMLProperty(XMLName xmlName) {
+ if (isPrototype()) {
+ return getMethod(xmlName.localName());
+ } else {
+ return getPropertyList(xmlName);
+ }
+ }
+
+ //
+ //
+ // Methods that merit further review
+ //
+ //
+
+ XmlNode.QName getNodeQname() {
+ return this.node.getQname();
+ }
+
+ XML[] getChildren() {
+ if (!isElement()) return null;
+ XmlNode[] children = this.node.getMatchingChildren(XmlNode.Filter.TRUE);
+ XML[] rv = new XML[children.length];
+ for (int i=0; i<rv.length; i++) {
+ rv[i] = toXML(children[i]);
+ }
+ return rv;
+ }
+
+ XML[] getAttributes() {
+ XmlNode[] attributes = this.node.getAttributes();
+ XML[] rv = new XML[attributes.length];
+ for (int i=0; i<rv.length; i++) {
+ rv[i] = toXML(attributes[i]);
+ }
+ return rv;
+ }
+
+ // Used only by XML, XMLList
+ XMLList getPropertyList(XMLName name) {
+ return name.getMyValueOn(this);
+ }
+
+ void deleteXMLProperty(XMLName name) {
+ XMLList list = getPropertyList(name);
+ for (int i=0; i<list.length(); i++) {
+ list.item(i).node.deleteMe();
+ }
+ }
+
+ void putXMLProperty(XMLName xmlName, Object value) {
+ if (isPrototype()) {
+ // TODO Is this really a no-op? Check the spec to be sure
+ } else {
+ xmlName.setMyValueOn(this, value);
+ }
+ }
+
+ boolean hasOwnProperty(XMLName xmlName) {
+ boolean hasProperty = false;
+
+ if (isPrototype()) {
+ String property = xmlName.localName();
+ hasProperty = (0 != findPrototypeId(property));
+ } else {
+ hasProperty = (getPropertyList(xmlName).length() > 0);
+ }
+
+ return hasProperty;
+ }
+
+ protected Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) {
+ if (args.length == 0 || args[0] == null || args[0] == Undefined.instance) {
+ args = new Object[] { "" };
+ }
+ // ECMA 13.4.2 does not appear to specify what to do if multiple arguments are sent.
+ XML toXml = ecmaToXml(args[0]);
+ if (inNewExpr) {
+ return toXml.copy();
+ } else {
+ return toXml;
+ }
+ }
+
+ // See ECMA 357, 11_2_2_1, Semantics, 3_f.
+ public Scriptable getExtraMethodSource(Context cx) {
+ if (hasSimpleContent()) {
+ String src = toString();
+ return ScriptRuntime.toObjectOrNull(cx, src);
+ }
+ return null;
+ }
+
+ //
+ // TODO Miscellaneous methods not yet grouped
+ //
+
+ void removeChild(int index) {
+ this.node.removeChild(index);
+ }
+
+ void normalize() {
+ this.node.normalize();
+ }
+
+ private XML toXML(XmlNode node) {
+ if (node.getXml() == null) {
+ node.setXml(newXML(node));
+ }
+ return node.getXml();
+ }
+
+ void setAttribute(XMLName xmlName, Object value) {
+ if (!isElement()) throw new IllegalStateException("Can only set attributes on elements.");
+ // TODO Is this legal, but just not "supported"? If so, support it.
+ if (xmlName.uri() == null && xmlName.localName().equals("*")) {
+ throw ScriptRuntime.typeError("@* assignment not supported.");
+ }
+ this.node.setAttribute(xmlName.toQname(), ScriptRuntime.toString(value));
+ }
+
+ void remove() {
+ this.node.deleteMe();
+ }
+
+ void addMatches(XMLList rv, XMLName name) {
+ name.addMatches(rv, this);
+ }
+
+ XMLList elements(XMLName name) {
+ XMLList rv = newXMLList();
+ rv.setTargets(this, name.toQname());
+ // TODO Should have an XMLNode.Filter implementation based on XMLName
+ XmlNode[] elements = this.node.getMatchingChildren(XmlNode.Filter.ELEMENT);
+ for (int i=0; i<elements.length; i++) {
+ if (name.matches( toXML(elements[i]) )) {
+ rv.addToList( toXML(elements[i]) );
+ }
+ }
+ return rv;
+ }
+
+ XMLList child(XMLName xmlName) {
+ // TODO Right now I think this method would allow child( "@xxx" ) to return the xxx attribute, which is wrong
+
+ XMLList rv = newXMLList();
+
+ // TODO Should this also match processing instructions? If so, we have to change the filter and also the XMLName
+ // class to add an acceptsProcessingInstruction() method
+
+ XmlNode[] elements = this.node.getMatchingChildren(XmlNode.Filter.ELEMENT);
+ for (int i=0; i<elements.length; i++) {
+ if (xmlName.matchesElement(elements[i].getQname())) {
+ rv.addToList( toXML(elements[i]) );
+ }
+ }
+ rv.setTargets(this, xmlName.toQname());
+ return rv;
+ }
+
+ XML replace(XMLName xmlName, Object xml) {
+ putXMLProperty(xmlName, xml);
+ return this;
+ }
+
+ XMLList children() {
+ XMLList rv = newXMLList();
+ XMLName all = XMLName.formStar();
+ rv.setTargets(this, all.toQname());
+ XmlNode[] children = this.node.getMatchingChildren(XmlNode.Filter.TRUE);
+ for (int i=0; i<children.length; i++) {
+ rv.addToList( toXML(children[i]) );
+ }
+ return rv;
+ }
+
+ XMLList child(int index) {
+ // ECMA357 13.4.4.6 (numeric case)
+ XMLList result = newXMLList();
+ result.setTargets(this, null);
+ if (index >= 0 && index < this.node.getChildCount()) {
+ result.addToList(getXmlChild(index));
+ }
+ return result;
+ }
+
+ XML getXmlChild(int index) {
+ XmlNode child = this.node.getChild(index);
+ if (child.getXml() == null) {
+ child.setXml(newXML(child));
+ }
+ return child.getXml();
+ }
+
+ int childIndex() {
+ return this.node.getChildIndex();
+ }
+
+ boolean contains(Object xml) {
+ if (xml instanceof XML) {
+ return equivalentXml(xml);
+ } else {
+ return false;
+ }
+ }
+
+ // Method overriding XMLObjectImpl
+ boolean equivalentXml(Object target) {
+ boolean result = false;
+
+ if (target instanceof XML) {
+ // TODO This is a horrifyingly inefficient way to do this so we should make it better. It may also not work.
+ return this.node.toXmlString(getProcessor()).equals( ((XML)target).node.toXmlString(getProcessor()) );
+ } else if (target instanceof XMLList) {
+ // TODO Is this right? Check the spec ...
+ XMLList otherList = (XMLList) target;
+
+ if (otherList.length() == 1) {
+ result = equivalentXml(otherList.getXML());
+ }
+ } else if (hasSimpleContent()) {
+ String otherStr = ScriptRuntime.toString(target);
+
+ result = toString().equals(otherStr);
+ }
+
+ return result;
+ }
+
+ XMLObjectImpl copy() {
+ return newXML( this.node.copy() );
+ }
+
+ boolean hasSimpleContent() {
+ if (isComment() || isProcessingInstruction()) return false;
+ if (isText() || this.node.isAttributeType()) return true;
+ return !this.node.hasChildElement();
+ }
+
+ boolean hasComplexContent() {
+ return !hasSimpleContent();
+ }
+
+ // TODO Cross-reference comment below with spec
+ // Comment is: Length of an XML object is always 1, it's a list of XML objects of size 1.
+ int length() {
+ return 1;
+ }
+
+ // TODO it is not clear what this method was for ...
+ boolean is(XML other) {
+ return this.node.isSameNode(other.node);
+ }
+
+ Object nodeKind() {
+ return ecmaClass();
+ }
+
+ Object parent() {
+ XmlNode parent = this.node.parent();
+ if (parent == null) return null;
+ return newXML(this.node.parent());
+ }
+
+ boolean propertyIsEnumerable(Object name)
+ {
+ boolean result;
+ if (name instanceof Integer) {
+ result = (((Integer)name).intValue() == 0);
+ } else if (name instanceof Number) {
+ double x = ((Number)name).doubleValue();
+ // Check that number is positive 0
+ result = (x == 0.0 && 1.0 / x > 0);
+ } else {
+ result = ScriptRuntime.toString(name).equals("0");
+ }
+ return result;
+ }
+
+ Object valueOf() {
+ return this;
+ }
+
+ //
+ // Selection of children
+ //
+
+ XMLList comments() {
+ XMLList rv = newXMLList();
+ this.node.addMatchingChildren(rv, XmlNode.Filter.COMMENT);
+ return rv;
+ }
+
+ XMLList text() {
+ XMLList rv = newXMLList();
+ this.node.addMatchingChildren(rv, XmlNode.Filter.TEXT);
+ return rv;
+ }
+
+ XMLList processingInstructions(XMLName xmlName) {
+ XMLList rv = newXMLList();
+ this.node.addMatchingChildren(rv, XmlNode.Filter.PROCESSING_INSTRUCTION(xmlName));
+ return rv;
+ }
+
+ //
+ // Methods relating to modification of child nodes
+ //
+
+ // We create all the nodes we are inserting before doing the insert to
+ // avoid nasty cycles caused by mutability of these objects. For example,
+ // what if the toString() method of value modifies the XML object we were
+ // going to insert into? insertAfter might get confused about where to
+ // insert. This actually came up with SpiderMonkey, leading to a (very)
+ // long discussion. See bug #354145.
+ private XmlNode[] getNodesForInsert(Object value) {
+ if (value instanceof XML) {
+ return new XmlNode[] { ((XML)value).node };
+ } else if (value instanceof XMLList) {
+ XMLList list = (XMLList)value;
+ XmlNode[] rv = new XmlNode[list.length()];
+ for (int i=0; i<list.length(); i++) {
+ rv[i] = list.item(i).node;
+ }
+ return rv;
+ } else {
+ return new XmlNode[] {
+ XmlNode.createText(getProcessor(), ScriptRuntime.toString(value))
+ };
+ }
+ }
+
+ XML replace(int index, Object xml) {
+ XMLList xlChildToReplace = child(index);
+ if (xlChildToReplace.length() > 0) {
+ // One exists an that index
+ XML childToReplace = xlChildToReplace.item(0);
+ insertChildAfter(childToReplace, xml);
+ removeChild(index);
+ }
+ return this;
+ }
+
+ XML prependChild(Object xml) {
+ if (this.node.isParentType()) {
+ this.node.insertChildrenAt(0, getNodesForInsert(xml));
+ }
+ return this;
+ }
+
+ XML appendChild(Object xml) {
+ if (this.node.isParentType()) {
+ XmlNode[] nodes = getNodesForInsert(xml);
+ this.node.insertChildrenAt(this.node.getChildCount(), nodes);
+ }
+ return this;
+ }
+
+ private int getChildIndexOf(XML child) {
+ for (int i=0; i<this.node.getChildCount(); i++) {
+ if (this.node.getChild(i).isSameNode(child.node)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ XML insertChildBefore(XML child, Object xml) {
+ if (child == null) {
+ // Spec says inserting before nothing is the same as appending
+ appendChild(xml);
+ } else {
+ XmlNode[] toInsert = getNodesForInsert(xml);
+ int index = getChildIndexOf(child);
+ if (index != -1) {
+ this.node.insertChildrenAt(index, toInsert);
+ }
+ }
+
+ return this;
+ }
+
+ XML insertChildAfter(XML child, Object xml) {
+ if (child == null) {
+ // Spec says inserting after nothing is the same as prepending
+ prependChild(xml);
+ } else {
+ XmlNode[] toInsert = getNodesForInsert(xml);
+ int index = getChildIndexOf(child);
+ if (index != -1) {
+ this.node.insertChildrenAt(index+1, toInsert);
+ }
+ }
+
+ return this;
+ }
+
+ XML setChildren(Object xml) {
+ // TODO Have not carefully considered the spec but it seems to call for this
+ if (!isElement()) return this;
+
+ while(this.node.getChildCount() > 0) {
+ this.node.removeChild(0);
+ }
+ XmlNode[] toInsert = getNodesForInsert(xml);
+ // append new children
+ this.node.insertChildrenAt(0, toInsert);
+
+ return this;
+ }
+
+ //
+ // Name and namespace-related methods
+ //
+
+ private void addInScopeNamespace(Namespace ns) {
+ if (!isElement()) {
+ return;
+ }
+ // See ECMA357 9.1.1.13
+ // in this implementation null prefix means ECMA undefined
+ if (ns.prefix() != null) {
+ if (ns.prefix().length() == 0 && ns.uri().length() == 0) {
+ return;
+ }
+ if (node.getQname().getNamespace().getPrefix().equals(ns.prefix())) {
+ node.invalidateNamespacePrefix();
+ }
+ node.declareNamespace(ns.prefix(), ns.uri());
+ } else {
+ return;
+ }
+ }
+
+ Namespace[] inScopeNamespaces() {
+ XmlNode.Namespace[] inScope = this.node.getInScopeNamespaces();
+ return createNamespaces(inScope);
+ }
+
+ private XmlNode.Namespace adapt(Namespace ns) {
+ if (ns.prefix() == null) {
+ return XmlNode.Namespace.create(ns.uri());
+ } else {
+ return XmlNode.Namespace.create(ns.prefix(), ns.uri());
+ }
+ }
+
+ XML removeNamespace(Namespace ns) {
+ if (!isElement()) return this;
+ this.node.removeNamespace(adapt(ns));
+ return this;
+ }
+
+ XML addNamespace(Namespace ns) {
+ addInScopeNamespace(ns);
+ return this;
+ }
+
+ QName name() {
+ if (isText() || isComment()) return null;
+ if (isProcessingInstruction()) return newQName("", this.node.getQname().getLocalName(), null);
+ return newQName(node.getQname());
+ }
+
+ Namespace[] namespaceDeclarations() {
+ XmlNode.Namespace[] declarations = node.getNamespaceDeclarations();
+ return createNamespaces(declarations);
+ }
+
+ Namespace namespace(String prefix) {
+ if (prefix == null) {
+ return createNamespace( this.node.getNamespaceDeclaration() );
+ } else {
+ return createNamespace( this.node.getNamespaceDeclaration(prefix) );
+ }
+ }
+
+ String localName() {
+ if (name() == null) return null;
+ return name().localName();
+ }
+
+ void setLocalName(String localName) {
+ // ECMA357 13.4.4.34
+ if (isText() || isComment()) return;
+ this.node.setLocalName(localName);
+ }
+
+ void setName(QName name) {
+ // See ECMA357 13.4.4.35
+ if (isText() || isComment()) return;
+ if (isProcessingInstruction()) {
+ // Spec says set the name URI to empty string and then set the [[Name]] property, but I understand this to do the same
+ // thing, unless we allow colons in processing instruction targets, which I think we do not.
+ this.node.setLocalName(name.localName());
+ return;
+ }
+ node.renameNode(name.getDelegate());
+ }
+
+ void setNamespace(Namespace ns) {
+ // See ECMA357 13.4.4.36
+ if (isText() || isComment() || isProcessingInstruction()) return;
+ setName(newQName(ns.uri(), localName(), ns.prefix()));
+ }
+
+ final String ecmaClass() {
+ // See ECMA357 9.1
+
+ // TODO See ECMA357 9.1.1 last paragraph for what defaults should be
+
+ if (node.isTextType()) {
+ return "text";
+ } else if (node.isAttributeType()) {
+ return "attribute";
+ } else if (node.isCommentType()) {
+ return "comment";
+ } else if (node.isProcessingInstructionType()) {
+ return "processing-instruction";
+ } else if (node.isElementType()) {
+ return "element";
+ } else {
+ throw new RuntimeException("Unrecognized type: " + node);
+ }
+ }
+
+ public String getClassName() {
+ // TODO: This appears to confuse the interpreter if we use the "real" class property from ECMA. Otherwise this code
+ // would be:
+ // return ecmaClass();
+ return "XML";
+ }
+
+ private String ecmaValue() {
+ return node.ecmaValue();
+ }
+
+ private String ecmaToString() {
+ // See ECMA357 10.1.1
+ if (isAttribute() || isText()) {
+ return ecmaValue();
+ }
+ if (this.hasSimpleContent()) {
+ StringBuffer rv = new StringBuffer();
+ for (int i=0; i < this.node.getChildCount(); i++) {
+ XmlNode child = this.node.getChild(i);
+ if (!child.isProcessingInstructionType() &&
+ !child.isCommentType())
+ {
+ // TODO: Probably inefficient; taking clean non-optimized
+ // solution for now
+ XML x = new XML(getLib(), getParentScope(),
+ (XMLObject)getPrototype(), child);
+ rv.append(x.toString());
+ }
+ }
+ return rv.toString();
+ }
+ return toXMLString();
+ }
+
+ public String toString() {
+ return ecmaToString();
+ }
+
+ String toXMLString() {
+ return this.node.ecmaToXMLString(getProcessor());
+ }
+
+ final boolean isAttribute() {
+ return node.isAttributeType();
+ }
+
+ final boolean isComment() {
+ return node.isCommentType();
+ }
+
+ final boolean isText() {
+ return node.isTextType();
+ }
+
+ final boolean isElement() {
+ return node.isElementType();
+ }
+
+ final boolean isProcessingInstruction() {
+ return node.isProcessingInstructionType();
+ }
+
+ // Support experimental Java interface
+ org.w3c.dom.Node toDomNode() {
+ return node.toDomNode();
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java
new file mode 100644
index 0000000..fac8773
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLCtor.java
@@ -0,0 +1,280 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+
+class XMLCtor extends IdFunctionObject
+{
+ static final long serialVersionUID = -8708195078359817341L;
+
+ private static final Object XMLCTOR_TAG = new Object();
+
+ private XmlProcessor options;
+// private XMLLibImpl lib;
+
+ XMLCtor(XML xml, Object tag, int id, int arity)
+ {
+ super(xml, tag, id, arity);
+// this.lib = xml.lib;
+ this.options = xml.getProcessor();
+ activatePrototypeMap(MAX_FUNCTION_ID);
+ }
+
+ private void writeSetting(Scriptable target)
+ {
+ for (int i = 1; i <= MAX_INSTANCE_ID; ++i) {
+ int id = super.getMaxInstanceId() + i;
+ String name = getInstanceIdName(id);
+ Object value = getInstanceIdValue(id);
+ ScriptableObject.putProperty(target, name, value);
+ }
+ }
+
+ private void readSettings(Scriptable source)
+ {
+ for (int i = 1; i <= MAX_INSTANCE_ID; ++i) {
+ int id = super.getMaxInstanceId() + i;
+ String name = getInstanceIdName(id);
+ Object value = ScriptableObject.getProperty(source, name);
+ if (value == Scriptable.NOT_FOUND) {
+ continue;
+ }
+ switch (i) {
+ case Id_ignoreComments:
+ case Id_ignoreProcessingInstructions:
+ case Id_ignoreWhitespace:
+ case Id_prettyPrinting:
+ if (!(value instanceof Boolean)) {
+ continue;
+ }
+ break;
+ case Id_prettyIndent:
+ if (!(value instanceof Number)) {
+ continue;
+ }
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ setInstanceIdValue(id, value);
+ }
+ }
+
+// #string_id_map#
+
+ private static final int
+ Id_ignoreComments = 1,
+ Id_ignoreProcessingInstructions = 2,
+ Id_ignoreWhitespace = 3,
+ Id_prettyIndent = 4,
+ Id_prettyPrinting = 5,
+
+ MAX_INSTANCE_ID = 5;
+
+ protected int getMaxInstanceId()
+ {
+ return super.getMaxInstanceId() + MAX_INSTANCE_ID;
+ }
+
+ protected int findInstanceIdInfo(String s) {
+ int id;
+// #generated# Last update: 2007-08-20 09:01:10 EDT
+ L0: { id = 0; String X = null; int c;
+ L: switch (s.length()) {
+ case 12: X="prettyIndent";id=Id_prettyIndent; break L;
+ case 14: c=s.charAt(0);
+ if (c=='i') { X="ignoreComments";id=Id_ignoreComments; }
+ else if (c=='p') { X="prettyPrinting";id=Id_prettyPrinting; }
+ break L;
+ case 16: X="ignoreWhitespace";id=Id_ignoreWhitespace; break L;
+ case 28: X="ignoreProcessingInstructions";id=Id_ignoreProcessingInstructions; break L;
+ }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+
+ if (id == 0) return super.findInstanceIdInfo(s);
+
+ int attr;
+ switch (id) {
+ case Id_ignoreComments:
+ case Id_ignoreProcessingInstructions:
+ case Id_ignoreWhitespace:
+ case Id_prettyIndent:
+ case Id_prettyPrinting:
+ attr = PERMANENT | DONTENUM;
+ break;
+ default: throw new IllegalStateException();
+ }
+ return instanceIdInfo(attr, super.getMaxInstanceId() + id);
+ }
+
+// #/string_id_map#
+
+ protected String getInstanceIdName(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_ignoreComments: return "ignoreComments";
+ case Id_ignoreProcessingInstructions: return "ignoreProcessingInstructions";
+ case Id_ignoreWhitespace: return "ignoreWhitespace";
+ case Id_prettyIndent: return "prettyIndent";
+ case Id_prettyPrinting: return "prettyPrinting";
+ }
+ return super.getInstanceIdName(id);
+ }
+
+ protected Object getInstanceIdValue(int id)
+ {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_ignoreComments:
+ return ScriptRuntime.wrapBoolean(options.isIgnoreComments());
+ case Id_ignoreProcessingInstructions:
+ return ScriptRuntime.wrapBoolean(options.isIgnoreProcessingInstructions());
+ case Id_ignoreWhitespace:
+ return ScriptRuntime.wrapBoolean(options.isIgnoreWhitespace());
+ case Id_prettyIndent:
+ return ScriptRuntime.wrapInt(options.getPrettyIndent());
+ case Id_prettyPrinting:
+ return ScriptRuntime.wrapBoolean(options.isPrettyPrinting());
+ }
+ return super.getInstanceIdValue(id);
+ }
+
+ protected void setInstanceIdValue(int id, Object value) {
+ switch (id - super.getMaxInstanceId()) {
+ case Id_ignoreComments:
+ options.setIgnoreComments(ScriptRuntime.toBoolean(value));
+ return;
+ case Id_ignoreProcessingInstructions:
+ options.setIgnoreProcessingInstructions(ScriptRuntime.toBoolean(value));
+ return;
+ case Id_ignoreWhitespace:
+ options.setIgnoreWhitespace(ScriptRuntime.toBoolean(value));
+ return;
+ case Id_prettyIndent:
+ options.setPrettyIndent(ScriptRuntime.toInt32(value));
+ return;
+ case Id_prettyPrinting:
+ options.setPrettyPrinting(ScriptRuntime.toBoolean(value));
+ return;
+ }
+ super.setInstanceIdValue(id, value);
+ }
+
+// #string_id_map#
+ private static final int
+ Id_defaultSettings = 1,
+ Id_settings = 2,
+ Id_setSettings = 3,
+ MAX_FUNCTION_ID = 3;
+
+ protected int findPrototypeId(String s)
+ {
+ int id;
+// #generated# Last update: 2007-08-20 09:01:10 EDT
+ L0: { id = 0; String X = null;
+ int s_length = s.length();
+ if (s_length==8) { X="settings";id=Id_settings; }
+ else if (s_length==11) { X="setSettings";id=Id_setSettings; }
+ else if (s_length==15) { X="defaultSettings";id=Id_defaultSettings; }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+ return id;
+ }
+// #/string_id_map#
+
+ protected void initPrototypeId(int id)
+ {
+ String s;
+ int arity;
+ switch (id) {
+ case Id_defaultSettings: arity=0; s="defaultSettings"; break;
+ case Id_settings: arity=0; s="settings"; break;
+ case Id_setSettings: arity=1; s="setSettings"; break;
+ default: throw new IllegalArgumentException(String.valueOf(id));
+ }
+ initPrototypeMethod(XMLCTOR_TAG, id, s, arity);
+ }
+
+ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
+ Scriptable thisObj, Object[] args)
+ {
+ if (!f.hasTag(XMLCTOR_TAG)) {
+ return super.execIdCall(f, cx, scope, thisObj, args);
+ }
+ int id = f.methodId();
+ switch (id) {
+ case Id_defaultSettings: {
+ options.setDefault();
+ Scriptable obj = cx.newObject(scope);
+ writeSetting(obj);
+ return obj;
+ }
+ case Id_settings: {
+ Scriptable obj = cx.newObject(scope);
+ writeSetting(obj);
+ return obj;
+ }
+ case Id_setSettings: {
+ if (args.length == 0
+ || args[0] == null
+ || args[0] == Undefined.instance)
+ {
+ options.setDefault();
+ } else if (args[0] instanceof Scriptable) {
+ readSettings((Scriptable)args[0]);
+ }
+ return Undefined.instance;
+ }
+ }
+ throw new IllegalArgumentException(String.valueOf(id));
+ }
+
+ /**
+ hasInstance for XML objects works differently than other objects; see ECMA357 13.4.3.10.
+ */
+ public boolean hasInstance(Scriptable instance) {
+ return (instance instanceof XML || instance instanceof XMLList);
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
new file mode 100644
index 0000000..6d45240
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
@@ -0,0 +1,606 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import java.io.Serializable;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.*;
+
+public final class XMLLibImpl extends XMLLib implements Serializable {
+ // TODO Document that this only works with JDK 1.5 or backport its
+ // features to earlier versions
+ private static final long serialVersionUID = 1L;
+
+ //
+ // EXPERIMENTAL Java interface
+ //
+
+ /**
+ This experimental interface is undocumented.
+ */
+ public static org.w3c.dom.Node toDomNode(Object xmlObject) {
+ // Could return DocumentFragment for XMLList
+ // Probably a single node for XMLList with one element
+ if (xmlObject instanceof XML) {
+ return ((XML)xmlObject).toDomNode();
+ } else {
+ throw new IllegalArgumentException("xmlObject is not an XML object in JavaScript.");
+ }
+ }
+
+ public static void init(Context cx, Scriptable scope, boolean sealed) {
+ XMLLibImpl lib = new XMLLibImpl(scope);
+ XMLLib bound = lib.bindToScope(scope);
+ if (bound == lib) {
+ lib.exportToScope(sealed);
+ }
+ }
+
+ private Scriptable globalScope;
+
+ private XML xmlPrototype;
+ private XMLList xmlListPrototype;
+ private Namespace namespacePrototype;
+ private QName qnamePrototype;
+
+ private XmlProcessor options = new XmlProcessor();
+
+ private XMLLibImpl(Scriptable globalScope) {
+ this.globalScope = globalScope;
+ }
+
+ /** @deprecated */
+ QName qnamePrototype() {
+ return qnamePrototype;
+ }
+
+ /** @deprecated */
+ Scriptable globalScope() {
+ return globalScope;
+ }
+
+ XmlProcessor getProcessor() {
+ return options;
+ }
+
+ private void exportToScope(boolean sealed) {
+ xmlPrototype = newXML(XmlNode.createText(options, ""));
+ xmlListPrototype = newXMLList();
+ namespacePrototype = Namespace.create(this.globalScope, null, XmlNode.Namespace.GLOBAL);
+ qnamePrototype = QName.create(this, this.globalScope, null, XmlNode.QName.create(XmlNode.Namespace.create(""), ""));
+
+ xmlPrototype.exportAsJSClass(sealed);
+ xmlListPrototype.exportAsJSClass(sealed);
+ namespacePrototype.exportAsJSClass(sealed);
+ qnamePrototype.exportAsJSClass(sealed);
+ }
+
+ /** @deprecated */
+ XMLName toAttributeName(Context cx, Object nameValue) {
+ if (nameValue instanceof XMLName) {
+ // TODO Will this always be an XMLName of type attribute name?
+ return (XMLName)nameValue;
+ } else if (nameValue instanceof QName) {
+ return XMLName.create( ((QName)nameValue).getDelegate(), true, false );
+ } else if (nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null) {
+ throw badXMLName(nameValue);
+ } else {
+ // TODO Not 100% sure that putting these in global namespace is the right thing to do
+ String localName = null;
+ if (nameValue instanceof String) {
+ localName = (String)nameValue;
+ } else {
+ localName = ScriptRuntime.toString(nameValue);
+ }
+ if (localName != null && localName.equals("*")) localName = null;
+ return XMLName.create(XmlNode.QName.create(XmlNode.Namespace.create(""), localName), true, false);
+ }
+ }
+
+ private static RuntimeException badXMLName(Object value)
+ {
+ String msg;
+ if (value instanceof Number) {
+ msg = "Can not construct XML name from number: ";
+ } else if (value instanceof Boolean) {
+ msg = "Can not construct XML name from boolean: ";
+ } else if (value == Undefined.instance || value == null) {
+ msg = "Can not construct XML name from ";
+ } else {
+ throw new IllegalArgumentException(value.toString());
+ }
+ return ScriptRuntime.typeError(msg+ScriptRuntime.toString(value));
+ }
+
+ XMLName toXMLNameFromString(Context cx, String name) {
+ return XMLName.create( getDefaultNamespaceURI(cx), name );
+ }
+
+ /** @deprecated */
+ XMLName toXMLName(Context cx, Object nameValue) {
+ XMLName result;
+
+ if (nameValue instanceof XMLName) {
+ result = (XMLName)nameValue;
+ } else if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ result = XMLName.formProperty(qname.uri(), qname.localName());
+ } else if (nameValue instanceof String) {
+ result = toXMLNameFromString(cx, (String)nameValue);
+ } else if (nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null) {
+ throw badXMLName(nameValue);
+ } else {
+ String name = ScriptRuntime.toString(nameValue);
+ result = toXMLNameFromString(cx, name);
+ }
+
+ return result;
+ }
+
+ /**
+ * If value represents Uint32 index, make it available through
+ * ScriptRuntime.lastUint32Result(cx) and return null.
+ * Otherwise return the same value as toXMLName(cx, value).
+ */
+ XMLName toXMLNameOrIndex(Context cx, Object value)
+ {
+ XMLName result;
+
+ if (value instanceof XMLName) {
+ result = (XMLName)value;
+ } else if (value instanceof String) {
+ String str = (String)value;
+ long test = ScriptRuntime.testUint32String(str);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ result = null;
+ } else {
+ result = toXMLNameFromString(cx, str);
+ }
+ } else if (value instanceof Number) {
+ double d = ((Number)value).doubleValue();
+ long l = (long)d;
+ if (l == d && 0 <= l && l <= 0xFFFFFFFFL) {
+ ScriptRuntime.storeUint32Result(cx, l);
+ result = null;
+ } else {
+ throw badXMLName(value);
+ }
+ } else if (value instanceof QName) {
+ QName qname = (QName)value;
+ String uri = qname.uri();
+ boolean number = false;
+ result = null;
+ if (uri != null && uri.length() == 0) {
+ // Only in this case qname.toString() can resemble uint32
+ long test = ScriptRuntime.testUint32String(uri);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ number = true;
+ }
+ }
+ if (!number) {
+ result = XMLName.formProperty(uri, qname.localName());
+ }
+ } else if (value instanceof Boolean
+ || value == Undefined.instance
+ || value == null)
+ {
+ throw badXMLName(value);
+ } else {
+ String str = ScriptRuntime.toString(value);
+ long test = ScriptRuntime.testUint32String(str);
+ if (test >= 0) {
+ ScriptRuntime.storeUint32Result(cx, test);
+ result = null;
+ } else {
+ result = toXMLNameFromString(cx, str);
+ }
+ }
+
+ return result;
+ }
+
+ Object addXMLObjects(Context cx, XMLObject obj1, XMLObject obj2)
+ {
+ XMLList listToAdd = newXMLList();
+
+ if (obj1 instanceof XMLList) {
+ XMLList list1 = (XMLList)obj1;
+ if (list1.length() == 1) {
+ listToAdd.addToList(list1.item(0));
+ } else {
+ // Might be xmlFragment + xmlFragment + xmlFragment + ...;
+ // then the result will be an XMLList which we want to be an
+ // rValue and allow it to be assigned to an lvalue.
+ listToAdd = newXMLListFrom(obj1);
+ }
+ } else {
+ listToAdd.addToList(obj1);
+ }
+
+ if (obj2 instanceof XMLList) {
+ XMLList list2 = (XMLList)obj2;
+ for (int i = 0; i < list2.length(); i++) {
+ listToAdd.addToList(list2.item(i));
+ }
+ } else if (obj2 instanceof XML) {
+ listToAdd.addToList(obj2);
+ }
+
+ return listToAdd;
+ }
+
+ private Ref xmlPrimaryReference(Context cx, XMLName xmlName, Scriptable scope) {
+ XMLObjectImpl xmlObj;
+ XMLObjectImpl firstXml = null;
+ for (;;) {
+ // XML object can only present on scope chain as a wrapper
+ // of XMLWithScope
+ if (scope instanceof XMLWithScope) {
+ xmlObj = (XMLObjectImpl)scope.getPrototype();
+ if (xmlObj.hasXMLProperty(xmlName)) {
+ break;
+ }
+ if (firstXml == null) {
+ firstXml = xmlObj;
+ }
+ }
+ scope = scope.getParentScope();
+ if (scope == null) {
+ xmlObj = firstXml;
+ break;
+ }
+ }
+
+ // xmlObj == null corresponds to undefined as the target of
+ // the reference
+ if (xmlObj != null) {
+ xmlName.initXMLObject(xmlObj);
+ }
+ return xmlName;
+ }
+
+ Namespace castToNamespace(Context cx, Object namespaceObj) {
+ return this.namespacePrototype.castToNamespace(namespaceObj);
+ }
+
+ private String getDefaultNamespaceURI(Context cx) {
+ return getDefaultNamespace(cx).uri();
+ }
+
+ Namespace newNamespace(String uri) {
+ return this.namespacePrototype.newNamespace(uri);
+ }
+
+ Namespace getDefaultNamespace(Context cx) {
+ if (cx == null) {
+ cx = Context.getCurrentContext();
+ if (cx == null) {
+ return namespacePrototype;
+ }
+ }
+
+ Object ns = ScriptRuntime.searchDefaultNamespace(cx);
+ if (ns == null) {
+ return namespacePrototype;
+ } else {
+ if (ns instanceof Namespace) {
+ return (Namespace)ns;
+ } else {
+ // TODO Clarify or remove the following comment
+ // Should not happen but for now it could
+ // due to bad searchDefaultNamespace implementation.
+ return namespacePrototype;
+ }
+ }
+ }
+
+ Namespace[] createNamespaces(XmlNode.Namespace[] declarations) {
+ Namespace[] rv = new Namespace[declarations.length];
+ for (int i=0; i<declarations.length; i++) {
+ rv[i] = this.namespacePrototype.newNamespace(declarations[i].getPrefix(), declarations[i].getUri());
+ }
+ return rv;
+ }
+
+ // See ECMA357 13.3.2
+ QName constructQName(Context cx, Object namespace, Object name) {
+ return this.qnamePrototype.constructQName(this, cx, namespace, name);
+ }
+
+ QName newQName(String uri, String localName, String prefix) {
+ return this.qnamePrototype.newQName(this, uri, localName, prefix);
+ }
+
+ QName constructQName(Context cx, Object nameValue) {
+// return constructQName(cx, Undefined.instance, nameValue);
+ return this.qnamePrototype.constructQName(this, cx, nameValue);
+ }
+
+ QName castToQName(Context cx, Object qnameValue) {
+ return this.qnamePrototype.castToQName(this, cx, qnameValue);
+ }
+
+ QName newQName(XmlNode.QName qname) {
+ return QName.create(this, this.globalScope, this.qnamePrototype, qname);
+ }
+
+ XML newXML(XmlNode node) {
+ return new XML(this, this.globalScope, this.xmlPrototype, node);
+ }
+
+ /**
+ @deprecated I believe this can be replaced by ecmaToXml below.
+ */
+ final XML newXMLFromJs(Object inputObject) {
+ String frag;
+
+ if (inputObject == null || inputObject == Undefined.instance) {
+ frag = "";
+ } else if (inputObject instanceof XMLObjectImpl) {
+ // todo: faster way for XMLObjects?
+ frag = ((XMLObjectImpl) inputObject).toXMLString();
+ } else {
+ frag = ScriptRuntime.toString(inputObject);
+ }
+
+ if (frag.trim().startsWith("<>")) {
+ throw ScriptRuntime.typeError("Invalid use of XML object anonymous tags <></>.");
+ }
+
+ if (frag.indexOf("<") == -1) {
+ // Solo text node
+ return newXML(XmlNode.createText(options, frag));
+ }
+ return parse(frag);
+ }
+
+ private XML parse(String frag) {
+ try {
+ return newXML(XmlNode.createElement(options, getDefaultNamespaceURI(Context.getCurrentContext()), frag));
+ } catch (org.xml.sax.SAXException e) {
+ throw ScriptRuntime.typeError("Cannot parse XML: " + e.getMessage());
+ }
+ }
+
+ final XML ecmaToXml(Object object) {
+ // See ECMA357 10.3
+ if (object == null || object == Undefined.instance) throw ScriptRuntime.typeError("Cannot convert " + object + " to XML");
+ if (object instanceof XML) return (XML)object;
+ if (object instanceof XMLList) {
+ XMLList list = (XMLList)object;
+ if (list.getXML() != null) {
+ return list.getXML();
+ } else {
+ throw ScriptRuntime.typeError("Cannot convert list of >1 element to XML");
+ }
+ }
+ // TODO Technically we should fail on anything except a String, Number or Boolean
+ // See ECMA357 10.3
+ // Extension: if object is a DOM node, use that to construct the XML
+ // object.
+ if (object instanceof Wrapper) {
+ object = ((Wrapper) object).unwrap();
+ }
+ if (object instanceof org.w3c.dom.Node) {
+ org.w3c.dom.Node node = (org.w3c.dom.Node) object;
+ return newXML(XmlNode.createElementFromNode(node));
+ }
+ // Instead we just blindly cast to a String and let them convert anything.
+ String s = ScriptRuntime.toString(object);
+ // TODO Could this get any uglier?
+ if (s.length() > 0 && s.charAt(0) == '<') {
+ return parse(s);
+ } else {
+ return newXML(XmlNode.createText(options, s));
+ }
+ }
+
+ final XML newTextElementXML(XmlNode reference, XmlNode.QName qname, String value) {
+ return newXML(XmlNode.newElementWithText(options, reference, qname, value));
+ }
+
+ XMLList newXMLList() {
+ return new XMLList(this, this.globalScope, this.xmlListPrototype);
+ }
+
+ final XMLList newXMLListFrom(Object inputObject) {
+ XMLList rv = newXMLList();
+
+ if (inputObject == null || inputObject instanceof Undefined) {
+ return rv;
+ } else if (inputObject instanceof XML) {
+ XML xml = (XML) inputObject;
+ rv.getNodeList().add(xml);
+ return rv;
+ } else if (inputObject instanceof XMLList) {
+ XMLList xmll = (XMLList) inputObject;
+ rv.getNodeList().add(xmll.getNodeList());
+ return rv;
+ } else {
+ String frag = ScriptRuntime.toString(inputObject).trim();
+
+ if (!frag.startsWith("<>")) {
+ frag = "<>" + frag + "</>";
+ }
+
+ frag = "<fragment>" + frag.substring(2);
+ if (!frag.endsWith("</>")) {
+ throw ScriptRuntime.typeError("XML with anonymous tag missing end anonymous tag");
+ }
+
+ frag = frag.substring(0, frag.length() - 3) + "</fragment>";
+
+ XML orgXML = newXMLFromJs(frag);
+
+ // Now orphan the children and add them to our XMLList.
+ XMLList children = orgXML.children();
+
+ for (int i = 0; i < children.getNodeList().length(); i++) {
+ // Copy here is so that they'll be orphaned (parent() will be undefined)
+ rv.getNodeList().add(((XML) children.item(i).copy()));
+ }
+ return rv;
+ }
+ }
+
+ XmlNode.QName toNodeQName(Context cx, Object namespaceValue, Object nameValue) {
+ // This is duplication of constructQName(cx, namespaceValue, nameValue)
+ // but for XMLName
+
+ String localName;
+
+ if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ localName = qname.localName();
+ } else {
+ localName = ScriptRuntime.toString(nameValue);
+ }
+
+ XmlNode.Namespace ns;
+ if (namespaceValue == Undefined.instance) {
+ if ("*".equals(localName)) {
+ ns = null;
+ } else {
+ ns = getDefaultNamespace(cx).getDelegate();
+ }
+ } else if (namespaceValue == null) {
+ ns = null;
+ } else if (namespaceValue instanceof Namespace) {
+ ns = ((Namespace)namespaceValue).getDelegate();
+ } else {
+ ns = this.namespacePrototype.constructNamespace(namespaceValue).getDelegate();
+ }
+
+ if (localName != null && localName.equals("*")) localName = null;
+ return XmlNode.QName.create(ns, localName);
+ }
+
+ XmlNode.QName toNodeQName(Context cx, String name, boolean attribute) {
+ XmlNode.Namespace defaultNamespace = getDefaultNamespace(cx).getDelegate();
+ if (name != null && name.equals("*")) {
+ return XmlNode.QName.create(null, null);
+ } else {
+ if (attribute) {
+ return XmlNode.QName.create(XmlNode.Namespace.GLOBAL, name);
+ } else {
+ return XmlNode.QName.create(defaultNamespace, name);
+ }
+ }
+ }
+
+ /**
+ @deprecated Too general; this should be split into overloaded methods.
+ Is that possible?
+ */
+ XmlNode.QName toNodeQName(Context cx, Object nameValue, boolean attribute) {
+ if (nameValue instanceof XMLName) {
+ return ((XMLName)nameValue).toQname();
+ } else if (nameValue instanceof QName) {
+ QName qname = (QName)nameValue;
+ return qname.getDelegate();
+ } else if (
+ nameValue instanceof Boolean
+ || nameValue instanceof Number
+ || nameValue == Undefined.instance
+ || nameValue == null
+ ) {
+ throw badXMLName(nameValue);
+ } else {
+ String local = null;
+ if (nameValue instanceof String) {
+ local = (String)nameValue;
+ } else {
+ local = ScriptRuntime.toString(nameValue);
+ }
+ return toNodeQName(cx, local, attribute);
+ }
+ }
+
+ //
+ // Override methods from XMLLib
+ //
+
+ public boolean isXMLName(Context _cx, Object nameObj) {
+ return XMLName.accept(nameObj);
+ }
+
+ public Object toDefaultXmlNamespace(Context cx, Object uriValue) {
+ return this.namespacePrototype.constructNamespace(uriValue);
+ }
+
+ public String escapeTextValue(Object o) {
+ return options.escapeTextValue(o);
+ }
+
+ public String escapeAttributeValue(Object o) {
+ return options.escapeAttributeValue(o);
+ }
+
+ public Ref nameRef(Context cx, Object name, Scriptable scope, int memberTypeFlags) {
+ if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) == 0) {
+ // should only be called foir cases like @name or @[expr]
+ throw Kit.codeBug();
+ }
+ XMLName xmlName = toAttributeName(cx, name);
+ return xmlPrimaryReference(cx, xmlName, scope);
+ }
+
+ public Ref nameRef(Context cx, Object namespace, Object name, Scriptable scope, int memberTypeFlags) {
+ XMLName xmlName = XMLName.create(toNodeQName(cx, namespace, name), false, false);
+
+ // No idea what is coming in from the parser in this case; is it detecting the "@"?
+ if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) {
+ if (!xmlName.isAttributeName()) {
+ xmlName.setAttributeName();
+ }
+ }
+
+ return xmlPrimaryReference(cx, xmlName, scope);
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java
new file mode 100644
index 0000000..59dcca3
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLList.java
@@ -0,0 +1,765 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.*;
+
+class XMLList extends XMLObjectImpl implements Function {
+ static final long serialVersionUID = -4543618751670781135L;
+
+ private XmlNode.List _annos;
+ private XMLObjectImpl targetObject = null;
+ private XmlNode.QName targetProperty = null;
+
+ XMLList(XMLLibImpl lib, Scriptable scope, XMLObject prototype) {
+ super(lib, scope, prototype);
+ _annos = new XmlNode.List();
+ }
+
+ /** @deprecated Will probably end up unnecessary as we move things around */
+ XmlNode.List getNodeList() {
+ return _annos;
+ }
+
+ // TODO Should be XMLObjectImpl, XMLName?
+ void setTargets(XMLObjectImpl object, XmlNode.QName property) {
+ targetObject = object;
+ targetProperty = property;
+ }
+
+ /** @deprecated */
+ private XML getXmlFromAnnotation(int index) {
+ return getXML(_annos, index);
+ }
+
+ XML getXML() {
+ if (length() == 1) return getXmlFromAnnotation(0);
+ return null;
+ }
+
+ private void internalRemoveFromList(int index) {
+ _annos.remove(index);
+ }
+
+ void replace(int index, XML xml) {
+ if (index < length()) {
+ XmlNode.List newAnnoList = new XmlNode.List();
+ newAnnoList.add(_annos, 0, index);
+ newAnnoList.add(xml);
+ newAnnoList.add(_annos, index+1, length());
+ _annos = newAnnoList;
+ }
+ }
+
+ private void insert(int index, XML xml) {
+ if (index < length()) {
+ XmlNode.List newAnnoList = new XmlNode.List();
+ newAnnoList.add(_annos, 0, index);
+ newAnnoList.add(xml);
+ newAnnoList.add(_annos, index, length());
+ _annos = newAnnoList;
+ }
+ }
+
+ //
+ //
+ // methods overriding ScriptableObject
+ //
+ //
+
+ public String getClassName() {
+ return "XMLList";
+ }
+
+ //
+ //
+ // methods overriding IdScriptableObject
+ //
+ //
+
+ public Object get(int index, Scriptable start) {
+ //Log("get index: " + index);
+
+ if (index >= 0 && index < length()) {
+ return getXmlFromAnnotation(index);
+ } else {
+ return Scriptable.NOT_FOUND;
+ }
+ }
+
+ boolean hasXMLProperty(XMLName xmlName) {
+ boolean result = false;
+
+ // Has now should return true if the property would have results > 0 or
+ // if it's a method name
+ String name = xmlName.localName();
+ if ((getPropertyList(xmlName).length() > 0) ||
+ (getMethod(name) != NOT_FOUND)) {
+ result = true;
+ }
+
+ return result;
+ }
+
+ public boolean has(int index, Scriptable start) {
+ return 0 <= index && index < length();
+ }
+
+ void putXMLProperty(XMLName xmlName, Object value) {
+ //Log("put property: " + name);
+
+ // Special-case checks for undefined and null
+ if (value == null) {
+ value = "null";
+ } else if (value instanceof Undefined) {
+ value = "undefined";
+ }
+
+ if (length() > 1) {
+ throw ScriptRuntime.typeError("Assignment to lists with more than one item is not supported");
+ } else if (length() == 0) {
+ // Secret sauce for super-expandos.
+ // We set an element here, and then add ourselves to our target.
+ if (targetObject != null && targetProperty != null && targetProperty.getLocalName() != null) {
+ // Add an empty element with our targetProperty name and then set it.
+ XML xmlValue = newTextElementXML(null, targetProperty, null);
+ addToList(xmlValue);
+
+ if(xmlName.isAttributeName()) {
+ setAttribute(xmlName, value);
+ } else {
+ XML xml = item(0);
+ xml.putXMLProperty(xmlName, value);
+
+ // Update the list with the new item at location 0.
+ replace(0, item(0));
+ }
+
+ // Now add us to our parent
+ XMLName name2 = XMLName.formProperty(targetProperty.getUri(), targetProperty.getLocalName());
+ targetObject.putXMLProperty(name2, this);
+ } else {
+ throw ScriptRuntime.typeError("Assignment to empty XMLList without targets not supported");
+ }
+ } else if(xmlName.isAttributeName()) {
+ setAttribute(xmlName, value);
+ } else {
+ XML xml = item(0);
+ xml.putXMLProperty(xmlName, value);
+
+ // Update the list with the new item at location 0.
+ replace(0, item(0));
+ }
+ }
+
+ Object getXMLProperty(XMLName name) {
+ return getPropertyList(name);
+ }
+
+ private void replaceNode(XML xml, XML with) {
+ xml.replaceWith(with);
+ }
+
+ public void put(int index, Scriptable start, Object value) {
+ Object parent = Undefined.instance;
+ // Convert text into XML if needed.
+ XMLObject xmlValue;
+
+ // Special-case checks for undefined and null
+ if (value == null) {
+ value = "null";
+ } else if (value instanceof Undefined) {
+ value = "undefined";
+ }
+
+ if (value instanceof XMLObject) {
+ xmlValue = (XMLObject) value;
+ } else {
+ if (targetProperty == null) {
+ xmlValue = newXMLFromJs(value.toString());
+ } else {
+ // Note that later in the code, we will use this as an argument to replace(int,value)
+ // So we will be "replacing" this element with itself
+ // There may well be a better way to do this
+ // TODO Find a way to refactor this whole method and simplify it
+ xmlValue = item(index);
+ ((XML)xmlValue).setChildren(value);
+ }
+ }
+
+ // Find the parent
+ if (index < length()) {
+ parent = item(index).parent();
+ } else {
+ // Appending
+ parent = parent();
+ }
+
+ if (parent instanceof XML) {
+ // found parent, alter doc
+ XML xmlParent = (XML) parent;
+
+ if (index < length()) {
+ // We're replacing the the node.
+ XML xmlNode = getXmlFromAnnotation(index);
+
+ if (xmlValue instanceof XML) {
+ replaceNode(xmlNode, (XML) xmlValue);
+ replace(index, xmlNode);
+ } else if (xmlValue instanceof XMLList) {
+ // Replace the first one, and add the rest on the list.
+ XMLList list = (XMLList) xmlValue;
+
+ if (list.length() > 0) {
+ int lastIndexAdded = xmlNode.childIndex();
+ replaceNode(xmlNode, list.item(0));
+ replace(index, list.item(0));
+
+ for (int i = 1; i < list.length(); i++) {
+ xmlParent.insertChildAfter(xmlParent.getXmlChild(lastIndexAdded), list.item(i));
+ lastIndexAdded++;
+ insert(index + i, list.item(i));
+ }
+ }
+ }
+ } else {
+ // Appending
+ xmlParent.appendChild(xmlValue);
+ addToList(xmlParent.getXmlChild(index));
+ }
+ } else {
+ // Don't all have same parent, no underlying doc to alter
+ if (index < length()) {
+ XML xmlNode = getXML(_annos, index);
+
+ if (xmlValue instanceof XML) {
+ replaceNode(xmlNode, (XML) xmlValue);
+ replace(index, xmlNode);
+ } else if (xmlValue instanceof XMLList) {
+ // Replace the first one, and add the rest on the list.
+ XMLList list = (XMLList) xmlValue;
+
+ if (list.length() > 0) {
+ replaceNode(xmlNode, list.item(0));
+ replace(index, list.item(0));
+
+ for (int i = 1; i < list.length(); i++) {
+ insert(index + i, list.item(i));
+ }
+ }
+ }
+ } else {
+ addToList(xmlValue);
+ }
+ }
+ }
+
+ private XML getXML(XmlNode.List _annos, int index) {
+ if (index >= 0 && index < length()) {
+ return xmlFromNode(_annos.item(index));
+ } else {
+ return null;
+ }
+ }
+
+ void deleteXMLProperty(XMLName name) {
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+
+ if (xml.isElement()) {
+ xml.deleteXMLProperty(name);
+ }
+ }
+ }
+
+ public void delete(int index) {
+ if (index >= 0 && index < length()) {
+ XML xml = getXmlFromAnnotation(index);
+
+ xml.remove();
+
+ internalRemoveFromList(index);
+ }
+ }
+
+ public Object[] getIds() {
+ Object enumObjs[];
+
+ if (isPrototype()) {
+ enumObjs = new Object[0];
+ } else {
+ enumObjs = new Object[length()];
+
+ for (int i = 0; i < enumObjs.length; i++) {
+ enumObjs[i] = new Integer(i);
+ }
+ }
+
+ return enumObjs;
+ }
+
+ public Object[] getIdsForDebug() {
+ return getIds();
+ }
+
+
+ // XMLList will remove will delete all items in the list (a set delete) this differs from the XMLList delete operator.
+ void remove() {
+ int nLen = length();
+ for (int i = nLen - 1; i >= 0; i--) {
+ XML xml = getXmlFromAnnotation(i);
+ if (xml != null) {
+ xml.remove();
+ internalRemoveFromList(i);
+ }
+ }
+ }
+
+ XML item(int index) {
+ return _annos != null
+ ? getXmlFromAnnotation(index) : createEmptyXML();
+ }
+
+ private void setAttribute(XMLName xmlName, Object value) {
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+ xml.setAttribute(xmlName, value);
+ }
+ }
+
+ void addToList(Object toAdd) {
+ _annos.addToList(toAdd);
+ }
+
+ //
+ //
+ // Methods from section 12.4.4 in the spec
+ //
+ //
+
+ XMLList child(int index) {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ result.addToList(getXmlFromAnnotation(i).child(index));
+ }
+
+ return result;
+ }
+
+ XMLList child(XMLName xmlName) {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ result.addToList(getXmlFromAnnotation(i).child(xmlName));
+ }
+
+ return result;
+ }
+
+ void addMatches(XMLList rv, XMLName name) {
+ for (int i=0; i<length(); i++) {
+ getXmlFromAnnotation(i).addMatches(rv, name);
+ }
+ }
+
+ XMLList children() {
+ java.util.Vector v = new java.util.Vector();
+
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+
+ if (xml != null) {
+ Object o = xml.children();
+ if (o instanceof XMLList) {
+ XMLList childList = (XMLList)o;
+
+ int cChildren = childList.length();
+ for (int j = 0; j < cChildren; j++) {
+ v.addElement(childList.item(j));
+ }
+ }
+ }
+ }
+
+ XMLList allChildren = newXMLList();
+ int sz = v.size();
+
+ for (int i = 0; i < sz; i++) {
+ allChildren.addToList(v.get(i));
+ }
+
+ return allChildren;
+ }
+
+ XMLList comments() {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+ result.addToList(xml.comments());
+ }
+
+ return result;
+ }
+
+ XMLList elements(XMLName name) {
+ XMLList rv = newXMLList();
+ for (int i=0; i<length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+ rv.addToList(xml.elements(name));
+ }
+ return rv;
+ }
+
+ boolean contains(Object xml) {
+ boolean result = false;
+
+ for (int i = 0; i < length(); i++) {
+ XML member = getXmlFromAnnotation(i);
+
+ if (member.equivalentXml(xml)) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ XMLObjectImpl copy() {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+ result.addToList(xml.copy());
+ }
+
+ return result;
+ }
+
+ boolean hasOwnProperty(XMLName xmlName) {
+ if (isPrototype()) {
+ String property = xmlName.localName();
+ return (findPrototypeId(property) != 0);
+ } else {
+ return (getPropertyList(xmlName).length() > 0);
+ }
+ }
+
+ boolean hasComplexContent() {
+ boolean complexContent;
+ int length = length();
+
+ if (length == 0) {
+ complexContent = false;
+ } else if (length == 1) {
+ complexContent = getXmlFromAnnotation(0).hasComplexContent();
+ } else {
+ complexContent = false;
+
+ for (int i = 0; i < length; i++) {
+ XML nextElement = getXmlFromAnnotation(i);
+ if (nextElement.isElement()) {
+ complexContent = true;
+ break;
+ }
+ }
+ }
+
+ return complexContent;
+ }
+
+ boolean hasSimpleContent() {
+ if (length() == 0) {
+ return true;
+ } else if (length() == 1) {
+ return getXmlFromAnnotation(0).hasSimpleContent();
+ } else {
+ for (int i=0; i<length(); i++) {
+ XML nextElement = getXmlFromAnnotation(i);
+ if (nextElement.isElement()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ int length() {
+ int result = 0;
+
+ if (_annos != null) {
+ result = _annos.length();
+ }
+
+ return result;
+ }
+
+ void normalize() {
+ for (int i = 0; i < length(); i++) {
+ getXmlFromAnnotation(i).normalize();
+ }
+ }
+
+ /**
+ * If list is empty, return undefined, if elements have different parents return undefined,
+ * If they all have the same parent, return that parent
+ */
+ Object parent() {
+ if (length() == 0) return Undefined.instance;
+
+ XML candidateParent = null;
+
+ for (int i = 0; i < length(); i++) {
+ Object currParent = getXmlFromAnnotation(i).parent();
+ if (!(currParent instanceof XML)) return Undefined.instance;
+ XML xml = (XML)currParent;
+ if (i == 0) {
+ // Set the first for the rest to compare to.
+ candidateParent = xml;
+ } else {
+ if (candidateParent.is(xml)) {
+ // keep looking
+ } else {
+ return Undefined.instance;
+ }
+ }
+ }
+ return candidateParent;
+ }
+
+ XMLList processingInstructions(XMLName xmlName) {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ XML xml = getXmlFromAnnotation(i);
+
+ result.addToList(xml.processingInstructions(xmlName));
+ }
+
+ return result;
+ }
+
+ boolean propertyIsEnumerable(Object name) {
+ long index;
+ if (name instanceof Integer) {
+ index = ((Integer)name).intValue();
+ } else if (name instanceof Number) {
+ double x = ((Number)name).doubleValue();
+ index = (long)x;
+ if (index != x) {
+ return false;
+ }
+ if (index == 0 && 1.0 / x < 0) {
+ // Negative 0
+ return false;
+ }
+ } else {
+ String s = ScriptRuntime.toString(name);
+ index = ScriptRuntime.testUint32String(s);
+ }
+ return (0 <= index && index < length());
+ }
+
+ XMLList text() {
+ XMLList result = newXMLList();
+
+ for (int i = 0; i < length(); i++) {
+ result.addToList(getXmlFromAnnotation(i).text());
+ }
+
+ return result;
+ }
+
+ public String toString() {
+ // ECMA357 10.1.2
+ if (hasSimpleContent()) {
+ StringBuffer sb = new StringBuffer();
+
+ for(int i = 0; i < length(); i++) {
+ XML next = getXmlFromAnnotation(i);
+ if (next.isComment() || next.isProcessingInstruction()) {
+ // do nothing
+ } else {
+ sb.append(next.toString());
+ }
+ }
+
+ return sb.toString();
+ } else {
+ return toXMLString();
+ }
+ }
+
+ String toXMLString() {
+ // See ECMA 10.2.1
+ StringBuffer sb = new StringBuffer();
+
+ for (int i=0; i<length(); i++) {
+ if (getProcessor().isPrettyPrinting() && i != 0) {
+ sb.append('\n');
+ }
+ sb.append(getXmlFromAnnotation(i).toXMLString());
+ }
+ return sb.toString();
+ }
+
+ Object valueOf() {
+ return this;
+ }
+
+ //
+ // Other public Functions from XMLObject
+ //
+
+ boolean equivalentXml(Object target) {
+ boolean result = false;
+
+ // Zero length list should equate to undefined
+ if (target instanceof Undefined && length() == 0) {
+ result = true;
+ } else if (length() == 1) {
+ result = getXmlFromAnnotation(0).equivalentXml(target);
+ } else if (target instanceof XMLList) {
+ XMLList otherList = (XMLList) target;
+
+ if (otherList.length() == length()) {
+ result = true;
+
+ for (int i = 0; i < length(); i++) {
+ if (!getXmlFromAnnotation(i).equivalentXml(otherList.getXmlFromAnnotation(i))) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private XMLList getPropertyList(XMLName name) {
+ XMLList propertyList = newXMLList();
+ XmlNode.QName qname = null;
+
+ if (!name.isDescendants() && !name.isAttributeName()) {
+ // Only set the targetProperty if this is a regular child get
+ // and not a descendant or attribute get
+ qname = name.toQname();
+ }
+
+ propertyList.setTargets(this, qname);
+
+ for (int i = 0; i < length(); i++) {
+ propertyList.addToList(
+ getXmlFromAnnotation(i).getPropertyList(name));
+ }
+
+ return propertyList;
+ }
+
+ private Object applyOrCall(boolean isApply,
+ Context cx, Scriptable scope,
+ Scriptable thisObj, Object[] args) {
+ String methodName = isApply ? "apply" : "call";
+ if(!(thisObj instanceof XMLList) ||
+ ((XMLList)thisObj).targetProperty == null)
+ throw ScriptRuntime.typeError1("msg.isnt.function",
+ methodName);
+
+ return ScriptRuntime.applyOrCall(isApply, cx, scope, thisObj, args);
+ }
+
+ protected Object jsConstructor(Context cx, boolean inNewExpr,
+ Object[] args) {
+ if (args.length == 0) {
+ return newXMLList();
+ } else {
+ Object arg0 = args[0];
+ if (!inNewExpr && arg0 instanceof XMLList) {
+ // XMLList(XMLList) returns the same object.
+ return arg0;
+ }
+ return newXMLListFrom(arg0);
+ }
+ }
+
+ /**
+ * See ECMA 357, 11_2_2_1, Semantics, 3_e.
+ */
+ public Scriptable getExtraMethodSource(Context cx) {
+ if (length() == 1) {
+ return getXmlFromAnnotation(0);
+ }
+ return null;
+ }
+
+ public Object call(Context cx, Scriptable scope, Scriptable thisObj,
+ Object[] args) {
+ // This XMLList is being called as a Function.
+ // Let's find the real Function object.
+ if(targetProperty == null)
+ throw ScriptRuntime.notFunctionError(this);
+
+ String methodName = targetProperty.getLocalName();
+
+ boolean isApply = methodName.equals("apply");
+ if(isApply || methodName.equals("call"))
+ return applyOrCall(isApply, cx, scope, thisObj, args);
+
+ Callable method = ScriptRuntime.getElemFunctionAndThis(
+ this, methodName, cx);
+ // Call lastStoredScriptable to clear stored thisObj
+ // but ignore the result as the method should use the supplied
+ // thisObj, not one from redirected call
+ ScriptRuntime.lastStoredScriptable(cx);
+ return method.call(cx, scope, thisObj, args);
+ }
+
+ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
+ throw ScriptRuntime.typeError1("msg.not.ctor", "XMLList");
+ }
+}
+
+
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java
new file mode 100644
index 0000000..edd7525
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLName.java
@@ -0,0 +1,469 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * Milen Nankov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+
+class XMLName extends Ref {
+ static final long serialVersionUID = 3832176310755686977L;
+
+ private static boolean isNCNameStartChar(int c) {
+ if ((c & ~0x7F) == 0) {
+ // Optimize for ASCII and use A..Z < _ < a..z
+ if (c >= 'a') {
+ return c <= 'z';
+ } else if (c >= 'A') {
+ if (c <= 'Z') {
+ return true;
+ }
+ return c == '_';
+ }
+ } else if ((c & ~0x1FFF) == 0) {
+ return (0xC0 <= c && c <= 0xD6)
+ || (0xD8 <= c && c <= 0xF6)
+ || (0xF8 <= c && c <= 0x2FF)
+ || (0x370 <= c && c <= 0x37D)
+ || 0x37F <= c;
+ }
+ return (0x200C <= c && c <= 0x200D)
+ || (0x2070 <= c && c <= 0x218F)
+ || (0x2C00 <= c && c <= 0x2FEF)
+ || (0x3001 <= c && c <= 0xD7FF)
+ || (0xF900 <= c && c <= 0xFDCF)
+ || (0xFDF0 <= c && c <= 0xFFFD)
+ || (0x10000 <= c && c <= 0xEFFFF);
+ }
+
+ private static boolean isNCNameChar(int c) {
+ if ((c & ~0x7F) == 0) {
+ // Optimize for ASCII and use - < . < 0..9 < A..Z < _ < a..z
+ if (c >= 'a') {
+ return c <= 'z';
+ } else if (c >= 'A') {
+ if (c <= 'Z') {
+ return true;
+ }
+ return c == '_';
+ } else if (c >= '0') {
+ return c <= '9';
+ } else {
+ return c == '-' || c == '.';
+ }
+ } else if ((c & ~0x1FFF) == 0) {
+ return isNCNameStartChar(c) || c == 0xB7
+ || (0x300 <= c && c <= 0x36F);
+ }
+ return isNCNameStartChar(c) || (0x203F <= c && c <= 0x2040);
+ }
+
+ // This means "accept" in the parsing sense
+ // See ECMA357 13.1.2.1
+ static boolean accept(Object nameObj) {
+ String name;
+ try {
+ name = ScriptRuntime.toString(nameObj);
+ } catch (EcmaError ee) {
+ if ("TypeError".equals(ee.getName())) {
+ return false;
+ }
+ throw ee;
+ }
+
+ // See http://w3.org/TR/xml-names11/#NT-NCName
+ int length = name.length();
+ if (length != 0) {
+ if (isNCNameStartChar(name.charAt(0))) {
+ for (int i = 1; i != length; ++i) {
+ if (!isNCNameChar(name.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private XmlNode.QName qname;
+ private boolean isAttributeName;
+ private boolean isDescendants;
+ private XMLObjectImpl xmlObject;
+
+ private XMLName() {
+ }
+
+ static XMLName formStar() {
+ XMLName rv = new XMLName();
+ rv.qname = XmlNode.QName.create(null, null);
+ return rv;
+ }
+
+ /** @deprecated */
+ static XMLName formProperty(XmlNode.Namespace namespace, String localName) {
+ if (localName != null && localName.equals("*")) localName = null;
+ XMLName rv = new XMLName();
+ rv.qname = XmlNode.QName.create(namespace, localName);
+ return rv;
+ }
+
+ /** @deprecated */
+ static XMLName formProperty(String uri, String localName) {
+ return formProperty(XmlNode.Namespace.create(uri), localName);
+ }
+
+ /** @deprecated */
+ static XMLName create(String defaultNamespaceUri, String name) {
+ if (name == null)
+ throw new IllegalArgumentException();
+
+ int l = name.length();
+ if (l != 0) {
+ char firstChar = name.charAt(0);
+ if (firstChar == '*') {
+ if (l == 1) {
+ return XMLName.formStar();
+ }
+ } else if (firstChar == '@') {
+ XMLName xmlName = XMLName.formProperty("", name.substring(1));
+ xmlName.setAttributeName();
+ return xmlName;
+ }
+ }
+
+ return XMLName.formProperty(defaultNamespaceUri, name);
+ }
+
+ static XMLName create(XmlNode.QName qname, boolean attribute, boolean descendants) {
+ XMLName rv = new XMLName();
+ rv.qname = qname;
+ rv.isAttributeName = attribute;
+ rv.isDescendants = descendants;
+ return rv;
+ }
+
+ /** @deprecated */
+ static XMLName create(XmlNode.QName qname) {
+ return create(qname, false, false);
+ }
+
+ void initXMLObject(XMLObjectImpl xmlObject) {
+ if (xmlObject == null) throw new IllegalArgumentException();
+ if (this.xmlObject != null) throw new IllegalStateException();
+ this.xmlObject = xmlObject;
+ }
+
+ String uri() {
+ if (qname.getNamespace() == null) return null;
+ return qname.getNamespace().getUri();
+ }
+
+ String localName() {
+ if (qname.getLocalName() == null) return "*";
+ return qname.getLocalName();
+ }
+
+ private void addDescendantChildren(XMLList list, XML target) {
+ XMLName xmlName = this;
+ if (target.isElement()) {
+ XML[] children = target.getChildren();
+ for (int i=0; i<children.length; i++) {
+ if (xmlName.matches( children[i] )) {
+ list.addToList( children[i] );
+ }
+ addDescendantChildren(list, children[i]);
+ }
+ }
+ }
+
+ void addMatchingAttributes(XMLList list, XML target) {
+ XMLName name = this;
+ if (target.isElement()) {
+ XML[] attributes = target.getAttributes();
+ for (int i=0; i<attributes.length; i++) {
+ if (name.matches( attributes[i]) ) {
+ list.addToList( attributes[i] );
+ }
+ }
+ }
+ }
+
+ private void addDescendantAttributes(XMLList list, XML target) {
+ if (target.isElement()) {
+ addMatchingAttributes(list, target);
+ XML[] children = target.getChildren();
+ for (int i=0; i<children.length; i++) {
+ addDescendantAttributes(list, children[i]);
+ }
+ }
+ }
+
+ XMLList matchDescendantAttributes(XMLList rv, XML target) {
+ rv.setTargets(target, null);
+ addDescendantAttributes(rv, target);
+ return rv;
+ }
+
+ XMLList matchDescendantChildren(XMLList rv, XML target) {
+ rv.setTargets(target, null);
+ addDescendantChildren(rv, target);
+ return rv;
+ }
+
+ void addDescendants(XMLList rv, XML target) {
+ XMLName xmlName = this;
+ if (xmlName.isAttributeName()) {
+ matchDescendantAttributes(rv, target);
+ } else {
+ matchDescendantChildren(rv, target);
+ }
+ }
+
+ private void addAttributes(XMLList rv, XML target) {
+ addMatchingAttributes(rv, target);
+ }
+
+ void addMatches(XMLList rv, XML target) {
+ if (isDescendants()) {
+ addDescendants(rv, target);
+ } else if (isAttributeName()) {
+ addAttributes(rv, target);
+ } else {
+ XML[] children = target.getChildren();
+ if (children != null) {
+ for (int i=0; i<children.length; i++) {
+ if (this.matches(children[i])) {
+ rv.addToList( children[i] );
+ }
+ }
+ }
+ rv.setTargets(target, this.toQname());
+ }
+ }
+
+ XMLList getMyValueOn(XML target) {
+ XMLList rv = target.newXMLList();
+ addMatches(rv, target);
+ return rv;
+ }
+
+ void setMyValueOn(XML target, Object value) {
+ // Special-case checks for undefined and null
+ if (value == null) {
+ value = "null";
+ } else if (value instanceof Undefined) {
+ value = "undefined";
+ }
+
+ XMLName xmlName = this;
+ // Get the named property
+ if (xmlName.isAttributeName()) {
+ target.setAttribute(xmlName, value);
+ } else if (xmlName.uri() == null && xmlName.localName().equals("*")) {
+ target.setChildren(value);
+ } else {
+ // Convert text into XML if needed.
+ XMLObjectImpl xmlValue = null;
+
+ if (value instanceof XMLObjectImpl) {
+ xmlValue = (XMLObjectImpl)value;
+
+ // Check for attribute type and convert to textNode
+ if (xmlValue instanceof XML) {
+ if (((XML)xmlValue).isAttribute()) {
+ xmlValue = target.makeXmlFromString(xmlName, xmlValue.toString());
+ }
+ }
+
+ if (xmlValue instanceof XMLList) {
+ for (int i = 0; i < xmlValue.length(); i++) {
+ XML xml = ((XMLList) xmlValue).item(i);
+
+ if (xml.isAttribute()) {
+ ((XMLList)xmlValue).replace(i, target.makeXmlFromString(xmlName, xml.toString()));
+ }
+ }
+ }
+ } else {
+ xmlValue = target.makeXmlFromString(xmlName, ScriptRuntime.toString(value));
+ }
+
+ XMLList matches = target.getPropertyList(xmlName);
+
+ if (matches.length() == 0) {
+ target.appendChild(xmlValue);
+ } else {
+ // Remove all other matches
+ for (int i = 1; i < matches.length(); i++) {
+ target.removeChild(matches.item(i).childIndex());
+ }
+
+ // Replace first match with new value.
+ XML firstMatch = matches.item(0);
+ target.replace(firstMatch.childIndex(), xmlValue);
+ }
+ }
+ }
+
+ public boolean has(Context cx) {
+ if (xmlObject == null) {
+ return false;
+ }
+ return xmlObject.hasXMLProperty(this);
+ }
+
+ public Object get(Context cx) {
+ if (xmlObject == null) {
+ throw ScriptRuntime.undefReadError(Undefined.instance,
+ toString());
+ }
+ return xmlObject.getXMLProperty(this);
+ }
+
+ public Object set(Context cx, Object value) {
+ if (xmlObject == null) {
+ throw ScriptRuntime.undefWriteError(Undefined.instance,
+ toString(),
+ value);
+ }
+ // Assignment to descendants causes parse error on bad reference
+ // and this should not be called
+ if (isDescendants) throw Kit.codeBug();
+ xmlObject.putXMLProperty(this, value);
+ return value;
+ }
+
+ public boolean delete(Context cx) {
+ if (xmlObject == null) {
+ return true;
+ }
+ xmlObject.deleteXMLProperty(this);
+ return !xmlObject.hasXMLProperty(this);
+ }
+
+ public String toString() {
+ //return qname.localName();
+ StringBuffer buff = new StringBuffer();
+ if (isDescendants) buff.append("..");
+ if (isAttributeName) buff.append('@');
+ if (uri() == null) {
+ buff.append('*');
+ if(localName().equals("*")) {
+ return buff.toString();
+ }
+ } else {
+ buff.append('"').append(uri()).append('"');
+ }
+ buff.append(':').append(localName());
+ return buff.toString();
+ }
+
+ final XmlNode.QName toQname() {
+ return this.qname;
+ }
+
+ final boolean matchesLocalName(String localName) {
+ return localName().equals("*") || localName().equals(localName);
+ }
+
+ final boolean matchesElement(XmlNode.QName qname) {
+ if (this.uri() == null || this.uri().equals(qname.getNamespace().getUri())) {
+ if (this.localName().equals("*") || this.localName().equals(qname.getLocalName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ final boolean matches(XML node) {
+ XmlNode.QName qname = node.getNodeQname();
+ String nodeUri = null;
+ if (qname.getNamespace() != null) {
+ nodeUri = qname.getNamespace().getUri();
+ }
+ if (isAttributeName) {
+ if (node.isAttribute()) {
+ if (this.uri() == null || this.uri().equals(nodeUri)) {
+ if (this.localName().equals("*") || this.localName().equals(qname.getLocalName())) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ // TODO Could throw exception maybe, should not call this method on attribute name with arbitrary node type
+ // unless we traverse all attributes and children habitually
+ return false;
+ }
+ } else {
+ if ( this.uri() == null || ((node.isElement()) && this.uri().equals(nodeUri)) ) {
+ if (localName().equals("*")) return true;
+ if (node.isElement()) {
+ if (localName().equals(qname.getLocalName())) return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /** @deprecated */
+ boolean isAttributeName() {
+ return isAttributeName;
+ }
+
+ // TODO Fix whether this is an attribute XMLName at construction?
+ /** @deprecated */
+ void setAttributeName() {
+// if (isAttributeName) throw new IllegalStateException();
+ isAttributeName = true;
+ }
+
+ /** @deprecated */
+ boolean isDescendants() {
+ return isDescendants;
+ }
+
+ // TODO Fix whether this is an descendant XMLName at construction?
+ /** @deprecated */
+ void setIsDescendants() {
+// if (isDescendants) throw new IllegalStateException();
+ isDescendants = true;
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java
new file mode 100644
index 0000000..db918f8
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLObjectImpl.java
@@ -0,0 +1,812 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.*;
+
+/**
+ * This abstract class describes what all XML objects (XML, XMLList) should
+ * have in common.
+ *
+ * @see XML
+ */
+abstract class XMLObjectImpl extends XMLObject {
+ private static final Object XMLOBJECT_TAG = new Object();
+ private XMLLibImpl lib;
+ private boolean prototypeFlag;
+
+ protected XMLObjectImpl(XMLLibImpl lib, Scriptable scope,
+ XMLObject prototype)
+ {
+ initialize(lib, scope, prototype);
+ }
+
+ final void initialize(XMLLibImpl lib, Scriptable scope,
+ XMLObject prototype)
+ {
+ setParentScope(scope);
+ setPrototype(prototype);
+ prototypeFlag = (prototype == null);
+ this.lib = lib;
+ }
+
+ final boolean isPrototype() {
+ return prototypeFlag;
+ }
+
+ XMLLibImpl getLib() {
+ return lib;
+ }
+
+ final XML newXML(XmlNode node) {
+ return lib.newXML(node);
+ }
+
+ XML xmlFromNode(XmlNode node) {
+ if (node.getXml() == null) {
+ node.setXml( newXML(node) );
+ }
+ return node.getXml();
+ }
+
+ final XMLList newXMLList() {
+ return lib.newXMLList();
+ }
+
+ final XMLList newXMLListFrom(Object o) {
+ return lib.newXMLListFrom(o);
+ }
+
+ final XmlProcessor getProcessor() {
+ return lib.getProcessor();
+ }
+
+ final QName newQName(String uri, String localName, String prefix) {
+ return lib.newQName(uri, localName, prefix);
+ }
+
+ final QName newQName(XmlNode.QName name) {
+ return lib.newQName(name);
+ }
+
+ final Namespace createNamespace(XmlNode.Namespace declaration) {
+ if (declaration == null) return null;
+ return lib.createNamespaces( new XmlNode.Namespace[] { declaration } )[0];
+ }
+
+ final Namespace[] createNamespaces(XmlNode.Namespace[] declarations) {
+ return lib.createNamespaces(declarations);
+ }
+
+ //
+ // Scriptable
+ //
+
+ public final Object get(String name, Scriptable start) {
+ return super.get(name, start);
+ }
+
+ public final boolean has(String name, Scriptable start) {
+ return super.has(name, start);
+ }
+
+ public final void put(String name, Scriptable start, Object value) {
+ super.put(name, start, value);
+ }
+
+ public final void delete(String name) {
+ // TODO I am not sure about this, but this is how I found it. DPC
+ throw new IllegalArgumentException("String: [" + name + "]");
+ }
+
+ public final Scriptable getPrototype() {
+ return super.getPrototype();
+ }
+
+ public final void setPrototype(Scriptable prototype) {
+ super.setPrototype(prototype);
+ }
+
+ public final Scriptable getParentScope() {
+ return super.getParentScope();
+ }
+
+ public final void setParentScope(Scriptable parent) {
+ super.setParentScope(parent);
+ }
+
+ public final Object getDefaultValue(Class hint) {
+ return this.toString();
+ }
+
+ public final boolean hasInstance(Scriptable scriptable) {
+ return super.hasInstance(scriptable);
+ }
+
+ /**
+ * ecmaHas(cx, id) calls this after resolving when id to XMLName
+ * and checking it is not Uint32 index.
+ */
+ abstract boolean hasXMLProperty(XMLName name);
+
+ /**
+ * ecmaGet(cx, id) calls this after resolving when id to XMLName
+ * and checking it is not Uint32 index.
+ */
+ abstract Object getXMLProperty(XMLName name);
+
+ /**
+ * ecmaPut(cx, id, value) calls this after resolving when id to XMLName
+ * and checking it is not Uint32 index.
+ */
+ abstract void putXMLProperty(XMLName name, Object value);
+
+ /**
+ * ecmaDelete(cx, id) calls this after resolving when id to XMLName
+ * and checking it is not Uint32 index.
+ */
+ abstract void deleteXMLProperty(XMLName name);
+
+ /**
+ * Test XML equality with target the target.
+ */
+ abstract boolean equivalentXml(Object target);
+
+ abstract void addMatches(XMLList rv, XMLName name);
+
+ private XMLList getMatches(XMLName name) {
+ XMLList rv = newXMLList();
+ addMatches(rv, name);
+ return rv;
+ }
+
+ abstract XML getXML();
+
+ // Methods from section 12.4.4 in the spec
+ abstract XMLList child(int index);
+ abstract XMLList child(XMLName xmlName);
+ abstract XMLList children();
+ abstract XMLList comments();
+ abstract boolean contains(Object xml);
+ abstract XMLObjectImpl copy();
+ abstract XMLList elements(XMLName xmlName);
+ abstract boolean hasOwnProperty(XMLName xmlName);
+ abstract boolean hasComplexContent();
+ abstract boolean hasSimpleContent();
+ abstract int length();
+ abstract void normalize();
+ abstract Object parent();
+ abstract XMLList processingInstructions(XMLName xmlName);
+ abstract boolean propertyIsEnumerable(Object member);
+ abstract XMLList text();
+ public abstract String toString();
+ abstract String toXMLString();
+ abstract Object valueOf();
+
+ protected abstract Object jsConstructor(Context cx, boolean inNewExpr, Object[] args);
+
+ final Object getMethod(String id) {
+ return super.get(id, this);
+ }
+
+ //
+ //
+ // Methods overriding ScriptableObject
+ //
+ //
+
+ /**
+ * XMLObject always compare with any value and equivalentValues
+ * never returns {@link Scriptable#NOT_FOUND} for them but rather
+ * calls equivalentXml(value) and wrap the result as Boolean.
+ */
+ protected final Object equivalentValues(Object value) {
+ boolean result = equivalentXml(value);
+ return result ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ //
+ //
+ // Methods overriding XMLObject
+ //
+ //
+
+ /**
+ * Implementation of ECMAScript [[Has]]
+ */
+ public final boolean ecmaHas(Context cx, Object id) {
+ if (cx == null) cx = Context.getCurrentContext();
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
+ if (xmlName == null) {
+ long index = ScriptRuntime.lastUint32Result(cx);
+ // XXX Fix this cast
+ return has((int)index, this);
+ }
+ return hasXMLProperty(xmlName);
+ }
+
+ /**
+ * Implementation of ECMAScript [[Get]]
+ */
+ public final Object ecmaGet(Context cx, Object id) {
+ if (cx == null) cx = Context.getCurrentContext();
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
+ if (xmlName == null) {
+ long index = ScriptRuntime.lastUint32Result(cx);
+ // XXX Fix this cast
+ Object result = get((int)index, this);
+ if (result == Scriptable.NOT_FOUND) {
+ result = Undefined.instance;
+ }
+ return result;
+ }
+ return getXMLProperty(xmlName);
+ }
+
+ /**
+ * Implementation of ECMAScript [[Put]]
+ */
+ public final void ecmaPut(Context cx, Object id, Object value) {
+ if (cx == null) cx = Context.getCurrentContext();
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
+ if (xmlName == null) {
+ long index = ScriptRuntime.lastUint32Result(cx);
+ // XXX Fix this cast
+ put((int)index, this, value);
+ return;
+ }
+ putXMLProperty(xmlName, value);
+ }
+
+ /**
+ * Implementation of ECMAScript [[Delete]].
+ */
+ public final boolean ecmaDelete(Context cx, Object id) {
+ if (cx == null) cx = Context.getCurrentContext();
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
+ if (xmlName == null) {
+ long index = ScriptRuntime.lastUint32Result(cx);
+ // XXX Fix this
+ delete((int)index);
+ return true;
+ }
+ deleteXMLProperty(xmlName);
+ return true;
+ }
+
+ // TODO Can this be made more strongly typed?
+ public Ref memberRef(Context cx, Object elem, int memberTypeFlags) {
+ boolean attribute = (memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0;
+ boolean descendants = (memberTypeFlags & Node.DESCENDANTS_FLAG) != 0;
+ if (!attribute && !descendants) {
+ // Code generation would use ecma(Get|Has|Delete|Set) for
+ // normal name identifiers so one ATTRIBUTE_FLAG
+ // or DESCENDANTS_FLAG has to be set
+ throw Kit.codeBug();
+ }
+ XmlNode.QName qname = lib.toNodeQName(cx, elem, attribute);
+ XMLName rv = XMLName.create(qname, attribute, descendants);
+ rv.initXMLObject(this);
+ return rv;
+ }
+
+ /**
+ * Generic reference to implement x::ns, x.@ns::y, x..@ns::y etc.
+ */
+ public Ref memberRef(Context cx, Object namespace, Object elem, int memberTypeFlags) {
+ boolean attribute = (memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0;
+ boolean descendants = (memberTypeFlags & Node.DESCENDANTS_FLAG) != 0;
+ XMLName rv = XMLName.create(lib.toNodeQName(cx, namespace, elem), attribute, descendants);
+ rv.initXMLObject(this);
+ return rv;
+ }
+
+ public NativeWith enterWith(Scriptable scope) {
+ return new XMLWithScope(lib, scope, this);
+ }
+
+ public NativeWith enterDotQuery(Scriptable scope) {
+ XMLWithScope xws = new XMLWithScope(lib, scope, this);
+ xws.initAsDotQuery();
+ return xws;
+ }
+
+ public final Object addValues(Context cx, boolean thisIsLeft,
+ Object value) {
+ if (value instanceof XMLObject) {
+ XMLObject v1, v2;
+ if (thisIsLeft) {
+ v1 = this;
+ v2 = (XMLObject)value;
+ } else {
+ v1 = (XMLObject)value;
+ v2 = this;
+ }
+ return lib.addXMLObjects(cx, v1, v2);
+ }
+ if (value == Undefined.instance) {
+ // both "xml + undefined" and "undefined + xml" gives String(xml)
+ return ScriptRuntime.toString(this);
+ }
+
+ return super.addValues(cx, thisIsLeft, value);
+ }
+
+ //
+ //
+ // IdScriptableObject machinery
+ //
+ //
+
+ final void exportAsJSClass(boolean sealed) {
+ prototypeFlag = true;
+ exportAsJSClass(MAX_PROTOTYPE_ID, getParentScope(), sealed);
+ }
+
+// #string_id_map#
+ private final static int
+ Id_constructor = 1,
+
+ Id_addNamespace = 2,
+ Id_appendChild = 3,
+ Id_attribute = 4,
+ Id_attributes = 5,
+ Id_child = 6,
+ Id_childIndex = 7,
+ Id_children = 8,
+ Id_comments = 9,
+ Id_contains = 10,
+ Id_copy = 11,
+ Id_descendants = 12,
+ Id_elements = 13,
+ Id_inScopeNamespaces = 14,
+ Id_insertChildAfter = 15,
+ Id_insertChildBefore = 16,
+ Id_hasOwnProperty = 17,
+ Id_hasComplexContent = 18,
+ Id_hasSimpleContent = 19,
+ Id_length = 20,
+ Id_localName = 21,
+ Id_name = 22,
+ Id_namespace = 23,
+ Id_namespaceDeclarations = 24,
+ Id_nodeKind = 25,
+ Id_normalize = 26,
+ Id_parent = 27,
+ Id_prependChild = 28,
+ Id_processingInstructions = 29,
+ Id_propertyIsEnumerable = 30,
+ Id_removeNamespace = 31,
+ Id_replace = 32,
+ Id_setChildren = 33,
+ Id_setLocalName = 34,
+ Id_setName = 35,
+ Id_setNamespace = 36,
+ Id_text = 37,
+ Id_toString = 38,
+ Id_toXMLString = 39,
+ Id_valueOf = 40,
+
+ MAX_PROTOTYPE_ID = 40;
+
+ protected int findPrototypeId(String s) {
+ int id;
+// #generated# Last update: 2007-08-20 09:04:06 EDT
+ L0: { id = 0; String X = null; int c;
+ L: switch (s.length()) {
+ case 4: c=s.charAt(0);
+ if (c=='c') { X="copy";id=Id_copy; }
+ else if (c=='n') { X="name";id=Id_name; }
+ else if (c=='t') { X="text";id=Id_text; }
+ break L;
+ case 5: X="child";id=Id_child; break L;
+ case 6: c=s.charAt(0);
+ if (c=='l') { X="length";id=Id_length; }
+ else if (c=='p') { X="parent";id=Id_parent; }
+ break L;
+ case 7: c=s.charAt(0);
+ if (c=='r') { X="replace";id=Id_replace; }
+ else if (c=='s') { X="setName";id=Id_setName; }
+ else if (c=='v') { X="valueOf";id=Id_valueOf; }
+ break L;
+ case 8: switch (s.charAt(2)) {
+ case 'S': X="toString";id=Id_toString; break L;
+ case 'd': X="nodeKind";id=Id_nodeKind; break L;
+ case 'e': X="elements";id=Id_elements; break L;
+ case 'i': X="children";id=Id_children; break L;
+ case 'm': X="comments";id=Id_comments; break L;
+ case 'n': X="contains";id=Id_contains; break L;
+ } break L;
+ case 9: switch (s.charAt(2)) {
+ case 'c': X="localName";id=Id_localName; break L;
+ case 'm': X="namespace";id=Id_namespace; break L;
+ case 'r': X="normalize";id=Id_normalize; break L;
+ case 't': X="attribute";id=Id_attribute; break L;
+ } break L;
+ case 10: c=s.charAt(0);
+ if (c=='a') { X="attributes";id=Id_attributes; }
+ else if (c=='c') { X="childIndex";id=Id_childIndex; }
+ break L;
+ case 11: switch (s.charAt(0)) {
+ case 'a': X="appendChild";id=Id_appendChild; break L;
+ case 'c': X="constructor";id=Id_constructor; break L;
+ case 'd': X="descendants";id=Id_descendants; break L;
+ case 's': X="setChildren";id=Id_setChildren; break L;
+ case 't': X="toXMLString";id=Id_toXMLString; break L;
+ } break L;
+ case 12: c=s.charAt(0);
+ if (c=='a') { X="addNamespace";id=Id_addNamespace; }
+ else if (c=='p') { X="prependChild";id=Id_prependChild; }
+ else if (c=='s') {
+ c=s.charAt(3);
+ if (c=='L') { X="setLocalName";id=Id_setLocalName; }
+ else if (c=='N') { X="setNamespace";id=Id_setNamespace; }
+ }
+ break L;
+ case 14: X="hasOwnProperty";id=Id_hasOwnProperty; break L;
+ case 15: X="removeNamespace";id=Id_removeNamespace; break L;
+ case 16: c=s.charAt(0);
+ if (c=='h') { X="hasSimpleContent";id=Id_hasSimpleContent; }
+ else if (c=='i') { X="insertChildAfter";id=Id_insertChildAfter; }
+ break L;
+ case 17: c=s.charAt(3);
+ if (c=='C') { X="hasComplexContent";id=Id_hasComplexContent; }
+ else if (c=='c') { X="inScopeNamespaces";id=Id_inScopeNamespaces; }
+ else if (c=='e') { X="insertChildBefore";id=Id_insertChildBefore; }
+ break L;
+ case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L;
+ case 21: X="namespaceDeclarations";id=Id_namespaceDeclarations; break L;
+ case 22: X="processingInstructions";id=Id_processingInstructions; break L;
+ }
+ if (X!=null && X!=s && !X.equals(s)) id = 0;
+ break L0;
+ }
+// #/generated#
+ return id;
+ }
+// #/string_id_map#
+
+ protected void initPrototypeId(int id) {
+ String s;
+ int arity;
+ switch (id) {
+ case Id_constructor: {
+ IdFunctionObject ctor;
+ if (this instanceof XML) {
+ ctor = new XMLCtor((XML)this, XMLOBJECT_TAG, id, 1);
+ } else {
+ ctor = new IdFunctionObject(this, XMLOBJECT_TAG, id, 1);
+ }
+ initPrototypeConstructor(ctor);
+ return;
+ }
+
+ case Id_addNamespace: arity=1; s="addNamespace"; break;
+ case Id_appendChild: arity=1; s="appendChild"; break;
+ case Id_attribute: arity=1; s="attribute"; break;
+ case Id_attributes: arity=0; s="attributes"; break;
+ case Id_child: arity=1; s="child"; break;
+ case Id_childIndex: arity=0; s="childIndex"; break;
+ case Id_children: arity=0; s="children"; break;
+ case Id_comments: arity=0; s="comments"; break;
+ case Id_contains: arity=1; s="contains"; break;
+ case Id_copy: arity=0; s="copy"; break;
+ case Id_descendants: arity=1; s="descendants"; break;
+ case Id_elements: arity=1; s="elements"; break;
+ case Id_hasComplexContent: arity=0; s="hasComplexContent"; break;
+ case Id_hasOwnProperty: arity=1; s="hasOwnProperty"; break;
+ case Id_hasSimpleContent: arity=0; s="hasSimpleContent"; break;
+ case Id_inScopeNamespaces: arity=0; s="inScopeNamespaces"; break;
+ case Id_insertChildAfter: arity=2; s="insertChildAfter"; break;
+ case Id_insertChildBefore: arity=2; s="insertChildBefore"; break;
+ case Id_length: arity=0; s="length"; break;
+ case Id_localName: arity=0; s="localName"; break;
+ case Id_name: arity=0; s="name"; break;
+ case Id_namespace: arity=1; s="namespace"; break;
+ case Id_namespaceDeclarations:
+ arity=0; s="namespaceDeclarations"; break;
+ case Id_nodeKind: arity=0; s="nodeKind"; break;
+ case Id_normalize: arity=0; s="normalize"; break;
+ case Id_parent: arity=0; s="parent"; break;
+ case Id_prependChild: arity=1; s="prependChild"; break;
+ case Id_processingInstructions:
+ arity=1; s="processingInstructions"; break;
+ case Id_propertyIsEnumerable:
+ arity=1; s="propertyIsEnumerable"; break;
+ case Id_removeNamespace: arity=1; s="removeNamespace"; break;
+ case Id_replace: arity=2; s="replace"; break;
+ case Id_setChildren: arity=1; s="setChildren"; break;
+ case Id_setLocalName: arity=1; s="setLocalName"; break;
+ case Id_setName: arity=1; s="setName"; break;
+ case Id_setNamespace: arity=1; s="setNamespace"; break;
+ case Id_text: arity=0; s="text"; break;
+ case Id_toString: arity=0; s="toString"; break;
+ case Id_toXMLString: arity=1; s="toXMLString"; break;
+ case Id_valueOf: arity=0; s="valueOf"; break;
+
+ default: throw new IllegalArgumentException(String.valueOf(id));
+ }
+ initPrototypeMethod(XMLOBJECT_TAG, id, s, arity);
+ }
+
+ private Object[] toObjectArray(Object[] typed) {
+ Object[] rv = new Object[typed.length];
+ for (int i=0; i<rv.length; i++) {
+ rv[i] = typed[i];
+ }
+ return rv;
+ }
+
+ private void xmlMethodNotFound(Object object, String name) {
+ throw ScriptRuntime.notFunctionError(object, name);
+ }
+
+ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
+ if (!f.hasTag(XMLOBJECT_TAG)) {
+ return super.execIdCall(f, cx, scope, thisObj, args);
+ }
+ int id = f.methodId();
+ if (id == Id_constructor) {
+ return jsConstructor(cx, thisObj == null, args);
+ }
+
+ // All (XML|XMLList).prototype methods require thisObj to be XML
+ if (!(thisObj instanceof XMLObjectImpl))
+ throw incompatibleCallError(f);
+ XMLObjectImpl realThis = (XMLObjectImpl)thisObj;
+
+ XML xml = realThis.getXML();
+ switch (id) {
+ case Id_appendChild: {
+ if (xml == null) xmlMethodNotFound(realThis, "appendChild");
+ return xml.appendChild(arg(args, 0));
+ }
+ case Id_addNamespace: {
+ if (xml == null) xmlMethodNotFound(realThis, "addNamespace");
+ Namespace ns = lib.castToNamespace(cx, arg(args, 0));
+ return xml.addNamespace(ns);
+ }
+ case Id_childIndex: {
+ if (xml == null) xmlMethodNotFound(realThis, "childIndex");
+ return ScriptRuntime.wrapInt(xml.childIndex());
+ }
+ case Id_inScopeNamespaces: {
+ if (xml == null) xmlMethodNotFound(realThis, "inScopeNamespaces");
+ return cx.newArray(scope, toObjectArray(xml.inScopeNamespaces()));
+ }
+ case Id_insertChildAfter: {
+ if (xml == null) xmlMethodNotFound(realThis, "insertChildAfter");
+ Object arg0 = arg(args, 0);
+ if (arg0 == null || arg0 instanceof XML) {
+ return xml.insertChildAfter((XML)arg0, arg(args, 1));
+ }
+ return Undefined.instance;
+ }
+ case Id_insertChildBefore: {
+ if (xml == null) xmlMethodNotFound(realThis, "insertChildBefore");
+ Object arg0 = arg(args, 0);
+ if (arg0 == null || arg0 instanceof XML) {
+ return xml.insertChildBefore((XML)arg0, arg(args, 1));
+ }
+ return Undefined.instance;
+ }
+ case Id_localName: {
+ if (xml == null) xmlMethodNotFound(realThis, "localName");
+ return xml.localName();
+ }
+ case Id_name: {
+ if (xml == null) xmlMethodNotFound(realThis, "name");
+ return xml.name();
+ }
+ case Id_namespace: {
+ if (xml == null) xmlMethodNotFound(realThis, "namespace");
+ String prefix = (args.length > 0) ? ScriptRuntime.toString(args[0]) : null;
+ Namespace rv = xml.namespace(prefix);
+ if (rv == null) {
+ return Undefined.instance;
+ } else {
+ return rv;
+ }
+ }
+ case Id_namespaceDeclarations: {
+ if (xml == null) xmlMethodNotFound(realThis, "namespaceDeclarations");
+ Namespace[] array = xml.namespaceDeclarations();
+ return cx.newArray(scope, toObjectArray(array));
+ }
+ case Id_nodeKind: {
+ if (xml == null) xmlMethodNotFound(realThis, "nodeKind");
+ return xml.nodeKind();
+ }
+ case Id_prependChild: {
+ if (xml == null) xmlMethodNotFound(realThis, "prependChild");
+ return xml.prependChild(arg(args, 0));
+ }
+ case Id_removeNamespace: {
+ if (xml == null) xmlMethodNotFound(realThis, "removeNamespace");
+ Namespace ns = lib.castToNamespace(cx, arg(args, 0));
+ return xml.removeNamespace(ns);
+ }
+ case Id_replace: {
+ if (xml == null) xmlMethodNotFound(realThis, "replace");
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, arg(args, 0));
+ Object arg1 = arg(args, 1);
+ if (xmlName == null) {
+ // I refuse to believe that this number will exceed 2^31
+ int index = (int)ScriptRuntime.lastUint32Result(cx);
+ return xml.replace(index, arg1);
+ } else {
+ return xml.replace(xmlName, arg1);
+ }
+ }
+ case Id_setChildren: {
+ if (xml == null) xmlMethodNotFound(realThis, "setChildren");
+ return xml.setChildren(arg(args, 0));
+ }
+ case Id_setLocalName: {
+ if (xml == null) xmlMethodNotFound(realThis, "setLocalName");
+ String localName;
+ Object arg = arg(args, 0);
+ if (arg instanceof QName) {
+ localName = ((QName)arg).localName();
+ } else {
+ localName = ScriptRuntime.toString(arg);
+ }
+ xml.setLocalName(localName);
+ return Undefined.instance;
+ }
+ case Id_setName: {
+ if (xml == null) xmlMethodNotFound(realThis, "setName");
+ Object arg = (args.length != 0) ? args[0] : Undefined.instance;
+ QName qname = lib.constructQName(cx, arg);
+ xml.setName(qname);
+ return Undefined.instance;
+ }
+ case Id_setNamespace: {
+ if (xml == null) xmlMethodNotFound(realThis, "setNamespace");
+ Namespace ns = lib.castToNamespace(cx, arg(args, 0));
+ xml.setNamespace(ns);
+ return Undefined.instance;
+ }
+
+ case Id_attribute: {
+ XMLName xmlName = XMLName.create( lib.toNodeQName(cx, arg(args, 0), true), true, false );
+ return realThis.getMatches(xmlName);
+ }
+ case Id_attributes:
+ return realThis.getMatches(XMLName.create(XmlNode.QName.create(null, null), true, false));
+ case Id_child: {
+ XMLName xmlName = lib.toXMLNameOrIndex(cx, arg(args, 0));
+ if (xmlName == null) {
+ // Two billion or so is a fine upper limit, so we cast to int
+ int index = (int)ScriptRuntime.lastUint32Result(cx);
+ return realThis.child(index);
+ } else {
+ return realThis.child(xmlName);
+ }
+ }
+ case Id_children:
+ return realThis.children();
+ case Id_comments:
+ return realThis.comments();
+ case Id_contains:
+ return ScriptRuntime.wrapBoolean(
+ realThis.contains(arg(args, 0)));
+ case Id_copy:
+ return realThis.copy();
+ case Id_descendants: {
+ XmlNode.QName qname = (args.length == 0) ? XmlNode.QName.create(null, null) : lib.toNodeQName(cx, args[0], false);
+ return realThis.getMatches( XMLName.create(qname, false, true) );
+ }
+ case Id_elements: {
+ XMLName xmlName = (args.length == 0)
+ ? XMLName.formStar()
+ : lib.toXMLName(cx, args[0]);
+ return realThis.elements(xmlName);
+ }
+ case Id_hasOwnProperty: {
+ XMLName xmlName = lib.toXMLName(cx, arg(args, 0));
+ return ScriptRuntime.wrapBoolean(
+ realThis.hasOwnProperty(xmlName));
+ }
+ case Id_hasComplexContent:
+ return ScriptRuntime.wrapBoolean(realThis.hasComplexContent());
+ case Id_hasSimpleContent:
+ return ScriptRuntime.wrapBoolean(realThis.hasSimpleContent());
+ case Id_length:
+ return ScriptRuntime.wrapInt(realThis.length());
+ case Id_normalize:
+ realThis.normalize();
+ return Undefined.instance;
+ case Id_parent:
+ return realThis.parent();
+ case Id_processingInstructions: {
+ XMLName xmlName = (args.length > 0)
+ ? lib.toXMLName(cx, args[0])
+ : XMLName.formStar();
+ return realThis.processingInstructions(xmlName);
+ }
+ case Id_propertyIsEnumerable: {
+ return ScriptRuntime.wrapBoolean(
+ realThis.propertyIsEnumerable(arg(args, 0)));
+ }
+ case Id_text:
+ return realThis.text();
+ case Id_toString:
+ return realThis.toString();
+ case Id_toXMLString: {
+ return realThis.toXMLString();
+ }
+ case Id_valueOf:
+ return realThis.valueOf();
+ }
+ throw new IllegalArgumentException(String.valueOf(id));
+ }
+
+ private static Object arg(Object[] args, int i) {
+ return (i < args.length) ? args[i] : Undefined.instance;
+ }
+
+ final XML newTextElementXML(XmlNode reference, XmlNode.QName qname, String value) {
+ return lib.newTextElementXML(reference, qname, value);
+ }
+
+ /** @deprecated Hopefully this can be replaced with ecmaToXml below. */
+ final XML newXMLFromJs(Object inputObject) {
+ return lib.newXMLFromJs(inputObject);
+ }
+
+ final XML ecmaToXml(Object object) {
+ return lib.ecmaToXml(object);
+ }
+
+ final String ecmaEscapeAttributeValue(String s) {
+ // TODO Check this
+ String quoted = lib.escapeAttributeValue(s);
+ return quoted.substring(1, quoted.length() - 1);
+ }
+
+ final XML createEmptyXML() {
+ return newXML(XmlNode.createEmpty(getProcessor()));
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java
new file mode 100644
index 0000000..fbeb45e
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XMLWithScope.java
@@ -0,0 +1,125 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Norris Boyd
+ * Ethan Hugg
+ * Terry Lucas
+ * Milen Nankov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.xml.*;
+
+final class XMLWithScope extends NativeWith
+{
+ private static final long serialVersionUID = -696429282095170887L;
+
+ private XMLLibImpl lib;
+ private int _currIndex;
+ private XMLList _xmlList;
+ private XMLObject _dqPrototype;
+
+ XMLWithScope(XMLLibImpl lib, Scriptable parent, XMLObject prototype)
+ {
+ super(parent, prototype);
+ this.lib = lib;
+ }
+
+ void initAsDotQuery()
+ {
+ XMLObject prototype = (XMLObject)getPrototype();
+ // XMLWithScope also handles the .(xxx) DotQuery for XML
+ // basically DotQuery is a for/in/with statement and in
+ // the following 3 statements we setup to signal it's
+ // DotQuery,
+ // the index and the object being looped over. The
+ // xws.setPrototype is the scope of the object which is
+ // is a element of the lhs (XMLList).
+ _currIndex = 0;
+ _dqPrototype = prototype;
+ if (prototype instanceof XMLList) {
+ XMLList xl = (XMLList)prototype;
+ if (xl.length() > 0) {
+ setPrototype((Scriptable)(xl.get(0, null)));
+ }
+ }
+ // Always return the outer-most type of XML lValue of
+ // XML to left of dotQuery.
+ _xmlList = lib.newXMLList();
+ }
+
+ protected Object updateDotQuery(boolean value)
+ {
+ // Return null to continue looping
+
+ XMLObject seed = _dqPrototype;
+ XMLList xmlL = _xmlList;
+
+ if (seed instanceof XMLList) {
+ // We're a list so keep testing each element of the list if the
+ // result on the top of stack is true then that element is added
+ // to our result list. If false, we try the next element.
+ XMLList orgXmlL = (XMLList)seed;
+
+ int idx = _currIndex;
+
+ if (value) {
+ xmlL.addToList(orgXmlL.get(idx, null));
+ }
+
+ // More elements to test?
+ if (++idx < orgXmlL.length()) {
+ // Yes, set our new index, get the next element and
+ // reset the expression to run with this object as
+ // the WITH selector.
+ _currIndex = idx;
+ setPrototype((Scriptable)(orgXmlL.get(idx, null)));
+
+ // continue looping
+ return null;
+ }
+ } else {
+ // If we're not a XMLList then there's no looping
+ // just return DQPrototype if the result is true.
+ if (value) {
+ xmlL.addToList(seed);
+ }
+ }
+
+ return xmlL;
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java
new file mode 100644
index 0000000..06955d0
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlNode.java
@@ -0,0 +1,869 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino DOM-only E4X implementation.
+ *
+ * The Initial Developer of the Original Code is
+ * David P. Caldwell.
+ * Portions created by David P. Caldwell are Copyright (C)
+ * 2007 David P. Caldwell. All Rights Reserved.
+ *
+ *
+ * Contributor(s):
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import java.util.*;
+
+import org.w3c.dom.*;
+
+import org.mozilla.javascript.*;
+
+// Disambiguate with org.mozilla.javascript
+import org.w3c.dom.Node;
+
+class XmlNode {
+ private static final String XML_NAMESPACES_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
+
+ private static final String USER_DATA_XMLNODE_KEY = XmlNode.class.getName();
+
+ private static final boolean DOM_LEVEL_3 = true;
+
+ private static XmlNode getUserData(Node node) {
+ if (DOM_LEVEL_3) {
+ return (XmlNode)node.getUserData(USER_DATA_XMLNODE_KEY);
+ }
+ return null;
+ }
+
+ private static void setUserData(Node node, XmlNode wrap) {
+ if (DOM_LEVEL_3) {
+ node.setUserData(USER_DATA_XMLNODE_KEY, wrap, wrap.events);
+ }
+ }
+
+ private static XmlNode createImpl(Node node) {
+ if (node instanceof Document) throw new IllegalArgumentException();
+ XmlNode rv = null;
+ if (getUserData(node) == null) {
+ rv = new XmlNode();
+ rv.dom = node;
+ setUserData(node, rv);
+ } else {
+ rv = getUserData(node);
+ }
+ return rv;
+ }
+
+ static XmlNode newElementWithText(XmlProcessor processor, XmlNode reference, XmlNode.QName qname, String value) {
+ if (reference instanceof org.w3c.dom.Document) throw new IllegalArgumentException("Cannot use Document node as reference");
+ Document document = null;
+ if (reference != null) {
+ document = reference.dom.getOwnerDocument();
+ } else {
+ document = processor.newDocument();
+ }
+ Node referenceDom = (reference != null) ? reference.dom : null;
+ Element e = document.createElementNS(qname.getUri(), qname.qualify(referenceDom));
+ if (value != null) {
+ e.appendChild(document.createTextNode(value));
+ }
+ return XmlNode.createImpl(e);
+ }
+
+ static XmlNode createText(XmlProcessor processor, String value) {
+ return createImpl( processor.newDocument().createTextNode(value) );
+ }
+
+ static XmlNode createElementFromNode(Node node) {
+ if (node instanceof Document)
+ node = ((Document) node).getDocumentElement();
+ return createImpl(node);
+ }
+
+ static XmlNode createElement(XmlProcessor processor, String namespaceUri, String xml) throws org.xml.sax.SAXException {
+ return createImpl( processor.toXml(namespaceUri, xml) );
+ }
+
+ static XmlNode createEmpty(XmlProcessor processor) {
+ return createText(processor, "");
+ }
+
+ private static XmlNode copy(XmlNode other) {
+ return createImpl( other.dom.cloneNode(true) );
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ private UserDataHandler events = new UserDataHandler() {
+ public void handle(short operation, String key, Object data, Node src, Node dest) {
+ }
+ };
+
+ private Node dom;
+
+ private XML xml;
+
+ private XmlNode() {
+ }
+
+ String debug() {
+ XmlProcessor raw = new XmlProcessor();
+ raw.setIgnoreComments(false);
+ raw.setIgnoreProcessingInstructions(false);
+ raw.setIgnoreWhitespace(false);
+ raw.setPrettyPrinting(false);
+ return raw.ecmaToXmlString(this.dom);
+ }
+
+ public String toString() {
+ return "XmlNode: type=" + dom.getNodeType() + " dom=" + dom.toString();
+ }
+
+ XML getXml() {
+ return xml;
+ }
+
+ void setXml(XML xml) {
+ this.xml = xml;
+ }
+
+ int getChildCount() {
+ return this.dom.getChildNodes().getLength();
+ }
+
+ XmlNode parent() {
+ Node domParent = dom.getParentNode();
+ if (domParent instanceof Document) return null;
+ if (domParent == null) return null;
+ return createImpl(domParent);
+ }
+
+ int getChildIndex() {
+ if (this.isAttributeType()) return -1;
+ if (parent() == null) return -1;
+ org.w3c.dom.NodeList siblings = this.dom.getParentNode().getChildNodes();
+ for (int i=0; i<siblings.getLength(); i++) {
+ if (siblings.item(i) == dom) {
+ return i;
+ }
+ }
+ // Either the parent is -1 or one of the this node's parent's children is this node.
+ throw new RuntimeException("Unreachable.");
+ }
+
+ void removeChild(int index) {
+ this.dom.removeChild( this.dom.getChildNodes().item(index) );
+ }
+
+ String toXmlString(XmlProcessor processor) {
+ return processor.ecmaToXmlString(this.dom);
+ }
+
+ String ecmaValue() {
+ // TODO See ECMA 357 Section 9.1
+ if (isTextType()) {
+ return ((org.w3c.dom.Text)dom).getData();
+ } else if (isAttributeType()) {
+ return ((org.w3c.dom.Attr)dom).getValue();
+ } else if (isProcessingInstructionType()) {
+ return ((org.w3c.dom.ProcessingInstruction)dom).getData();
+ } else if (isCommentType()) {
+ return ((org.w3c.dom.Comment)dom).getNodeValue();
+ } else if (isElementType()) {
+ throw new RuntimeException("Unimplemented ecmaValue() for elements.");
+ } else {
+ throw new RuntimeException("Unimplemented for node " + dom);
+ }
+ }
+
+ void deleteMe() {
+ if (dom instanceof Attr) {
+ Attr attr = (Attr)this.dom;
+ attr.getOwnerElement().getAttributes().removeNamedItemNS(attr.getNamespaceURI(), attr.getLocalName());
+ } else {
+ if (this.dom.getParentNode() != null) {
+ this.dom.getParentNode().removeChild(this.dom);
+ } else {
+ // This case can be exercised at least when executing the regression
+ // tests under https://bugzilla.mozilla.org/show_bug.cgi?id=354145
+ }
+ }
+ }
+
+ void normalize() {
+ this.dom.normalize();
+ }
+
+ void insertChildAt(int index, XmlNode node) {
+ Node parent = this.dom;
+ Node child = parent.getOwnerDocument().importNode( node.dom, true );
+ if (parent.getChildNodes().getLength() < index) {
+ // TODO Check ECMA for what happens here
+ throw new IllegalArgumentException("index=" + index + " length=" + parent.getChildNodes().getLength());
+ }
+ if (parent.getChildNodes().getLength() == index) {
+ parent.appendChild(child);
+ } else {
+ parent.insertBefore(child, parent.getChildNodes().item(index));
+ }
+ }
+
+ void insertChildrenAt(int index, XmlNode[] nodes) {
+ for (int i=0; i<nodes.length; i++) {
+ insertChildAt(index+i, nodes[i]);
+ }
+ }
+
+ XmlNode getChild(int index) {
+ Node child = dom.getChildNodes().item(index);
+ return createImpl(child);
+ }
+
+ // Helper method for XML.hasSimpleContent()
+ boolean hasChildElement() {
+ org.w3c.dom.NodeList nodes = this.dom.getChildNodes();
+ for (int i=0; i<nodes.getLength(); i++) {
+ if (nodes.item(i).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) return true;
+ }
+ return false;
+ }
+
+ boolean isSameNode(XmlNode other) {
+ // TODO May need to be changed if we allow XmlNode to refer to several Node objects
+ return this.dom == other.dom;
+ }
+
+ private String toUri(String ns) {
+ return (ns == null) ? "" : ns;
+ }
+
+ private void addNamespaces(Namespaces rv, Element element) {
+ if (element == null) throw new RuntimeException("element must not be null");
+ String myDefaultNamespace = toUri(element.lookupNamespaceURI(null));
+ String parentDefaultNamespace = "";
+ if (element.getParentNode() != null) {
+ parentDefaultNamespace = toUri(element.getParentNode().lookupNamespaceURI(null));
+ }
+ if (!myDefaultNamespace.equals(parentDefaultNamespace) || !(element.getParentNode() instanceof Element) ) {
+ rv.declare(Namespace.create("", myDefaultNamespace));
+ }
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i=0; i<attributes.getLength(); i++) {
+ Attr attr = (Attr)attributes.item(i);
+ if (attr.getPrefix() != null && attr.getPrefix().equals("xmlns")) {
+ rv.declare(Namespace.create(attr.getLocalName(), attr.getValue()));
+ }
+ }
+ }
+
+ private Namespaces getAllNamespaces() {
+ Namespaces rv = new Namespaces();
+
+ Node target = this.dom;
+ if (target instanceof Attr) {
+ target = ((Attr)target).getOwnerElement();
+ }
+ while(target != null) {
+ if (target instanceof Element) {
+ addNamespaces(rv, (Element)target);
+ }
+ target = target.getParentNode();
+ }
+ // Fallback in case no namespace was declared
+ rv.declare(Namespace.create("", ""));
+ return rv;
+ }
+
+ Namespace[] getInScopeNamespaces() {
+ Namespaces rv = getAllNamespaces();
+ return rv.getNamespaces();
+ }
+
+ Namespace[] getNamespaceDeclarations() {
+ // ECMA357 13.4.4.24
+ if (this.dom instanceof Element) {
+ Namespaces rv = new Namespaces();
+ addNamespaces( rv, (Element)this.dom );
+ return rv.getNamespaces();
+ } else {
+ return new Namespace[0];
+ }
+ }
+
+ Namespace getNamespaceDeclaration(String prefix) {
+ if (prefix.equals("") && dom instanceof Attr) {
+ // Default namespaces do not apply to attributes; see XML Namespaces section 5.2
+ return Namespace.create("", "");
+ }
+ Namespaces rv = getAllNamespaces();
+ return rv.getNamespace(prefix);
+ }
+
+ Namespace getNamespaceDeclaration() {
+ if (dom.getPrefix() == null) return getNamespaceDeclaration("");
+ return getNamespaceDeclaration(dom.getPrefix());
+ }
+
+ private static class Namespaces {
+ private HashMap map = new HashMap();
+ private HashMap uriToPrefix = new HashMap();
+
+ Namespaces() {
+ }
+
+ void declare(Namespace n) {
+ if (map.get(n.prefix) == null) {
+ map.put(n.prefix, n.uri);
+ }
+ // TODO I think this is analogous to the other way, but have not really thought it through ... should local scope
+ // matter more than outer scope?
+ if (uriToPrefix.get(n.uri) == null) {
+ uriToPrefix.put(n.uri, n.prefix);
+ }
+ }
+
+ Namespace getNamespaceByUri(String uri) {
+ if (uriToPrefix.get(uri) == null) return null;
+ return Namespace.create(uri, (String)uriToPrefix.get(uri));
+ }
+
+ Namespace getNamespace(String prefix) {
+ if (map.get(prefix) == null) return null;
+ return Namespace.create(prefix, (String)map.get(prefix));
+ }
+
+ Namespace[] getNamespaces() {
+ Iterator i = map.keySet().iterator();
+ ArrayList rv = new ArrayList();
+ while(i.hasNext()) {
+ String prefix = (String)i.next();
+ String uri = (String)map.get(prefix);
+ Namespace n = Namespace.create(prefix, uri);
+ if (!n.isEmpty()) {
+ rv.add( n );
+ }
+ }
+ return (Namespace[])rv.toArray(new Namespace[0]);
+ }
+ }
+
+ final XmlNode copy() {
+ return copy( this );
+ }
+
+ // Returns whether this node is capable of being a parent
+ final boolean isParentType() {
+ return isElementType();
+ }
+
+ final boolean isTextType() {
+ return dom.getNodeType() == Node.TEXT_NODE || dom.getNodeType() == Node.CDATA_SECTION_NODE;
+ }
+
+ final boolean isAttributeType() {
+ return dom.getNodeType() == Node.ATTRIBUTE_NODE;
+ }
+
+ final boolean isProcessingInstructionType() {
+ return dom.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE;
+ }
+
+ final boolean isCommentType() {
+ return dom.getNodeType() == Node.COMMENT_NODE;
+ }
+
+ final boolean isElementType() {
+ return dom.getNodeType() == Node.ELEMENT_NODE;
+ }
+
+ final void renameNode(QName qname) {
+ this.dom = dom.getOwnerDocument().renameNode(dom, qname.getUri(), qname.qualify(dom));
+ }
+
+ void invalidateNamespacePrefix() {
+ if (!(dom instanceof Element)) throw new IllegalStateException();
+ String prefix = this.dom.getPrefix();
+ QName after = QName.create(this.dom.getNamespaceURI(), this.dom.getLocalName(), null);
+ renameNode(after);
+ NamedNodeMap attrs = this.dom.getAttributes();
+ for (int i=0; i<attrs.getLength(); i++) {
+ if (attrs.item(i).getPrefix().equals(prefix)) {
+ createImpl( attrs.item(i) ).renameNode( QName.create(attrs.item(i).getNamespaceURI(), attrs.item(i).getLocalName(), null) );
+ }
+ }
+ }
+
+ private void declareNamespace(Element e, String prefix, String uri) {
+ if (prefix.length() > 0) {
+ e.setAttributeNS(XML_NAMESPACES_NAMESPACE_URI, "xmlns:" + prefix, uri);
+ } else {
+ e.setAttribute("xmlns", uri);
+ }
+ }
+
+ void declareNamespace(String prefix, String uri) {
+ if (!(dom instanceof Element)) throw new IllegalStateException();
+ if (dom.lookupNamespaceURI(uri) != null && dom.lookupNamespaceURI(uri).equals(prefix)) {
+ // do nothing
+ } else {
+ Element e = (Element)dom;
+ declareNamespace(e, prefix, uri);
+ }
+ }
+
+ private Namespace getDefaultNamespace() {
+ String prefix = "";
+ String uri = (dom.lookupNamespaceURI(null) == null) ? "" : dom.lookupNamespaceURI(null);
+ return Namespace.create(prefix, uri);
+ }
+
+ private String getExistingPrefixFor(Namespace namespace) {
+ if (getDefaultNamespace().getUri().equals(namespace.getUri())) {
+ return "";
+ }
+ return dom.lookupPrefix(namespace.getUri());
+ }
+
+ private Namespace getNodeNamespace() {
+ String uri = dom.getNamespaceURI();
+ String prefix = dom.getPrefix();
+ if (uri == null) uri = "";
+ if (prefix == null) prefix = "";
+ return Namespace.create(prefix, uri);
+ }
+
+ Namespace getNamespace() {
+ return getNodeNamespace();
+ }
+
+ void removeNamespace(Namespace namespace) {
+ Namespace current = getNodeNamespace();
+
+ // Do not remove in-use namespace
+ if (namespace.is(current)) return;
+ NamedNodeMap attrs = this.dom.getAttributes();
+ for (int i=0; i<attrs.getLength(); i++) {
+ XmlNode attr = XmlNode.createImpl(attrs.item(i));
+ if (namespace.is(attr.getNodeNamespace())) return;
+ }
+
+ // TODO I must confess I am not sure I understand the spec fully. See ECMA357 13.4.4.31
+ String existingPrefix = getExistingPrefixFor(namespace);
+ if (existingPrefix != null) {
+ if (namespace.isUnspecifiedPrefix()) {
+ // we should remove any namespace with this URI from scope; we do this by declaring a namespace with the same
+ // prefix as the existing prefix and setting its URI to the default namespace
+ declareNamespace(existingPrefix, getDefaultNamespace().getUri());
+ } else {
+ if (existingPrefix.equals(namespace.getPrefix())) {
+ declareNamespace(existingPrefix, getDefaultNamespace().getUri());
+ }
+ }
+ } else {
+ // the argument namespace is not declared in this scope, so do nothing.
+ }
+ }
+
+ private void setProcessingInstructionName(String localName) {
+ org.w3c.dom.ProcessingInstruction pi = (ProcessingInstruction)this.dom;
+ // We cannot set the node name; Document.renameNode() only supports elements and attributes. So we replace it
+ pi.getParentNode().replaceChild(
+ pi,
+ pi.getOwnerDocument().createProcessingInstruction(localName, pi.getData())
+ );
+ }
+
+ final void setLocalName(String localName) {
+ if (dom instanceof ProcessingInstruction) {
+ setProcessingInstructionName(localName);
+ } else {
+ String prefix = dom.getPrefix();
+ if (prefix == null) prefix = "";
+ this.dom = dom.getOwnerDocument().renameNode(dom, dom.getNamespaceURI(), QName.qualify(prefix, localName));
+ }
+ }
+
+ final QName getQname() {
+ String uri = (dom.getNamespaceURI()) == null ? "" : dom.getNamespaceURI();
+ String prefix = (dom.getPrefix() == null) ? "" : dom.getPrefix();
+ return QName.create( uri, dom.getLocalName(), prefix );
+ }
+
+ void addMatchingChildren(XMLList result, XmlNode.Filter filter) {
+ Node node = this.dom;
+ NodeList children = node.getChildNodes();
+ for(int i=0; i<children.getLength(); i++) {
+ Node childnode = children.item(i);
+ XmlNode child = XmlNode.createImpl(childnode);
+ if (filter.accept(childnode)) {
+ result.addToList(child);
+ }
+ }
+ }
+
+ XmlNode[] getMatchingChildren(Filter filter) {
+ ArrayList rv = new ArrayList();
+ NodeList nodes = this.dom.getChildNodes();
+ for (int i=0; i<nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+ if (filter.accept(node)) {
+ rv.add( createImpl(node) );
+ }
+ }
+ return (XmlNode[])rv.toArray(new XmlNode[0]);
+ }
+
+ XmlNode[] getAttributes() {
+ NamedNodeMap attrs = this.dom.getAttributes();
+ // TODO Or could make callers handle null?
+ if (attrs == null) throw new IllegalStateException("Must be element.");
+ XmlNode[] rv = new XmlNode[attrs.getLength()];
+ for (int i=0; i<attrs.getLength(); i++) {
+ rv[i] = createImpl( attrs.item(i) );
+ }
+ return rv;
+ }
+
+ String getAttributeValue() {
+ return ((Attr)dom).getValue();
+ }
+
+ void setAttribute(QName name, String value) {
+ if (!(dom instanceof Element)) throw new IllegalStateException("Can only set attribute on elements.");
+ name.setAttribute( (Element)dom, value );
+ }
+
+ void replaceWith(XmlNode other) {
+ Node replacement = other.dom;
+ if (replacement.getOwnerDocument() != this.dom.getOwnerDocument()) {
+ replacement = this.dom.getOwnerDocument().importNode(replacement, true);
+ }
+ this.dom.getParentNode().replaceChild(replacement, this.dom);
+ }
+
+ String ecmaToXMLString(XmlProcessor processor) {
+ if (this.isElementType()) {
+ Element copy = (Element)this.dom.cloneNode(true);
+ Namespace[] inScope = this.getInScopeNamespaces();
+ for (int i=0; i<inScope.length; i++) {
+ declareNamespace(copy, inScope[i].getPrefix(), inScope[i].getUri());
+ }
+ return processor.ecmaToXmlString(copy);
+ } else {
+ return processor.ecmaToXmlString(dom);
+ }
+ }
+
+ static class Namespace {
+ static Namespace create(String prefix, String uri) {
+ if (prefix == null) throw new IllegalArgumentException("Empty string represents default namespace prefix");
+ if (uri == null) throw new IllegalArgumentException("Namespace may not lack a URI");
+ Namespace rv = new Namespace();
+ rv.prefix = prefix;
+ rv.uri = uri;
+ return rv;
+ }
+
+ static Namespace create(String uri) {
+ Namespace rv = new Namespace();
+ rv.uri = uri;
+ return rv;
+ }
+
+ static final Namespace GLOBAL = create("", "");
+
+ private String prefix;
+ private String uri;
+
+ private Namespace() {
+ }
+
+ public String toString() {
+ if (prefix == null) return "XmlNode.Namespace [" + uri + "]";
+ return "XmlNode.Namespace [" + prefix + "{" + uri + "}]";
+ }
+
+ boolean isUnspecifiedPrefix() {
+ return prefix == null;
+ }
+
+ boolean is(Namespace other) {
+ return this.prefix != null && other.prefix != null && this.prefix.equals(other.prefix) && this.uri.equals(other.uri);
+ }
+
+ boolean isEmpty() {
+ return prefix != null && prefix.equals("") && uri.equals("");
+ }
+
+ boolean isDefault() {
+ return prefix != null && prefix.equals("");
+ }
+
+ boolean isGlobal() {
+ return uri != null && uri.equals("");
+ }
+
+ // Called by QName
+ // TODO Move functionality from QName lookupPrefix to here
+ private void setPrefix(String prefix) {
+ if (prefix == null) throw new IllegalArgumentException();
+ this.prefix = prefix;
+ }
+
+ String getPrefix() {
+ return prefix;
+ }
+
+ String getUri() {
+ return uri;
+ }
+ }
+
+ // TODO Where is this class used? No longer using it in QName implementation
+ static class QName {
+ static QName create(Namespace namespace, String localName) {
+ // A null namespace indicates a wild-card match for any namespace
+ // A null localName indicates "*" from the point of view of ECMA357
+ if (localName != null && localName.equals("*")) throw new RuntimeException("* is not valid localName");
+ QName rv = new QName();
+ rv.namespace = namespace;
+ rv.localName = localName;
+ return rv;
+ }
+
+ /** @deprecated */
+ static QName create(String uri, String localName, String prefix) {
+ return create(Namespace.create(prefix, uri), localName);
+ }
+
+ static String qualify(String prefix, String localName) {
+ if (prefix == null) throw new IllegalArgumentException("prefix must not be null");
+ if (prefix.length() > 0) return prefix + ":" + localName;
+ return localName;
+ }
+
+ private Namespace namespace;
+ private String localName;
+
+ private QName() {
+ }
+
+ public String toString() {
+ return "XmlNode.QName [" + localName + "," + namespace + "]";
+ }
+
+ private boolean equals(String one, String two) {
+ if (one == null && two == null) return true;
+ if (one == null || two == null) return false;
+ return one.equals(two);
+ }
+
+ private boolean namespacesEqual(Namespace one, Namespace two) {
+ if (one == null && two == null) return true;
+ if (one == null || two == null) return false;
+ return equals(one.getUri(), two.getUri());
+ }
+
+ final boolean isEqualTo(QName other) {
+ if (!namespacesEqual(this.namespace, other.namespace)) return false;
+ if (!equals(this.localName, other.localName)) return false;
+ return true;
+ }
+
+ void lookupPrefix(org.w3c.dom.Node node) {
+ if (node == null) throw new IllegalArgumentException("node must not be null");
+ String prefix = node.lookupPrefix(namespace.getUri());
+ if (prefix == null) {
+ // check to see if we match the default namespace
+ String defaultNamespace = node.lookupNamespaceURI(null);
+ if (defaultNamespace == null) defaultNamespace = "";
+ String nodeNamespace = namespace.getUri();
+ if (nodeNamespace.equals(defaultNamespace)) {
+ prefix = "";
+ }
+ }
+ int i = 0;
+ while(prefix == null) {
+ String generatedPrefix = "e4x_" + i++;
+ String generatedUri = node.lookupNamespaceURI(generatedPrefix);
+ if (generatedUri == null) {
+ prefix = generatedPrefix;
+ org.w3c.dom.Node top = node;
+ while(top.getParentNode() != null && top.getParentNode() instanceof org.w3c.dom.Element) {
+ top = top.getParentNode();
+ }
+ ((org.w3c.dom.Element)top).setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + prefix, namespace.getUri());
+ }
+ }
+ namespace.setPrefix(prefix);
+ }
+
+ String qualify(org.w3c.dom.Node node) {
+ if (namespace.getPrefix() == null) {
+ if (node != null) {
+ lookupPrefix(node);
+ } else {
+ if (namespace.getUri().equals("")) {
+ namespace.setPrefix("");
+ } else {
+ // TODO I am not sure this is right, but if we are creating a standalone node, I think we can set the
+ // default namespace on the node itself and not worry about setting a prefix for that namespace.
+ namespace.setPrefix("");
+ }
+ }
+ }
+ return qualify(namespace.getPrefix(), localName);
+ }
+
+ void setAttribute(org.w3c.dom.Element element, String value) {
+ if (namespace.getPrefix() == null) lookupPrefix(element);
+ element.setAttributeNS(namespace.getUri(), qualify(namespace.getPrefix(), localName), value);
+ }
+
+ /** @deprecated Use getNamespace() */
+ String getUri() {
+ return namespace.getUri();
+ }
+
+ /** @deprecated Use getNamespace() */
+ String getPrefix() {
+ return namespace.getPrefix();
+ }
+
+ Namespace getNamespace() {
+ return namespace;
+ }
+
+ String getLocalName() {
+ return localName;
+ }
+ }
+
+ static class List {
+ private java.util.Vector v;
+
+ List() {
+ v = new java.util.Vector();
+ }
+
+ private void _add(XmlNode n) {
+ v.add(n);
+ }
+
+ XmlNode item(int index) {
+ return (XmlNode)(v.get(index));
+ }
+
+ void remove(int index) {
+ v.remove(index);
+ }
+
+ void add(List other) {
+ for (int i=0; i<other.length(); i++) {
+ _add(other.item(i));
+ }
+ }
+
+ void add(List from, int startInclusive, int endExclusive) {
+ for (int i=startInclusive; i<endExclusive; i++) {
+ _add(from.item(i));
+ }
+ }
+
+ void add(XmlNode node) {
+ _add(node);
+ }
+
+ /** @deprecated */
+ void add(XML xml) {
+ _add(xml.getAnnotation());
+ }
+
+ /** @deprecated */
+ void addToList(Object toAdd) {
+ if (toAdd instanceof Undefined) {
+ // Missing argument do nothing...
+ return;
+ }
+
+ if (toAdd instanceof XMLList) {
+ XMLList xmlSrc = (XMLList)toAdd;
+ for (int i = 0; i < xmlSrc.length(); i++) {
+ this._add((xmlSrc.item(i)).getAnnotation());
+ }
+ } else if (toAdd instanceof XML) {
+ this._add(((XML)(toAdd)).getAnnotation());
+ } else if (toAdd instanceof XmlNode) {
+ this._add((XmlNode)toAdd);
+ }
+ }
+
+ int length() {
+ return v.size();
+ }
+ }
+
+ static abstract class Filter {
+ static final Filter COMMENT = new Filter() {
+ boolean accept(Node node) {
+ return node.getNodeType() == Node.COMMENT_NODE;
+ }
+ };
+ static final Filter TEXT = new Filter() {
+ boolean accept(Node node) {
+ return node.getNodeType() == Node.TEXT_NODE;
+ }
+ };
+ static Filter PROCESSING_INSTRUCTION(final XMLName name) {
+ return new Filter() {
+ boolean accept(Node node) {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
+ ProcessingInstruction pi = (ProcessingInstruction)node;
+ return name.matchesLocalName(pi.getTarget());
+ }
+ return false;
+ }
+ };
+ }
+ static Filter ELEMENT = new Filter() {
+ boolean accept(Node node) {
+ return node.getNodeType() == Node.ELEMENT_NODE;
+ }
+ };
+ static Filter TRUE = new Filter() {
+ boolean accept(Node node) {
+ return true;
+ }
+ };
+ abstract boolean accept(Node node);
+ }
+
+ // Support experimental Java interface
+ org.w3c.dom.Node toDomNode() {
+ return this.dom;
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java
new file mode 100644
index 0000000..d8ad495
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/xmlimplsrc/org/mozilla/javascript/xmlimpl/XmlProcessor.java
@@ -0,0 +1,445 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino DOM-only E4X implementation.
+ *
+ * The Initial Developer of the Original Code is
+ * David P. Caldwell.
+ * Portions created by David P. Caldwell are Copyright (C)
+ * 2007 David P. Caldwell. All Rights Reserved.
+ *
+ *
+ * Contributor(s):
+ * David P. Caldwell <inonit@inonit.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.xmlimpl;
+
+import org.w3c.dom.*;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import org.mozilla.javascript.*;
+
+// Disambiguate from org.mozilla.javascript.Node
+import org.w3c.dom.Node;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+
+class XmlProcessor {
+ private boolean ignoreComments;
+ private boolean ignoreProcessingInstructions;
+ private boolean ignoreWhitespace;
+ private boolean prettyPrint;
+ private int prettyIndent;
+
+ private javax.xml.parsers.DocumentBuilderFactory dom;
+ private javax.xml.transform.TransformerFactory xform;
+ private DocumentBuilder documentBuilder;
+ private RhinoSAXErrorHandler errorHandler = new RhinoSAXErrorHandler();
+
+
+ private static class RhinoSAXErrorHandler implements ErrorHandler {
+
+ private void throwError(SAXParseException e) {
+ throw ScriptRuntime.constructError("TypeError", e.getMessage(),
+ e.getLineNumber() - 1);
+ }
+
+ public void error(SAXParseException e) {
+ throwError(e);
+ }
+
+ public void fatalError(SAXParseException e) {
+ throwError(e);
+ }
+
+ public void warning(SAXParseException e) {
+ Context.reportWarning(e.getMessage());
+ }
+ }
+
+ XmlProcessor() {
+ setDefault();
+ this.dom = javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ this.dom.setNamespaceAware(true);
+ this.dom.setIgnoringComments(false);
+ this.xform = javax.xml.transform.TransformerFactory.newInstance();
+ }
+
+ final void setDefault() {
+ this.setIgnoreComments(true);
+ this.setIgnoreProcessingInstructions(true);
+ this.setIgnoreWhitespace(true);
+ this.setPrettyPrinting(true);
+ this.setPrettyIndent(2);
+ }
+
+ final void setIgnoreComments(boolean b) {
+ this.ignoreComments = b;
+ }
+
+ final void setIgnoreWhitespace(boolean b) {
+ this.ignoreWhitespace = b;
+ }
+
+ final void setIgnoreProcessingInstructions(boolean b) {
+ this.ignoreProcessingInstructions = b;
+ }
+
+ final void setPrettyPrinting(boolean b) {
+ this.prettyPrint = b;
+ }
+
+ final void setPrettyIndent(int i) {
+ this.prettyIndent = i;
+ }
+
+ final boolean isIgnoreComments() {
+ return ignoreComments;
+ }
+
+ final boolean isIgnoreProcessingInstructions() {
+ return ignoreProcessingInstructions;
+ }
+
+ final boolean isIgnoreWhitespace() {
+ return ignoreWhitespace;
+ }
+
+ final boolean isPrettyPrinting() {
+ return prettyPrint;
+ }
+
+ final int getPrettyIndent() {
+ return prettyIndent;
+ }
+
+ private String toXmlNewlines(String rv) {
+ StringBuffer nl = new StringBuffer();
+ for (int i=0; i<rv.length(); i++) {
+ if (rv.charAt(i) == '\r') {
+ if (rv.charAt(i+1) == '\n') {
+ // DOS, do nothing and skip the \r
+ } else {
+ // Macintosh, substitute \n
+ nl.append('\n');
+ }
+ } else {
+ nl.append(rv.charAt(i));
+ }
+ }
+ return nl.toString();
+ }
+
+ private javax.xml.parsers.DocumentBuilderFactory getDomFactory() {
+ return dom;
+ }
+
+ private synchronized DocumentBuilder getDocumentBuilderFromPool()
+ throws javax.xml.parsers.ParserConfigurationException
+ {
+ DocumentBuilder result;
+ if (documentBuilder == null) {
+ javax.xml.parsers.DocumentBuilderFactory factory = getDomFactory();
+ result = factory.newDocumentBuilder();
+ } else {
+ result = documentBuilder;
+ documentBuilder = null;
+ }
+ result.setErrorHandler(errorHandler);
+ return result;
+ }
+
+ private synchronized void returnDocumentBuilderToPool(DocumentBuilder db) {
+ if (documentBuilder == null) {
+ documentBuilder = db;
+ documentBuilder.reset();
+ }
+ }
+
+ private void addProcessingInstructionsTo(java.util.Vector v, Node node) {
+ if (node instanceof ProcessingInstruction) {
+ v.add(node);
+ }
+ if (node.getChildNodes() != null) {
+ for (int i=0; i<node.getChildNodes().getLength(); i++) {
+ addProcessingInstructionsTo(v, node.getChildNodes().item(i));
+ }
+ }
+ }
+
+ private void addCommentsTo(java.util.Vector v, Node node) {
+ if (node instanceof Comment) {
+ v.add(node);
+ }
+ if (node.getChildNodes() != null) {
+ for (int i=0; i<node.getChildNodes().getLength(); i++) {
+ addProcessingInstructionsTo(v, node.getChildNodes().item(i));
+ }
+ }
+ }
+
+ private void addTextNodesToRemoveAndTrim(java.util.Vector toRemove, Node node) {
+ if (node instanceof Text) {
+ Text text = (Text)node;
+ boolean BUG_369394_IS_VALID = false;
+ if (!BUG_369394_IS_VALID) {
+ text.setData(text.getData().trim());
+ } else {
+ if (text.getData().trim().length() == 0) {
+ text.setData("");
+ }
+ }
+ if (text.getData().length() == 0) {
+ toRemove.add(node);
+ }
+ }
+ if (node.getChildNodes() != null) {
+ for (int i=0; i<node.getChildNodes().getLength(); i++) {
+ addTextNodesToRemoveAndTrim(toRemove, node.getChildNodes().item(i));
+ }
+ }
+ }
+
+ final Node toXml(String defaultNamespaceUri, String xml) throws org.xml.sax.SAXException {
+ // See ECMA357 10.3.1
+ DocumentBuilder builder = null;
+ try {
+ String syntheticXml = "<parent xmlns=\"" + defaultNamespaceUri +
+ "\">" + xml + "</parent>";
+ builder = getDocumentBuilderFromPool();
+ Document document = builder.parse( new org.xml.sax.InputSource(new java.io.StringReader(syntheticXml)) );
+ if (ignoreProcessingInstructions) {
+ java.util.Vector v = new java.util.Vector();
+ addProcessingInstructionsTo(v, document);
+ for (int i=0; i<v.size(); i++) {
+ Node node = (Node)v.elementAt(i);
+ node.getParentNode().removeChild(node);
+ }
+ }
+ if (ignoreComments) {
+ java.util.Vector v = new java.util.Vector();
+ addCommentsTo(v, document);
+ for (int i=0; i<v.size(); i++) {
+ Node node = (Node)v.elementAt(i);
+ node.getParentNode().removeChild(node);
+ }
+ }
+ if (ignoreWhitespace) {
+ // Apparently JAXP setIgnoringElementContentWhitespace() has a different meaning, it appears from the Javadoc
+ // Refers to element-only content models, which means we would need to have a validating parser and DTD or schema
+ // so that it would know which whitespace to ignore.
+
+ // Instead we will try to delete it ourselves.
+ java.util.Vector v = new java.util.Vector();
+ addTextNodesToRemoveAndTrim(v, document);
+ for (int i=0; i<v.size(); i++) {
+ Node node = (Node)v.elementAt(i);
+ node.getParentNode().removeChild(node);
+ }
+ }
+ NodeList rv = document.getDocumentElement().getChildNodes();
+ if (rv.getLength() > 1) {
+ throw ScriptRuntime.constructError("SyntaxError", "XML objects may contain at most one node.");
+ } else if (rv.getLength() == 0) {
+ Node node = document.createTextNode("");
+ return node;
+ } else {
+ Node node = rv.item(0);
+ document.getDocumentElement().removeChild(node);
+ return node;
+ }
+ } catch (java.io.IOException e) {
+ throw new RuntimeException("Unreachable.");
+ } catch (javax.xml.parsers.ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (builder != null)
+ returnDocumentBuilderToPool(builder);
+ }
+ }
+
+ Document newDocument() {
+ DocumentBuilder builder = null;
+ try {
+ // TODO Should this use XML settings?
+ builder = getDocumentBuilderFromPool();
+ return builder.newDocument();
+ } catch (javax.xml.parsers.ParserConfigurationException ex) {
+ // TODO How to handle these runtime errors?
+ throw new RuntimeException(ex);
+ } finally {
+ if (builder != null)
+ returnDocumentBuilderToPool(builder);
+ }
+ }
+
+ // TODO Cannot remember what this is for, so whether it should use settings or not
+ private String toString(Node node) {
+ javax.xml.transform.dom.DOMSource source = new javax.xml.transform.dom.DOMSource(node);
+ java.io.StringWriter writer = new java.io.StringWriter();
+ javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(writer);
+ try {
+ javax.xml.transform.Transformer transformer = xform.newTransformer();
+ transformer.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "no");
+ transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml");
+ transformer.transform(source, result);
+ } catch (javax.xml.transform.TransformerConfigurationException ex) {
+ // TODO How to handle these runtime errors?
+ throw new RuntimeException(ex);
+ } catch (javax.xml.transform.TransformerException ex) {
+ // TODO How to handle these runtime errors?
+ throw new RuntimeException(ex);
+ }
+ return toXmlNewlines(writer.toString());
+ }
+
+ String escapeAttributeValue(Object value) {
+ String text = ScriptRuntime.toString(value);
+
+ if (text.length() == 0) return "";
+
+ Document dom = newDocument();
+ Element e = dom.createElement("a");
+ e.setAttribute("b", text);
+ String elementText = toString(e);
+ int begin = elementText.indexOf('"');
+ int end = elementText.lastIndexOf('"');
+ return elementText.substring(begin+1,end);
+ }
+
+ String escapeTextValue(Object value) {
+ if (value instanceof XMLObjectImpl) {
+ return ((XMLObjectImpl)value).toXMLString();
+ }
+
+ String text = ScriptRuntime.toString(value);
+
+ if (text.length() == 0) return text;
+
+ Document dom = newDocument();
+ Element e = dom.createElement("a");
+ e.setTextContent(text);
+ String elementText = toString(e);
+
+ int begin = elementText.indexOf('>') + 1;
+ int end = elementText.lastIndexOf('<');
+ return (begin < end) ? elementText.substring(begin, end) : "";
+ }
+
+ private String escapeElementValue(String s) {
+ // TODO Check this
+ return escapeTextValue(s);
+ }
+
+ private String elementToXmlString(Element element) {
+ // TODO My goodness ECMA is complicated (see 10.2.1). We'll try this first.
+ Element copy = (Element)element.cloneNode(true);
+ if (prettyPrint) {
+ beautifyElement(copy, 0);
+ }
+ return toString(copy);
+ }
+
+ final String ecmaToXmlString(Node node) {
+ // See ECMA 357 Section 10.2.1
+ StringBuffer s = new StringBuffer();
+ int indentLevel = 0;
+ if (prettyPrint) {
+ for (int i=0; i<indentLevel; i++) {
+ s.append(' ');
+ }
+ }
+ if (node instanceof Text) {
+ String data = ((Text)node).getData();
+ // TODO Does Java trim() work same as XMLWhitespace?
+ String v = (prettyPrint) ? data.trim() : data;
+ s.append(escapeElementValue(v));
+ return s.toString();
+ }
+ if (node instanceof Attr) {
+ String value = ((Attr)node).getValue();
+ s.append(escapeAttributeValue(value));
+ return s.toString();
+ }
+ if (node instanceof Comment) {
+ s.append("<!--" + ((Comment)node).getNodeValue() + "-->");
+ return s.toString();
+ }
+ if (node instanceof ProcessingInstruction) {
+ ProcessingInstruction pi = (ProcessingInstruction)node;
+ s.append("<?" + pi.getTarget() + " " + pi.getData() + "?>");
+ return s.toString();
+ }
+ s.append(elementToXmlString((Element)node));
+ return s.toString();
+ }
+
+ private void beautifyElement(Element e, int indent) {
+ StringBuffer s = new StringBuffer();
+ s.append('\n');
+ for (int i=0; i<indent; i++) {
+ s.append(' ');
+ }
+ String afterContent = s.toString();
+ for (int i=0; i<prettyIndent; i++) {
+ s.append(' ');
+ }
+ String beforeContent = s.toString();
+
+ // We "mark" all the nodes first; if we tried to do this loop otherwise, it would behave unexpectedly (the inserted nodes
+ // would contribute to the length and it might never terminate).
+ java.util.Vector toIndent = new java.util.Vector();
+ boolean indentChildren = false;
+ for (int i=0; i<e.getChildNodes().getLength(); i++) {
+ if (i == 1) indentChildren = true;
+ if (e.getChildNodes().item(i) instanceof Text) {
+ toIndent.add(e.getChildNodes().item(i));
+ } else {
+ indentChildren = true;
+ toIndent.add(e.getChildNodes().item(i));
+ }
+ }
+ if (indentChildren) {
+ for (int i=0; i<toIndent.size(); i++) {
+ e.insertBefore( e.getOwnerDocument().createTextNode(beforeContent), (Node)toIndent.elementAt(i) );
+ }
+ }
+ NodeList nodes = e.getChildNodes();
+ java.util.Vector v = new java.util.Vector();
+ for (int i=0; i<nodes.getLength(); i++) {
+ if (nodes.item(i) instanceof Element) {
+ v.add( nodes.item(i) );
+ }
+ }
+ for (int i=0; i<v.size(); i++) {
+ beautifyElement( (Element)v.elementAt(i), indent + prettyIndent );
+ }
+ if (indentChildren) {
+ e.appendChild( e.getOwnerDocument().createTextNode(afterContent) );
+ }
+ }
+}