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