]>
Commit | Line | Data |
---|---|---|
c680a8e1 RS |
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 | scopeMarkerNode | |
22 | ) | |
23 | ||
24 | // Section 12.2.3.3 says "scope markers are inserted when entering applet | |
25 | // elements, buttons, object elements, marquees, table cells, and table | |
26 | // captions, and are used to prevent formatting from 'leaking'". | |
27 | var scopeMarker = Node{Type: scopeMarkerNode} | |
28 | ||
29 | // A Node consists of a NodeType and some Data (tag name for element nodes, | |
30 | // content for text) and are part of a tree of Nodes. Element nodes may also | |
31 | // have a Namespace and contain a slice of Attributes. Data is unescaped, so | |
32 | // that it looks like "a<b" rather than "a<b". For element nodes, DataAtom | |
33 | // is the atom for Data, or zero if Data is not a known tag name. | |
34 | // | |
35 | // An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. | |
36 | // Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and | |
37 | // "svg" is short for "http://www.w3.org/2000/svg". | |
38 | type Node struct { | |
39 | Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node | |
40 | ||
41 | Type NodeType | |
42 | DataAtom atom.Atom | |
43 | Data string | |
44 | Namespace string | |
45 | Attr []Attribute | |
46 | } | |
47 | ||
48 | // InsertBefore inserts newChild as a child of n, immediately before oldChild | |
49 | // in the sequence of n's children. oldChild may be nil, in which case newChild | |
50 | // is appended to the end of n's children. | |
51 | // | |
52 | // It will panic if newChild already has a parent or siblings. | |
53 | func (n *Node) InsertBefore(newChild, oldChild *Node) { | |
54 | if newChild.Parent != nil || newChild.PrevSibling != nil || newChild.NextSibling != nil { | |
55 | panic("html: InsertBefore called for an attached child Node") | |
56 | } | |
57 | var prev, next *Node | |
58 | if oldChild != nil { | |
59 | prev, next = oldChild.PrevSibling, oldChild | |
60 | } else { | |
61 | prev = n.LastChild | |
62 | } | |
63 | if prev != nil { | |
64 | prev.NextSibling = newChild | |
65 | } else { | |
66 | n.FirstChild = newChild | |
67 | } | |
68 | if next != nil { | |
69 | next.PrevSibling = newChild | |
70 | } else { | |
71 | n.LastChild = newChild | |
72 | } | |
73 | newChild.Parent = n | |
74 | newChild.PrevSibling = prev | |
75 | newChild.NextSibling = next | |
76 | } | |
77 | ||
78 | // AppendChild adds a node c as a child of n. | |
79 | // | |
80 | // It will panic if c already has a parent or siblings. | |
81 | func (n *Node) AppendChild(c *Node) { | |
82 | if c.Parent != nil || c.PrevSibling != nil || c.NextSibling != nil { | |
83 | panic("html: AppendChild called for an attached child Node") | |
84 | } | |
85 | last := n.LastChild | |
86 | if last != nil { | |
87 | last.NextSibling = c | |
88 | } else { | |
89 | n.FirstChild = c | |
90 | } | |
91 | n.LastChild = c | |
92 | c.Parent = n | |
93 | c.PrevSibling = last | |
94 | } | |
95 | ||
96 | // RemoveChild removes a node c that is a child of n. Afterwards, c will have | |
97 | // no parent and no siblings. | |
98 | // | |
99 | // It will panic if c's parent is not n. | |
100 | func (n *Node) RemoveChild(c *Node) { | |
101 | if c.Parent != n { | |
102 | panic("html: RemoveChild called for a non-child Node") | |
103 | } | |
104 | if n.FirstChild == c { | |
105 | n.FirstChild = c.NextSibling | |
106 | } | |
107 | if c.NextSibling != nil { | |
108 | c.NextSibling.PrevSibling = c.PrevSibling | |
109 | } | |
110 | if n.LastChild == c { | |
111 | n.LastChild = c.PrevSibling | |
112 | } | |
113 | if c.PrevSibling != nil { | |
114 | c.PrevSibling.NextSibling = c.NextSibling | |
115 | } | |
116 | c.Parent = nil | |
117 | c.PrevSibling = nil | |
118 | c.NextSibling = nil | |
119 | } | |
120 | ||
121 | // reparentChildren reparents all of src's child nodes to dst. | |
122 | func reparentChildren(dst, src *Node) { | |
123 | for { | |
124 | child := src.FirstChild | |
125 | if child == nil { | |
126 | break | |
127 | } | |
128 | src.RemoveChild(child) | |
129 | dst.AppendChild(child) | |
130 | } | |
131 | } | |
132 | ||
133 | // clone returns a new node with the same type, data and attributes. | |
134 | // The clone has no parent, no siblings and no children. | |
135 | func (n *Node) clone() *Node { | |
136 | m := &Node{ | |
137 | Type: n.Type, | |
138 | DataAtom: n.DataAtom, | |
139 | Data: n.Data, | |
140 | Attr: make([]Attribute, len(n.Attr)), | |
141 | } | |
142 | copy(m.Attr, n.Attr) | |
143 | return m | |
144 | } | |
145 | ||
146 | // nodeStack is a stack of nodes. | |
147 | type nodeStack []*Node | |
148 | ||
149 | // pop pops the stack. It will panic if s is empty. | |
150 | func (s *nodeStack) pop() *Node { | |
151 | i := len(*s) | |
152 | n := (*s)[i-1] | |
153 | *s = (*s)[:i-1] | |
154 | return n | |
155 | } | |
156 | ||
157 | // top returns the most recently pushed node, or nil if s is empty. | |
158 | func (s *nodeStack) top() *Node { | |
159 | if i := len(*s); i > 0 { | |
160 | return (*s)[i-1] | |
161 | } | |
162 | return nil | |
163 | } | |
164 | ||
165 | // index returns the index of the top-most occurrence of n in the stack, or -1 | |
166 | // if n is not present. | |
167 | func (s *nodeStack) index(n *Node) int { | |
168 | for i := len(*s) - 1; i >= 0; i-- { | |
169 | if (*s)[i] == n { | |
170 | return i | |
171 | } | |
172 | } | |
173 | return -1 | |
174 | } | |
175 | ||
176 | // insert inserts a node at the given index. | |
177 | func (s *nodeStack) insert(i int, n *Node) { | |
178 | (*s) = append(*s, nil) | |
179 | copy((*s)[i+1:], (*s)[i:]) | |
180 | (*s)[i] = n | |
181 | } | |
182 | ||
183 | // remove removes a node from the stack. It is a no-op if n is not present. | |
184 | func (s *nodeStack) remove(n *Node) { | |
185 | i := s.index(n) | |
186 | if i == -1 { | |
187 | return | |
188 | } | |
189 | copy((*s)[i:], (*s)[i+1:]) | |
190 | j := len(*s) - 1 | |
191 | (*s)[j] = nil | |
192 | *s = (*s)[:j] | |
193 | } |