@@ -61,35 +61,37 @@ pub struct PullParser {
61
61
pop_namespace : bool
62
62
}
63
63
64
- /// Returns a new parser using the given config.
65
- pub fn new ( config : ParserConfig ) -> PullParser {
66
- PullParser {
67
- config : config,
68
- lexer : lexer:: new ( ) ,
69
- st : OutsideTag ,
70
- buf : String :: new ( ) ,
71
- nst : NamespaceStack :: default ( ) ,
72
-
73
- data : MarkupData {
74
- name : String :: new ( ) ,
75
- version : None ,
76
- encoding : None ,
77
- standalone : None ,
78
- ref_data : String :: new ( ) ,
79
- element_name : None ,
80
- quote : None ,
81
- attr_name : None ,
82
- attributes : vec ! ( )
83
- } ,
84
- finish_event : None ,
85
- next_event : None ,
86
- est : Vec :: new ( ) ,
87
-
88
- encountered_element : false ,
89
- parsed_declaration : false ,
90
- inside_whitespace : true ,
91
- read_prefix_separator : false ,
92
- pop_namespace : false
64
+ impl PullParser {
65
+ /// Returns a new parser using the given config.
66
+ pub fn new ( config : ParserConfig ) -> PullParser {
67
+ PullParser {
68
+ config : config,
69
+ lexer : lexer:: new ( ) ,
70
+ st : OutsideTag ,
71
+ buf : String :: new ( ) ,
72
+ nst : NamespaceStack :: default ( ) ,
73
+
74
+ data : MarkupData {
75
+ name : String :: new ( ) ,
76
+ version : None ,
77
+ encoding : None ,
78
+ standalone : None ,
79
+ ref_data : String :: new ( ) ,
80
+ element_name : None ,
81
+ quote : None ,
82
+ attr_name : None ,
83
+ attributes : vec ! ( )
84
+ } ,
85
+ finish_event : None ,
86
+ next_event : None ,
87
+ est : Vec :: new ( ) ,
88
+
89
+ encountered_element : false ,
90
+ parsed_declaration : false ,
91
+ inside_whitespace : true ,
92
+ read_prefix_separator : false ,
93
+ pop_namespace : false
94
+ }
93
95
}
94
96
}
95
97
@@ -159,6 +161,29 @@ enum QualifiedNameTarget {
159
161
ClosingTagNameTarget
160
162
}
161
163
164
+ #[ deriving( PartialEq , Eq ) ]
165
+ enum QuoteToken {
166
+ SingleQuoteToken ,
167
+ DoubleQuoteToken
168
+ }
169
+
170
+ impl QuoteToken {
171
+ fn from_token ( t : & Token ) -> QuoteToken {
172
+ match * t {
173
+ SingleQuote => SingleQuoteToken ,
174
+ DoubleQuote => DoubleQuoteToken ,
175
+ _ => fail ! ( "Unexpected token: {}" , t)
176
+ }
177
+ }
178
+
179
+ fn as_token ( self ) -> Token {
180
+ match self {
181
+ SingleQuoteToken => SingleQuote ,
182
+ DoubleQuoteToken => DoubleQuote
183
+ }
184
+ }
185
+ }
186
+
162
187
struct AttributeData {
163
188
name : Name ,
164
189
value : String
@@ -184,7 +209,7 @@ struct MarkupData {
184
209
185
210
element_name : Option < Name > , // used for element name
186
211
187
- quote : Option < Token > , // used to hold opening quote for attribute value
212
+ quote : Option < QuoteToken > , // used to hold opening quote for attribute value
188
213
attr_name : Option < Name > , // used to hold attribute name
189
214
attributes : Vec < AttributeData > // used to hold all accumulated attributes
190
215
}
@@ -397,12 +422,12 @@ impl PullParser {
397
422
match t {
398
423
Whitespace ( _) if self . data. quote. is_none( ) => None , // skip leading whitespace
399
424
400
- DoubleQuote | SingleQuote => match self . data. quote. clone ( ) {
425
+ DoubleQuote | SingleQuote => match self . data. quote {
401
426
None => { // Entered attribute value
402
- self . data . quote = Some ( t ) ;
427
+ self. data. quote = Some ( QuoteToken :: from_token ( & t ) ) ;
403
428
None
404
429
}
405
- Some ( ref q) if * q == t => {
430
+ Some ( q) if q . as_token ( ) == t => {
406
431
self . data. quote = None ;
407
432
let value = self . take_buf( ) ;
408
433
on_value ( self , value )
@@ -415,10 +440,8 @@ impl PullParser {
415
440
self . into_state_continue( InsideReference ( st) )
416
441
}
417
442
418
- // Everything characters except " and '
419
- _ if t. contains_char_data ( ) => self . append_str_continue ( t. to_string ( ) . as_slice ( ) ) ,
420
-
421
- _ => Some ( self_error ! ( self ; "Unexpected token inside attribute value: {}" , t) )
443
+ // Every character except " and ' is okay
444
+ _ => self . append_str_continue( t. to_string( ) . as_slice( ) ) ,
422
445
}
423
446
}
424
447
@@ -1026,4 +1049,49 @@ impl PullParser {
1026
1049
1027
1050
#[ cfg( test) ]
1028
1051
mod tests {
1052
+ use std:: io:: BufReader ;
1053
+
1054
+ use common:: { Name , Attribute } ;
1055
+ use reader:: parser:: PullParser ;
1056
+ use reader:: ParserConfig ;
1057
+ use reader:: events;
1058
+
1059
+ fn new_parser ( ) -> PullParser {
1060
+ PullParser :: new ( ParserConfig :: new ( ) )
1061
+ }
1062
+
1063
+ macro_rules! expect_event(
1064
+ ( $r: expr, $p: expr, $t: pat) => (
1065
+ match $p. next( & mut $r) {
1066
+ $t => { }
1067
+ e => fail!( "Unexpected event: {}" , e)
1068
+ }
1069
+ ) ;
1070
+ ( $r: expr, $p: expr, $t: pat if $c: expr) => (
1071
+ match $p. next( & mut $r) {
1072
+ $t if $c => { }
1073
+ e => fail!( "Unexpected event: {}" , e)
1074
+ }
1075
+ )
1076
+ )
1077
+
1078
+ #[ test]
1079
+ fn semicolon_in_attribute_issue_3 ( ) {
1080
+ static DATA : & ' static str = r#"
1081
+ <a attr="zzz;zzz" />
1082
+ "# ;
1083
+ let mut r = BufReader :: new ( DATA . as_bytes ( ) ) ;
1084
+
1085
+ let mut p = new_parser ( ) ;
1086
+
1087
+ expect_event ! ( r, p, events:: StartDocument { .. } ) ;
1088
+ expect_event ! ( r, p, events:: StartElement { ref name, ref attributes, ref namespace }
1089
+ if * name == Name :: new_local( "a" ) &&
1090
+ attributes. len( ) == 1 &&
1091
+ attributes[ 0 ] == Attribute :: new_local( "attr" , "zzz;zzz" ) &&
1092
+ namespace. is_essentially_empty( )
1093
+ ) ;
1094
+ expect_event ! ( r, p, events:: EndElement { ref name } if * name == Name :: new_local( "a" ) ) ;
1095
+ expect_event ! ( r, p, events:: EndDocument ) ;
1096
+ }
1029
1097
}
0 commit comments