2009-10-05 15:00:50 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package xml
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"io";
|
|
|
|
|
"os";
|
|
|
|
|
"reflect";
|
|
|
|
|
"strings";
|
|
|
|
|
"testing";
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const testInput = `
|
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
|
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2009-12-09 16:54:07 -08:00
|
|
|
<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
|
|
|
|
|
"\r\n\t" + ` >
|
2009-10-05 15:00:50 -07:00
|
|
|
<hello lang="en">World <>'" 白鵬翔</hello>
|
|
|
|
|
<goodbye />
|
|
|
|
|
<outer foo:attr="value" xmlns:tag="ns4">
|
|
|
|
|
<inner/>
|
|
|
|
|
</outer>
|
|
|
|
|
<tag:name>
|
2009-11-14 11:46:09 -08:00
|
|
|
<![CDATA[Some text here.]]>
|
2009-10-05 15:00:50 -07:00
|
|
|
</tag:name>
|
|
|
|
|
</body><!-- missing final newline -->`
|
|
|
|
|
|
|
|
|
|
var rawTokens = []Token{
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
ProcInst{"xml", strings.Bytes(`version="1.0" encoding="UTF-8"`)},
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
Directive(strings.Bytes(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
|
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`)),
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
StartElement{Name{"", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}},
|
|
|
|
|
CharData(strings.Bytes("World <>'\" 白鵬翔")),
|
|
|
|
|
EndElement{Name{"", "hello"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"", "goodbye"}, nil},
|
|
|
|
|
EndElement{Name{"", "goodbye"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"", "outer"}, []Attr{Attr{Name{"foo", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"", "inner"}, nil},
|
|
|
|
|
EndElement{Name{"", "inner"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
EndElement{Name{"", "outer"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"tag", "name"}, nil},
|
2009-11-14 11:46:09 -08:00
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
CharData(strings.Bytes("Some text here.")),
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
2009-10-05 15:00:50 -07:00
|
|
|
EndElement{Name{"tag", "name"}},
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
EndElement{Name{"", "body"}},
|
|
|
|
|
Comment(strings.Bytes(" missing final newline ")),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var cookedTokens = []Token{
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
ProcInst{"xml", strings.Bytes(`version="1.0" encoding="UTF-8"`)},
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
Directive(strings.Bytes(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
|
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`)),
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
StartElement{Name{"ns2", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"ns2", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}},
|
|
|
|
|
CharData(strings.Bytes("World <>'\" 白鵬翔")),
|
|
|
|
|
EndElement{Name{"ns2", "hello"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"ns2", "goodbye"}, nil},
|
|
|
|
|
EndElement{Name{"ns2", "goodbye"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"ns2", "outer"}, []Attr{Attr{Name{"ns1", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"ns2", "inner"}, nil},
|
|
|
|
|
EndElement{Name{"ns2", "inner"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
EndElement{Name{"ns2", "outer"}},
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
StartElement{Name{"ns3", "name"}, nil},
|
2009-11-14 11:46:09 -08:00
|
|
|
CharData(strings.Bytes("\n ")),
|
|
|
|
|
CharData(strings.Bytes("Some text here.")),
|
|
|
|
|
CharData(strings.Bytes("\n ")),
|
2009-10-05 15:00:50 -07:00
|
|
|
EndElement{Name{"ns3", "name"}},
|
|
|
|
|
CharData(strings.Bytes("\n")),
|
|
|
|
|
EndElement{Name{"ns2", "body"}},
|
|
|
|
|
Comment(strings.Bytes(" missing final newline ")),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type stringReader struct {
|
2009-11-05 18:14:47 -08:00
|
|
|
s string;
|
|
|
|
|
off int;
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
|
|
|
|
if r.off >= len(r.s) {
|
2009-11-09 12:07:39 -08:00
|
|
|
return 0, os.EOF
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
for r.off < len(r.s) && n < len(b) {
|
|
|
|
|
b[n] = r.s[r.off];
|
|
|
|
|
n++;
|
|
|
|
|
r.off++;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *stringReader) ReadByte() (b byte, err os.Error) {
|
|
|
|
|
if r.off >= len(r.s) {
|
2009-11-09 12:07:39 -08:00
|
|
|
return 0, os.EOF
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
b = r.s[r.off];
|
|
|
|
|
r.off++;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-06 14:24:38 -08:00
|
|
|
func StringReader(s string) io.Reader { return &stringReader{s, 0} }
|
2009-10-05 15:00:50 -07:00
|
|
|
|
|
|
|
|
func TestRawToken(t *testing.T) {
|
|
|
|
|
p := NewParser(StringReader(testInput));
|
|
|
|
|
|
|
|
|
|
for i, want := range rawTokens {
|
|
|
|
|
have, err := p.RawToken();
|
|
|
|
|
if err != nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Fatalf("token %d: unexpected error: %s", i, err)
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(have, want) {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Errorf("token %d = %#v want %#v", i, have, want)
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestToken(t *testing.T) {
|
|
|
|
|
p := NewParser(StringReader(testInput));
|
|
|
|
|
|
|
|
|
|
for i, want := range cookedTokens {
|
|
|
|
|
have, err := p.Token();
|
|
|
|
|
if err != nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Fatalf("token %d: unexpected error: %s", i, err)
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(have, want) {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Errorf("token %d = %#v want %#v", i, have, want)
|
2009-10-05 15:00:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|