readFrom reads XML data from the provided reader and populates the node and its children accordingly.
(r io.Reader)
| 91 | // readFrom reads XML data from the provided reader |
| 92 | // and populates the node and its children accordingly. |
| 93 | func (n *Node) readFrom(r io.Reader) error { |
| 94 | if n.Parent != nil { |
| 95 | return errors.New("cannot read child node") |
| 96 | } |
| 97 | |
| 98 | dec := NewDecoder(r) |
| 99 | defer dec.Close() |
| 100 | |
| 101 | curNode := n |
| 102 | |
| 103 | for { |
| 104 | // Read raw token so decoder doesn't mess with attributes and namespaces. |
| 105 | tok, err := dec.Token() |
| 106 | if errors.Is(err, io.EOF) { |
| 107 | break |
| 108 | } |
| 109 | if err != nil { |
| 110 | return err |
| 111 | } |
| 112 | |
| 113 | switch t := tok.(type) { |
| 114 | case *StartElement: |
| 115 | // An element is opened, create a node for it |
| 116 | el := &Node{ |
| 117 | Parent: curNode, |
| 118 | Name: t.Name, |
| 119 | Attrs: t.Attrs, |
| 120 | } |
| 121 | // Append the node to the current node's children and make it current |
| 122 | curNode.Children = append(curNode.Children, el) |
| 123 | |
| 124 | if !t.SelfClosing { |
| 125 | curNode = el |
| 126 | } |
| 127 | |
| 128 | case *EndElement: |
| 129 | // If the current node has no parent, then we are at the root, |
| 130 | // which can't be closed. |
| 131 | if curNode.Parent == nil { |
| 132 | return fmt.Errorf( |
| 133 | "malformed XML: unexpected closing tag </%s> while no elements are opened", |
| 134 | t.Name, |
| 135 | ) |
| 136 | } |
| 137 | // Closing tag name should match opened node name (which is current) |
| 138 | if curNode.Name != t.Name { |
| 139 | return fmt.Errorf( |
| 140 | "malformed XML: unexpected closing tag </%s> for opened <%s> element", |
| 141 | t.Name, |
| 142 | curNode.Name, |
| 143 | ) |
| 144 | } |
| 145 | // The node is closed, return to its parent |
| 146 | curNode = curNode.Parent |
| 147 | |
| 148 | case *Text: |
| 149 | curNode.Children = append(curNode.Children, t.Clone()) |
| 150 |
no test coverage detected