Added document and element Copy() functions.
Allows deep (recursive) copies of element trees.
diff --git a/etree.go b/etree.go
index 444fb0f..d71a264 100644
--- a/etree.go
+++ b/etree.go
@@ -28,6 +28,7 @@
 // A Token is an empty interface that represents an Element,
 // Comment, CharData, or ProcInst.
 type Token interface {
+	dup(parent *Element) Token
 	writeTo(w *bufio.Writer)
 }
 
@@ -87,6 +88,11 @@
 	return &Document{Element{Child: make([]Token, 0)}}
 }
 
+// Copy returns a recursive, deep copy of the document.
+func (doc *Document) Copy() *Document {
+	return &Document{*(doc.dup(nil).(*Element))}
+}
+
 // ReadFrom reads XML from the reader r into the document d.
 // It returns the number of bytes read and any error encountered.
 func (d *Document) ReadFrom(r io.Reader) (n int64, err error) {
@@ -184,6 +190,15 @@
 	d.Element.indent(0, indent)
 }
 
+// Copy creates a parentless, recursive, deep copy of the element and
+// all its attributes and children. The returned element has no
+// parent but can be parented to a document using the CreateDocument
+// function.
+func (e *Element) Copy() *Element {
+	var parent *Element
+	return e.dup(parent).(*Element)
+}
+
 // Text returns the characters immediately following the element's
 // opening tag.
 func (e *Element) Text() string {
@@ -470,6 +485,24 @@
 	e.Child = newChild
 }
 
+// dup duplicates the element.
+func (e *Element) dup(parent *Element) Token {
+	ne := &Element{
+		Space:  e.Space,
+		Tag:    e.Tag,
+		Attr:   make([]Attr, len(e.Attr)),
+		Child:  make([]Token, len(e.Child)),
+		Parent: parent,
+	}
+	for i, t := range e.Child {
+		ne.Child[i] = t.dup(ne)
+	}
+	for i, a := range e.Attr {
+		ne.Attr[i] = a
+	}
+	return ne
+}
+
 // writeTo serializes the element to the writer w.
 func (e *Element) writeTo(w *bufio.Writer) {
 	w.WriteByte('<')
@@ -594,6 +627,11 @@
 	return c
 }
 
+// dup duplicates the character data.
+func (c *CharData) dup(parent *Element) Token {
+	return newCharData(c.Data, c.whitespace)
+}
+
 // writeTo serializes the character data entity to the writer.
 func (c *CharData) writeTo(w *bufio.Writer) {
 	w.WriteString(escape(c.Data))
@@ -612,6 +650,11 @@
 	return c
 }
 
+// dup duplicates the comment.
+func (c *Comment) dup(parent *Element) Token {
+	return newComment(c.Data)
+}
+
 // writeTo serialies the comment to the writer.
 func (c *Comment) writeTo(w *bufio.Writer) {
 	w.WriteString("<!--")
@@ -632,6 +675,11 @@
 	return d
 }
 
+// dup duplicates the directive.
+func (d *Directive) dup(parent *Element) Token {
+	return newDirective(d.Data)
+}
+
 // writeTo serializes the XML directive to the writer.
 func (d *Directive) writeTo(w *bufio.Writer) {
 	w.WriteString("<!")
@@ -652,6 +700,11 @@
 	return p
 }
 
+// dup duplicates the procinst.
+func (p *ProcInst) dup(parent *Element) Token {
+	return newProcInst(p.Target, p.Inst)
+}
+
 // writeTo serializes the processing instruction to the writer.
 func (p *ProcInst) writeTo(w *bufio.Writer) {
 	w.WriteString("<?")
diff --git a/etree_test.go b/etree_test.go
index fb38905..14b94d2 100644
--- a/etree_test.go
+++ b/etree_test.go
@@ -137,6 +137,52 @@
 	}
 }
 
+func TestCopy(t *testing.T) {
+	s := `<store>
+	<book lang="en">
+		<title>Great Expectations</title>
+		<author>Charles Dickens</author>
+	</book>
+</store>`
+
+	doc1 := NewDocument()
+	err := doc1.ReadFromString(s)
+	if err != nil {
+		t.Fail()
+	}
+
+	s1, err := doc1.WriteToString()
+	if err != nil {
+		t.Fail()
+	}
+
+	doc2 := doc1.Copy()
+	s2, err := doc2.WriteToString()
+	if err != nil {
+		t.Fail()
+	}
+
+	if s1 != s2 {
+		t.Error("Copied documents don't match")
+	}
+
+	e1 := doc1.FindElement("./store/book/title")
+	e2 := doc2.FindElement("./store/book/title")
+	if e1 == nil || e2 == nil {
+		t.Error("Failed to find element")
+	}
+	if e1 == e2 {
+		t.Error("Copied documents contain same element")
+	}
+
+	e1.Parent.RemoveElement(e1)
+	s1, _ = doc1.WriteToString()
+	s2, _ = doc2.WriteToString()
+	if s1 == s2 {
+		t.Error("Copied and modified documents should not match")
+	}
+}
+
 func compareElements(a []*Element, b []*Element) bool {
 	if len(a) != len(b) {
 		return true