bug 253753: handle namespaces when reading documents

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/core/DisplayDevice.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/core/DisplayDevice.java
index 24038ae..c958acb 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/core/DisplayDevice.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/core/DisplayDevice.java
@@ -16,6 +16,18 @@
  */
 public abstract class DisplayDevice {
 
+	public static final DisplayDevice NULL = new DisplayDevice() {
+		@Override
+		public int getHorizontalPPI() {
+			return 0;
+		}
+
+		@Override
+		public int getVerticalPPI() {
+			return 0;
+		}
+	};
+	
 	/**
 	 * Class constructor.
 	 */
@@ -52,5 +64,5 @@
 
 	// ======================================================= PRIVATE
 
-	private static DisplayDevice current;
+	private static DisplayDevice current = NULL;
 }
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DOMDocumentReader.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DOMDocumentReader.java
deleted file mode 100644
index 2e05c7a..0000000
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DOMDocumentReader.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Standards for Technology in Automotive Retail 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:
- *     David Carver (STAR) - initial API and implementation
- *******************************************************************************/
-package org.eclipse.wst.xml.vex.core.internal.dom;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/**
- * Class for creating documents given a DOM Document.
- */
-@SuppressWarnings("restriction")
-public class DOMDocumentReader extends DocumentReader {
-
-	/**
-	 * Reads a document given a DOM Document
-	 * 
-	 * @param domDocument
-	 *            IDOMDocument from which to load the document.
-	 */
-	public Document read(IDOMDocument domDocument) throws IOException,
-			ParserConfigurationException, SAXException {
-		final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(domDocument.getModel().getBaseLocation()));
-		final Reader reader = new StringReader(domDocument.getSource());
-		final InputSource inputSource = new InputSource(new BufferedReader(reader));
-		inputSource.setSystemId(file.getLocationURI().toString());
-		final Document result = read(inputSource);
-		return result;
-	}
-
-}
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentBuilder.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentBuilder.java
index 0517367..9a13e8f 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentBuilder.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentBuilder.java
@@ -13,6 +13,8 @@
 
 import java.util.LinkedList;
 
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.QualifiedName;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
@@ -33,23 +35,25 @@
  * </ul>
  */
 public class DocumentBuilder implements ContentHandler, LexicalHandler {
-	private IWhitespacePolicyFactory policyFactory;
+	private final IWhitespacePolicyFactory policyFactory;
 	private IWhitespacePolicy policy;
 
 	// Holds pending characters until we see another element boundary.
 	// This is (a) so we can collapse spaces in multiple adjacent character
 	// blocks, and (b) so we can trim trailing whitespace, if necessary.
-	private StringBuffer pendingChars = new StringBuffer();
+	private final StringBuffer pendingChars = new StringBuffer();
 
 	// If true, trim the leading whitespace from the next received block of
 	// text.
 	private boolean trimLeading = false;
 
 	// Content object to hold document content
-	private Content content = new GapContent(100);
+	private final Content content = new GapContent(100);
 
 	// Stack of StackElement objects
-	private LinkedList<StackEntry> stack = new LinkedList<StackEntry>();
+	private final LinkedList<StackEntry> stack = new LinkedList<StackEntry>();
+
+	private final NamespaceStack namespaceStack = new NamespaceStack();
 
 	private RootElement rootElement;
 
@@ -65,126 +69,148 @@
 	 *            Used to determine the WhitespacePolicy to use for a given
 	 *            document type.
 	 */
-	public DocumentBuilder(IWhitespacePolicyFactory policyFactory) {
+	public DocumentBuilder(final IWhitespacePolicyFactory policyFactory) {
 		this.policyFactory = policyFactory;
 	}
-	
+
 	/**
 	 * Returns the newly built <code>Document</code> object.
 	 */
 	public Document getDocument() {
-		return this.doc;
+		return doc;
 	}
 
 	// ============================================= ContentHandler methods
 
-	public void characters(char[] ch, int start, int length)
-			throws SAXException {
+	public void characters(final char[] ch, final int start, final int length) throws SAXException {
 
 		// Convert nulls to spaces, since we use nulls for element delimiters
-		char[] chars = new char[length];
+		final char[] chars = new char[length];
 		System.arraycopy(ch, start, chars, 0, length);
-		for (int i = 0; i < chars.length; i++) {
-			if (Character.isISOControl(chars[i]) && chars[i] != '\n'
-					&& chars[i] != '\r' && chars[i] != '\t') {
+		for (int i = 0; i < chars.length; i++)
+			if (Character.isISOControl(chars[i]) && chars[i] != '\n' && chars[i] != '\r' && chars[i] != '\t')
 				chars[i] = ' ';
-			}
-			
-		}
-		this.pendingChars.append(chars);
+		pendingChars.append(chars);
 	}
 
 	public void endDocument() {
 		if (rootElement == null)
 			return;
-		
+
 		doc = new Document(content, rootElement);
 		doc.setPublicID(dtdPublicID);
 		doc.setSystemID(dtdSystemID);
 		rootElement.setDocument(doc);
 	}
 
-	public void endElement(String namespaceURI, String localName, String qName) {
-		this.appendChars(true);
+	public void endElement(final String namespaceURI, final String localName, final String qName) {
+		appendChars(true);
 
-		final StackEntry entry = this.stack.removeLast();
+		final StackEntry entry = stack.removeLast();
 
 		// we must insert the trailing sentinel first, else the insertion
 		// pushes the end position of the element to after the sentinel
-		this.content.insertString(content.getLength(), "\0");
-		entry.element.setContent(this.content, entry.offset, content
-				.getLength() - 1);
+		content.insertString(content.getLength(), "\0");
+		entry.element.setContent(content, entry.offset, content.getLength() - 1);
 
-		if (this.isBlock(entry.element))
-			this.trimLeading = true;
+		if (isBlock(entry.element))
+			trimLeading = true;
 	}
 
-	public void endPrefixMapping(java.lang.String prefix) {
+	public void endPrefixMapping(final String prefix) {
+		System.out.println("end prefix: '" + prefix + "'"); // TODO trace
 	}
 
-	public void ignorableWhitespace(char[] ch, int start, int length) {
+	public void ignorableWhitespace(final char[] ch, final int start, final int length) {
 	}
 
-	public void processingInstruction(String target, String data) {
+	public void processingInstruction(final String target, final String data) {
 	}
 
-	public void setDocumentLocator(Locator locator) {
+	public void setDocumentLocator(final Locator locator) {
 		this.locator = locator;
 	}
 
-	public void skippedEntity(java.lang.String name) {
+	public void skippedEntity(final java.lang.String name) {
 	}
 
 	public void startDocument() {
 	}
 
-	public void startElement(String namespaceURI, String localName,
-			String qName, Attributes attrs)
+	public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes attrs) throws SAXException {
+		System.out.println("element: '" + qName + "' namespaceUri: '" + namespaceURI + "' local: '" + localName + "'"); // TODO trace
+		final QualifiedName elementName;
+		if ("".equals(localName))
+			elementName = new QualifiedName(null, qName);
+		else
+		elementName = new QualifiedName(namespaceURI, localName);
+		Element element;
+		if (stack.isEmpty()) {
+			rootElement = new RootElement(elementName);
+			element = rootElement;
+			if (policyFactory != null)
+				policy = policyFactory.getPolicy(dtdPublicID);
+		} else {
+			element = new Element(elementName);
 
-	throws SAXException {
-
-		try {
-			Element element;
-			if (stack.isEmpty()) {
-				rootElement = new RootElement(qName);
-				element = this.rootElement;
-				if (this.policyFactory != null) {
-					this.policy = this.policyFactory
-							.getPolicy(this.dtdPublicID);
-				}
-			} else {
-				element = new Element(qName);
-
-				Element parent = stack.getLast().element;
-				parent.addChild(element);
-			}
-
-			int n = attrs.getLength();
-			for (int i = 0; i < n; i++) {
-				element.setAttribute(attrs.getQName(i), attrs.getValue(i));
-			}
-
-			this.appendChars(this.isBlock(element));
-
-			stack.add(new StackEntry(element, content.getLength(), this
-					.isPre(element)));
-			content.insertString(content.getLength(), "\0");
-
-			this.trimLeading = true;
-
-		} catch (DocumentValidationException ex) {
-			throw new SAXParseException("DocumentValidationException",
-					this.locator, ex);
+			final Element parent = stack.getLast().element;
+			parent.addChild(element);
 		}
 
+		final String defaultNamespaceUri = namespaceStack.peekDefault();
+		if (defaultNamespaceUri != null)
+			element.declareDefaultNamespace(defaultNamespaceUri);
+		
+		for (final String prefix : namespaceStack.getPrefixes())
+			element.declareNamespace(prefix, namespaceStack.peek(prefix));
+		
+		final int n = attrs.getLength();
+		for (int i = 0; i < n; i++) {
+			System.out.println("attr: " + attrs.getQName(i)); // TODO trace
+			final QualifiedName attributeName;
+			if ("".equals(attrs.getLocalName(i)))
+				attributeName = new QualifiedName(null, attrs.getQName(i));
+			else if ("".equals(attrs.getURI(i)))
+				attributeName = new QualifiedName(elementName.getQualifier(), attrs.getLocalName(i));
+			else
+				attributeName = new QualifiedName(attrs.getURI(i), attrs.getLocalName(i));
+			try {
+				element.setAttribute(attributeName, attrs.getValue(i));
+			} catch (final DocumentValidationException e) {
+				throw new SAXParseException("DocumentValidationException", locator, e);
+			}
+		}
+
+		appendChars(isBlock(element));
+
+		stack.add(new StackEntry(element, content.getLength(), isPre(element)));
+		content.insertString(content.getLength(), "\0");
+
+		trimLeading = true;
+
+		namespaceStack.clear();
 	}
-	
-	public void startPrefixMapping(String prefix, String uri) {
+
+	public void startPrefixMapping(final String prefix, final String uri) {
+		System.out.println("prefix: '" + prefix + "' uri: '" + uri + "'"); // TODO trace
+		checkPrefix(prefix);
+		if (isDefaultPrefix(prefix))
+			namespaceStack.pushDefault(uri);
+		else
+			namespaceStack.push(prefix, uri);
+	}
+
+	private static void checkPrefix(final String prefix) {
+		Assert.isNotNull(prefix, "null is not a valid namespace prefix.");
+	}
+
+	private static boolean isDefaultPrefix(final String prefix) {
+		return "".equals(prefix);
 	}
 
 	// ============================================== LexicalHandler methods
 
-	public void comment(char[] ch, int start, int length) {
+	public void comment(final char[] ch, final int start, final int length) {
 	}
 
 	public void endCDATA() {
@@ -193,54 +219,51 @@
 	public void endDTD() {
 	}
 
-	public void endEntity(String name) {
+	public void endEntity(final String name) {
 	}
 
 	public void startCDATA() {
 	}
 
-	public void startDTD(String name, String publicId, String systemId) {
-		this.dtdPublicID = publicId;
-		this.dtdSystemID = systemId;
+	public void startDTD(final String name, final String publicId, final String systemId) {
+		dtdPublicID = publicId;
+		dtdSystemID = systemId;
 	}
 
-	public void startEntity(java.lang.String name) {
+	public void startEntity(final java.lang.String name) {
 	}
 
 	// ======================================================== PRIVATE
 
-
 	// Append any pending characters to the content
-	private void appendChars(boolean trimTrailing) {
+	private void appendChars(final boolean trimTrailing) {
 
 		StringBuffer sb;
 
 		sb = cleanUpTextContent(trimTrailing);
 
-		this.content.insertString(this.content.getLength(), sb.toString());
+		content.insertString(content.getLength(), sb.toString());
 
-		this.pendingChars.setLength(0);
-		this.trimLeading = false;
+		pendingChars.setLength(0);
+		trimLeading = false;
 	}
 
-	private StringBuffer cleanUpTextContent(boolean trimTrailing) {
+	private StringBuffer cleanUpTextContent(final boolean trimTrailing) {
 		StringBuffer sb;
-		StackEntry entry = this.stack.isEmpty() ? null : this.stack.getLast();
+		final StackEntry entry = stack.isEmpty() ? null : stack.getLast();
 
-		if (entry != null && entry.pre) {
-
-			sb = this.pendingChars;
-
-		} else {
+		if (entry != null && entry.pre)
+			sb = pendingChars;
+		else {
 
 			// collapse the space in the pending characters
-			sb = new StringBuffer(this.pendingChars.length());
+			sb = new StringBuffer(pendingChars.length());
 			boolean ws = false; // true if we're in a run of whitespace
-			for (int i = 0; i < this.pendingChars.length(); i++) {
-				char c = this.pendingChars.charAt(i);
-				if (Character.isWhitespace(c)) {
+			for (int i = 0; i < pendingChars.length(); i++) {
+				final char c = pendingChars.charAt(i);
+				if (Character.isWhitespace(c))
 					ws = true;
-				} else {
+				else {
 					if (ws) {
 						sb.append(' ');
 						ws = false;
@@ -248,29 +271,25 @@
 					sb.append(c);
 				}
 			}
-			if (ws) {
+			if (ws)
 				sb.append(' ');
-			}
 			// trim leading and trailing space, if necessary
-			if (this.trimLeading && sb.length() > 0 && sb.charAt(0) == ' ') {
+			if (trimLeading && sb.length() > 0 && sb.charAt(0) == ' ')
 				sb.deleteCharAt(0);
-			}
-			if (trimTrailing && sb.length() > 0
-					&& sb.charAt(sb.length() - 1) == ' ') {
+			if (trimTrailing && sb.length() > 0 && sb.charAt(sb.length() - 1) == ' ')
 				sb.setLength(sb.length() - 1);
-			}
 		}
 
-		this.normalizeNewlines(sb);
+		normalizeNewlines(sb);
 		return sb;
 	}
 
-	private boolean isBlock(Element element) {
-		return this.policy != null && this.policy.isBlock(element);
+	private boolean isBlock(final Element element) {
+		return policy != null && policy.isBlock(element);
 	}
 
-	private boolean isPre(Element element) {
-		return this.policy != null && this.policy.isPre(element);
+	private boolean isPre(final Element element) {
+		return policy != null && policy.isPre(element);
 	}
 
 	/**
@@ -279,7 +298,7 @@
 	 * @param sb
 	 *            StringBuffer to be normalized.
 	 */
-	private void normalizeNewlines(StringBuffer sb) {
+	private void normalizeNewlines(final StringBuffer sb) {
 
 		// State machine states
 		final int START = 0;
@@ -290,13 +309,12 @@
 		while (i < sb.length()) {
 			// No simple 'for' here, since we may delete chars
 
-			char c = sb.charAt(i);
+			final char c = sb.charAt(i);
 
 			switch (state) {
 			case START:
-				if (c == '\r') {
+				if (c == '\r')
 					state = SEEN_CR;
-				}
 				i++;
 				break;
 
@@ -331,7 +349,7 @@
 		public int offset;
 		public boolean pre;
 
-		public StackEntry(Element element, int offset, boolean pre) {
+		public StackEntry(final Element element, final int offset, final boolean pre) {
 			this.element = element;
 			this.offset = offset;
 			this.pre = pre;
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentReader.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentReader.java
index f3f76ad..a94975c 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentReader.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.core/src/org/eclipse/wst/xml/vex/core/internal/dom/DocumentReader.java
@@ -18,6 +18,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.net.URL;
+
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
@@ -60,8 +61,7 @@
 	 * @param url
 	 *            URL from which to load the document.
 	 */
-	public Document read(URL url) throws IOException,
-			ParserConfigurationException, SAXException {
+	public Document read(final URL url) throws IOException, ParserConfigurationException, SAXException {
 
 		return read(new InputSource(url.toString()));
 	}
@@ -73,10 +73,9 @@
 	 * @param s
 	 *            String containing the document to be read.
 	 */
-	public Document read(String s) throws IOException,
-			ParserConfigurationException, SAXException {
+	public Document read(final String s) throws IOException, ParserConfigurationException, SAXException {
 
-		Reader reader = new CharArrayReader(s.toCharArray());
+		final Reader reader = new CharArrayReader(s.toCharArray());
 		return this.read(new InputSource(reader));
 	}
 
@@ -86,45 +85,41 @@
 	 * @param is
 	 *            SAX InputSource from which to load the document.
 	 */
-	public Document read(InputSource is) throws IOException,
-			ParserConfigurationException, SAXException {
+	public Document read(final InputSource is) throws IOException, ParserConfigurationException, SAXException {
 
-		SAXParserFactory factory = SAXParserFactory.newInstance();
+		final SAXParserFactory factory = SAXParserFactory.newInstance();
 		factory.setValidating(false); // TODO: experimental--SWT implementation
-		XMLReader xmlReader = factory.newSAXParser().getXMLReader();
+		factory.setNamespaceAware(true);
+		final XMLReader xmlReader = factory.newSAXParser().getXMLReader();
 		// xmlReader.setFeature("http://xml.org/sax/features/validation",
 		// false);
 		final org.eclipse.wst.xml.vex.core.internal.dom.DocumentBuilder builder = new org.eclipse.wst.xml.vex.core.internal.dom.DocumentBuilder(
-				this.getWhitespacePolicyFactory());
+				getWhitespacePolicyFactory());
 
 		ContentHandler contentHandler = builder;
 		LexicalHandler lexicalHandler = builder;
 
-		if (this.isDebugging()) {
-			Object proxy = Proxy.newProxyInstance(this.getClass()
-					.getClassLoader(), new Class[] { ContentHandler.class,
-					LexicalHandler.class }, new InvocationHandler() {
-				public Object invoke(Object proxy, Method method, Object[] args)
-						throws Throwable {
-					try {
-						return method.invoke(builder, args);
-					} catch (InvocationTargetException ex) {
-						ex.getCause().printStackTrace();
-						throw ex.getCause();
-					}
-				}
-			});
+		if (isDebugging()) {
+			final Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { ContentHandler.class, LexicalHandler.class },
+					new InvocationHandler() {
+						public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+							try {
+								return method.invoke(builder, args);
+							} catch (final InvocationTargetException ex) {
+								ex.getCause().printStackTrace();
+								throw ex.getCause();
+							}
+						}
+					});
 
 			contentHandler = (ContentHandler) proxy;
 			lexicalHandler = (LexicalHandler) proxy;
 		}
 
 		xmlReader.setContentHandler(contentHandler);
-		xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",
-				lexicalHandler);
-		if (this.getEntityResolver() != null) {
-			xmlReader.setEntityResolver(this.getEntityResolver());
-		}
+		xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler);
+		if (getEntityResolver() != null)
+			xmlReader.setEntityResolver(getEntityResolver());
 		xmlReader.parse(is);
 		final Document result = builder.getDocument();
 		if (result != null)
@@ -138,7 +133,7 @@
 	 * @param debugging
 	 *            true if the component should log debugging info to stdout.
 	 */
-	public void setDebugging(boolean debugging) {
+	public void setDebugging(final boolean debugging) {
 		this.debugging = debugging;
 	}
 
@@ -148,7 +143,7 @@
 	 * @param entityResolver
 	 *            The entityResolver to set.
 	 */
-	public void setEntityResolver(EntityResolver entityResolver) {
+	public void setEntityResolver(final EntityResolver entityResolver) {
 		this.entityResolver = entityResolver;
 	}
 
@@ -160,8 +155,7 @@
 	 * @param whitespacePolicyFactory
 	 *            The whitespacePolicyFactory to set.
 	 */
-	public void setWhitespacePolicyFactory(
-			IWhitespacePolicyFactory whitespacePolicyFactory) {
+	public void setWhitespacePolicyFactory(final IWhitespacePolicyFactory whitespacePolicyFactory) {
 		this.whitespacePolicyFactory = whitespacePolicyFactory;
 	}
 
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/VexEditor.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/VexEditor.java
index 425b956..d455ac3 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/VexEditor.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/VexEditor.java
@@ -28,7 +28,6 @@
 import org.eclipse.core.resources.IResourceChangeListener;
 import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
@@ -67,13 +66,9 @@
 import org.eclipse.ui.views.properties.IPropertySource;
 import org.eclipse.ui.views.properties.IPropertySourceProvider;
 import org.eclipse.ui.views.properties.PropertySheetPage;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
 import org.eclipse.wst.xml.vex.core.internal.core.ListenerList;
-import org.eclipse.wst.xml.vex.core.internal.dom.DOMDocumentReader;
 import org.eclipse.wst.xml.vex.core.internal.dom.Document;
+import org.eclipse.wst.xml.vex.core.internal.dom.DocumentReader;
 import org.eclipse.wst.xml.vex.core.internal.dom.DocumentWriter;
 import org.eclipse.wst.xml.vex.core.internal.dom.Element;
 import org.eclipse.wst.xml.vex.core.internal.dom.IWhitespacePolicy;
@@ -297,13 +292,13 @@
 				return;
 			}
 
-			final DOMDocumentReader reader = new DOMDocumentReader();
+			final DocumentReader reader = new DocumentReader();
 			reader.setDebugging(debugging);
 			reader.setEntityResolver(entityResolver);
 			reader.setWhitespacePolicyFactory(wsFactory);
 			doctype = null; // must be null to set it to a new value via
 							// entityResolveras by following read():
-			doc = reader.read(getDOMDocument(file));
+			doc = reader.read(file.getLocationURI().toURL());
 
 			if (debugging) {
 				final long end = System.currentTimeMillis();
@@ -390,19 +385,6 @@
 		}
 	}
 
-	private IDOMDocument getDOMDocument(final IFile file) throws IOException, CoreException {
-		final IStructuredModel model = StructuredModelManager.getModelManager().getModelForRead(file);
-		IDOMDocument modelDocument = null;
-		try {
-			if (model instanceof IDOMModel)
-				modelDocument = ((IDOMModel) model).getDocument();
-		} finally {
-			if (model != null)
-				model.releaseFromRead();
-		}
-		return modelDocument;
-	}
-
 	@Override
 	public boolean isDirty() {
 		if (vexWidget != null)
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/internal/dom/NamespaceTest.java b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/internal/dom/NamespaceTest.java
index 9370648..27d6430 100644
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/internal/dom/NamespaceTest.java
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/internal/dom/NamespaceTest.java
@@ -12,8 +12,17 @@
 

 import static org.junit.Assert.*;

 

+import java.io.IOException;

+import java.util.Collections;

+

+import javax.xml.parsers.ParserConfigurationException;

+

 import org.eclipse.core.runtime.QualifiedName;

+import org.eclipse.wst.xml.vex.core.internal.css.Rule;

+import org.eclipse.wst.xml.vex.core.internal.css.StyleSheet;

+import org.eclipse.wst.xml.vex.core.internal.widget.CssWhitespacePolicy;

 import org.junit.Test;

+import org.xml.sax.SAXException;

 

 /**

  * @author Florian Thienel

@@ -27,18 +36,18 @@
 		final Attribute attributeWithNamespace = new Attribute(null, new QualifiedName("http://namespace/uri", "localName"), "value");

 		assertEquals("http://namespace/uri:localName", attributeWithNamespace.getQualifiedName().toString());

 	}

-	

+

 	@Test

 	public void declareNamespace() throws Exception {

 		final Element element = new Element("element");

 		assertNull(element.getNamespaceURI("nsPrefix"));

 		assertNull(element.getNamespacePrefix("http://namespace/uri"));

-		

+

 		element.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("http://namespace/uri", element.getNamespaceURI("nsPrefix"));

 		assertEquals("nsPrefix", element.getNamespacePrefix("http://namespace/uri"));

 	}

-	

+

 	@Test

 	public void transitiveNamespaceDeclaration() throws Exception {

 		final Element parent = new Element("parent");

@@ -46,24 +55,24 @@
 		child.setParent(parent);

 		assertNull(child.getNamespaceURI("nsPrefix"));

 		assertNull(child.getNamespacePrefix("http://namespace/uri"));

-		

+

 		parent.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("http://namespace/uri", child.getNamespaceURI("nsPrefix"));

 		assertEquals("nsPrefix", child.getNamespacePrefix("http://namespace/uri"));

 	}

-	

+

 	@Test

 	public void removeNamespaceDeclaration() throws Exception {

 		final Element element = new Element("element");

 		element.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("http://namespace/uri", element.getNamespaceURI("nsPrefix"));

 		assertEquals("nsPrefix", element.getNamespacePrefix("http://namespace/uri"));

-		

+

 		element.removeNamespace("nsPrefix");

 		assertNull(element.getNamespaceURI("nsPrefix"));

 		assertNull(element.getNamespacePrefix("http://namespace/uri"));

 	}

-	

+

 	@Test

 	public void overloadNamespaceDeclaration() throws Exception {

 		final Element element = new Element("element");

@@ -73,7 +82,7 @@
 		assertEquals("http://namespace/uri", element.getNamespaceURI("nsPrefix2"));

 		assertNotNull(element.getNamespacePrefix("http://namespace/uri"));

 	}

-	

+

 	@Test

 	public void overrideNamespaceDeclaration() throws Exception {

 		final Element parent = new Element("parent");

@@ -82,30 +91,30 @@
 		parent.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("http://namespace/uri", child.getNamespaceURI("nsPrefix"));

 		assertEquals("nsPrefix", child.getNamespacePrefix("http://namespace/uri"));

-		

+

 		child.declareNamespace("nsPrefix", "http://namespace2/uri");

 		assertNull(child.getNamespacePrefix("http://namespace/uri"));

 		assertEquals("http://namespace2/uri", child.getNamespaceURI("nsPrefix"));

 		assertEquals("nsPrefix", child.getNamespacePrefix("http://namespace2/uri"));

 	}

-	

+

 	@Test

 	public void ignoreEmptyNamespaceURI() throws Exception {

 		final Element element = new Element("element");

 		element.declareNamespace("nsPrefix", null);

 		assertNull(element.getNamespaceURI("nsPrefix"));

 		assertNull(element.getNamespacePrefix(null));

-		

+

 		element.declareNamespace("nsPrefix", "");

 		assertNull(element.getNamespaceURI("nsPrefix"));

 		assertNull(element.getNamespacePrefix(""));

-		

+

 		element.declareNamespace("nsPrefix", " ");

 		assertNull(element.getNamespaceURI("nsPrefix"));

 		assertNull(element.getNamespacePrefix(" "));

 		assertNull(element.getNamespacePrefix(""));

 	}

-	

+

 	@Test

 	public void handleDefaultNamespace() throws Exception {

 		final Element element = new Element("element");

@@ -113,7 +122,7 @@
 		element.declareDefaultNamespace("http://namespace/uri");

 		assertEquals("http://namespace/uri", element.getDefaultNamespaceURI());

 	}

-	

+

 	@Test

 	public void elementLocalName() throws Exception {

 		final Element elementWithoutNamespace = new Element("localName");

@@ -121,7 +130,7 @@
 		final Element elementWithNamespace = new Element(new QualifiedName("http://namespace/uri", "localName"));

 		assertEquals("localName", elementWithNamespace.getLocalName());

 	}

-	

+

 	@Test

 	public void elementQualifiedName() throws Exception {

 		final Element elementWithoutNamespace = new Element("localName");

@@ -129,7 +138,7 @@
 		final Element elementWithNamespace = new Element(new QualifiedName("http://namespace/uri", "localName"));

 		assertEquals("http://namespace/uri:localName", elementWithNamespace.getQualifiedName().toString());

 	}

-	

+

 	@Test

 	public void elementPrefix() throws Exception {

 		final Element elementWithoutNamespace = new Element("element");

@@ -138,12 +147,12 @@
 		final Element elementWithNamespace = new Element(new QualifiedName("http://namespace/uri", "element"));

 		elementWithNamespace.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("nsPrefix", elementWithNamespace.getPrefix());

-		

+

 		final Element elementWithDefaultNamespace = new Element(new QualifiedName("http://namespace/uri", "element"));

 		elementWithDefaultNamespace.declareDefaultNamespace("http://namespace/uri");

 		assertNull(elementWithDefaultNamespace.getPrefix());

 	}

-	

+

 	@Test

 	public void elementPrefixedName() throws Exception {

 		final Element elementWithoutNamespace = new Element("element");

@@ -152,12 +161,12 @@
 		final Element elementWithNamespace = new Element(new QualifiedName("http://namespace/uri", "element"));

 		elementWithNamespace.declareNamespace("nsPrefix", "http://namespace/uri");

 		assertEquals("nsPrefix:element", elementWithNamespace.getPrefixedName());

-		

+

 		final Element elementWithDefaultNamespace = new Element(new QualifiedName("http://namespace/uri", "element"));

 		elementWithDefaultNamespace.declareDefaultNamespace("http://namespace/uri");

 		assertEquals("element", elementWithDefaultNamespace.getPrefixedName());

 	}

-	

+

 	@Test

 	public void attributePrefixedName() throws Exception {

 		final Element element = new Element(new QualifiedName("http://namespace/uri/1", "element"));

@@ -167,9 +176,88 @@
 		element.setAttribute("attribute1", "value1");

 		element.setAttribute(new QualifiedName("http://namespace/uri/1", "attribute2"), "value2");

 		element.setAttribute(new QualifiedName("http://namespace/uri/2", "attribute3"), "value3");

-		

+

 		assertEquals("attribute1", element.getAttribute("attribute1").getPrefixedName());

 		assertEquals("attribute2", element.getAttribute(new QualifiedName("http://namespace/uri/1", "attribute2")).getPrefixedName());

 		assertEquals("ns2:attribute3", element.getAttribute(new QualifiedName("http://namespace/uri/2", "attribute3")).getPrefixedName());

 	}

+

+	@Test

+	public void readNamespaceDeclarations() throws Exception {

+		final Document document = readDocumentFromString("<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\"/>");

+		final Element rootElement = document.getRootElement();

+

+		assertEquals("http://namespace/default", rootElement.getDefaultNamespaceURI());

+		assertEquals("http://namespace/uri/1", rootElement.getNamespaceURI("ns1"));

+	}

+

+	private Document readDocumentFromString(final String documentContent) throws IOException, ParserConfigurationException, SAXException {

+		final DocumentReader documentReader = new DocumentReader();

+		documentReader.setWhitespacePolicyFactory(new IWhitespacePolicyFactory() {

+			public IWhitespacePolicy getPolicy(final String publicId) {

+				return new CssWhitespacePolicy(new StyleSheet(Collections.<Rule> emptyList()));

+			}

+		});

+		return documentReader.read(documentContent);

+	}

+

+	@Test

+	public void readNestedNamespaceDeclarations() throws Exception {

+		final Document document = readDocumentFromString(

+				"<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\">"

+				+ "<ns2:b xmlns:ns2=\"http://namespace/uri/2\"/>" 

+				+ "</ns1:a>");

+		final Element rootElement = document.getRootElement();

+		final Element nestedElement = rootElement.getChildElements().get(0);

+		assertEquals("http://namespace/default", nestedElement.getDefaultNamespaceURI());

+		assertEquals("http://namespace/uri/1", nestedElement.getNamespaceURI("ns1"));

+		assertEquals("http://namespace/uri/2", nestedElement.getNamespaceURI("ns2"));

+		assertNull(rootElement.getNamespaceURI("ns2"));

+	}

+	

+	@Test

+	public void evaluateElementPrefix() throws Exception {

+		final Document document = readDocumentFromString(

+				"<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\">"

+				+ "<ns2:b xmlns:ns2=\"http://namespace/uri/2\"/>" 

+				+ "<c />" 

+				+ "</ns1:a>");

+		final Element rootElement = document.getRootElement();

+		assertEquals("http://namespace/uri/1", rootElement.getQualifiedName().getQualifier());

+		assertEquals("a", rootElement.getLocalName());

+		assertEquals("ns1:a", rootElement.getPrefixedName());

+		

+		final Element firstNestedElement = rootElement.getChildElements().get(0);

+		assertEquals("http://namespace/uri/2", firstNestedElement.getQualifiedName().getQualifier());

+		assertEquals("b", firstNestedElement.getLocalName());

+		assertEquals("ns2:b", firstNestedElement.getPrefixedName());

+		

+		final Element secondNestedElement = rootElement.getChildElements().get(1);

+		assertEquals("http://namespace/default", secondNestedElement.getQualifiedName().getQualifier());

+		assertEquals("c", secondNestedElement.getLocalName());

+		assertEquals("c", secondNestedElement.getPrefixedName());

+	}

+	

+	@Test

+	public void evaluateAttributePrefix() throws Exception {

+		final Document document = readDocumentFromString(

+				"<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\" attr1=\"value1\">"

+				+ "<ns2:b xmlns:ns2=\"http://namespace/uri/2\" ns1:attr2=\"value2\" ns2:attr3=\"value3\" attr4=\"value4\" />" 

+				+ "<c ns1:attr5=\"value5\" attr6=\"value6\" />" 

+				+ "</ns1:a>");

+		final Element rootElement = document.getRootElement();

+		assertTrue(rootElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr1")));

+		assertFalse(rootElement.getAttributeNames().contains(new QualifiedName("http://namespace/default", "attr1")));

+		assertFalse(rootElement.getAttributeNames().contains(new QualifiedName("", "attr1")));

+		assertFalse(rootElement.getAttributeNames().contains(new QualifiedName(null, "attr1")));

+		

+		final Element firstNestedElement = rootElement.getChildElements().get(0);

+		assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr2")));

+		assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/2", "attr3")));

+		assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/2", "attr4")));

+		

+		final Element secondNestedElement = rootElement.getChildElements().get(1);

+		assertTrue(secondNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr5")));

+		assertTrue(secondNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/default", "attr6")));

+	}

 }

diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
index b2b19f8..8a2e9e1 100755
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
@@ -19,11 +19,12 @@
 import org.eclipse.wst.xml.vex.core.internal.css.CssTest;
 import org.eclipse.wst.xml.vex.core.internal.css.PropertyTest;
 import org.eclipse.wst.xml.vex.core.internal.css.RuleTest;
-import org.eclipse.wst.xml.vex.core.internal.dom.NamespaceTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.BlockElementBoxTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.DTDValidatorTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.DocumentWriterTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.GapContentTest;
+import org.eclipse.wst.xml.vex.core.internal.dom.NamespaceStackTest;
+import org.eclipse.wst.xml.vex.core.internal.dom.NamespaceTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.SpaceNormalizerTest;
 import org.eclipse.wst.xml.vex.core.internal.dom.TextWrapperTest;
 import org.eclipse.wst.xml.vex.core.internal.layout.ImageBoxTest;
@@ -41,6 +42,7 @@
 
 	public VEXCoreTestSuite() {
 		super("Vex Core Tests");
+		addTest(new JUnit4TestAdapter(NamespaceStackTest.class));
 		addTest(new JUnit4TestAdapter(NamespaceTest.class));
 		addTestSuite(CssTest.class);
 		addTestSuite(PropertyTest.class);