Skip to content

Commit

Permalink
Add support for auto-closing tags
Browse files Browse the repository at this point in the history
  • Loading branch information
dpotapov authored and beevik committed Apr 28, 2024
1 parent d46b199 commit d21e1ce
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
31 changes: 31 additions & 0 deletions etree.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ type ReadSettings struct {

// Entity to be passed to standard xml.Decoder. Default: nil.
Entity map[string]string

// When Permissive is true, AutoClose indicates a set of elements to
// consider closed immediately after they are opened, regardless of
// whether an end element is present. Commonly set to xml.HTMLAutoClose.
// Default: nil.
AutoClose []string
}

// newReadSettings creates a default ReadSettings record.
Expand Down Expand Up @@ -796,6 +802,27 @@ func (e *Element) RemoveChildAt(index int) Token {
return t
}

// autoClose analyzes the stack's top element and the current token to decide
// whether the top element should be closed.
func (e *Element) autoClose(stack *stack, t xml.Token, tags []string) {
if stack.empty() {
return
}

top := stack.peek().(*Element)

for _, tag := range tags {
if strings.EqualFold(tag, top.FullTag()) {
if e, ok := t.(xml.EndElement); !ok ||
!strings.EqualFold(e.Name.Space, top.Space) ||
!strings.EqualFold(e.Name.Local, top.Tag) {
stack.pop()
}
break
}
}
}

// ReadFrom reads XML from the reader 'ri' and stores the result as a new
// child of this element.
func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err error) {
Expand All @@ -822,6 +849,10 @@ func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err er

t, err := dec.RawToken()

if settings.Permissive && settings.AutoClose != nil {
e.autoClose(&stack, t, settings.AutoClose)
}

switch {
case err == io.EOF:
if len(stack.data) != 1 {
Expand Down
39 changes: 39 additions & 0 deletions etree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,45 @@ func TestDocumentReadHTMLEntities(t *testing.T) {
}
}

func TestDocumentReadHTMLAutoClose(t *testing.T) {
cases := []struct {
name string
input string
want string
}{
{"empty", ``, ``},
{"oneSelfClosing", `<br>`, `<br/>`},
{"twoSelfClosingAndText", `<br>some text<br>`, `<br/>some text<br/>`},
{
name: "largerExample",
input: `<img src="cover.jpg">
<hr>
Author: Charles Dickens<br>
Book: Great Expectations<br>`,
want: `<img src="cover.jpg"/>
<hr/>
Author: Charles Dickens<br/>
Book: Great Expectations<br/>`},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
doc := NewDocument()
doc.ReadSettings.Permissive = true
doc.ReadSettings.AutoClose = xml.HTMLAutoClose
err := doc.ReadFromString(c.input)
if err != nil {
t.Fatal("etree: ReadFromString() error = ", err)
}
s, err := doc.WriteToString()
if err != nil {
t.Fatal("etree: WriteToString() error = ", err)
}
checkStrEq(t, s, c.want)
})
}
}

func TestEscapeCodes(t *testing.T) {
cases := []struct {
input string
Expand Down

0 comments on commit d21e1ce

Please sign in to comment.