Skip to content

Commit ce28337

Browse files
committed
Merge branch '#92'
2 parents 67c6eff + bf79512 commit ce28337

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ title.FirstChild = title_text
235235
channel.FirstChild = title
236236
fmt.Println(doc.OutputXML(true))
237237
// <?xml version="1.0"?><rss><channel><title>W3Schools Home Page</title></channel></rss>
238+
239+
fmt.Println(doc.OutputXMLWithOptions(WithOutputSelf()))
240+
// <?xml version="1.0"?><rss><channel><title>W3Schools Home Page</title></channel></rss>
238241
```
239242

240243
Questions

node.go

+60-5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,29 @@ type Node struct {
5050
level int // node level in the tree
5151
}
5252

53+
type outputConfiguration struct {
54+
printSelf bool
55+
preserveSpaces bool
56+
emptyElementTagSupport bool
57+
}
58+
59+
type OutputOption func(*outputConfiguration)
60+
61+
// WithOutputSelf configures the Node to print the root node itself
62+
func WithOutputSelf() OutputOption {
63+
return func(oc *outputConfiguration) {
64+
oc.printSelf = true
65+
}
66+
}
67+
68+
// WithEmptyTagSupport empty tags should be written as <empty/> and
69+
// not as <empty></empty>
70+
func WithEmptyTagSupport() OutputOption {
71+
return func(oc *outputConfiguration) {
72+
oc.emptyElementTagSupport = true
73+
}
74+
}
75+
5376
// InnerText returns the text between the start and end tags of the object.
5477
func (n *Node) InnerText() string {
5578
var output func(*bytes.Buffer, *Node)
@@ -86,7 +109,7 @@ func calculatePreserveSpaces(n *Node, pastValue bool) bool {
86109
return pastValue
87110
}
88111

89-
func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
112+
func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool, config *outputConfiguration) {
90113
preserveSpaces = calculatePreserveSpaces(n, preserveSpaces)
91114
switch n.Type {
92115
case TextNode:
@@ -125,10 +148,15 @@ func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
125148
if n.Type == DeclarationNode {
126149
buf.WriteString("?>")
127150
} else {
128-
buf.WriteString(">")
151+
if n.FirstChild != nil || !config.emptyElementTagSupport {
152+
buf.WriteString(">")
153+
} else {
154+
buf.WriteString("/>")
155+
return
156+
}
129157
}
130158
for child := n.FirstChild; child != nil; child = child.NextSibling {
131-
outputXML(buf, child, preserveSpaces)
159+
outputXML(buf, child, preserveSpaces, config)
132160
}
133161
if n.Type != DeclarationNode {
134162
if n.Prefix == "" {
@@ -141,13 +169,40 @@ func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
141169

142170
// OutputXML returns the text that including tags name.
143171
func (n *Node) OutputXML(self bool) string {
172+
173+
config := &outputConfiguration{
174+
printSelf: true,
175+
emptyElementTagSupport: false,
176+
}
144177
preserveSpaces := calculatePreserveSpaces(n, false)
145178
var buf bytes.Buffer
146179
if self && n.Type != DocumentNode {
147-
outputXML(&buf, n, preserveSpaces)
180+
outputXML(&buf, n, preserveSpaces, config)
181+
} else {
182+
for n := n.FirstChild; n != nil; n = n.NextSibling {
183+
outputXML(&buf, n, preserveSpaces, config)
184+
}
185+
}
186+
187+
return buf.String()
188+
}
189+
190+
// OutputXMLWithOptions returns the text that including tags name.
191+
func (n *Node) OutputXMLWithOptions(opts ...OutputOption) string {
192+
193+
config := &outputConfiguration{}
194+
// Set the options
195+
for _, opt := range opts {
196+
opt(config)
197+
}
198+
199+
preserveSpaces := calculatePreserveSpaces(n, false)
200+
var buf bytes.Buffer
201+
if config.printSelf && n.Type != DocumentNode {
202+
outputXML(&buf, n, preserveSpaces, config)
148203
} else {
149204
for n := n.FirstChild; n != nil; n = n.NextSibling {
150-
outputXML(&buf, n, preserveSpaces)
205+
outputXML(&buf, n, preserveSpaces, config)
151206
}
152207
}
153208

node_test.go

+24-3
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ func TestSetAttr(t *testing.T) {
183183
val: "v2",
184184
expected: `< k1="v2"></>`,
185185
},
186-
187186
} {
188187

189188
t.Run(test.name, func(t *testing.T) {
@@ -224,7 +223,6 @@ func TestRemoveAttr(t *testing.T) {
224223
key: "k1",
225224
expected: `<></>`,
226225
},
227-
228226
} {
229227

230228
t.Run(test.name, func(t *testing.T) {
@@ -234,7 +232,6 @@ func TestRemoveAttr(t *testing.T) {
234232
}
235233
}
236234

237-
238235
func TestRemoveFromTree(t *testing.T) {
239236
xml := `<?procinst?>
240237
<!--comment-->
@@ -556,3 +553,27 @@ func TestOutputXMLWithXMLInCDATA(t *testing.T) {
556553
t.Errorf("the outputted xml escaped CDATA section")
557554
}
558555
}
556+
557+
func TestOutputXMLWithDefaultOptions(t *testing.T) {
558+
s := `<?xml version="1.0" encoding="utf-8"?><node><empty></empty></node>`
559+
expected := `<?xml version="1.0" encoding="utf-8"?><node><empty></empty></node>`
560+
561+
doc, _ := Parse(strings.NewReader(s))
562+
result := doc.OutputXMLWithOptions()
563+
t.Log(result)
564+
if result != expected {
565+
t.Errorf("output was not expected. expected %v but got %v", expected, result)
566+
}
567+
}
568+
569+
func TestOutputXMLWithOptions(t *testing.T) {
570+
s := `<?xml version="1.0" encoding="utf-8"?><node><empty></empty></node>`
571+
expected := `<?xml version="1.0" encoding="utf-8"?><node><empty/></node>`
572+
573+
doc, _ := Parse(strings.NewReader(s))
574+
result := doc.OutputXMLWithOptions(WithEmptyTagSupport())
575+
t.Log(result)
576+
if result != expected {
577+
t.Errorf("output was not expected. expected %v but got %v", expected, result)
578+
}
579+
}

0 commit comments

Comments
 (0)