[272378] Element returns null instead of empty string for undefined attributes
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java
index d62030d..691970f 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java
@@ -21,13 +21,16 @@
// for org.apache.xerces 3.2.1
// import org.apache.xerces.utils.XMLCharacterProperties;
// DMW modified for XML4J 4.0.1
+import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.xerces.dom.TreeWalkerImpl;
import org.eclipse.wst.sse.core.internal.ltk.modelhandler.IModelHandler;
import org.eclipse.wst.xml.core.internal.commentelement.impl.CommentElementRegistry;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMEntityDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery;
@@ -118,6 +121,18 @@
}
+ private class LimitedCache extends LinkedHashMap {
+ private static final long serialVersionUID = 1L;
+ private static final int MAX_SIZE = 10;
+ public LimitedCache() {
+ super(0, 0.75f, true);
+ }
+
+ protected boolean removeEldestEntry(java.util.Map.Entry entry) {
+ return size() > MAX_SIZE;
+ }
+ }
+
// this is a constant just to give compile-time control over
// whether or not to use the cache. If, in future, its found that
// there are no (or few) "duplicate requests" ... then this cache
@@ -129,6 +144,7 @@
private DOMModelImpl model = null;
private TagNameCache tagNameCache;
+ private Map fCMCache;
/**
* DocumentImpl constructor
*/
@@ -137,6 +153,7 @@
if (usetagnamecache) {
tagNameCache = new TagNameCache();
}
+ fCMCache = Collections.synchronizedMap(new LimitedCache());
}
/**
@@ -150,6 +167,7 @@
if (usetagnamecache) {
tagNameCache = new TagNameCache();
}
+ fCMCache = Collections.synchronizedMap(new LimitedCache());
}
/**
@@ -1045,6 +1063,23 @@
}
/**
+ * Provides an element's attribute declarations
+ * @param element the element to retrieve the attribute map of
+ * @return a <code>CMNamedNodeMap</code> of attributes if the declaration exists; null otherwise.
+ */
+ CMNamedNodeMap getCMAttributes(Element element) {
+ CMNamedNodeMap map = (CMNamedNodeMap) fCMCache.get(element);
+ if (map == null) {
+ CMElementDeclaration decl = ModelQueryUtil.getModelQuery(this).getCMElementDeclaration(element);
+ if (decl != null) {
+ map = decl.getAttributes();
+ fCMCache.put(element, map);
+ }
+ }
+ return map;
+ }
+
+ /**
* <p>
* EXPERIMENTAL! Based on the <a
* href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
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 2de1968..bf2d0bc 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
@@ -28,7 +28,10 @@
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
import org.eclipse.wst.xml.core.internal.commentelement.CommentElementAdapter;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery;
import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil;
import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser;
@@ -235,9 +238,23 @@
*/
public String getAttribute(String name) {
Attr attr = getAttributeNode(name);
- if (attr == null)
- return null;
- return attr.getValue();
+ // In the absence of the attribute, get the default value
+ return (attr != null) ? attr.getValue() : getDefaultValue(name);
+ }
+
+ /**
+ * 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 new String();
}
/**
@@ -303,9 +320,8 @@
*/
public String getAttributeNS(String uri, String name) {
Attr attr = getAttributeNodeNS(uri, name);
- if (attr == null)
- return null;
- return attr.getValue();
+ // In the absence of the attribute, get the default value
+ return (attr != null) ? attr.getValue() : getDefaultValue(name);
}
/**