encapsulate initialization of documentType and style to
VexDocumentContentModel; use an entityResolver to make use of the XML
catalog

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java
new file mode 100644
index 0000000..0fa7ab3
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java
@@ -0,0 +1,59 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Florian Thienel 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:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.vex.core.internal.dom;

+

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertFalse;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertTrue;

+

+import org.eclipse.core.runtime.QualifiedName;

+import org.junit.Before;

+import org.junit.Test;

+

+/**

+ * @author Florian Thienel

+ */

+public class DocumentContentModelTest {

+

+	private DocumentContentModel model;

+

+	@Before

+	public void setUp() throws Exception {

+		model = new DocumentContentModel();

+	}

+	

+	@Test

+	public void initializeWithPublicId() throws Exception {

+		model.initialize("publicId", "systemId", new RootElement(new QualifiedName("schemaId", "rootElement")));

+		assertEquals("publicId", model.getMainDocumentTypeIdentifier());

+		assertTrue(model.isDtdAssigned());

+	}

+

+	@Test

+	public void initializeWithSystemId() throws Exception {

+		model.initialize(null, "systemId", new RootElement(new QualifiedName("schemaId", "rootElement")));

+		assertEquals("systemId", model.getMainDocumentTypeIdentifier());

+		assertTrue(model.isDtdAssigned());

+	}

+	

+	@Test

+	public void initializeWithNamespace() throws Exception {

+		model.initialize(null, null, new RootElement(new QualifiedName("schemaId", "rootElement")));

+		assertEquals("schemaId", model.getMainDocumentTypeIdentifier());

+		assertFalse(model.isDtdAssigned());

+	}

+	

+	@Test

+	public void createWhitespacePolicy() throws Exception {

+		assertNotNull(model.getWhitespacePolicy());

+	}

+}

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
index f7708f9..0c9a363 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
@@ -10,7 +10,6 @@
  *******************************************************************************/

 package org.eclipse.vex.core.internal.dom;

 

-import static org.junit.Assert.*;

 import static org.junit.Assert.assertEquals;

 import static org.junit.Assert.assertNotNull;

 import static org.junit.Assert.assertNull;

@@ -30,7 +29,6 @@
 	@Test

 	public void readDocumentWithDtdPublic() throws Exception {

 		final DocumentReader reader = new DocumentReader();

-		reader.setWhitespacePolicyFactory(IWhitespacePolicyFactory.NULL);

 		final Document document = reader.read(TestResources.get("documentWithDtdPublic.xml"));

 		assertEquals("-//Eclipse Foundation//DTD Vex Test//EN", document.getPublicID());

 		assertEquals("test1.dtd", document.getSystemID());

@@ -39,7 +37,6 @@
 	@Test

 	public void testname() throws Exception {

 		final DocumentReader reader = new DocumentReader();

-		reader.setWhitespacePolicyFactory(IWhitespacePolicyFactory.NULL);

 		final URL documentUrl = TestResources.get("documentWithDtdSystem.xml");

 		final Document document = reader.read(documentUrl);

 		assertNull(document.getPublicID());

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentWriterTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentWriterTest.java
index caa9178..92584c3 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentWriterTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentWriterTest.java
@@ -28,12 +28,6 @@
 import org.eclipse.vex.core.internal.css.MockDisplayDevice;
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.StyleSheetReader;
-import org.eclipse.vex.core.internal.dom.Document;
-import org.eclipse.vex.core.internal.dom.DocumentWriter;
-import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
-import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;
-import org.eclipse.vex.core.internal.dom.Node;
 import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
 import org.eclipse.vex.core.tests.TestResources;
 import org.xml.sax.InputSource;
@@ -111,14 +105,12 @@
 		final DefaultHandler defaultHandler = new DefaultHandler();
 
 		final IWhitespacePolicy policy = new CssWhitespacePolicy(ss);
-
-		final IWhitespacePolicyFactory wsFactory = new IWhitespacePolicyFactory() {
-			public IWhitespacePolicy getPolicy(final String publicId) {
+		final DocumentBuilder builder = new DocumentBuilder(new DocumentContentModel() {
+			@Override
+			public IWhitespacePolicy getWhitespacePolicy() {
 				return policy;
 			}
-		};
-
-		final org.eclipse.vex.core.internal.dom.DocumentBuilder builder = new org.eclipse.vex.core.internal.dom.DocumentBuilder(wsFactory);
+		});
 
 		xmlReader.setContentHandler(builder);
 		xmlReader.setDTDHandler(defaultHandler);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
index 292923a..558deaa 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
@@ -10,25 +10,18 @@
  *******************************************************************************/

 package org.eclipse.vex.core.internal.dom;

 

-import static org.junit.Assert.*;

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertFalse;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertNull;

+import static org.junit.Assert.assertTrue;

 

 import java.io.ByteArrayOutputStream;

 import java.io.IOException;

-import java.util.Collections;

 

 import javax.xml.parsers.ParserConfigurationException;

 

 import org.eclipse.core.runtime.QualifiedName;

-import org.eclipse.vex.core.internal.css.Rule;

-import org.eclipse.vex.core.internal.css.StyleSheet;

-import org.eclipse.vex.core.internal.dom.Attribute;

-import org.eclipse.vex.core.internal.dom.Document;

-import org.eclipse.vex.core.internal.dom.DocumentReader;

-import org.eclipse.vex.core.internal.dom.DocumentWriter;

-import org.eclipse.vex.core.internal.dom.Element;

-import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;

-import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;

-import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;

 import org.junit.Test;

 import org.xml.sax.SAXException;

 

@@ -130,32 +123,32 @@
 		element.declareDefaultNamespace("http://namespace/uri");

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

 	}

-	

+

 	@Test

 	public void getDeclaredDefaultNamespaceURI() throws Exception {

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

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

 		element.addChild(child);

-		

+

 		assertNull(element.getDeclaredDefaultNamespaceURI());

 		element.declareDefaultNamespace("http://namespace/default/element");

 		assertEquals("http://namespace/default/element", element.getDeclaredDefaultNamespaceURI());

-		

+

 		assertNull(child.getDeclaredDefaultNamespaceURI());

 		child.declareDefaultNamespace("http://namespace/default/child");

 		assertEquals("http://namespace/default/child", child.getDeclaredDefaultNamespaceURI());

 	}

-	

+

 	@Test

 	public void getDeclaredNamespacePrefixes() throws Exception {

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

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

 		element.addChild(child);

-		

+

 		assertTrue(element.getDeclaredNamespacePrefixes().isEmpty());

 		element.declareDefaultNamespace("http://namespace/default/element");

 		assertTrue(element.getDeclaredNamespacePrefixes().isEmpty());

-		

+

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

 		assertEquals(1, element.getDeclaredNamespacePrefixes().size());

 		assertTrue(element.getDeclaredNamespacePrefixes().contains("ns1"));

@@ -163,7 +156,7 @@
 		assertEquals(2, element.getDeclaredNamespacePrefixes().size());

 		assertTrue(element.getDeclaredNamespacePrefixes().contains("ns1"));

 		assertTrue(element.getDeclaredNamespacePrefixes().contains("ns2"));

-		

+

 		assertTrue(child.getDeclaredNamespacePrefixes().isEmpty());

 		child.declareNamespace("ns3", "http://namespace/uri/3");

 		assertEquals(1, child.getDeclaredNamespacePrefixes().size());

@@ -235,12 +228,12 @@
 		element.declareDefaultNamespace("http://namespace/uri/default");

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

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

-		

+

 		final Element clone = (Element) element.clone();

 		assertEquals("http://namespace/uri/default", clone.getDeclaredDefaultNamespaceURI());

-		

+

 	}

-	

+

 	@Test

 	public void readNamespaceDeclarations() throws Exception {

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

@@ -251,21 +244,13 @@
 	}

 

 	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);

+		return new 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 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());

@@ -273,66 +258,60 @@
 		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 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 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")));

 	}

-	

+

 	@Test

 	public void readWriteCycle() throws Exception {

 		final String inputContent = "<?xml version='1.0'?> <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\" attr3=\"value3\"/> " 

-		+ "<c attr4=\"value4\" ns1:attr5=\"value5\"/>" 

-		+ "</ns1:a> ";

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

+				+ "</ns1:a> ";

 		final Document document = readDocumentFromString(inputContent);

-		

+

 		final DocumentWriter documentWriter = new DocumentWriter();

 		final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

 		documentWriter.write(document, buffer);

 		final String outputContent = new String(buffer.toByteArray()).replaceAll("\\s+", " ");

-		

+

 		assertEquals(inputContent, outputContent);

 	}

 }

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
index 806d044..db2b914 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
@@ -11,10 +11,14 @@
 package org.eclipse.vex.core.internal.dom;

 

 import static org.eclipse.vex.core.internal.dom.Validator.PCDATA;

-import static org.eclipse.vex.core.tests.TestResources.*;

-import static org.junit.Assert.*;

+import static org.eclipse.vex.core.tests.TestResources.CONTENT_NS;

+import static org.eclipse.vex.core.tests.TestResources.STRUCTURE_NS;

+import static org.eclipse.vex.core.tests.TestResources.TEST_DTD;

+import static org.eclipse.vex.core.tests.TestResources.getAsStream;

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertTrue;

 

-import java.io.IOException;

 import java.io.InputStream;

 import java.util.ArrayList;

 import java.util.Collections;

@@ -23,12 +27,6 @@
 import java.util.Set;

 

 import org.eclipse.core.runtime.QualifiedName;

-import org.eclipse.vex.core.internal.dom.Document;

-import org.eclipse.vex.core.internal.dom.DocumentReader;

-import org.eclipse.vex.core.internal.dom.Element;

-import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;

-import org.eclipse.vex.core.internal.dom.RootElement;

-import org.eclipse.vex.core.internal.dom.Validator;

 import org.eclipse.vex.core.internal.validator.WTPVEXValidator;

 import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;

 import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;

@@ -36,40 +34,30 @@
 import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;

 import org.eclipse.wst.xml.core.internal.contentmodel.ContentModelManager;

 import org.junit.Test;

-import org.xml.sax.EntityResolver;

 import org.xml.sax.InputSource;

-import org.xml.sax.SAXException;

 

 /**

  * @author Florian Thienel

  */

 public class SchemaValidatorTest {

-	

+

 	private static final QualifiedName CHAPTER = new QualifiedName(STRUCTURE_NS, "chapter");

 	private static final QualifiedName TITLE = new QualifiedName(STRUCTURE_NS, "title");

-	

+

 	private static final QualifiedName P = new QualifiedName(CONTENT_NS, "p");

 	private static final QualifiedName B = new QualifiedName(CONTENT_NS, "b");

 	private static final QualifiedName I = new QualifiedName(CONTENT_NS, "i");

-	

+

 	@Test

 	public void readDocumentWithTwoSchemas() throws Exception {

-		final EntityResolver entityResolver = new EntityResolver() {

-			public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {

-				return null;

-			}

-		};

-		

 		final InputStream documentStream = getAsStream("document.xml");

 		final InputSource documentInputSource = new InputSource(documentStream);

-		

+

 		final DocumentReader reader = new DocumentReader();

 		reader.setDebugging(true);

-		reader.setEntityResolver(entityResolver);

-		reader.setWhitespacePolicyFactory(IWhitespacePolicyFactory.NULL);

 		final Document document = reader.read(documentInputSource);

 		assertNotNull(document);

-		

+

 		final Element rootElement = document.getRootElement();

 		assertNotNull(rootElement);

 		assertEquals("chapter", rootElement.getLocalName());

@@ -77,11 +65,11 @@
 		assertEquals(CHAPTER, rootElement.getQualifiedName());

 		assertEquals(STRUCTURE_NS, rootElement.getDefaultNamespaceURI());

 		assertEquals(CONTENT_NS, rootElement.getNamespaceURI("c"));

-		

+

 		final Element subChapterElement = rootElement.getChildElements().get(1);

 		assertEquals("chapter", subChapterElement.getPrefixedName());

 		assertEquals(CHAPTER, subChapterElement.getQualifiedName());

-		

+

 		final Element paragraphElement = subChapterElement.getChildElements().get(1);

 		assertEquals("p", paragraphElement.getLocalName());

 		assertEquals("c:p", paragraphElement.getPrefixedName());

@@ -92,47 +80,47 @@
 	public void getCMDocumentsByLogicalName() throws Exception {

 		final URIResolver uriResolver = URIResolverPlugin.createResolver();

 		final ContentModelManager modelManager = ContentModelManager.getInstance();

-		

+

 		final String schemaLocation = uriResolver.resolve(null, STRUCTURE_NS, null);

 		assertNotNull(schemaLocation);

 		final CMDocument schema = modelManager.createCMDocument(schemaLocation, null);

 		assertNotNull(schema);

-		

+

 		final String dtdLocation = uriResolver.resolve(null, TEST_DTD, null);

 		assertNotNull(dtdLocation);

 		final CMDocument dtd = modelManager.createCMDocument(dtdLocation, null);

 		assertNotNull(dtd);

 	}

-	

+

 	@Test

 	public void useCMDocument() throws Exception {

 		final URIResolver uriResolver = URIResolverPlugin.createResolver();

 		final ContentModelManager modelManager = ContentModelManager.getInstance();

-		

+

 		final String structureSchemaLocation = uriResolver.resolve(null, STRUCTURE_NS, null);

 		final CMDocument structureSchema = modelManager.createCMDocument(structureSchemaLocation, null);

-		

+

 		assertEquals(1, structureSchema.getElements().getLength());

-		

+

 		final CMElementDeclaration chapterElement = (CMElementDeclaration) structureSchema.getElements().item(0);

 		assertEquals("chapter", chapterElement.getNodeName());

-		

+

 		assertEquals(2, chapterElement.getLocalElements().getLength());

 	}

-	

+

 	@Test

 	public void createValidatorWithNamespaceUri() throws Exception {

 		final Validator validator = new WTPVEXValidator(CONTENT_NS);

 		assertEquals(1, validator.getValidRootElements().size());

 		assertTrue(validator.getValidRootElements().contains(P));

 	}

-	

+

 	@Test

 	public void createValidatorWithDTDPublicId() throws Exception {

 		final Validator validator = new WTPVEXValidator("-//Eclipse Foundation//DTD Vex Test//EN");

 		assertEquals(10, validator.getValidRootElements().size());

 	}

-	

+

 	@Test

 	public void validateSimpleSchema() throws Exception {

 		final Validator validator = new WTPVEXValidator(CONTENT_NS);

@@ -145,7 +133,7 @@
 		assertIsValidSequence(validator, I, I, B);

 		assertIsValidSequence(validator, I, PCDATA, I, B);

 	}

-	

+

 	@Test

 	public void proposeElementsFromSimpleSchema() throws Exception {

 		final Validator validator = new WTPVEXValidator(CONTENT_NS);

@@ -155,7 +143,7 @@
 		doc.insertText(2, "ab");

 		doc.insertElement(5, new Element(I));

 		assertEquals(8, doc.getLength());

-		

+

 		assertValidItemsAt(doc, 1, B, I);

 		assertValidItemsAt(doc, 2, B, I);

 		assertValidItemsAt(doc, 3, B, I);

@@ -164,7 +152,7 @@
 		assertValidItemsAt(doc, 6, B, I);

 		assertValidItemsAt(doc, 7, B, I);

 	}

-	

+

 	@Test

 	public void validateComplexSchema() throws Exception {

 		final Validator validator = new WTPVEXValidator(STRUCTURE_NS);

@@ -172,7 +160,7 @@
 		assertIsValidSequence(validator, CHAPTER, P);

 		assertIsValidSequence(validator, P, PCDATA, B, I);

 	}

-	

+

 	@Test

 	public void proposeElementsFromComplexSchema() throws Exception {

 		final Validator validator = new WTPVEXValidator();

@@ -185,7 +173,7 @@
 		doc.insertText(7, "cd");

 		doc.insertElement(10, new Element(P));

 		doc.insertElement(11, new Element(B));

-		

+

 		assertValidItemsAt(doc, 1, TITLE, CHAPTER, P);

 		assertValidItemsAt(doc, 2);

 		assertValidItemsAt(doc, 3);

@@ -201,7 +189,7 @@
 		assertValidItemsAt(doc, 13, B, I);

 		assertValidItemsAt(doc, 14, TITLE, CHAPTER, P);

 	}

-	

+

 	private void assertIsValidSequence(final Validator validator, final QualifiedName parentElement, final QualifiedName... sequence) {

 		for (int i = 0; i < sequence.length; i++) {

 			final List<QualifiedName> prefix = createPrefix(i, sequence);

@@ -225,7 +213,7 @@
 			suffix.add(sequence[i]);

 		return suffix;

 	}

-	

+

 	private static void assertValidItemsAt(final Document doc, final int offset, final QualifiedName... expectedItems) {

 		final Set<QualifiedName> expected = new HashSet<QualifiedName>(expectedItems.length);

 		for (final QualifiedName expectedItem : expectedItems)

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SpaceNormalizerTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SpaceNormalizerTest.java
index 11ecaf0..07d641d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SpaceNormalizerTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SpaceNormalizerTest.java
@@ -285,16 +285,14 @@
 	}
 
 	private Document createDocument(final String s, final StyleSheet ss) throws ParserConfigurationException, SAXException, IOException {
-
 		final SAXParserFactory factory = SAXParserFactory.newInstance();
 		final XMLReader xmlReader = factory.newSAXParser().getXMLReader();
 		final StyleSheet mySS = ss;
-		final DocumentBuilder builder = new DocumentBuilder(new IWhitespacePolicyFactory() {
-
-			public IWhitespacePolicy getPolicy(final String publicId) {
-				return new CssWhitespacePolicy(mySS);
+		final CssWhitespacePolicy policy = new CssWhitespacePolicy(mySS);
+		final DocumentBuilder builder = new DocumentBuilder(new DocumentContentModel() {
+			public IWhitespacePolicy getWhitespacePolicy() {
+				return policy;
 			}
-
 		});
 
 		final InputSource is = new InputSource(new ByteArrayInputStream(s.getBytes()));
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java
index a2ab270..ebd7d6b 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java
@@ -28,13 +28,9 @@
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.StyleSheetReader;
 import org.eclipse.vex.core.internal.dom.Document;
+import org.eclipse.vex.core.internal.dom.DocumentContentModel;
 import org.eclipse.vex.core.internal.dom.DocumentReader;
 import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
-import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.layout.LayoutContext;
-import org.eclipse.vex.core.internal.layout.RootBox;
-import org.eclipse.vex.core.internal.layout.TextBox;
 import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -48,212 +44,194 @@
  */
 public class LayoutTestSuite extends TestCase {
 
-    public String id;
-    public String doc;
-    public int layoutWidth = 100;
-    public BoxSpec result;
-    public String css;
+	public String id;
+	public String doc;
+	public int layoutWidth = 100;
+	public BoxSpec result;
+	public String css;
 
-    public static Test suite() throws ParserConfigurationException,
-            FactoryConfigurationError, IOException, SAXException {
-        TestSuite suite = new TestSuite(LayoutTestSuite.class.getName());
-        suite.addTest(loadSuite("block-inline.xml"));
-        suite.addTest(loadSuite("before-after.xml"));
-        suite.addTest(loadSuite("linebreaks.xml"));
-        suite.addTest(loadSuite("tables.xml"));
-        return suite;
-    }
+	public static Test suite() throws ParserConfigurationException, FactoryConfigurationError, IOException, SAXException {
+		final TestSuite suite = new TestSuite(LayoutTestSuite.class.getName());
+		suite.addTest(loadSuite("block-inline.xml"));
+		suite.addTest(loadSuite("before-after.xml"));
+		suite.addTest(loadSuite("linebreaks.xml"));
+		suite.addTest(loadSuite("tables.xml"));
+		return suite;
+	}
 
-    public static Test loadSuite(String filename)
-            throws ParserConfigurationException, FactoryConfigurationError,
-            IOException, SAXException {
-        XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
-                .getXMLReader();
-        TestCaseBuilder builder = new TestCaseBuilder();
-        xmlReader.setContentHandler(builder);
-        // xmlReader.setEntityResolver(builder);
-        URL url = LayoutTestSuite.class.getResource(filename);
-        xmlReader.parse(new InputSource(url.toString()));
+	public static Test loadSuite(final String filename) throws ParserConfigurationException, FactoryConfigurationError, IOException, SAXException {
+		final XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+		final TestCaseBuilder builder = new TestCaseBuilder();
+		xmlReader.setContentHandler(builder);
+		// xmlReader.setEntityResolver(builder);
+		final URL url = LayoutTestSuite.class.getResource(filename);
+		xmlReader.parse(new InputSource(url.toString()));
 
-        TestSuite suite = new TestSuite(filename);
-        for (TestCase test : builder.testCases) {
-            suite.addTest(test);
-        }
-        return suite;
-    }
+		final TestSuite suite = new TestSuite(filename);
+		for (final TestCase test : builder.testCases)
+			suite.addTest(test);
+		return suite;
+	}
 
-    public LayoutTestSuite() {
-        super("testLayout");
-    }
+	public LayoutTestSuite() {
+		super("testLayout");
+	}
 
-    public String getName() {
-        return this.id;
-    }
+	@Override
+	public String getName() {
+		return id;
+	}
 
-    public void testLayout() throws Exception {
+	public void testLayout() throws Exception {
 
-        URL url = LayoutTestSuite.class.getResource(this.css);
-        StyleSheetReader reader = new StyleSheetReader();
-        final StyleSheet ss = reader.read(url);
+		final URL url = LayoutTestSuite.class.getResource(css);
+		final StyleSheetReader reader = new StyleSheetReader();
+		final StyleSheet ss = reader.read(url);
 
-        FakeGraphics g = new FakeGraphics();
+		final FakeGraphics g = new FakeGraphics();
 
-        LayoutContext context = new LayoutContext();
-        context.setBoxFactory(new MockBoxFactory());
-        context.setGraphics(g);
-        context.setStyleSheet(ss);
+		final LayoutContext context = new LayoutContext();
+		context.setBoxFactory(new MockBoxFactory());
+		context.setGraphics(g);
+		context.setStyleSheet(ss);
+		final CssWhitespacePolicy policy = new CssWhitespacePolicy(ss);
 
-        DocumentReader docReader = new DocumentReader();
-        docReader.setWhitespacePolicyFactory(new IWhitespacePolicyFactory() {
-            public IWhitespacePolicy getPolicy(String publicId) {
-                return new CssWhitespacePolicy(ss);
-            }
-        });
-        Document doc = docReader.read(this.doc);
-        context.setDocument(doc);
+		final DocumentReader docReader = new DocumentReader();
+		docReader.setDocumentContentModel(new DocumentContentModel() {
+			@Override
+			public IWhitespacePolicy getWhitespacePolicy() {
+				return policy;
+			}
+		});
+		final Document doc = docReader.read(this.doc);
+		context.setDocument(doc);
 
-        RootBox rootBox = new RootBox(context, doc.getRootElement(),
-                this.layoutWidth);
-        rootBox.layout(context, 0, Integer.MAX_VALUE);
+		final RootBox rootBox = new RootBox(context, doc.getRootElement(), layoutWidth);
+		rootBox.layout(context, 0, Integer.MAX_VALUE);
 
-        assertBox(this.result, rootBox, "");
-    }
+		assertBox(result, rootBox, "");
+	}
 
-    private static void assertBox(BoxSpec boxSpec, Box box, String indent) {
+	private static void assertBox(final BoxSpec boxSpec, final Box box, final String indent) {
 
-        System.out.println(indent + boxSpec.className);
+		System.out.println(indent + boxSpec.className);
 
-        if (boxSpec.className != null) {
-            String actualClassName = box.getClass().getName();
-            if (boxSpec.className.lastIndexOf('.') == -1) {
-                // no dot in box spec classname, so strip the prefix from the
-                // actual classname
-                int lastDot = actualClassName.lastIndexOf('.');
-                actualClassName = actualClassName.substring(lastDot + 1);
-            }
-            assertEquals(boxSpec.className, actualClassName);
-        }
+		if (boxSpec.className != null) {
+			String actualClassName = box.getClass().getName();
+			if (boxSpec.className.lastIndexOf('.') == -1) {
+				// no dot in box spec classname, so strip the prefix from the
+				// actual classname
+				final int lastDot = actualClassName.lastIndexOf('.');
+				actualClassName = actualClassName.substring(lastDot + 1);
+			}
+			assertEquals(boxSpec.className, actualClassName);
+		}
 
-        if (boxSpec.element != null) {
-            assertNotNull(box.getElement());
-            assertEquals(boxSpec.element, box.getElement().getPrefixedName());
-        }
+		if (boxSpec.element != null) {
+			assertNotNull(box.getElement());
+			assertEquals(boxSpec.element, box.getElement().getPrefixedName());
+		}
 
-        if (boxSpec.text != null && box instanceof TextBox) {
-            assertEquals(boxSpec.text, ((TextBox) box).getText());
-        }
+		if (boxSpec.text != null && box instanceof TextBox)
+			assertEquals(boxSpec.text, ((TextBox) box).getText());
 
-        if (!boxSpec.children.isEmpty() && box.getChildren() == null) {
-            fail("Expected " + boxSpec.children.size() + " children, but "
-                    + boxSpec.className + "'s children is null");
-        }
+		if (!boxSpec.children.isEmpty() && box.getChildren() == null)
+			fail("Expected " + boxSpec.children.size() + " children, but " + boxSpec.className + "'s children is null");
 
-        if (boxSpec.children.size() != box.getChildren().length) {
-            System.out.println("Wrong number of child boxes");
-            System.out.println("  Expected:");
-            for (BoxSpec childSpec : boxSpec.children) {
-                System.out.print("    " + childSpec.className);
-                if (childSpec.text != null) {
-                    System.out.print(" '" + childSpec.text + "'");
-                }
-                System.out.println();
-            }
-            System.out.println("  Actual:");
-            for (Box childBox : box.getChildren()) {
-                System.out.println("    " + childBox.getClass() + ": "
-                        + childBox);
-            }
-            fail("Wrong number of child boxes.");
-        }
+		if (boxSpec.children.size() != box.getChildren().length) {
+			System.out.println("Wrong number of child boxes");
+			System.out.println("  Expected:");
+			for (final BoxSpec childSpec : boxSpec.children) {
+				System.out.print("    " + childSpec.className);
+				if (childSpec.text != null)
+					System.out.print(" '" + childSpec.text + "'");
+				System.out.println();
+			}
+			System.out.println("  Actual:");
+			for (final Box childBox : box.getChildren())
+				System.out.println("    " + childBox.getClass() + ": " + childBox);
+			fail("Wrong number of child boxes.");
+		}
 
-        for (int i = 0; i < boxSpec.children.size(); i++) {
-            assertBox((BoxSpec) boxSpec.children.get(i), box.getChildren()[i],
-                    indent + "  ");
-        }
+		for (int i = 0; i < boxSpec.children.size(); i++)
+			assertBox(boxSpec.children.get(i), box.getChildren()[i], indent + "  ");
 
-    }
+	}
 
-    private static class TestCaseBuilder extends DefaultHandler {
+	private static class TestCaseBuilder extends DefaultHandler {
 
-        private List<TestCase> testCases;
-        private String css;
-        private LayoutTestSuite testCase;
-        private BoxSpec boxSpec;
-        private Stack<BoxSpec> boxSpecs;
-        private boolean inDoc;
+		private List<TestCase> testCases;
+		private String css;
+		private LayoutTestSuite testCase;
+		private BoxSpec boxSpec;
+		private Stack<BoxSpec> boxSpecs;
+		private boolean inDoc;
 
-        public void characters(char[] ch, int start, int length)
-                throws SAXException {
+		@Override
+		public void characters(final char[] ch, final int start, final int length) throws SAXException {
 
-            String s = new String(ch, start, length).trim();
-            if (s.length() > 0) {
-                if (inDoc) {
-                    this.testCase.doc = new String(ch, start, length);
-                } else {
-                    throw new IllegalStateException();
-                }
-            }
-        }
+			final String s = new String(ch, start, length).trim();
+			if (s.length() > 0)
+				if (inDoc)
+					testCase.doc = new String(ch, start, length);
+				else
+					throw new IllegalStateException();
+		}
 
-        public void endElement(String uri, String localName, String qName)
-                throws SAXException {
-            if (qName.equals("box")) {
-                if (this.boxSpecs.isEmpty()) {
-                    this.boxSpec = null;
-                } else {
-                    this.boxSpec = this.boxSpecs.pop();
-                }
-            } else if (qName.equals("doc")) {
-                this.inDoc = false;
-            }
-        }
+		@Override
+		public void endElement(final String uri, final String localName, final String qName) throws SAXException {
+			if (qName.equals("box")) {
+				if (boxSpecs.isEmpty())
+					boxSpec = null;
+				else
+					boxSpec = boxSpecs.pop();
+			} else if (qName.equals("doc"))
+				inDoc = false;
+		}
 
-        public void startElement(String uri, String localName, String qName,
-                Attributes attributes) throws SAXException {
+		@Override
+		public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
 
-            if (qName.equals("testcases")) {
-                this.testCases = new ArrayList<TestCase>();
-                this.css = attributes.getValue("css");
-                if (this.css == null) {
-                    this.css = "test.css";
-                }
-                this.testCase = null;
-                this.boxSpecs = new Stack<BoxSpec>();
-            } else if (qName.equals("test")) {
-                this.testCase = new LayoutTestSuite();
-                this.testCase.id = attributes.getValue("id");
-                this.testCase.css = this.css;
-                String layoutWidth = attributes.getValue("layoutWidth");
-                if (layoutWidth != null) {
-                    this.testCase.layoutWidth = Integer.parseInt(layoutWidth);
-                }
-                testCases.add(this.testCase);
-            } else if (qName.equals("doc")) {
-                this.inDoc = true;
-            } else if (qName.equals("result")) {
-            } else if (qName.equals("box")) {
-                BoxSpec parent = this.boxSpec;
-                this.boxSpec = new BoxSpec();
-                this.boxSpec.className = attributes.getValue("class");
-                this.boxSpec.element = attributes.getValue("element");
-                this.boxSpec.text = attributes.getValue("text");
-                if (parent == null) {
-                    this.testCase.result = this.boxSpec;
-                } else {
-                    this.boxSpecs.push(parent);
-                    parent.children.add(this.boxSpec);
-                }
-            } else {
-                throw new SAXException("Unrecognized element: " + qName);
-            }
-        }
-    }
+			if (qName.equals("testcases")) {
+				testCases = new ArrayList<TestCase>();
+				css = attributes.getValue("css");
+				if (css == null)
+					css = "test.css";
+				testCase = null;
+				boxSpecs = new Stack<BoxSpec>();
+			} else if (qName.equals("test")) {
+				testCase = new LayoutTestSuite();
+				testCase.id = attributes.getValue("id");
+				testCase.css = css;
+				final String layoutWidth = attributes.getValue("layoutWidth");
+				if (layoutWidth != null)
+					testCase.layoutWidth = Integer.parseInt(layoutWidth);
+				testCases.add(testCase);
+			} else if (qName.equals("doc"))
+				inDoc = true;
+			else if (qName.equals("result")) {
+			} else if (qName.equals("box")) {
+				final BoxSpec parent = boxSpec;
+				boxSpec = new BoxSpec();
+				boxSpec.className = attributes.getValue("class");
+				boxSpec.element = attributes.getValue("element");
+				boxSpec.text = attributes.getValue("text");
+				if (parent == null)
+					testCase.result = boxSpec;
+				else {
+					boxSpecs.push(parent);
+					parent.children.add(boxSpec);
+				}
+			} else
+				throw new SAXException("Unrecognized element: " + qName);
+		}
+	}
 
-    private static class BoxSpec {
-        public String className;
-        public String element;
-        public List<BoxSpec> children = new ArrayList<BoxSpec>();
-        public String text;
-    }
+	private static class BoxSpec {
+		public String className;
+		public String element;
+		public List<BoxSpec> children = new ArrayList<BoxSpec>();
+		public String text;
+	}
 
 }
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java
index de69eba..ce6c31d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java
@@ -21,6 +21,7 @@
 import org.eclipse.vex.core.internal.css.RuleTest;
 import org.eclipse.vex.core.internal.dom.BlockElementBoxTest;
 import org.eclipse.vex.core.internal.dom.DTDValidatorTest;
+import org.eclipse.vex.core.internal.dom.DocumentContentModelTest;
 import org.eclipse.vex.core.internal.dom.DocumentReaderTest;
 import org.eclipse.vex.core.internal.dom.DocumentWriterTest;
 import org.eclipse.vex.core.internal.dom.GapContentTest;
@@ -47,6 +48,7 @@
 		addTest(new JUnit4TestAdapter(NamespaceStackTest.class));
 		addTest(new JUnit4TestAdapter(NamespaceTest.class));
 		addTest(new JUnit4TestAdapter(DocumentReaderTest.class));
+		addTest(new JUnit4TestAdapter(DocumentContentModelTest.class));
 		addTest(new JUnit4TestAdapter(SchemaValidatorTest.class));
 		addTestSuite(CssTest.class);
 		addTestSuite(PropertyTest.class);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
index d1e645e..7da219c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
@@ -35,7 +35,9 @@
  * </ul>
  */
 public class DocumentBuilder implements ContentHandler, LexicalHandler {
-	private final IWhitespacePolicyFactory policyFactory;
+
+	private DocumentContentModel documentContentModel;
+
 	private IWhitespacePolicy policy;
 
 	// Holds pending characters until we see another element boundary.
@@ -59,7 +61,7 @@
 
 	private String dtdPublicID;
 	private String dtdSystemID;
-	private Document doc;
+	private Document document;
 	private Locator locator;
 
 	/**
@@ -69,15 +71,15 @@
 	 *            Used to determine the WhitespacePolicy to use for a given
 	 *            document type.
 	 */
-	public DocumentBuilder(final IWhitespacePolicyFactory policyFactory) {
-		this.policyFactory = policyFactory;
+	public DocumentBuilder(final DocumentContentModel documentContentModel) {
+		this.documentContentModel = documentContentModel;
 	}
 
 	/**
 	 * Returns the newly built <code>Document</code> object.
 	 */
 	public Document getDocument() {
-		return doc;
+		return document;
 	}
 
 	// ============================================= ContentHandler methods
@@ -97,10 +99,10 @@
 		if (rootElement == null)
 			return;
 
-		doc = new Document(content, rootElement);
-		doc.setPublicID(dtdPublicID);
-		doc.setSystemID(dtdSystemID);
-		rootElement.setDocument(doc);
+		document = new Document(content, rootElement);
+		document.setPublicID(dtdPublicID);
+		document.setSystemID(dtdSystemID);
+		rootElement.setDocument(document);
 	}
 
 	public void endElement(final String namespaceURI, final String localName, final String qName) {
@@ -146,8 +148,6 @@
 		if (stack.isEmpty()) {
 			rootElement = new RootElement(elementName);
 			element = rootElement;
-			if (policyFactory != null)
-				policy = policyFactory.getPolicy(dtdPublicID);
 		} else {
 			element = new Element(elementName);
 
@@ -178,6 +178,11 @@
 			}
 		}
 
+		if (stack.isEmpty() && documentContentModel != null) {
+			documentContentModel.initialize(dtdPublicID, dtdSystemID, rootElement);
+			policy = documentContentModel.getWhitespacePolicy();
+		}
+		
 		appendChars(isBlock(element));
 
 		stack.add(new StackEntry(element, content.getLength(), isPre(element)));
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java
new file mode 100644
index 0000000..7768215
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java
@@ -0,0 +1,44 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Florian Thienel 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:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.vex.core.internal.dom;

+

+/**

+ * @author Florian Thienel

+ */

+public class DocumentContentModel {

+

+	private String publicId;

+	private String systemId;

+	private String schemaId;

+

+	public void initialize(final String publicId, final String systemId, final RootElement rootElement) {

+		this.publicId = publicId;

+		this.systemId = systemId;

+		schemaId = rootElement.getQualifiedName().getQualifier();

+	}

+

+	public String getMainDocumentTypeIdentifier() {

+		if (publicId != null)

+			return publicId;

+		if (systemId != null)

+			return systemId;

+		return schemaId;

+	}

+

+	public boolean isDtdAssigned() {

+		return publicId != null || systemId != null;

+	}

+

+	public IWhitespacePolicy getWhitespacePolicy() {

+		return IWhitespacePolicy.NULL;

+	}

+

+}

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentReader.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentReader.java
index 271a844..b8e63a1 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentReader.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentReader.java
@@ -36,9 +36,9 @@
 
 	private boolean debugging;
 
-	private EntityResolver entityResolver;
+	private DocumentContentModel documentContentModel = new DocumentContentModel(); // use the default implementation as default
 	
-	private IWhitespacePolicyFactory whitespacePolicyFactory;
+	private EntityResolver entityResolver;
 
 	/**
 	 * Returns the debugging flag.
@@ -55,13 +55,6 @@
 	}
 
 	/**
-	 * Returns the whitespace policy factory for this reader.
-	 */
-	public IWhitespacePolicyFactory getWhitespacePolicyFactory() {
-		return whitespacePolicyFactory;
-	}
-
-	/**
 	 * Reads a document given a URL.
 	 * 
 	 * @param url
@@ -95,9 +88,7 @@
 		factory.setNamespaceAware(true);
 
 		final XMLReader xmlReader = factory.newSAXParser().getXMLReader();
-		// xmlReader.setFeature("http://xml.org/sax/features/validation",
-		// false);
-		final org.eclipse.vex.core.internal.dom.DocumentBuilder builder = new org.eclipse.vex.core.internal.dom.DocumentBuilder(getWhitespacePolicyFactory());
+		final DocumentBuilder builder = new DocumentBuilder(getDocumentContentModel());
 
 		ContentHandler contentHandler = builder;
 		LexicalHandler lexicalHandler = builder;
@@ -149,17 +140,13 @@
 	public void setEntityResolver(final EntityResolver entityResolver) {
 		this.entityResolver = entityResolver;
 	}
-
-	/**
-	 * Sets the whitespace policy factory for this reader. This factory is used
-	 * to obtain a whitespace policy once the public ID of the document is
-	 * known.
-	 * 
-	 * @param whitespacePolicyFactory
-	 *            The whitespacePolicyFactory to set.
-	 */
-	public void setWhitespacePolicyFactory(final IWhitespacePolicyFactory whitespacePolicyFactory) {
-		this.whitespacePolicyFactory = whitespacePolicyFactory;
+	
+	public DocumentContentModel getDocumentContentModel() {
+		return documentContentModel;
+	}
+	
+	public void setDocumentContentModel(DocumentContentModel documentContentModel) {
+		this.documentContentModel = documentContentModel;
 	}
 
 }
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoRegisteredDoctypeException.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoRegisteredDoctypeException.java
new file mode 100644
index 0000000..8117fba
--- /dev/null
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoRegisteredDoctypeException.java
@@ -0,0 +1,30 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Florian Thienel 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:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.vex.ui.internal.editor;

+

+/**

+ * Indicates that no document type is registered for the public ID in the

+ * document, or that the document does not have a PUBLIC DOCTYPE decl, in

+ * which case publicId is null.

+ */

+public class NoRegisteredDoctypeException extends RuntimeException {

+	private static final long serialVersionUID = 1L;

+

+	public NoRegisteredDoctypeException(final String publicId) {

+		this.publicId = publicId;

+	}

+

+	public String getPublicId() {

+		return publicId;

+	}

+

+	private final String publicId;

+}
\ No newline at end of file
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoStyleForDoctypeException.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoStyleForDoctypeException.java
new file mode 100644
index 0000000..a4cab24
--- /dev/null
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/NoStyleForDoctypeException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Florian Thienel 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:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.vex.ui.internal.editor;

+

+/**

+ * Indicates that the document was matched to a registered doctype, but that

+ * the given doctype does not have a matching style.

+ */

+public class NoStyleForDoctypeException extends RuntimeException {

+

+	private static final long serialVersionUID = 1L;

+}
\ No newline at end of file
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java
new file mode 100644
index 0000000..71aaa39
--- /dev/null
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java
@@ -0,0 +1,92 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Florian Thienel 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:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.vex.ui.internal.editor;

+

+import org.eclipse.swt.widgets.Shell;

+import org.eclipse.vex.core.internal.dom.DocumentContentModel;

+import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;

+import org.eclipse.vex.core.internal.dom.RootElement;

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

+import org.eclipse.vex.ui.internal.VexPlugin;

+import org.eclipse.vex.ui.internal.config.DocumentType;

+import org.eclipse.vex.ui.internal.config.Style;

+

+/**

+ * @author Florian Thienel

+ */

+public class VexDocumentContentModel extends DocumentContentModel {

+

+	private final Shell shell;

+	

+	private DocumentType documentType;

+

+	private Style style;

+	

+	private boolean shouldAssignInferredDocumentType;

+	

+	public VexDocumentContentModel(final Shell shell) {

+		this.shell = shell;

+	}

+

+	@Override

+	public void initialize(final String publicId, final String systemId, final RootElement rootElement) {

+		super.initialize(publicId, systemId, rootElement);

+		final String mainDocumentTypeIdentifier = getMainDocumentTypeIdentifier();

+		documentType = getRegisteredDocumentType();

+		if (documentType == null)

+			documentType = queryUserForDocumentType();

+		

+		if (documentType == null)

+			throw new NoRegisteredDoctypeException(mainDocumentTypeIdentifier);

+

+		// TODO verify documentType URL???

+//		final URL url = documentType.getResourceUrl();

+//		if (url == null) {

+//			final String message = MessageFormat.format(Messages.getString("VexEditor.noUrlForDoctype"), mainDocumentTypeIdentifier);

+//			throw new RuntimeException(message);

+//		}

+

+		style = VexEditor.getPreferredStyle(documentType.getPublicId());

+		if (style == null)

+			throw new NoStyleForDoctypeException();

+	}

+

+	private DocumentType getRegisteredDocumentType() {

+		return VexPlugin.getInstance().getConfigurationRegistry().getDocumentType(getMainDocumentTypeIdentifier());

+	}

+	

+	private DocumentType queryUserForDocumentType() {

+		final DocumentTypeSelectionDialog dialog = DocumentTypeSelectionDialog.create(shell, getMainDocumentTypeIdentifier());

+		dialog.open();

+		if (dialog.alwaysUseThisDoctype())

+			shouldAssignInferredDocumentType = true;

+		return dialog.getDoctype();

+	}

+

+	@Override

+	public IWhitespacePolicy getWhitespacePolicy() {

+		if (style == null)

+			return super.getWhitespacePolicy();

+		return new CssWhitespacePolicy(style.getStyleSheet());

+	}

+	

+	public DocumentType getDocumentType() {

+		return documentType;

+	}

+	

+	public Style getStyle() {

+		return style;

+	}

+	

+	public boolean shouldAssignInferredDocumentType() {

+		return shouldAssignInferredDocumentType;

+	}

+}

diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
index 89aefa6..3a423a8 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
@@ -16,7 +16,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.net.URL;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -71,8 +70,6 @@
 import org.eclipse.vex.core.internal.dom.DocumentReader;
 import org.eclipse.vex.core.internal.dom.DocumentWriter;
 import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
-import org.eclipse.vex.core.internal.dom.IWhitespacePolicyFactory;
 import org.eclipse.vex.core.internal.dom.Validator;
 import org.eclipse.vex.core.internal.validator.WTPVEXValidator;
 import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
@@ -86,6 +83,8 @@
 import org.eclipse.vex.ui.internal.outline.DocumentOutlinePage;
 import org.eclipse.vex.ui.internal.property.ElementPropertySource;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
+import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
+import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
 import org.osgi.service.prefs.BackingStoreException;
 import org.osgi.service.prefs.Preferences;
 import org.xml.sax.EntityResolver;
@@ -146,13 +145,13 @@
 
 			if (input instanceof IFileEditorInput) {
 				final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-				writer.write(doc, baos);
+				writer.write(document, baos);
 				baos.close();
 				final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 				((IFileEditorInput) input).getFile().setContents(bais, false, false, monitor);
 			} else {
 				os = new FileOutputStream(((ILocationProvider) input).getPath(input).toFile());
-				writer.write(doc, os);
+				writer.write(document, os);
 			}
 
 			savedUndoDepth = vexWidget.getUndoDepth();
@@ -186,7 +185,7 @@
 				final ByteArrayOutputStream baos = new ByteArrayOutputStream();
 				final DocumentWriter writer = new DocumentWriter();
 				writer.setWhitespacePolicy(new CssWhitespacePolicy(style.getStyleSheet()));
-				writer.write(doc, baos);
+				writer.write(document, baos);
 				baos.close();
 
 				final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
@@ -281,7 +280,7 @@
 		try {
 			final long start = System.currentTimeMillis();
 
-			IFile file = null;
+			final IFile file;
 
 			if (input instanceof IFileEditorInput)
 				file = ((IFileEditorInput) input).getFile();
@@ -291,15 +290,24 @@
 				showLabel(msg);
 				return;
 			}
+			
+			final URIResolver uriResolver = URIResolverPlugin.createResolver();
 
+			final VexDocumentContentModel documentContentModel = new VexDocumentContentModel(getSite().getShell());
 			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(file.getLocationURI().toURL());
-
+			reader.setDocumentContentModel(documentContentModel);
+			reader.setEntityResolver(new EntityResolver() {
+				public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
+					final String resolved = uriResolver.resolve(file.getLocationURI().toString(), publicId, systemId);
+					System.out.println("Resolved " + publicId + " " + systemId + " -> " + resolved);
+					if (resolved != null)
+						return new InputSource(resolved);
+					return null;
+				}
+			});
+			document = reader.read(file.getLocationURI().toURL());
+			
 			if (debugging) {
 				final long end = System.currentTimeMillis();
 				final String message = "Parsed document in " //$NON-NLS-1$
@@ -307,19 +315,17 @@
 				System.out.println(message);
 			}
 
-			if (doc == null) {
+			if (document == null) {
 				showLabel(MessageFormat.format(Messages.getString("VexEditor.noContent"), file));
 				return;
 			}
-			
-			// this.doctype is set either by wsPolicyFactory or entityResolver
-			// this.style is set by wsPolicyFactory
-			// Otherwise, a PartInitException would have been thrown by now
 
-			//IValidator validator = this.doctype.getValidator(); 
+			doctype = documentContentModel.getDocumentType();
+			style = documentContentModel.getStyle();
+			
 			final Validator validator = new WTPVEXValidator(doctype.getResourceUrl());
 			if (validator != null) {
-				doc.setValidator(validator);
+				document.setValidator(validator);
 				if (debugging) {
 					final long end = System.currentTimeMillis();
 					System.out.println("Got validator in " + (end - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -329,11 +335,11 @@
 			showVexWidget();
 
 			vexWidget.setDebugging(debugging);
-			vexWidget.setDocument(doc, style.getStyleSheet());
+			vexWidget.setDocument(document, style.getStyleSheet());
 
-			if (updateDoctypeDecl) {
-				doc.setPublicID(doctype.getPublicId());
-				((Document) doc).setSystemID(doctype.getSystemId());
+			if (documentContentModel.shouldAssignInferredDocumentType()) {
+				document.setPublicID(doctype.getPublicId());
+				((Document) document).setSystemID(doctype.getSystemId());
 				doSave(null);
 			}
 
@@ -458,7 +464,7 @@
 		this.style = style;
 		if (vexWidget != null) {
 			vexWidget.setStyleSheet(style.getStyleSheet());
-			setPreferredStyleId(doc.getPublicID(), style.getUniqueId());
+			setPreferredStyleId(document.getPublicID(), style.getUniqueId());
 		}
 	}
 
@@ -482,7 +488,7 @@
 
 	private boolean loaded;
 	private DocumentType doctype;
-	private Document doc;
+	private Document document;
 	private Style style;
 
 	private VexWidget vexWidget;
@@ -491,11 +497,6 @@
 	private boolean wasDirty;
 	// private Label statusLabel;
 
-	// This is true if the document's doctype decl is missing or unrecognized
-	// AND the user selected a new document type
-	// AND the user wants to always use the doctype for this document
-	private boolean updateDoctypeDecl;
-
 	private final ListenerList<IVexEditorListener, VexEditorEvent> vexEditorListeners = new ListenerList<IVexEditorListener, VexEditorEvent>(
 			IVexEditorListener.class);
 
@@ -704,65 +705,6 @@
 		}
 	};
 
-	private final EntityResolver entityResolver = new EntityResolver() {
-		public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
-
-			// System.out.println("### Resolving publicId " + publicId +
-			// ", systemId " + systemId);
-
-			if (doctype == null) {
-				//
-				// If doctype hasn't already been set, this must be the doctype
-				// decl.
-				//
-				if (publicId != null)
-					doctype = VexPlugin.getInstance().getConfigurationRegistry().getDocumentType(publicId);
-
-				if (doctype == null) {
-					final DocumentTypeSelectionDialog dlg = DocumentTypeSelectionDialog.create(getSite().getShell(), publicId);
-					dlg.open();
-					doctype = dlg.getDoctype();
-					updateDoctypeDecl = dlg.alwaysUseThisDoctype();
-
-					if (doctype == null)
-						throw new NoRegisteredDoctypeException(publicId);
-				}
-
-				final URL url = doctype.getResourceUrl();
-
-				if (url == null) {
-					final String message = MessageFormat.format(Messages.getString("VexEditor.noUrlForDoctype"), //$NON-NLS-1$
-							new Object[] { publicId });
-					throw new RuntimeException(message);
-				}
-
-				return new InputSource(url.toString());
-			} else
-				return null;
-		}
-	};
-
-	private final IWhitespacePolicyFactory wsFactory = new IWhitespacePolicyFactory() {
-		public IWhitespacePolicy getPolicy(final String publicId) {
-			if (doctype == null) {
-				final DocumentTypeSelectionDialog dlg = DocumentTypeSelectionDialog.create(getSite().getShell(), publicId);
-				dlg.open();
-				doctype = dlg.getDoctype();
-				updateDoctypeDecl = dlg.alwaysUseThisDoctype();
-
-				if (doctype == null)
-					throw new NoRegisteredDoctypeException(null);
-			}
-
-			style = VexEditor.getPreferredStyle(doctype.getPublicId());
-			if (style == null)
-				throw new NoStyleForDoctypeException();
-
-			return new CssWhitespacePolicy(style.getStyleSheet());
-		}
-
-	};
-
 	private class ResourceChangeListener implements IResourceChangeListener {
 
 		public void resourceChanged(final IResourceChangeEvent event) {
@@ -795,34 +737,6 @@
 	// by throwing one of these exceptions
 	//
 
-	/**
-	 * Indicates that no document type is registered for the public ID in the
-	 * document, or that the document does not have a PUBLIC DOCTYPE decl, in
-	 * which case publicId is null.
-	 */
-	private static class NoRegisteredDoctypeException extends RuntimeException {
-		private static final long serialVersionUID = 1L;
-
-		public NoRegisteredDoctypeException(final String publicId) {
-			this.publicId = publicId;
-		}
-
-		public String getPublicId() {
-			return publicId;
-		}
-
-		private final String publicId;
-	}
-
-	/**
-	 * Indicates that the document was matched to a registered doctype, but that
-	 * the given doctype does not have a matching style.
-	 */
-	private static class NoStyleForDoctypeException extends RuntimeException {
-
-		private static final long serialVersionUID = 1L;
-	}
-
 	private String getLocation() {
 		final List<String> path = new ArrayList<String>();
 		Element element = vexWidget.getCurrentElement();
@@ -840,7 +754,7 @@
 	}
 
 	@Override
-	public Object getAdapter(final Class adapter) {
+	public Object getAdapter(@SuppressWarnings("rawtypes") final Class adapter) {
 
 		if (adapter == IContentOutlinePage.class)
 			return new DocumentOutlinePage();
@@ -884,15 +798,15 @@
 					return new CharSequence() {
 
 						public CharSequence subSequence(final int start, final int end) {
-							return doc.getRawText(start, end);
+							return document.getRawText(start, end);
 						}
 
 						public int length() {
-							return doc.getLength();
+							return document.getLength();
 						}
 
 						public char charAt(final int index) {
-							return doc.getCharacterAt(index);
+							return document.getCharacterAt(index);
 						}
 					};
 				}