Skip to content

Commit 2c1ebad

Browse files
committed
Merge branch '#125'
2 parents 15733e6 + 486f36d commit 2c1ebad

2 files changed

Lines changed: 61 additions & 16 deletions

File tree

node.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func (n *Node) OutputXML(self bool) string {
321321
// OutputXMLWithOptions returns the text that including tags name.
322322
func (n *Node) OutputXMLWithOptions(opts ...OutputOption) string {
323323
var b strings.Builder
324-
n.WriteWithOptions(&b, opts...)
324+
_ = n.WriteWithOptions(&b, opts...)
325325
return b.String()
326326
}
327327

@@ -362,36 +362,53 @@ func (n *Node) WriteWithOptions(writer io.Writer, opts ...OutputOption) (err err
362362
}
363363

364364
// AddAttr adds a new attribute specified by 'key' and 'val' to a node 'n'.
365-
func AddAttr(n *Node, key, val string) {
365+
// Returns false if the attribute already exists.
366+
func AddAttr(n *Node, key, val string) bool {
367+
if n.HasAttr(key) {
368+
return false
369+
}
366370
attr := Attr{
367371
Name: newXMLName(key),
368372
Value: val,
369373
}
370374
n.Attr = append(n.Attr, attr)
375+
return true
376+
}
377+
378+
// HasAttr determines if an attribute exists.
379+
func (n *Node) HasAttr(key string) bool {
380+
name := newXMLName(key)
381+
for _, attr := range n.Attr {
382+
if attr.Name == name {
383+
return true
384+
}
385+
}
386+
return false
371387
}
372388

373389
// SetAttr allows an attribute value with the specified name to be changed.
374390
// If the attribute did not previously exist, it will be created.
375-
func (n *Node) SetAttr(key, value string) {
391+
func (n *Node) SetAttr(key, value string) bool {
376392
name := newXMLName(key)
377393
for i, attr := range n.Attr {
378394
if attr.Name == name {
379395
n.Attr[i].Value = value
380-
return
396+
return true
381397
}
382398
}
383-
AddAttr(n, key, value)
399+
return AddAttr(n, key, value)
384400
}
385401

386402
// RemoveAttr removes the attribute with the specified name.
387-
func (n *Node) RemoveAttr(key string) {
403+
func (n *Node) RemoveAttr(key string) bool {
388404
name := newXMLName(key)
389405
for i, attr := range n.Attr {
390406
if attr.Name == name {
391407
n.Attr = append(n.Attr[:i], n.Attr[i+1:]...)
392-
return
408+
return true
393409
}
394410
}
411+
return false
395412
}
396413

397414
// AddChild adds a new node 'n' to a node 'parent' as its last child.

node_test.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,36 @@ func TestAddAttr(t *testing.T) {
124124
key string
125125
val string
126126
expected string
127+
ok bool
127128
}{
128129
{
129130
name: "node has no existing attr",
130131
n: &Node{Type: AttributeNode},
131132
key: "ns:k1",
132133
val: "v1",
133134
expected: `< ns:k1="v1"></>`,
135+
ok: true,
134136
},
135137
{
136138
name: "node has existing attrs",
137139
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Local: "k1"}, Value: "v1"}}},
138140
key: "k2",
139141
val: "v2",
140142
expected: `< k1="v1" k2="v2"></>`,
143+
ok: true,
144+
},
145+
{
146+
name: "node already has existing attr",
147+
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Local: "k1"}, Value: "v1"}}},
148+
key: "k1",
149+
val: "v1",
150+
expected: `< k1="v1"></>`,
151+
ok: false,
141152
},
142153
} {
143154
t.Run(test.name, func(t *testing.T) {
144-
AddAttr(test.n, test.key, test.val)
155+
ok := AddAttr(test.n, test.key, test.val)
156+
testTrue(t, ok == test.ok)
145157
testValue(t, test.n.OutputXML(true), test.expected)
146158
})
147159
}
@@ -154,39 +166,45 @@ func TestSetAttr(t *testing.T) {
154166
key string
155167
val string
156168
expected string
169+
ok bool
157170
}{
158171
{
159172
name: "node has no existing attr",
160173
n: &Node{Type: AttributeNode},
161174
key: "ns:k1",
162175
val: "v1",
163176
expected: `< ns:k1="v1"></>`,
177+
ok: true,
164178
},
165179
{
166180
name: "node has an existing attr, overwriting",
167181
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Space: "ns", Local: "k1"}, Value: "v1"}}},
168182
key: "ns:k1",
169183
val: "v2",
170184
expected: `< ns:k1="v2"></>`,
185+
ok: true,
171186
},
172187
{
173188
name: "node has no existing attr, no ns",
174189
n: &Node{Type: AttributeNode},
175190
key: "k1",
176191
val: "v1",
177192
expected: `< k1="v1"></>`,
193+
ok: true,
178194
},
179195
{
180196
name: "node has an existing attr, no ns, overwriting",
181197
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Local: "k1"}, Value: "v1"}}},
182198
key: "k1",
183199
val: "v2",
184200
expected: `< k1="v2"></>`,
201+
ok: true,
185202
},
186203
} {
187204

188205
t.Run(test.name, func(t *testing.T) {
189-
test.n.SetAttr(test.key, test.val)
206+
ok := test.n.SetAttr(test.key, test.val)
207+
testTrue(t, ok == test.ok)
190208
testValue(t, test.n.OutputXML(true), test.expected)
191209
})
192210
}
@@ -198,48 +216,54 @@ func TestRemoveAttr(t *testing.T) {
198216
n *Node
199217
key string
200218
expected string
219+
ok bool
201220
}{
202221
{
203222
name: "node has no existing attr",
204223
n: &Node{Type: AttributeNode},
205224
key: "ns:k1",
206225
expected: `<></>`,
226+
ok: false,
207227
},
208228
{
209229
name: "node has an existing attr, overwriting",
210230
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Space: "ns", Local: "k1"}, Value: "v1"}}},
211231
key: "ns:k1",
212232
expected: `<></>`,
233+
ok: true,
213234
},
214235
{
215236
name: "node has no existing attr, no ns",
216237
n: &Node{Type: AttributeNode},
217238
key: "k1",
218239
expected: `<></>`,
240+
ok: false,
219241
},
220242
{
221243
name: "node has an existing attr, no ns, overwriting",
222244
n: &Node{Type: AttributeNode, Attr: []Attr{{Name: xml.Name{Local: "k1"}, Value: "v1"}}},
223245
key: "k1",
224246
expected: `<></>`,
247+
ok: true,
225248
},
226249
} {
227250

228251
t.Run(test.name, func(t *testing.T) {
229-
test.n.RemoveAttr(test.key)
252+
ok := test.n.RemoveAttr(test.key)
253+
testTrue(t, ok == test.ok)
230254
testValue(t, test.n.OutputXML(true), test.expected)
231255
})
232256
}
233257
}
234258

235259
func TestRemoveFromTree(t *testing.T) {
236-
xml := `<?procinst?>
260+
xmlStr := `<?procinst?>
237261
<!--comment-->
238262
<aaa><bbb/>
239263
<ddd><eee><fff/></eee></ddd>
240264
<ggg/></aaa>`
241265
parseXML := func() *Node {
242-
doc, err := Parse(strings.NewReader(xml))
266+
doc, err := Parse(strings.NewReader(xmlStr))
243267
testTrue(t, err == nil)
244268
return doc
245269
}
@@ -398,7 +422,8 @@ func TestEscapeValueWrite(t *testing.T) {
398422
}
399423

400424
var b strings.Builder
401-
root.Write(&b, true)
425+
err = root.Write(&b, true)
426+
testTrue(t, err == nil)
402427
escapedInnerText := b.String()
403428
if !strings.Contains(escapedInnerText, "&lt;*&gt;") {
404429
t.Fatal("Inner Text has not been escaped")
@@ -448,7 +473,8 @@ func TestUnnecessaryEscapeValueWrite(t *testing.T) {
448473
}
449474

450475
var b strings.Builder
451-
root.Write(&b, true)
476+
err = root.Write(&b, true)
477+
testTrue(t, err == nil)
452478
escapedInnerText := b.String()
453479
if strings.Contains(escapedInnerText, "&#x9") {
454480
t.Fatal("\\n has been escaped unnecessarily")
@@ -492,7 +518,8 @@ func TestHtmlUnescapeStringOriginStringWrite(t *testing.T) {
492518
}
493519

494520
var b strings.Builder
495-
root.Write(&b, false)
521+
err = root.Write(&b, false)
522+
testTrue(t, err == nil)
496523
escapedInnerText := b.String()
497524
unescapeString := html.UnescapeString(escapedInnerText)
498525
if strings.Contains(unescapeString, "&amp;") {
@@ -516,7 +543,8 @@ func TestWriteWithNamespacePrefix(t *testing.T) {
516543
s := `<?xml version="1.0" encoding="UTF-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body></S:Body></S:Envelope>`
517544
doc, _ := Parse(strings.NewReader(s))
518545
var b strings.Builder
519-
doc.Write(&b, false)
546+
err := doc.Write(&b, false)
547+
testTrue(t, err == nil)
520548
if s != b.String() {
521549
t.Fatal("xml document missing some characters")
522550
}

0 commit comments

Comments
 (0)