OSDN Git Service

libgo: Update to weekly.2011-11-02.
[pf3gnuchains/gcc-fork.git] / libgo / go / html / render.go
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         "bufio"
9         "errors"
10         "fmt"
11         "io"
12 )
13
14 type writer interface {
15         io.Writer
16         WriteByte(byte) error
17         WriteString(string) (int, error)
18 }
19
20 // Render renders the parse tree n to the given writer.
21 //
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
26 // complicated.
27 //
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'.
37 // 
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 {
46                 return render(x, n)
47         }
48         buf := bufio.NewWriter(w)
49         if err := render(buf, n); err != nil {
50                 return err
51         }
52         return buf.Flush()
53 }
54
55 func render(w writer, n *Node) error {
56         // Render non-element nodes; these are the easy cases.
57         switch n.Type {
58         case ErrorNode:
59                 return errors.New("html: cannot render an ErrorNode node")
60         case TextNode:
61                 return escape(w, n.Data)
62         case DocumentNode:
63                 for _, c := range n.Child {
64                         if err := render(w, c); err != nil {
65                                 return err
66                         }
67                 }
68                 return nil
69         case ElementNode:
70                 // No-op.
71         case CommentNode:
72                 if _, err := w.WriteString("<!--"); err != nil {
73                         return err
74                 }
75                 if _, err := w.WriteString(n.Data); err != nil {
76                         return err
77                 }
78                 if _, err := w.WriteString("-->"); err != nil {
79                         return err
80                 }
81                 return nil
82         case DoctypeNode:
83                 if _, err := w.WriteString("<!DOCTYPE "); err != nil {
84                         return err
85                 }
86                 if _, err := w.WriteString(n.Data); err != nil {
87                         return err
88                 }
89                 return w.WriteByte('>')
90         default:
91                 return errors.New("html: unknown node type")
92         }
93
94         // Render the <xxx> opening tag.
95         if err := w.WriteByte('<'); err != nil {
96                 return err
97         }
98         if _, err := w.WriteString(n.Data); err != nil {
99                 return err
100         }
101         for _, a := range n.Attr {
102                 if err := w.WriteByte(' '); err != nil {
103                         return err
104                 }
105                 if _, err := w.WriteString(a.Key); err != nil {
106                         return err
107                 }
108                 if _, err := w.WriteString(`="`); err != nil {
109                         return err
110                 }
111                 if err := escape(w, a.Val); err != nil {
112                         return err
113                 }
114                 if err := w.WriteByte('"'); err != nil {
115                         return err
116                 }
117         }
118         if voidElements[n.Data] {
119                 if len(n.Child) != 0 {
120                         return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
121                 }
122                 _, err := w.WriteString("/>")
123                 return err
124         }
125         if err := w.WriteByte('>'); err != nil {
126                 return err
127         }
128
129         // Render any child nodes.
130         switch n.Data {
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)
135                         }
136                         if _, err := w.WriteString(c.Data); err != nil {
137                                 return err
138                         }
139                 }
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)
144                         }
145                         if err := render(w, c); err != nil {
146                                 return err
147                         }
148                 }
149         default:
150                 for _, c := range n.Child {
151                         if err := render(w, c); err != nil {
152                                 return err
153                         }
154                 }
155         }
156
157         // Render the </xxx> closing tag.
158         if _, err := w.WriteString("</"); err != nil {
159                 return err
160         }
161         if _, err := w.WriteString(n.Data); err != nil {
162                 return err
163         }
164         return w.WriteByte('>')
165 }
166
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{
170         "area":    true,
171         "base":    true,
172         "br":      true,
173         "col":     true,
174         "command": true,
175         "embed":   true,
176         "hr":      true,
177         "img":     true,
178         "input":   true,
179         "keygen":  true,
180         "link":    true,
181         "meta":    true,
182         "param":   true,
183         "source":  true,
184         "track":   true,
185         "wbr":     true,
186 }