use XML reader/writer for serialization
https://bugs.eclipse.org/bugs/show_bug.cgi?id=397450

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/META-INF/MANIFEST.MF b/org.eclipse.vex.core.tests/META-INF/MANIFEST.MF
index c9265c2..78eee64 100644
--- a/org.eclipse.vex.core.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.vex.core.tests/META-INF/MANIFEST.MF
@@ -21,6 +21,7 @@
 Bundle-ActivationPolicy: lazy
 Export-Package: org.eclipse.vex.core.internal.css;x-internal:=true,
  org.eclipse.vex.core.internal.dom;x-internal:=true,
+ org.eclipse.vex.core.internal.io,
  org.eclipse.vex.core.internal.layout;x-internal:=true,
  org.eclipse.vex.core.internal.widget;x-internal:=true,
  org.eclipse.vex.core.tests
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java
index 0c18d23..c2890b4 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java
@@ -10,31 +10,19 @@
  *******************************************************************************/
 package org.eclipse.vex.core.internal.io;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.eclipse.vex.core.internal.io.RoundTrip.assertDocumentsEqual;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.Collection;
-import java.util.List;
 
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.eclipse.core.runtime.QualifiedName;
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.css.StyleSheetReader;
-import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
-import org.eclipse.vex.core.internal.dom.Comment;
 import org.eclipse.vex.core.internal.dom.Document;
-import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.Node;
-import org.eclipse.vex.core.internal.dom.Parent;
-import org.eclipse.vex.core.internal.dom.Text;
-import org.eclipse.vex.core.internal.io.DocumentReader;
-import org.eclipse.vex.core.internal.io.DocumentWriter;
 import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
 import org.eclipse.vex.core.tests.TestResources;
 import org.junit.Test;
@@ -92,65 +80,4 @@
 		return documentReader.read(inputSource);
 	}
 
-	private static void assertDocumentsEqual(final Document expected, final Document actual) {
-		assertEquals(expected.getPublicID(), actual.getPublicID());
-		assertEquals(expected.getSystemID(), actual.getSystemID());
-		assertContentEqual(expected, actual);
-	}
-
-	private static void assertContentEqual(final Parent expected, final Parent actual) {
-		final List<Node> expectedContent = expected.getChildNodes();
-		final List<Node> actualContent = actual.getChildNodes();
-		assertEquals("children of " + expected, expectedContent.size(), actualContent.size());
-		for (int i = 0; i < expectedContent.size(); i++) {
-			final Node expectedNode = expectedContent.get(i);
-			final Node actualNode = actualContent.get(i);
-			assertEquals(expectedNode.getClass(), actualNode.getClass());
-			expectedNode.accept(new BaseNodeVisitor() {
-				@Override
-				public void visit(final Element element) {
-					assertElementsEqual((Element) expectedNode, (Element) actualNode);
-				}
-
-				@Override
-				public void visit(final Comment comment) {
-					assertEquals(expectedNode.getText(), actualNode.getText());
-				}
-
-				@Override
-				public void visit(final Text text) {
-					assertEquals(expectedNode.getText(), actualNode.getText());
-				}
-			});
-		}
-	}
-
-	private static void assertElementsEqual(final Element expected, final Element actual) {
-		assertEquals("qualified name of " + expected, expected.getQualifiedName(), actual.getQualifiedName());
-		assertAttributesEqual(expected, actual);
-		assertNamespacesEqual(expected, actual);
-		assertContentEqual(expected, actual);
-	}
-
-	private static void assertAttributesEqual(final Element expected, final Element actual) {
-		final List<QualifiedName> expectedAttrs = expected.getAttributeNames();
-		final List<QualifiedName> actualAttrs = actual.getAttributeNames();
-
-		assertEquals("attributes of " + expected, expectedAttrs.size(), actualAttrs.size());
-		for (int i = 0; i < expectedAttrs.size(); i++) {
-			assertEquals(expectedAttrs.get(i), actualAttrs.get(i));
-		}
-	}
-
-	private static void assertNamespacesEqual(final Element expected, final Element actual) {
-		assertEquals("declared default namespace of " + expected, expected.getDeclaredDefaultNamespaceURI(), actual.getDeclaredDefaultNamespaceURI());
-
-		final Collection<String> expectedNamespacePrefixes = expected.getDeclaredNamespacePrefixes();
-		final Collection<String> actualNamespacePrefixes = actual.getDeclaredNamespacePrefixes();
-		assertEquals("declared namespaces of " + expected, expectedNamespacePrefixes.size(), actualNamespacePrefixes.size());
-		for (final String prefix : expectedNamespacePrefixes) {
-			assertTrue("namespace not declared: " + prefix, actualNamespacePrefixes.contains(prefix));
-			assertEquals("namespace URI of prefix " + prefix, expected.getNamespaceURI(prefix), actual.getNamespaceURI(prefix));
-		}
-	}
 }
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/RoundTrip.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/RoundTrip.java
new file mode 100644
index 0000000..73689b1
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/RoundTrip.java
@@ -0,0 +1,103 @@
+/*******************************************************************************

+ * Copyright (c) 2013 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.io;

+

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertTrue;

+

+import java.util.Collection;

+import java.util.List;

+

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

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

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

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

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

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

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

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

+

+/**

+ * This class provides some special assertions for round trip tests.

+ * 

+ * @author Florian Thienel

+ */

+public class RoundTrip {

+

+	public static void assertDocumentsEqual(final Document expected, final Document actual) {

+		assertEquals(expected.getPublicID(), actual.getPublicID());

+		assertEquals(expected.getSystemID(), actual.getSystemID());

+		assertContentEqual(expected, actual);

+	}

+

+	public static void assertContentEqual(final Parent expected, final Parent actual) {

+		assertContentRangeEqual(expected, actual);

+		final List<Node> expectedContent = expected.getChildNodes();

+		final List<Node> actualContent = actual.getChildNodes();

+		assertEquals("children of " + expected, expectedContent.size(), actualContent.size());

+		for (int i = 0; i < expectedContent.size(); i++) {

+			final Node expectedNode = expectedContent.get(i);

+			final Node actualNode = actualContent.get(i);

+			assertContentRangeEqual(expectedNode, actualNode);

+			assertEquals(expectedNode.getClass(), actualNode.getClass());

+			expectedNode.accept(new BaseNodeVisitor() {

+				@Override

+				public void visit(final Element element) {

+					assertElementsEqual((Element) expectedNode, (Element) actualNode);

+				}

+

+				@Override

+				public void visit(final Comment comment) {

+					assertEquals(expectedNode.getText(), actualNode.getText());

+				}

+

+				@Override

+				public void visit(final Text text) {

+					assertEquals(expectedNode.getText(), actualNode.getText());

+				}

+			});

+		}

+	}

+

+	public static void assertContentRangeEqual(final Node expected, final Node actual) {

+		assertEquals("content range of " + expected, expected.getRange(), actual.getRange());

+	}

+

+	public static void assertElementsEqual(final Element expected, final Element actual) {

+		assertEquals("qualified name of " + expected, expected.getQualifiedName(), actual.getQualifiedName());

+		assertAttributesEqual(expected, actual);

+		assertNamespacesEqual(expected, actual);

+		assertContentEqual(expected, actual);

+	}

+

+	public static void assertAttributesEqual(final Element expected, final Element actual) {

+		final List<QualifiedName> expectedAttrs = expected.getAttributeNames();

+		final List<QualifiedName> actualAttrs = actual.getAttributeNames();

+

+		assertEquals("attributes of " + expected, expectedAttrs.size(), actualAttrs.size());

+		for (int i = 0; i < expectedAttrs.size(); i++) {

+			assertEquals(expectedAttrs.get(i), actualAttrs.get(i));

+		}

+	}

+

+	public static void assertNamespacesEqual(final Element expected, final Element actual) {

+		assertEquals("declared default namespace of " + expected, expected.getDeclaredDefaultNamespaceURI(), actual.getDeclaredDefaultNamespaceURI());

+

+		final Collection<String> expectedNamespacePrefixes = expected.getDeclaredNamespacePrefixes();

+		final Collection<String> actualNamespacePrefixes = actual.getDeclaredNamespacePrefixes();

+		assertEquals("declared namespaces of " + expected, expectedNamespacePrefixes.size(), actualNamespacePrefixes.size());

+		for (final String prefix : expectedNamespacePrefixes) {

+			assertTrue("namespace not declared: " + prefix, actualNamespacePrefixes.contains(prefix));

+			assertEquals("namespace URI of prefix " + prefix, expected.getNamespaceURI(prefix), actual.getNamespaceURI(prefix));

+		}

+	}

+

+}

diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java
index 02d8a37..c4d83f4 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java
@@ -22,6 +22,7 @@
 import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
 import org.eclipse.vex.core.internal.dom.Comment;
 import org.eclipse.vex.core.internal.dom.Document;
+import org.eclipse.vex.core.internal.dom.DocumentFragment;
 import org.eclipse.vex.core.internal.dom.Element;
 import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
 import org.eclipse.vex.core.internal.dom.Node;
@@ -147,6 +148,14 @@
 		printWriter.flush();
 	}
 
+	public void write(final DocumentFragment fragment, final OutputStream out) throws IOException {
+		final PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
+		printWriter.println("<?xml version='1.0' encoding='UTF-8'?>");
+
+		writeNode(fragment, printWriter, "");
+		printWriter.flush();
+	}
+
 	// ====================================================== PRIVATE
 
 	private void writeNode(final Node node, final PrintWriter out, final String indent) {
@@ -177,6 +186,15 @@
 			}
 
 			@Override
+			public void visit(final DocumentFragment fragment) {
+				out.print("<vex_fragment>");
+				for (final Node child : fragment.getChildNodes()) {
+					writeNodeNoWrap(child, out);
+				}
+				out.println("</vex_fragment>");
+			}
+
+			@Override
 			public void visit(final Element element) {
 				if (whitespacePolicy.isPre(element)) {
 					out.print(indent);
@@ -356,7 +374,8 @@
 	}
 
 	private static String getAttributeString(final Element element) {
-		final Validator validator = element.getDocument().getValidator();
+		final Document document = element.getDocument();
+		final Validator validator = document != null ? document.getValidator() : null;
 
 		final StringBuffer result = new StringBuffer();
 		for (final Attribute attribute : element.getAttributes()) {
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/swt/tests/DocumentFragmentTransferTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/swt/tests/DocumentFragmentTransferTest.java
new file mode 100644
index 0000000..1341f74
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/swt/tests/DocumentFragmentTransferTest.java
@@ -0,0 +1,96 @@
+/*******************************************************************************

+ * Copyright (c) 2013 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.swt.tests;

+

+import static org.eclipse.vex.core.internal.io.RoundTrip.assertContentEqual;

+

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

+

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

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

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

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

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

+import org.eclipse.vex.ui.internal.swt.DocumentFragmentTransfer;

+import org.junit.Before;

+import org.junit.Test;

+

+public class DocumentFragmentTransferTest {

+

+	private Document document;

+

+	@Before

+	public void setUp() throws Exception {

+		document = new Document(new QualifiedName(null, "root"));

+	}

+

+	@Test

+	public void shouldTransferSimpleText() throws Exception {

+		document.insertText(document.getRootElement().getEndOffset(), "Hello World");

+

+		assertRoundTripWorks(getExpectedFragment());

+	}

+

+	@Test

+	public void shouldTransferElementAndText() throws Exception {

+		document.insertText(document.getRootElement().getEndOffset(), "Hello");

+		final Element child = addChild();

+		document.insertText(child.getEndOffset(), "New");

+		document.insertText(document.getRootElement().getEndOffset(), "World");

+

+		assertRoundTripWorks(getExpectedFragment());

+	}

+

+	@Test

+	public void shouldTransferElementWithNamespace() throws Exception {

+		final Element child = addChild();

+		child.declareNamespace("ns1", "http://namespaceUri/1");

+

+		assertRoundTripWorks(getExpectedFragment());

+	}

+

+	@Test

+	public void shouldTransferElementWithDefaultNamespace() throws Exception {

+		final Element child = addChild(new QualifiedName("http://namespaceUri/default", "child"));

+		child.declareDefaultNamespace("http://namespaceUri/default");

+

+		assertRoundTripWorks(getExpectedFragment());

+	}

+

+	@Test

+	public void shouldTransferComment() throws Exception {

+		final Comment comment = document.insertComment(document.getRootElement().getEndOffset());

+		document.insertText(comment.getEndOffset(), "Hello World");

+		assertRoundTripWorks(getExpectedFragment());

+	}

+

+	private Element addChild() {

+		return addChild(new QualifiedName(null, "child"));

+	}

+

+	private Element addChild(final QualifiedName elementName) {

+		return document.insertElement(document.getRootElement().getEndOffset(), elementName);

+	}

+

+	private DocumentFragment getExpectedFragment() {

+		return document.getFragment(document.getRootElement().getRange().resizeBy(1, -1));

+	}

+

+	private static void assertRoundTripWorks(final DocumentFragment expectedFragment) throws Exception {

+		final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

+		final DocumentFragmentTransfer transfer = new DocumentFragmentTransfer();

+		transfer.writeFragmentToStream(expectedFragment, buffer);

+		final DocumentFragment actualFragment = transfer.readFragmentFromStream(new ByteArrayInputStream(buffer.toByteArray()));

+		assertContentEqual(expectedFragment, actualFragment);

+	}

+

+}

diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java
index 49088a8..e5f7e02 100644
--- a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java
@@ -18,6 +18,7 @@
 import org.eclipse.vex.ui.internal.config.tests.ConfigurationRegistryTest;
 import org.eclipse.vex.ui.internal.editor.tests.FindReplaceTargetTest;
 import org.eclipse.vex.ui.internal.namespace.tests.EditNamespacesControllerTest;
+import org.eclipse.vex.ui.internal.swt.tests.DocumentFragmentTransferTest;
 import org.eclipse.vex.ui.internal.tests.ResourceTrackerTest;
 
 public class VexUiTestSuite extends TestSuite {
@@ -31,7 +32,8 @@
 		addTest(new JUnit4TestAdapter(ConfigLoaderJobTest.class));
 		addTest(new JUnit4TestAdapter(ConfigurationRegistryTest.class));
 		addTest(new JUnit4TestAdapter(EditNamespacesControllerTest.class));
-		addTestSuite(IconTest.class);
+		addTest(new JUnit4TestAdapter(DocumentFragmentTransferTest.class));
+		//		addTestSuite(IconTest.class);
 		addTestSuite(FindReplaceTargetTest.class);
 		addTestSuite(ResourceTrackerTest.class);
 	}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
index 6a325ed..90a90f4 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2013 John Krasnay 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
@@ -7,30 +7,26 @@
  * 
  * Contributors:
  *     John Krasnay - initial API and implementation
+ *     Florian Thienel - use XML reader/writer for serialization
  *******************************************************************************/
 package org.eclipse.vex.ui.internal.swt;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.io.InputStream;
+import java.io.OutputStream;
 
-import org.eclipse.core.runtime.QualifiedName;
+import javax.xml.parsers.ParserConfigurationException;
+
 import org.eclipse.swt.dnd.ByteArrayTransfer;
 import org.eclipse.swt.dnd.TransferData;
-import org.eclipse.vex.core.internal.dom.Attribute;
-import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
-import org.eclipse.vex.core.internal.dom.Content;
-import org.eclipse.vex.core.internal.dom.ContentRange;
+import org.eclipse.vex.core.internal.dom.Document;
 import org.eclipse.vex.core.internal.dom.DocumentFragment;
-import org.eclipse.vex.core.internal.dom.DocumentValidationException;
-import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.GapContent;
-import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.io.DocumentReader;
+import org.eclipse.vex.core.internal.io.DocumentWriter;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
 
 /**
  * Transfer object that handles Vex DocumentFragments.
@@ -39,8 +35,13 @@
 
 	private static final String MIME_TYPE = "application/x-vex-document-fragment";
 
+	private static final String[] typeNames = { MIME_TYPE };
+	private static final int[] typeIds = { ByteArrayTransfer.registerType(MIME_TYPE) };
+
+	private static DocumentFragmentTransfer instance;
+
 	/**
-	 * Returns the singleton instance of the DocumentFragmentTransfer.
+	 * @return the singleton instance of the DocumentFragmentTransfer.
 	 */
 	public static DocumentFragmentTransfer getInstance() {
 		if (instance == null) {
@@ -59,45 +60,44 @@
 		return typeIds;
 	}
 
+	// Writing
+
 	@Override
 	public void javaToNative(final Object object, final TransferData transferData) {
 		if (object == null || !(object instanceof DocumentFragment)) {
 			return;
 		}
 
-		if (isSupportedType(transferData)) {
-			final DocumentFragment frag = (DocumentFragment) object;
-			try {
-				// write data to a byte array and then ask super to convert to
-				// pMedium
-				final ByteArrayOutputStream out = new ByteArrayOutputStream();
-				final ObjectOutputStream oos = new ObjectOutputStream(out);
-				writeFragment(frag, oos);
-				final byte[] buffer = out.toByteArray();
-				oos.close();
-				super.javaToNative(buffer, transferData);
-			} catch (final IOException e) {
-			}
+		if (!isSupportedType(transferData)) {
+			return;
 		}
+
+		final DocumentFragment fragment = (DocumentFragment) object;
+		final ByteArrayOutputStream out = new ByteArrayOutputStream();
+		try {
+			writeFragmentToStream(fragment, out);
+		} catch (final IOException e) {
+		}
+		super.javaToNative(out.toByteArray(), transferData);
 	}
 
+	public void writeFragmentToStream(final DocumentFragment fragment, final OutputStream out) throws IOException {
+		new DocumentWriter().write(fragment, out);
+	}
+
+	// Reading
+
 	@Override
 	public Object nativeToJava(final TransferData transferData) {
-
 		if (isSupportedType(transferData)) {
 			final byte[] buffer = (byte[]) super.nativeToJava(transferData);
 			if (buffer == null) {
 				return null;
 			}
+			final ByteArrayInputStream in = new ByteArrayInputStream(buffer);
 
 			try {
-				final ByteArrayInputStream in = new ByteArrayInputStream(buffer);
-				final ObjectInputStream ois = new ObjectInputStream(in);
-				final Object object = readFragment(ois);
-				ois.close();
-				return object;
-			} catch (final ClassNotFoundException ex) {
-				return null;
+				return readFragmentFromStream(in);
 			} catch (final IOException ex) {
 				return null;
 			}
@@ -106,124 +106,18 @@
 		return null;
 	}
 
-	// =================================================== PRIVATE
-
-	private static final String[] typeNames = { MIME_TYPE };
-	private static final int[] typeIds = { ByteArrayTransfer.registerType(MIME_TYPE) };
-
-	private static DocumentFragmentTransfer instance;
-
-	private DocumentFragmentTransfer() {
-	}
-
-	private void writeFragment(final DocumentFragment fragment, final ObjectOutputStream out) throws IOException {
-		writeContent(fragment.getContent(), out);
-		for (final Node node : fragment.getNodes()) {
-			node.accept(new BaseNodeVisitor() {
-				@Override
-				public void visit(final Element element) {
-					try {
-						writeElement(element, out);
-					} catch (final IOException e) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
-					}
-				}
-			});
+	public DocumentFragment readFragmentFromStream(final InputStream in) throws IOException {
+		try {
+			final Document document = new DocumentReader().read(new InputSource(in));
+			return document.getFragment(document.getRootElement().getRange().resizeBy(1, -1));
+		} catch (final ParserConfigurationException e) {
+			// TODO shoult never happen - log this exception?
+			e.printStackTrace();
+			return null;
+		} catch (final SAXException e) {
+			// TODO shoult never happen - log this exception?
+			e.printStackTrace();
+			return null;
 		}
 	}
-
-	private static void writeContent(final Content content, final ObjectOutputStream out) throws IOException {
-		final int contentLength = content.length();
-		out.write(contentLength);
-		for (int i = 0; i < contentLength; i++) {
-			if (content.isTagMarker(i)) {
-				out.writeUTF("\0"); // This internal representation of tag markers has nothing to do with the internal representation in GapContent.
-			} else {
-				out.writeUTF(content.getText(new ContentRange(i, i)));
-			}
-		}
-	}
-
-	private static void writeElement(final Element element, final ObjectOutputStream out) throws IOException {
-		out.writeObject(element.getQualifiedName());
-		out.writeInt(element.getStartOffset());
-		out.writeInt(element.getEndOffset());
-		final Collection<Attribute> attributes = element.getAttributes();
-		out.writeInt(attributes.size());
-		for (final Attribute attribute : attributes) {
-			out.writeObject(attribute.getQualifiedName());
-			out.writeObject(attribute.getValue());
-		}
-		final List<Element> children = element.getChildElements();
-		out.writeInt(children.size());
-		for (int i = 0; i < children.size(); i++) {
-			writeElement(children.get(i), out);
-		}
-	}
-
-	private DocumentFragment readFragment(final ObjectInputStream in) throws IOException, ClassNotFoundException {
-		final Content content = readContent(in);
-		final int n = in.readInt();
-		final ArrayList<Node> nodes = new ArrayList<Node>(n);
-		for (int i = 0; i < n; i++) {
-			nodes.add(readElement(in, content));
-		}
-		return new DocumentFragment(content, nodes);
-	}
-
-	private static Content readContent(final ObjectInputStream in) throws IOException {
-		final int contentLength = in.readInt();
-		final Content result = new GapContent(contentLength);
-		for (int i = 0; i < contentLength; i++) {
-			final String input = in.readUTF();
-			if ("\0".equals(input)) { // This internal representation of tag markers has nothing to do with the internal representation in GapContent.
-				result.insertTagMarker(i);
-			} else {
-				result.insertText(i, input);
-			}
-		}
-		return result;
-	}
-
-	private static Element readElement(final ObjectInputStream in, final Content content) throws IOException, ClassNotFoundException {
-		final QualifiedName elementName = createQualifiedName(in.readObject());
-		final int startOffset = in.readInt();
-		final int endOffset = in.readInt();
-		final Element element = new Element(elementName);
-		element.associate(content, new ContentRange(startOffset, endOffset));
-
-		final int attrCount = in.readInt();
-		for (int i = 0; i < attrCount; i++) {
-			final QualifiedName attributeName = createQualifiedName(in.readObject());
-			final String value = (String) in.readObject();
-			try {
-				element.setAttribute(attributeName, value);
-			} catch (final DocumentValidationException e) {
-				// Should never happen; there ain't no document
-				e.printStackTrace();
-			}
-		}
-
-		final int childCount = in.readInt();
-		for (int i = 0; i < childCount; i++) {
-			final Element child = readElement(in, content);
-			child.setParent(element);
-			element.insertChild(i, child);
-		}
-
-		return element;
-	}
-
-	private static QualifiedName createQualifiedName(final Object object) {
-		final String serializedQualifiedName = object.toString();
-		final int localNameStartIndex = serializedQualifiedName.lastIndexOf(':') + 1;
-		if (localNameStartIndex == 0) {
-			return new QualifiedName(null, serializedQualifiedName);
-		}
-		final String qualifier = serializedQualifiedName.substring(0, localNameStartIndex - 1);
-		final String localName = serializedQualifiedName.substring(localNameStartIndex);
-		return new QualifiedName(qualifier, localName);
-	}
-
 }