node.go (5649B)
1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package html 6 7 import ( 8 "golang.org/x/net/html/atom" 9 ) 10 11 // A NodeType is the type of a Node. 12 type NodeType uint32 13 14 const ( 15 ErrorNode NodeType = iota 16 TextNode 17 DocumentNode 18 ElementNode 19 CommentNode 20 DoctypeNode 21 // RawNode nodes are not returned by the parser, but can be part of the 22 // Node tree passed to func Render to insert raw HTML (without escaping). 23 // If so, this package makes no guarantee that the rendered HTML is secure 24 // (from e.g. Cross Site Scripting attacks) or well-formed. 25 RawNode 26 scopeMarkerNode 27 ) 28 29 // Section 12.2.4.3 says "The markers are inserted when entering applet, 30 // object, marquee, template, td, th, and caption elements, and are used 31 // to prevent formatting from "leaking" into applet, object, marquee, 32 // template, td, th, and caption elements". 33 var scopeMarker = Node{Type: scopeMarkerNode} 34 35 // A Node consists of a NodeType and some Data (tag name for element nodes, 36 // content for text) and are part of a tree of Nodes. Element nodes may also 37 // have a Namespace and contain a slice of Attributes. Data is unescaped, so 38 // that it looks like "a<b" rather than "a<b". For element nodes, DataAtom 39 // is the atom for Data, or zero if Data is not a known tag name. 40 // 41 // An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. 42 // Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and 43 // "svg" is short for "http://www.w3.org/2000/svg". 44 type Node struct { 45 Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node 46 47 Type NodeType 48 DataAtom atom.Atom 49 Data string 50 Namespace string 51 Attr []Attribute 52 } 53 54 // InsertBefore inserts newChild as a child of n, immediately before oldChild 55 // in the sequence of n's children. oldChild may be nil, in which case newChild 56 // is appended to the end of n's children. 57 // 58 // It will panic if newChild already has a parent or siblings. 59 func (n *Node) InsertBefore(newChild, oldChild *Node) { 60 if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil { 61 panic("html: InsertBefore called for an attached child Node") 62 } 63 var prev, next *Node 64 if oldChild != nil { 65 prev, next = oldChild.PrevSibling, oldChild 66 } else { 67 prev = n.LastChild 68 } 69 if prev != nil { 70 prev.NextSibling = newChild 71 } else { 72 n.FirstChild = newChild 73 } 74 if next != nil { 75 next.PrevSibling = newChild 76 } else { 77 n.LastChild = newChild 78 } 79 newChild.Parent = n 80 newChild.PrevSibling = prev 81 newChild.NextSibling = next 82 } 83 84 // AppendChild adds a node c as a child of n. 85 // 86 // It will panic if c already has a parent or siblings. 87 func (n *Node) AppendChild(c *Node) { 88 if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil { 89 panic("html: AppendChild called for an attached child Node") 90 } 91 last := n.LastChild 92 if last != nil { 93 last.NextSibling = c 94 } else { 95 n.FirstChild = c 96 } 97 n.LastChild = c 98 c.Parent = n 99 c.PrevSibling = last 100 } 101 102 // RemoveChild removes a node c that is a child of n. Afterwards, c will have 103 // no parent and no siblings. 104 // 105 // It will panic if c's parent is not n. 106 func (n *Node) RemoveChild(c *Node) { 107 if c.Parent != n { 108 panic("html: RemoveChild called for a non-child Node") 109 } 110 if n.FirstChild == c { 111 n.FirstChild = c.NextSibling 112 } 113 if c.NextSibling != nil { 114 c.NextSibling.PrevSibling = c.PrevSibling 115 } 116 if n.LastChild == c { 117 n.LastChild = c.PrevSibling 118 } 119 if c.PrevSibling != nil { 120 c.PrevSibling.NextSibling = c.NextSibling 121 } 122 c.Parent = nil 123 c.PrevSibling = nil 124 c.NextSibling = nil 125 } 126 127 // reparentChildren reparents all of src's child nodes to dst. 128 func reparentChildren(dst, src *Node) { 129 for { 130 child := src.FirstChild 131 if child == nil { 132 break 133 } 134 src.RemoveChild(child) 135 dst.AppendChild(child) 136 } 137 } 138 139 // clone returns a new node with the same type, data and attributes. 140 // The clone has no parent, no siblings and no children. 141 func (n *Node) clone() *Node { 142 m := &Node{ 143 Type: n.Type, 144 DataAtom: n.DataAtom, 145 Data: n.Data, 146 Attr: make([]Attribute, len(n.Attr)), 147 } 148 copy(m.Attr, n.Attr) 149 return m 150 } 151 152 // nodeStack is a stack of nodes. 153 type nodeStack []*Node 154 155 // pop pops the stack. It will panic if s is empty. 156 func (s *nodeStack) pop() *Node { 157 i := len(*s) 158 n := (*s)[i-1] 159 *s = (*s)[:i-1] 160 return n 161 } 162 163 // top returns the most recently pushed node, or nil if s is empty. 164 func (s *nodeStack) top() *Node { 165 if i := len(*s); i > 0 { 166 return (*s)[i-1] 167 } 168 return nil 169 } 170 171 // index returns the index of the top-most occurrence of n in the stack, or -1 172 // if n is not present. 173 func (s *nodeStack) index(n *Node) int { 174 for i := len(*s) - 1; i >= 0; i-- { 175 if (*s)[i] == n { 176 return i 177 } 178 } 179 return -1 180 } 181 182 // contains returns whether a is within s. 183 func (s *nodeStack) contains(a atom.Atom) bool { 184 for _, n := range *s { 185 if n.DataAtom == a && n.Namespace == "" { 186 return true 187 } 188 } 189 return false 190 } 191 192 // insert inserts a node at the given index. 193 func (s *nodeStack) insert(i int, n *Node) { 194 (*s) = append(*s, nil) 195 copy((*s)[i+1:], (*s)[i:]) 196 (*s)[i] = n 197 } 198 199 // remove removes a node from the stack. It is a no-op if n is not present. 200 func (s *nodeStack) remove(n *Node) { 201 i := s.index(n) 202 if i == -1 { 203 return 204 } 205 copy((*s)[i:], (*s)[i+1:]) 206 j := len(*s) - 1 207 (*s)[j] = nil 208 *s = (*s)[:j] 209 } 210 211 type insertionModeStack []insertionMode 212 213 func (s *insertionModeStack) pop() (im insertionMode) { 214 i := len(*s) 215 im = (*s)[i-1] 216 *s = (*s)[:i-1] 217 return im 218 } 219 220 func (s *insertionModeStack) top() insertionMode { 221 if i := len(*s); i > 0 { 222 return (*s)[i-1] 223 } 224 return nil 225 }