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.
14 type writer interface {
17 WriteString(string) (int, error)
20 // Render renders the parse tree n to the given writer.
22 // Rendering is done on a 'best effort' basis: calling Parse on the output of
23 // Render will always result in something similar to the original tree, but it
24 // is not necessarily an exact clone unless the original tree was 'well-formed'.
25 // 'Well-formed' is not easily specified; the HTML5 specification is
28 // Calling Parse on arbitrary input typically results in a 'well-formed' parse
29 // tree. However, it is possible for Parse to yield a 'badly-formed' parse tree.
30 // For example, in a 'well-formed' parse tree, no <a> element is a child of
31 // another <a> element: parsing "<a><a>" results in two sibling elements.
32 // Similarly, in a 'well-formed' parse tree, no <a> element is a child of a
33 // <table> element: parsing "<p><table><a>" results in a <p> with two sibling
34 // children; the <a> is reparented to the <table>'s parent. However, calling
35 // Parse on "<a><table><a>" does not return an error, but the result has an <a>
36 // element with an <a> child, and is therefore not 'well-formed'.
38 // Programmatically constructed trees are typically also 'well-formed', but it
39 // is possible to construct a tree that looks innocuous but, when rendered and
40 // re-parsed, results in a different tree. A simple example is that a solitary
41 // text node would become a tree containing <html>, <head> and <body> elements.
42 // Another example is that the programmatic equivalent of "a<head>b</head>c"
43 // becomes "<html><head><head/><body>abc</body></html>".
44 func Render(w io.Writer, n *Node) error {
45 if x, ok := w.(writer); ok {
48 buf := bufio.NewWriter(w)
49 if err := render(buf, n); err != nil {
55 func render(w writer, n *Node) error {
56 // Render non-element nodes; these are the easy cases.
59 return errors.New("html: cannot render an ErrorNode node")
61 return escape(w, n.Data)
63 for _, c := range n.Child {
64 if err := render(w, c); err != nil {
72 if _, err := w.WriteString("<!--"); err != nil {
75 if _, err := w.WriteString(n.Data); err != nil {
78 if _, err := w.WriteString("-->"); err != nil {
83 if _, err := w.WriteString("<!DOCTYPE "); err != nil {
86 if _, err := w.WriteString(n.Data); err != nil {
89 return w.WriteByte('>')
91 return errors.New("html: unknown node type")
94 // Render the <xxx> opening tag.
95 if err := w.WriteByte('<'); err != nil {
98 if _, err := w.WriteString(n.Data); err != nil {
101 for _, a := range n.Attr {
102 if err := w.WriteByte(' '); err != nil {
105 if _, err := w.WriteString(a.Key); err != nil {
108 if _, err := w.WriteString(`="`); err != nil {
111 if err := escape(w, a.Val); err != nil {
114 if err := w.WriteByte('"'); err != nil {
118 if voidElements[n.Data] {
119 if len(n.Child) != 0 {
120 return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
122 _, err := w.WriteString("/>")
125 if err := w.WriteByte('>'); err != nil {
129 // Render any child nodes.
131 case "noembed", "noframes", "noscript", "script", "style":
132 for _, c := range n.Child {
133 if c.Type != TextNode {
134 return fmt.Errorf("html: raw text element <%s> has non-text child node", n.Data)
136 if _, err := w.WriteString(c.Data); err != nil {
140 case "textarea", "title":
141 for _, c := range n.Child {
142 if c.Type != TextNode {
143 return fmt.Errorf("html: RCDATA element <%s> has non-text child node", n.Data)
145 if err := render(w, c); err != nil {
150 for _, c := range n.Child {
151 if err := render(w, c); err != nil {
157 // Render the </xxx> closing tag.
158 if _, err := w.WriteString("</"); err != nil {
161 if _, err := w.WriteString(n.Data); err != nil {
164 return w.WriteByte('>')
167 // Section 13.1.2, "Elements", gives this list of void elements. Void elements
168 // are those that can't have any contents.
169 var voidElements = map[string]bool{