| /******************************************************************************* |
| * Copyright (c) 1998, 2008 IBM Corporation and Others |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Goh KONDOH - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.actf.model.internal.dom.sgml.impl; |
| |
| import java.io.PrintWriter; |
| |
| import org.eclipse.actf.model.internal.dom.sgml.IPrintXML; |
| import org.eclipse.actf.model.internal.dom.sgml.ISGMLElement; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.TypeInfo; |
| |
| /** |
| * Element class of SGML. |
| * |
| */ |
| public class SGMLElement extends SGMLParentNode implements ISGMLElement { |
| /** |
| * |
| */ |
| private static final long serialVersionUID = -8088815760723728378L; |
| |
| /** |
| * |
| */ |
| private String tagName; |
| |
| /** |
| * |
| */ |
| private SGMLAttribute attributes[] = new SGMLAttribute[8]; |
| |
| /** |
| * |
| */ |
| private int attrNum = 0; |
| |
| /** |
| * Constructs an element. |
| * |
| * @param name |
| * element's name |
| * @param doc |
| * owner document of this element. |
| */ |
| public SGMLElement(String name, Document doc) { |
| super(doc); |
| this.tagName = name; |
| } |
| |
| /** |
| * Checks if an specified node is appropriate as a child. |
| * |
| * @param node |
| * child node to add |
| * @exception DOMException |
| * If <code> node </code> is not appropriate as a child. |
| */ |
| void check(Node node) throws DOMException { |
| if (node == null) { |
| throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, |
| "trying to insert null") { |
| }; |
| } else if (node.getOwnerDocument() != ownerDocument) { |
| throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, node |
| + " created from " + node.getOwnerDocument() + ". " + this |
| + " created from " + ownerDocument) { |
| }; |
| } |
| switch (node.getNodeType()) { |
| case ELEMENT_NODE: |
| case TEXT_NODE: |
| case COMMENT_NODE: |
| case PROCESSING_INSTRUCTION_NODE: |
| case CDATA_SECTION_NODE: |
| case ENTITY_REFERENCE_NODE: |
| break; |
| default: |
| throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, node |
| + " is not allowed as a child of " + this) { |
| }; |
| } |
| } |
| |
| public String getAttribute(String name) { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute attr = attributes[i]; |
| if (attr.getNodeName().equalsIgnoreCase(name)) { |
| return attr.getNodeValue(); |
| } |
| } |
| return ""; |
| } |
| |
| public Attr getAttributeNode(String name) { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute ret = attributes[i]; |
| if (ret.getNodeName().equalsIgnoreCase(name)) { |
| return ret; |
| } |
| } |
| return null; |
| } |
| |
| private void expandAttrBuf() { |
| SGMLAttribute newBuf[] = new SGMLAttribute[attrNum * 2]; |
| System.arraycopy(attributes, 0, newBuf, 0, attrNum); |
| attributes = newBuf; |
| } |
| |
| /** |
| * returned instance always ignores <code>namespaceURI</code> |
| */ |
| public NamedNodeMap getAttributes() { |
| return new NamedNodeMap() { |
| public String toString() { |
| StringBuffer ret = new StringBuffer('['); |
| for (int i = 0; i < attrNum - 1; i++) { |
| ret.append(attributes[i] + ", "); |
| } |
| if (attrNum > 0) { |
| ret.append(attributes[attrNum - 1]); |
| } |
| ret.append(']'); |
| return ret.toString(); |
| } |
| |
| public Node getNamedItem(String name) { |
| return getAttributeNode(name); |
| } |
| |
| public Node getNamedItemNS(String namespaceURI, String localName) { |
| return getNamedItem(localName); |
| } |
| |
| public Node setNamedItem(Node arg) throws DOMException { |
| if (arg instanceof SGMLAttribute) { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute ret = attributes[i]; |
| if (ret.getNodeName().equalsIgnoreCase( |
| arg.getNodeName())) { |
| attributes[i] = (SGMLAttribute) arg; |
| attributes[i].setOwnerElement(SGMLElement.this); |
| return ret; |
| } |
| } |
| if (attrNum == attributes.length) { |
| expandAttrBuf(); |
| } |
| attributes[attrNum++] = (SGMLAttribute) arg; |
| ((SGMLAttribute) arg).setOwnerElement(SGMLElement.this); |
| return null; |
| } else { |
| throw new DOMException( |
| DOMException.NO_MODIFICATION_ALLOWED_ERR, |
| "only Attr instance can be set: " + arg) { |
| }; |
| } |
| } |
| |
| public Node setNamedItemNS(Node arg) throws DOMException { |
| return setNamedItem(arg); |
| } |
| |
| public Node removeNamedItem(String name) throws DOMException { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute attr = attributes[i]; |
| if (attr.getNodeName().equalsIgnoreCase(name)) { |
| attributes[i] = null; |
| attr.setOwnerElement(null); |
| for (i++; i < attrNum; i++) { |
| attributes[i - 1] = attributes[i]; |
| } |
| attrNum--; |
| return attr; |
| } |
| } |
| return null; |
| } |
| |
| public Node removeNamedItemNS(String namespaceURI, String localName) |
| throws DOMException { |
| return removeNamedItem(localName); |
| } |
| |
| public Node item(int index) { |
| if (0 <= index && index < attrNum) { |
| return attributes[index]; |
| } |
| return null; |
| } |
| |
| public int getLength() { |
| return attrNum; |
| } |
| }; |
| } |
| |
| public NodeList getElementsByTagName(String name) { |
| final boolean all = name.equals("*"); |
| final String targetName = name; |
| return new NodeList() { |
| public int getLength() { |
| int ret = 0; |
| Node tmp1, tmp2; |
| tmp1 = SGMLElement.this.firstChild; |
| outer: while (tmp1 != null) { |
| if (tmp1 instanceof Element |
| && (all || targetName.equalsIgnoreCase(tmp1 |
| .getNodeName())) |
| && tmp1 != SGMLElement.this) { |
| ret++; |
| } |
| if ((tmp2 = tmp1.getFirstChild()) == null) { |
| if (tmp1 == SGMLElement.this) { |
| break outer; |
| } else { |
| tmp2 = tmp1.getNextSibling(); |
| } |
| } |
| while (tmp2 == null && tmp1 != null) { |
| tmp1 = tmp2 = tmp1.getParentNode(); |
| if (tmp1 != SGMLElement.this) { |
| tmp2 = tmp1.getNextSibling(); |
| } else { |
| break outer; |
| } |
| } |
| tmp1 = tmp2; |
| } |
| return ret; |
| } |
| |
| public Node item(int index) { |
| Node tmp1, tmp2; |
| tmp1 = SGMLElement.this.firstChild; |
| outer: while (tmp1 != null) { |
| if (tmp1 instanceof Element |
| && (all || targetName.equalsIgnoreCase(tmp1 |
| .getNodeName())) |
| && tmp1 != SGMLElement.this) { |
| if (index == 0) { |
| return tmp1; |
| } else { |
| index--; |
| } |
| } |
| if ((tmp2 = tmp1.getFirstChild()) == null) { |
| if (tmp1 == SGMLElement.this) { |
| break outer; |
| } else { |
| tmp2 = tmp1.getNextSibling(); |
| } |
| } |
| while (tmp2 == null && tmp1 != null) { |
| tmp1 = tmp2 = tmp1.getParentNode(); |
| if (tmp1 != SGMLElement.this) { |
| tmp2 = tmp1.getNextSibling(); |
| } else { |
| break outer; |
| } |
| } |
| tmp1 = tmp2; |
| } |
| return null; |
| } |
| }; |
| |
| } |
| |
| public String getNodeName() { |
| return tagName; |
| } |
| |
| public short getNodeType() { |
| return ELEMENT_NODE; |
| } |
| |
| public String getNodeValue() { |
| return null; |
| } |
| |
| public String getTagName() { |
| return tagName; |
| } |
| |
| public void removeAttribute(String name) throws DOMException { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute attr = attributes[i]; |
| if (attr.getNodeName().equalsIgnoreCase(name)) { |
| String defaultValue = getDefaultValue(name); |
| if (defaultValue != null) { |
| attr.setNodeValue(defaultValue); |
| } else { |
| attributes[i] = null; |
| attr.setOwnerElement(null); |
| for (i++; i < attrNum; i++) { |
| attributes[i - 1] = attributes[i]; |
| } |
| attrNum--; |
| } |
| return; |
| } |
| } |
| } |
| |
| private String getDefaultValue(String attrName) { |
| ElementDefinition edef; |
| SGMLDocTypeDef dtd = ((SGMLDocument) ownerDocument).getDTD(); |
| if (dtd == null) |
| return null; |
| edef = dtd.getElementDefinition(tagName); |
| if (edef == null) |
| return null; |
| AttributeDefinition adef = edef.getAttributeDef(attrName); |
| return adef != null ? adef.getDefaultValue() : null; |
| } |
| |
| public Attr removeAttributeNode(Attr oldAttr) { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| if (attributes[i] == oldAttr) { |
| String defaultValue = getDefaultValue(oldAttr.getNodeName()); |
| if (defaultValue != null) { |
| SGMLAttribute attr = (SGMLAttribute) ownerDocument |
| .createAttribute(oldAttr.getNodeName()); |
| attr.setValue(defaultValue); |
| attributes[i] = attr; |
| attr.setOwnerElement(this); |
| } else { |
| attributes[i] = null; |
| for (i++; i < attrNum; i++) { |
| attributes[i - 1] = attributes[i]; |
| } |
| attrNum--; |
| } |
| break; |
| } |
| } |
| ((SGMLAttribute) oldAttr).setOwnerElement(this); |
| return oldAttr; |
| } |
| |
| public void setAttribute(String name, String value) throws DOMException { |
| SGMLAttribute attr; |
| for (int i = attrNum - 1; i >= 0; i--) { |
| attr = attributes[i]; |
| if (attr.getName().equalsIgnoreCase(name)) { |
| attr.setValue(value); |
| return; |
| } |
| } |
| attr = (SGMLAttribute) ownerDocument.createAttribute(name); |
| attr.setValue(value); |
| attr.setOwnerElement(this); |
| if (attributes.length == attrNum) { |
| expandAttrBuf(); |
| } |
| attributes[attrNum++] = attr; |
| } |
| |
| public Attr setAttributeNode(Attr newAttr) throws DOMException { |
| if (!(newAttr instanceof SGMLAttribute)) { |
| throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, newAttr |
| + "is not SGMLAttribute") { |
| }; |
| } |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute attr = attributes[i]; |
| if (attr.getName().equalsIgnoreCase(newAttr.getName())) { |
| attr.setOwnerElement(null); |
| attributes[i] = (SGMLAttribute) newAttr; |
| attributes[i].setOwnerElement(this); |
| return attr; |
| } |
| } |
| if (attributes.length == attrNum) { |
| expandAttrBuf(); |
| } |
| attributes[attrNum] = (SGMLAttribute) newAttr; |
| attributes[attrNum++].setOwnerElement(this); |
| return null; |
| } |
| |
| public void setNodeValue(String nodeValue) throws DOMException { |
| throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, |
| "can't set value in " + this) { |
| }; |
| } |
| |
| /** |
| * Get start tag string. If attribute value includes a character that can be |
| * reverted, replaces it to original character entity. |
| * |
| * @return string of start tag. |
| */ |
| public String toString() { |
| StringBuffer ret = new StringBuffer(); |
| ret.append('<'); |
| ret.append(tagName); |
| for (int i = 0; i < attrNum; i++) |
| ret.append(attributes[i].toString()); |
| ret.append('>'); |
| return new String(ret); |
| } |
| |
| public void printAsXML(PrintWriter pw, int indentLevel, boolean indent) { |
| if (indent |
| && (previousSibling == null || previousSibling.getNodeType() != Node.TEXT_NODE |
| && previousSibling.getNodeType() != Node.CDATA_SECTION_NODE)) { |
| for (int i = 0; i < indentLevel; i++) |
| pw.print(' '); |
| } |
| pw.print('<' + getTagName()); |
| for (int i = 0; i < attrNum; i++) { |
| pw.print(attributes[i].toXMLString()); |
| } |
| if (hasChildNodes()) { |
| pw.print('>'); |
| for (Node child = getFirstChild(); child != null; child = child |
| .getNextSibling()) { |
| if (indent && child.getNodeType() != Node.TEXT_NODE |
| && child.getNodeType() != Node.CDATA_SECTION_NODE) { |
| pw.println(); |
| } |
| ((IPrintXML) child).printAsXML(pw, indentLevel + 1, indent); |
| } |
| if (indent |
| && (getLastChild() == null || getLastChild().getNodeType() != Node.TEXT_NODE |
| && getLastChild().getNodeType() != Node.CDATA_SECTION_NODE)) { |
| pw.println(); |
| for (int i = indentLevel; i > 0; i--) |
| pw.print(' '); |
| } |
| pw.print("</" + getTagName() + '>'); |
| } else { |
| pw.print("/>"); |
| } |
| } |
| |
| public void printAsSGML(PrintWriter pw, int indentLevel, boolean indent) { |
| if (indent |
| && (previousSibling == null || previousSibling.getNodeType() != Node.TEXT_NODE |
| && previousSibling.getNodeType() != Node.CDATA_SECTION_NODE)) { |
| for (int i = indentLevel; i > 0; i--) |
| pw.print(' '); |
| } |
| pw.print(toString()); |
| boolean parent; |
| if (parent = hasChildNodes()) { |
| for (Node child = getFirstChild(); child != null; child = child |
| .getNextSibling()) { |
| if (indent && child.getNodeType() != Node.TEXT_NODE |
| && child.getNodeType() != Node.CDATA_SECTION_NODE) { |
| pw.println(); |
| } |
| ((IPrintXML) child).printAsSGML(pw, indentLevel + 1, indent); |
| } |
| } |
| SGMLDocTypeDef dtd = ((SGMLDocument) getOwnerDocument()).getDTD(); |
| ElementDefinition ed = null; |
| if (dtd != null) { |
| ed = dtd.getElementDefinition(tagName); |
| } |
| if (parent || ed == null || ed.getContentModel() != SGMLParser.empty) { |
| if (indent |
| && (getLastChild() == null || getLastChild().getNodeType() != Node.TEXT_NODE |
| && getLastChild().getNodeType() != Node.CDATA_SECTION_NODE)) { |
| pw.println(); |
| for (int i = indentLevel; i > 0; i--) |
| pw.print(' '); |
| } |
| pw.print("</" + getTagName() + '>'); |
| } |
| } |
| |
| public Node cloneNode(boolean deep) { |
| SGMLElement ret = (SGMLElement) super.cloneNode(deep); |
| SGMLAttribute cloneAttributes[] = new SGMLAttribute[attributes.length]; |
| for (int i = attrNum - 1; i >= 0; i--) { |
| cloneAttributes[i] = (SGMLAttribute) attributes[i].cloneNode(false); |
| cloneAttributes[i].setOwnerElement(ret); |
| } |
| ret.attributes = cloneAttributes; |
| return ret; |
| } |
| |
| /** |
| * @param namespaceURI |
| * always ignored |
| * @return same as <code>getAttribute(localName)</code> |
| */ |
| public String getAttributeNS(String namespaceURI, String localName) { |
| return getAttribute(localName); |
| } |
| |
| /** |
| * Sets an attribute. In this implementation, this method is same as |
| * <code>setAttribute(qualifiedName, value)</code> |
| * |
| * @param namespaceURI |
| * always ignored |
| */ |
| public void setAttributeNS(String namespaceURI, String qualifiedName, |
| String value) throws DOMException { |
| setAttribute(qualifiedName, value); |
| } |
| |
| /** |
| * Removes an attribute. In this implementation, this method is same as |
| * <code>removeAttribute(localName)</code> |
| * |
| * @param namespaceURI |
| * always ignored |
| */ |
| public void removeAttributeNS(String namespaceURI, String localName) |
| throws DOMException { |
| removeAttribute(localName); |
| } |
| |
| /** |
| * @param namespaceURI |
| * always ignored |
| * @return same as <code>getAttributeNode(localName)</code> |
| */ |
| public Attr getAttributeNodeNS(String namespaceURI, String localName) { |
| return getAttributeNode(localName); |
| } |
| |
| /** |
| * @return same as <code>setAttributeNode(newAttr)</code> |
| */ |
| public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { |
| return setAttributeNode(newAttr); |
| } |
| |
| /** |
| * @param namespaceURI |
| * always ignored |
| * @return same as <code>getElementsByTagName(localName)</code> |
| */ |
| public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { |
| return getElementsByTagName(localName); |
| } |
| |
| public boolean hasAttribute(String name) { |
| for (int i = attrNum - 1; i >= 0; i--) { |
| SGMLAttribute attr = attributes[i]; |
| if (attr.getNodeName().equalsIgnoreCase(name)) { |
| return true; |
| } |
| } |
| return getDefaultValue(name) != null; |
| } |
| |
| /** |
| * @param namespaceURI |
| * ignored |
| * @return same as <code>hasAttributeNS(localName)</code> |
| */ |
| public boolean hasAttributeNS(String namespaceURI, String localName) { |
| return hasAttribute(localName); |
| } |
| |
| public boolean hasAttributes() { |
| return attrNum > 0; |
| } |
| |
| /** |
| * DOM Level 3 |
| */ |
| |
| public TypeInfo getSchemaTypeInfo() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public void setIdAttribute(String name, boolean isId) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setIdAttributeNS(String namespaceURI, String localName, |
| boolean isId) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setIdAttributeNode(Attr idAttr, boolean isId) |
| throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| } |