Skip to content

Commit b00f731

Browse files
ehedgehogrsc
authored andcommitted
xml: permit nested directives
Return <!DOCTYPE ...> with nested directives as one big token. Fixes #1549. R=niemeyer, rsc CC=golang-dev https://golang.org/cl/4216050
1 parent b2efedb commit b00f731

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

src/pkg/xml/xml.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,17 +541,36 @@ func (p *Parser) RawToken() (Token, os.Error) {
541541
}
542542

543543
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
544-
// We don't care, but accumulate for caller.
544+
// We don't care, but accumulate for caller. Quoted angle
545+
// brackets do not count for nesting.
545546
p.buf.Reset()
546547
p.buf.WriteByte(b)
548+
inquote := uint8(0)
549+
depth := 0
547550
for {
548551
if b, ok = p.mustgetc(); !ok {
549552
return nil, p.err
550553
}
551-
if b == '>' {
554+
if inquote == 0 && b == '>' && depth == 0 {
552555
break
553556
}
554557
p.buf.WriteByte(b)
558+
switch {
559+
case b == inquote:
560+
inquote = 0
561+
562+
case inquote != 0:
563+
// in quotes, no special action
564+
565+
case b == '\'' || b == '"':
566+
inquote = b
567+
568+
case b == '>' && inquote == 0:
569+
depth--
570+
571+
case b == '<' && inquote == 0:
572+
depth++
573+
}
555574
}
556575
return Directive(p.buf.Bytes()), nil
557576
}

src/pkg/xml/xml_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,52 @@ func TestRawToken(t *testing.T) {
185185
}
186186
}
187187

188+
// Ensure that directives (specifically !DOCTYPE) include the complete
189+
// text of any nested directives, noting that < and > do not change
190+
// nesting depth if they are in single or double quotes.
191+
192+
var nestedDirectivesInput = `
193+
<!DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]>
194+
<!DOCTYPE [<!ENTITY xlt ">">]>
195+
<!DOCTYPE [<!ENTITY xlt "<">]>
196+
<!DOCTYPE [<!ENTITY xlt '>'>]>
197+
<!DOCTYPE [<!ENTITY xlt '<'>]>
198+
<!DOCTYPE [<!ENTITY xlt '">'>]>
199+
<!DOCTYPE [<!ENTITY xlt "'<">]>
200+
`
201+
202+
var nestedDirectivesTokens = []Token{
203+
CharData([]byte("\n")),
204+
Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
205+
CharData([]byte("\n")),
206+
Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
207+
CharData([]byte("\n")),
208+
Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
209+
CharData([]byte("\n")),
210+
Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
211+
CharData([]byte("\n")),
212+
Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
213+
CharData([]byte("\n")),
214+
Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
215+
CharData([]byte("\n")),
216+
Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
217+
CharData([]byte("\n")),
218+
}
219+
220+
func TestNestedDirectives(t *testing.T) {
221+
p := NewParser(StringReader(nestedDirectivesInput))
222+
223+
for i, want := range nestedDirectivesTokens {
224+
have, err := p.Token()
225+
if err != nil {
226+
t.Fatalf("token %d: unexpected error: %s", i, err)
227+
}
228+
if !reflect.DeepEqual(have, want) {
229+
t.Errorf("token %d = %#v want %#v", i, have, want)
230+
}
231+
}
232+
}
233+
188234
func TestToken(t *testing.T) {
189235
p := NewParser(StringReader(testInput))
190236

0 commit comments

Comments
 (0)