[214439] WTP DOM fails W3C DOM Test Suite
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java
index b4462bc..75c40dd 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java
@@ -21,6 +21,7 @@
 
 
 import java.util.Iterator;
+import java.util.Stack;
 
 import org.eclipse.wst.sse.core.internal.ltk.parser.RegionParser;
 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
@@ -79,6 +80,8 @@
 		public Node item(int index) {
 			if (attrNodes == null)
 				return null;
+			if (index >= attrNodes.getLength())
+				return null;
 			return attrNodes.item(index);
 		}
 
@@ -112,6 +115,8 @@
 	private char[] fTagName = null;
 
 	private char[] fNamespaceURI = null;
+	
+	private Stack fDefaultValueLookups = null;
 
 	/**
 	 * ElementImpl constructor
@@ -240,33 +245,13 @@
 		Attr attr = getAttributeNode(name);
 		// In the absence of the attribute, get the default value
 		if (attr == null) {
-			String defaultValue = getDefaultValue(name);
-			return (defaultValue != null) ? defaultValue : NodeImpl.EMPTY_STRING;
+			return getDefaultValue(name, NodeImpl.EMPTY_STRING);
 		}
 		return attr.getValue();
 	}
 
-	/**
-	 * get the default value for attribute <code>name</code>. Returns an empty string
-	 * @param name
-	 * @return
-	 */
-	private String getDefaultValue(String name) {
-		CMNamedNodeMap map = ((DocumentImpl) getOwnerDocument()).getCMAttributes(this);
-		if (map != null) {
-			CMNode attribute = map.getNamedItem(name);
-			if (attribute instanceof CMAttributeDeclaration)
-				return ((CMAttributeDeclaration) attribute).getAttrType().getImpliedValue();
-		}
-		return NodeImpl.EMPTY_STRING;
-	}
-
-	/**
-	 * getAttributeNode method
-	 * 
-	 * @return org.w3c.dom.Attr
-	 * @param name
-	 *            java.lang.String
+	/* (non-Javadoc)
+	 * @see org.w3c.dom.Element#getAttributeNode(java.lang.String)
 	 */
 	public Attr getAttributeNode(String name) {
 		if (name == null)
@@ -284,10 +269,18 @@
 				return attr; // found
 		}
 
+		String implied = getDefaultValue(name, null);
+		if (implied != null) {
+			Attr createdAttribute = getOwnerDocument().createAttribute(name);
+			createdAttribute.setNodeValue(implied);
+			return createdAttribute;
+		}
+		
 		return null; // not found
 	}
 
-	/**
+	/* (non-Javadoc)
+	 * @see org.w3c.dom.Element#getAttributeNodeNS(java.lang.String, java.lang.String)
 	 */
 	public Attr getAttributeNodeNS(String uri, String name) {
 		if (name == null)
@@ -320,14 +313,14 @@
 		return null; // not found
 	}
 
-	/**
+	/* (non-Javadoc)
+	 * @see org.w3c.dom.Element#getAttributeNS(java.lang.String, java.lang.String)
 	 */
 	public String getAttributeNS(String uri, String name) {
 		Attr attr = getAttributeNodeNS(uri, name);
 		// In the absence of the attribute, get the default value
 		if (attr == null) {
-			String defaultValue = getDefaultValue(name);
-			return (defaultValue != null) ? defaultValue : NodeImpl.EMPTY_STRING;
+			return getDefaultValue(name, NodeImpl.EMPTY_STRING);
 		}
 		return attr.getValue();
 	}
@@ -354,6 +347,33 @@
 	}
 
 	/**
+	 * Get the implied default value for attribute <code>name</code>
+	 * 
+	 * @param name
+	 * @return returns the default value for attribute <code>name</code> if it
+	 *         is found in the content model, <code>unknownDefault</code> otherwise
+	 */
+	private String getDefaultValue(String name, String unknownDefault) {
+		if (fDefaultValueLookups != null && fDefaultValueLookups.contains(name))
+			return null;
+		try {
+			if (fDefaultValueLookups == null)
+				fDefaultValueLookups = new Stack();
+			fDefaultValueLookups.push(name);
+			CMNamedNodeMap map = ((DocumentImpl) getOwnerDocument()).getCMAttributes(this);
+			if (map != null) {
+				CMNode attribute = map.getNamedItem(name);
+				if (attribute instanceof CMAttributeDeclaration)
+					return ((CMAttributeDeclaration) attribute).getAttrType().getImpliedValue();
+			}
+			return unknownDefault;
+		}
+		finally {
+			fDefaultValueLookups.pop();
+		}
+	}
+
+	/**
 	 * getElementsByTagName method
 	 * 
 	 * @return org.w3c.dom.NodeList
@@ -995,11 +1015,8 @@
 		return (decl.getContentType() == CMElementDeclaration.EMPTY);
 	}
 
-	/**
-	 * removeAttribute method
-	 * 
-	 * @param name
-	 *            java.lang.String
+	/* (non-Javadoc)
+	 * @see org.w3c.dom.Element#removeAttribute(java.lang.String)
 	 */
 	public void removeAttribute(String name) throws DOMException {
 		removeAttributeNode(name);
@@ -1043,13 +1060,14 @@
 	}
 
 	/**
-	 * removeAttributeNode method
-	 * 
-	 * @return org.w3c.dom.Attr
 	 * @param name
-	 *            java.lang.String
+	 * @return
 	 */
 	public Attr removeAttributeNode(String name) {
+		return removeAttributeNode(name, true);
+	}
+	
+	private  Attr removeAttributeNode(String name, boolean exceptionOnNotFound) {
 		if (name == null)
 			return null; // invalid parameter
 		if (this.attrNodes == null)
@@ -1075,6 +1093,8 @@
 			return attr;
 		}
 
+		if (exceptionOnNotFound)
+			throw new DOMException(DOMException.NOT_FOUND_ERR, DOMMessages.NOT_FOUND_ERR);
 		return null; // not found
 	}
 
@@ -1230,12 +1250,8 @@
 		appendAttributeNode(attr);
 	}
 
-	/**
-	 * setAttributeNode method
-	 * 
-	 * @return org.w3c.dom.Attr
-	 * @param newAttr
-	 *            org.w3c.dom.Attr
+	/* (non-Javadoc)
+	 * @see org.w3c.dom.Element#setAttributeNode(org.w3c.dom.Attr)
 	 */
 	public Attr setAttributeNode(Attr newAttr) throws DOMException {
 		if (newAttr == null)
@@ -1253,7 +1269,7 @@
 			throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, DOMMessages.INUSE_ATTRIBUTE_ERR);
 		}
 
-		Attr oldAttr = removeAttributeNode(newAttr.getName());
+		Attr oldAttr = removeAttributeNode(newAttr.getName(), false);
 		appendAttributeNode(attr);
 		return oldAttr;
 	}