From 7cf4882e7581f14831a39fc0542358cd90e20596 Mon Sep 17 00:00:00 2001 From: Brett Vickers Date: Fri, 17 Jan 2025 15:34:50 -0800 Subject: [PATCH] Add CreateChild to create elements with continuations Introduced the Element.CreateChild function to support the creation of child elements with continuation functions. --- etree.go | 25 ++++++++++++++++++++++-- etree_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/etree.go b/etree.go index 9de4645..e1dde1c 100644 --- a/etree.go +++ b/etree.go @@ -752,13 +752,34 @@ func (e *Element) findTermCharDataIndex(start int) int { } // CreateElement creates a new element with the specified tag (i.e., name) and -// adds it as the last child token of this element. The tag may include a -// prefix followed by a colon. +// adds it as the last child of element 'e'. The tag may include a prefix +// followed by a colon. func (e *Element) CreateElement(tag string) *Element { space, stag := spaceDecompose(tag) return newElement(space, stag, e) } +// CreateChild performs the same task as CreateElement but calls a +// continuation function after the child element is created, allowing +// additional actions to be performed on the child element before returning. +// +// This method of element creation is particularly useful when building nested +// XML documents from code. For example: +// +// org := doc.CreateChild("organization", func(e *Element) { +// e.CreateComment("Mary") +// e.CreateChild("person", func(e *Element) { +// e.CreateAttr("name", "Mary") +// e.CreateAttr("age", "30") +// e.CreateAttr("hair", "brown") +// }) +// }) +func (e *Element) CreateChild(tag string, cont func(e *Element)) *Element { + child := e.CreateElement(tag) + cont(child) + return child +} + // AddChild adds the token 't' as the last child of the element. If token 't' // was already the child of another element, it is first removed from its // parent element. diff --git a/etree_test.go b/etree_test.go index d34a800..1f26207 100644 --- a/etree_test.go +++ b/etree_test.go @@ -1629,3 +1629,56 @@ func TestSiblingElement(t *testing.T) { } } } + +func TestContinuations(t *testing.T) { + doc := NewDocument() + root := doc.CreateChild("root", func(e *Element) { + e.CreateChild("child1", func(e *Element) { + e.CreateComment("Grandchildren of child #1") + e.CreateChild("grandchild1", func(e *Element) { + e.CreateAttr("attr1", "1") + e.CreateAttr("attr2", "2") + }) + e.CreateChild("grandchild2", func(e *Element) { + e.CreateAttr("attr1", "3") + e.CreateAttr("attr2", "4") + }) + }) + e.CreateChild("child2", func(e *Element) { + e.CreateComment("Grandchildren of child #2") + e.CreateChild("grandchild1", func(e *Element) { + e.CreateAttr("attr1", "5") + e.CreateAttr("attr2", "6") + }) + e.CreateChild("grandchild2", func(e *Element) { + e.CreateAttr("attr1", "7") + e.CreateAttr("attr2", "8") + }) + }) + }) + checkStrEq(t, root.Tag, "root") + + // Serialize the document to a string + doc.IndentTabs() + s, err := doc.WriteToString() + if err != nil { + t.Error("etree: failed to serialize document") + } + + // Make sure the serialized XML matches expectation. + expected := ` + + + + + + + + + + + +` + + checkStrEq(t, s, expected) +}