📄 xml.java
字号:
/* -*- 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -