1 // Copyright 2014-2017 The html5ever Project Developers. See the
2 // COPYRIGHT file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 mod types;
11
12 use log::{debug, warn};
13 use mac::{matches, _tt_as_expr_hack, unwrap_or_return};
14 use markup5ever::{local_name, namespace_prefix, namespace_url, ns};
15 use std::borrow::Cow;
16 use std::borrow::Cow::Borrowed;
17 use std::collections::btree_map::Iter;
18 use std::collections::{BTreeMap, HashSet, VecDeque};
19 use std::fmt::{Debug, Error, Formatter};
20 use std::mem;
21 use std::result::Result;
22
23 pub use self::interface::{NextParserState, NodeOrText, Tracer, TreeSink};
24 use self::types::*;
25 use crate::interface::{self, create_element, AppendNode, Attribute, QualName};
26 use crate::interface::{AppendText, ExpandedName};
27 use crate::tokenizer::states::Quiescent;
28 use crate::tokenizer::{self, EndTag, StartTag, Tag, TokenSink};
29 use crate::tokenizer::{Doctype, EmptyTag, Pi, ShortTag};
30 use crate::{LocalName, Namespace, Prefix};
31
32 use crate::tendril::{StrTendril, Tendril};
33
34 static XML_URI: &'static str = "http://www.w3.org/XML/1998/namespace";
35 static XMLNS_URI: &'static str = "http://www.w3.org/2000/xmlns/";
36
37 type InsResult = Result<(), Cow<'static, str>>;
38
39 #[derive(Debug)]
40 struct NamespaceMapStack(Vec<NamespaceMap>);
41
42 impl NamespaceMapStack {
new() -> NamespaceMapStack43 fn new() -> NamespaceMapStack {
44 NamespaceMapStack({
45 let mut vec = Vec::new();
46 vec.push(NamespaceMap::default());
47 vec
48 })
49 }
50
push(&mut self, map: NamespaceMap)51 fn push(&mut self, map: NamespaceMap) {
52 self.0.push(map);
53 }
54
55 #[doc(hidden)]
pop(&mut self)56 pub fn pop(&mut self) {
57 self.0.pop();
58 }
59 }
60
61 #[doc(hidden)]
62 pub struct NamespaceMap {
63 // Map that maps prefixes to URI.
64 //
65 // Key denotes namespace prefix, and value denotes
66 // URI it maps to.
67 //
68 // If value of value is None, that means the namespace
69 // denoted by key has been undeclared.
70 scope: BTreeMap<Option<Prefix>, Option<Namespace>>,
71 }
72
73 impl Debug for NamespaceMap {
fmt(&self, f: &mut Formatter) -> Result<(), Error>74 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
75 write!(f, "\nNamespaceMap[")?;
76 for (key, value) in &self.scope {
77 write!(f, " {:?} : {:?}\n", key, value)?;
78 }
79 write!(f, "]")
80 }
81 }
82
83 impl NamespaceMap {
84 // Returns an empty namespace.
85 #[doc(hidden)]
empty() -> NamespaceMap86 pub fn empty() -> NamespaceMap {
87 NamespaceMap {
88 scope: BTreeMap::new(),
89 }
90 }
91
default() -> NamespaceMap92 fn default() -> NamespaceMap {
93 NamespaceMap {
94 scope: {
95 let mut map = BTreeMap::new();
96 map.insert(None, None);
97 map.insert(Some(namespace_prefix!("xml")), Some(ns!(xml)));
98 map.insert(Some(namespace_prefix!("xmlns")), Some(ns!(xmlns)));
99 map
100 },
101 }
102 }
103
104 #[doc(hidden)]
get(&self, prefix: &Option<Prefix>) -> Option<&Option<Namespace>>105 pub fn get(&self, prefix: &Option<Prefix>) -> Option<&Option<Namespace>> {
106 self.scope.get(prefix)
107 }
108
109 #[doc(hidden)]
get_scope_iter(&self) -> Iter<Option<Prefix>, Option<Namespace>>110 pub fn get_scope_iter(&self) -> Iter<Option<Prefix>, Option<Namespace>> {
111 self.scope.iter()
112 }
113
114 #[doc(hidden)]
insert(&mut self, name: &QualName)115 pub fn insert(&mut self, name: &QualName) {
116 let prefix = if let Some(ref p) = name.prefix {
117 Some(p.clone())
118 } else {
119 None
120 };
121 let namespace = Some(Namespace::from(&*name.ns));
122 self.scope.insert(prefix, namespace);
123 }
124
insert_ns(&mut self, attr: &Attribute) -> InsResult125 fn insert_ns(&mut self, attr: &Attribute) -> InsResult {
126 if &*attr.value == XMLNS_URI {
127 return Err(Borrowed("Can't declare XMLNS URI"));
128 };
129
130 let opt_uri = if attr.value.is_empty() {
131 None
132 } else {
133 Some(Namespace::from(&*attr.value))
134 };
135
136 let result = match (&attr.name.prefix, &*attr.name.local) {
137 (&Some(namespace_prefix!("xmlns")), "xml") => {
138 if &*attr.value != XML_URI {
139 Err(Borrowed("XML namespace can't be redeclared"))
140 } else {
141 Ok(())
142 }
143 },
144
145 (&Some(namespace_prefix!("xmlns")), "xmlns") => {
146 Err(Borrowed("XMLNS namespaces can't be changed"))
147 },
148
149 (&Some(namespace_prefix!("xmlns")), _) | (&None, "xmlns") => {
150 // We can have two cases of properly defined xmlns
151 // First with default namespace e.g.
152 //
153 // <a xmlns = "www.uri.org" />
154 let ns_prefix = if &*attr.name.local == "xmlns" {
155 None
156
157 // Second is with named namespace e.g.
158 //
159 // <a xmlns:a = "www.uri.org" />
160 } else {
161 Some(Prefix::from(&*attr.name.local))
162 };
163
164 if opt_uri.is_some() && self.scope.contains_key(&ns_prefix) {
165 Err(Borrowed("Namespace already defined"))
166 } else {
167 self.scope.insert(ns_prefix, opt_uri);
168 Ok(())
169 }
170 },
171
172 (_, _) => Err(Borrowed("Invalid namespace declaration.")),
173 };
174 result
175 }
176 }
177
178 /// Tree builder options, with an impl for Default.
179 #[derive(Copy, Clone)]
180 pub struct XmlTreeBuilderOpts {}
181
182 impl Default for XmlTreeBuilderOpts {
default() -> XmlTreeBuilderOpts183 fn default() -> XmlTreeBuilderOpts {
184 XmlTreeBuilderOpts {}
185 }
186 }
187
188 /// The XML tree builder.
189 pub struct XmlTreeBuilder<Handle, Sink> {
190 /// Configuration options for XmlTreeBuilder
191 _opts: XmlTreeBuilderOpts,
192
193 /// Consumer of tree modifications.
194 pub sink: Sink,
195
196 /// The document node, which is created by the sink.
197 doc_handle: Handle,
198
199 /// Next state change for the tokenizer, if any.
200 next_tokenizer_state: Option<tokenizer::states::XmlState>,
201
202 /// Stack of open elements, most recently added at end.
203 open_elems: Vec<Handle>,
204
205 /// Current element pointer.
206 curr_elem: Option<Handle>,
207
208 /// Stack of namespace identifiers and namespaces.
209 namespace_stack: NamespaceMapStack,
210
211 /// Current namespace identifier
212 current_namespace: NamespaceMap,
213
214 /// List of already present namespace local name attribute pairs.
215 present_attrs: HashSet<(Namespace, LocalName)>,
216
217 /// Current tree builder phase.
218 phase: XmlPhase,
219 }
220 impl<Handle, Sink> XmlTreeBuilder<Handle, Sink>
221 where
222 Handle: Clone,
223 Sink: TreeSink<Handle = Handle>,
224 {
225 /// Create a new tree builder which sends tree modifications to a particular `TreeSink`.
226 ///
227 /// The tree builder is also a `TokenSink`.
new(mut sink: Sink, opts: XmlTreeBuilderOpts) -> XmlTreeBuilder<Handle, Sink>228 pub fn new(mut sink: Sink, opts: XmlTreeBuilderOpts) -> XmlTreeBuilder<Handle, Sink> {
229 let doc_handle = sink.get_document();
230 XmlTreeBuilder {
231 _opts: opts,
232 sink: sink,
233 doc_handle: doc_handle,
234 next_tokenizer_state: None,
235 open_elems: vec![],
236 curr_elem: None,
237 namespace_stack: NamespaceMapStack::new(),
238 current_namespace: NamespaceMap::empty(),
239 present_attrs: HashSet::new(),
240 phase: StartPhase,
241 }
242 }
243
244 /// Call the `Tracer`'s `trace_handle` method on every `Handle` in the tree builder's
245 /// internal state. This is intended to support garbage-collected DOMs.
trace_handles(&self, tracer: &dyn Tracer<Handle = Handle>)246 pub fn trace_handles(&self, tracer: &dyn Tracer<Handle = Handle>) {
247 tracer.trace_handle(&self.doc_handle);
248 for e in self.open_elems.iter() {
249 tracer.trace_handle(&e);
250 }
251 self.curr_elem.as_ref().map(|h| tracer.trace_handle(&h));
252 }
253
254 // Debug helper
255 #[cfg(not(for_c))]
256 #[allow(dead_code)]
dump_state(&self, label: String)257 fn dump_state(&self, label: String) {
258 debug!("dump_state on {}", label);
259 debug!(" open_elems:");
260 for node in self.open_elems.iter() {
261 debug!(" {:?}", self.sink.elem_name(node));
262 }
263 debug!("");
264 }
265
266 #[cfg(for_c)]
debug_step(&self, _mode: XmlPhase, _token: &Token)267 fn debug_step(&self, _mode: XmlPhase, _token: &Token) {}
268
269 #[cfg(not(for_c))]
debug_step(&self, mode: XmlPhase, token: &Token)270 fn debug_step(&self, mode: XmlPhase, token: &Token) {
271 debug!(
272 "processing {:?} in insertion mode {:?}",
273 format!("{:?}", token),
274 mode
275 );
276 }
277
declare_ns(&mut self, attr: &mut Attribute)278 fn declare_ns(&mut self, attr: &mut Attribute) {
279 if let Err(msg) = self.current_namespace.insert_ns(&attr) {
280 self.sink.parse_error(msg);
281 } else {
282 attr.name.ns = ns!(xmlns);
283 }
284 }
285
find_uri(&self, prefix: &Option<Prefix>) -> Result<Option<Namespace>, Cow<'static, str>>286 fn find_uri(&self, prefix: &Option<Prefix>) -> Result<Option<Namespace>, Cow<'static, str>> {
287 let mut uri = Err(Borrowed("No appropriate namespace found"));
288
289 for ns in self
290 .namespace_stack
291 .0
292 .iter()
293 .chain(Some(&self.current_namespace))
294 .rev()
295 {
296 if let Some(el) = ns.get(prefix) {
297 uri = Ok(el.clone());
298 break;
299 }
300 }
301 uri
302 }
303
bind_qname(&mut self, name: &mut QualName)304 fn bind_qname(&mut self, name: &mut QualName) {
305 match self.find_uri(&name.prefix) {
306 Ok(uri) => {
307 let ns_uri = match uri {
308 Some(e) => e,
309 None => ns!(),
310 };
311 name.ns = ns_uri;
312 },
313 Err(msg) => {
314 self.sink.parse_error(msg);
315 },
316 }
317 }
318
319 // This method takes in name qualified name and binds it to the
320 // existing namespace context.
321 //
322 // Returns false if the attribute is a duplicate, returns true otherwise.
bind_attr_qname(&mut self, name: &mut QualName) -> bool323 fn bind_attr_qname(&mut self, name: &mut QualName) -> bool {
324 // Attributes don't have default namespace
325 let mut not_duplicate = true;
326
327 if name.prefix.is_some() {
328 self.bind_qname(name);
329 not_duplicate = self.check_duplicate_attr(name);
330 }
331 not_duplicate
332 }
333
check_duplicate_attr(&mut self, name: &QualName) -> bool334 fn check_duplicate_attr(&mut self, name: &QualName) -> bool {
335 let pair = (name.ns.clone(), name.local.clone());
336
337 if self.present_attrs.contains(&pair) {
338 return false;
339 }
340 self.present_attrs.insert(pair);
341 true
342 }
343
process_namespaces(&mut self, tag: &mut Tag)344 fn process_namespaces(&mut self, tag: &mut Tag) {
345 let mut new_attr = vec![];
346 // First we extract all namespace declarations
347 for mut attr in tag.attrs.iter_mut().filter(|attr| {
348 attr.name.prefix == Some(namespace_prefix!("xmlns")) ||
349 attr.name.local == local_name!("xmlns")
350 }) {
351 self.declare_ns(&mut attr);
352 }
353
354 // Then we bind those namespace declarations to attributes
355 for attr in tag.attrs.iter_mut().filter(|attr| {
356 attr.name.prefix != Some(namespace_prefix!("xmlns")) &&
357 attr.name.local != local_name!("xmlns")
358 }) {
359 if self.bind_attr_qname(&mut attr.name) {
360 new_attr.push(attr.clone());
361 }
362 }
363 mem::replace(&mut tag.attrs, new_attr);
364 // Then we bind the tags namespace.
365 self.bind_qname(&mut tag.name);
366
367 // Finally, we dump current namespace if its unneeded.
368 let x = mem::replace(&mut self.current_namespace, NamespaceMap::empty());
369
370 // Only start tag doesn't dump current namespace. However, <script /> is treated
371 // differently than every other empty tag, so it needs to retain the current
372 // namespace as well.
373 if tag.kind == StartTag || (tag.kind == EmptyTag && tag.name.local == local_name!("script"))
374 {
375 self.namespace_stack.push(x);
376 }
377 }
378
process_to_completion(&mut self, mut token: Token)379 fn process_to_completion(&mut self, mut token: Token) {
380 // Queue of additional tokens yet to be processed.
381 // This stays empty in the common case where we don't split whitespace.
382 let mut more_tokens = VecDeque::new();
383
384 loop {
385 let phase = self.phase;
386 match self.step(phase, token) {
387 Done => {
388 token = unwrap_or_return!(more_tokens.pop_front(), ());
389 },
390 Reprocess(m, t) => {
391 self.phase = m;
392 token = t;
393 },
394 }
395 }
396 }
397 }
398
399 impl<Handle, Sink> TokenSink for XmlTreeBuilder<Handle, Sink>
400 where
401 Handle: Clone,
402 Sink: TreeSink<Handle = Handle>,
403 {
process_token(&mut self, token: tokenizer::Token)404 fn process_token(&mut self, token: tokenizer::Token) {
405 // Handle `ParseError` and `DoctypeToken`; convert everything else to the local `Token` type.
406 let token = match token {
407 tokenizer::ParseError(e) => {
408 self.sink.parse_error(e);
409 return;
410 },
411
412 tokenizer::DoctypeToken(d) => DoctypeToken(d),
413 tokenizer::PIToken(x) => PIToken(x),
414 tokenizer::TagToken(x) => TagToken(x),
415 tokenizer::CommentToken(x) => CommentToken(x),
416 tokenizer::NullCharacterToken => NullCharacterToken,
417 tokenizer::EOFToken => EOFToken,
418 tokenizer::CharacterTokens(x) => CharacterTokens(x),
419 };
420
421 self.process_to_completion(token);
422 }
423
end(&mut self)424 fn end(&mut self) {
425 for node in self.open_elems.drain(..).rev() {
426 self.sink.pop(&node);
427 }
428 }
429
query_state_change(&mut self) -> Option<tokenizer::states::XmlState>430 fn query_state_change(&mut self) -> Option<tokenizer::states::XmlState> {
431 self.next_tokenizer_state.take()
432 }
433 }
434
current_node<Handle>(open_elems: &[Handle]) -> &Handle435 fn current_node<Handle>(open_elems: &[Handle]) -> &Handle {
436 open_elems.last().expect("no current element")
437 }
438
439 #[doc(hidden)]
440 impl<Handle, Sink> XmlTreeBuilder<Handle, Sink>
441 where
442 Handle: Clone,
443 Sink: TreeSink<Handle = Handle>,
444 {
current_node(&self) -> &Handle445 fn current_node(&self) -> &Handle {
446 self.open_elems.last().expect("no current element")
447 }
448
insert_appropriately(&mut self, child: NodeOrText<Handle>)449 fn insert_appropriately(&mut self, child: NodeOrText<Handle>) {
450 let target = current_node(&self.open_elems);
451 self.sink.append(target, child);
452 }
453
insert_tag(&mut self, tag: Tag) -> XmlProcessResult454 fn insert_tag(&mut self, tag: Tag) -> XmlProcessResult {
455 let child = create_element(&mut self.sink, tag.name, tag.attrs);
456 self.insert_appropriately(AppendNode(child.clone()));
457 self.add_to_open_elems(child)
458 }
459
append_tag(&mut self, tag: Tag) -> XmlProcessResult460 fn append_tag(&mut self, tag: Tag) -> XmlProcessResult {
461 let child = create_element(&mut self.sink, tag.name, tag.attrs);
462 self.insert_appropriately(AppendNode(child.clone()));
463 self.sink.pop(&child);
464 Done
465 }
466
append_tag_to_doc(&mut self, tag: Tag) -> Handle467 fn append_tag_to_doc(&mut self, tag: Tag) -> Handle {
468 let child = create_element(&mut self.sink, tag.name, tag.attrs);
469
470 self.sink
471 .append(&self.doc_handle, AppendNode(child.clone()));
472 child
473 }
474
add_to_open_elems(&mut self, el: Handle) -> XmlProcessResult475 fn add_to_open_elems(&mut self, el: Handle) -> XmlProcessResult {
476 self.open_elems.push(el);
477
478 Done
479 }
480
append_comment_to_doc(&mut self, text: StrTendril) -> XmlProcessResult481 fn append_comment_to_doc(&mut self, text: StrTendril) -> XmlProcessResult {
482 let comment = self.sink.create_comment(text);
483 self.sink.append(&self.doc_handle, AppendNode(comment));
484 Done
485 }
486
append_comment_to_tag(&mut self, text: StrTendril) -> XmlProcessResult487 fn append_comment_to_tag(&mut self, text: StrTendril) -> XmlProcessResult {
488 let target = current_node(&self.open_elems);
489 let comment = self.sink.create_comment(text);
490 self.sink.append(target, AppendNode(comment));
491 Done
492 }
493
append_doctype_to_doc(&mut self, doctype: Doctype) -> XmlProcessResult494 fn append_doctype_to_doc(&mut self, doctype: Doctype) -> XmlProcessResult {
495 fn get_tendril(opt: Option<StrTendril>) -> StrTendril {
496 match opt {
497 Some(expr) => expr,
498 None => Tendril::new(),
499 }
500 };
501 self.sink.append_doctype_to_document(
502 get_tendril(doctype.name),
503 get_tendril(doctype.public_id),
504 get_tendril(doctype.system_id),
505 );
506 Done
507 }
508
append_pi_to_doc(&mut self, pi: Pi) -> XmlProcessResult509 fn append_pi_to_doc(&mut self, pi: Pi) -> XmlProcessResult {
510 let pi = self.sink.create_pi(pi.target, pi.data);
511 self.sink.append(&self.doc_handle, AppendNode(pi));
512 Done
513 }
514
append_pi_to_tag(&mut self, pi: Pi) -> XmlProcessResult515 fn append_pi_to_tag(&mut self, pi: Pi) -> XmlProcessResult {
516 let target = current_node(&self.open_elems);
517 let pi = self.sink.create_pi(pi.target, pi.data);
518 self.sink.append(target, AppendNode(pi));
519 Done
520 }
521
append_text(&mut self, chars: StrTendril) -> XmlProcessResult522 fn append_text(&mut self, chars: StrTendril) -> XmlProcessResult {
523 self.insert_appropriately(AppendText(chars));
524 Done
525 }
526
tag_in_open_elems(&self, tag: &Tag) -> bool527 fn tag_in_open_elems(&self, tag: &Tag) -> bool {
528 self.open_elems
529 .iter()
530 .any(|a| self.sink.elem_name(a) == tag.name.expanded())
531 }
532
533 // Pop elements until an element from the set has been popped. Returns the
534 // number of elements popped.
pop_until<P>(&mut self, pred: P) where P: Fn(ExpandedName) -> bool,535 fn pop_until<P>(&mut self, pred: P)
536 where
537 P: Fn(ExpandedName) -> bool,
538 {
539 loop {
540 if self.current_node_in(|x| pred(x)) {
541 break;
542 }
543 self.pop();
544 }
545 }
546
current_node_in<TagSet>(&self, set: TagSet) -> bool where TagSet: Fn(ExpandedName) -> bool,547 fn current_node_in<TagSet>(&self, set: TagSet) -> bool
548 where
549 TagSet: Fn(ExpandedName) -> bool,
550 {
551 // FIXME: take namespace into consideration:
552 set(self.sink.elem_name(self.current_node()))
553 }
554
close_tag(&mut self, tag: Tag) -> XmlProcessResult555 fn close_tag(&mut self, tag: Tag) -> XmlProcessResult {
556 debug!(
557 "Close tag: current_node.name {:?} \n Current tag {:?}",
558 self.sink.elem_name(self.current_node()),
559 &tag.name
560 );
561
562 if *self.sink.elem_name(self.current_node()).local != tag.name.local {
563 self.sink
564 .parse_error(Borrowed("Current node doesn't match tag"));
565 }
566
567 let is_closed = self.tag_in_open_elems(&tag);
568
569 if is_closed {
570 self.pop_until(|p| p == tag.name.expanded());
571 self.pop();
572 }
573
574 Done
575 }
576
no_open_elems(&self) -> bool577 fn no_open_elems(&self) -> bool {
578 self.open_elems.is_empty()
579 }
580
pop(&mut self) -> Handle581 fn pop(&mut self) -> Handle {
582 self.namespace_stack.pop();
583 let node = self.open_elems.pop().expect("no current element");
584 self.sink.pop(&node);
585 node
586 }
587
stop_parsing(&mut self) -> XmlProcessResult588 fn stop_parsing(&mut self) -> XmlProcessResult {
589 warn!("stop_parsing for XML5 not implemented, full speed ahead!");
590 Done
591 }
592
complete_script(&mut self)593 fn complete_script(&mut self) {
594 let current = current_node(&self.open_elems);
595 if self.sink.complete_script(current) == NextParserState::Suspend {
596 self.next_tokenizer_state = Some(Quiescent);
597 }
598 }
599 }
600
any_not_whitespace(x: &StrTendril) -> bool601 fn any_not_whitespace(x: &StrTendril) -> bool {
602 !x.bytes()
603 .all(|b| matches!(b, b'\t' | b'\r' | b'\n' | b'\x0C' | b' '))
604 }
605
606 #[doc(hidden)]
607 impl<Handle, Sink> XmlTreeBuilder<Handle, Sink>
608 where
609 Handle: Clone,
610 Sink: TreeSink<Handle = Handle>,
611 {
step(&mut self, mode: XmlPhase, token: Token) -> XmlProcessResult612 fn step(&mut self, mode: XmlPhase, token: Token) -> XmlProcessResult {
613 self.debug_step(mode, &token);
614
615 match mode {
616 StartPhase => match token {
617 TagToken(Tag {
618 kind: StartTag,
619 name,
620 attrs,
621 }) => {
622 let tag = {
623 let mut tag = Tag {
624 kind: StartTag,
625 name: name,
626 attrs: attrs,
627 };
628 self.process_namespaces(&mut tag);
629 tag
630 };
631 self.phase = MainPhase;
632 let handle = self.append_tag_to_doc(tag);
633 self.add_to_open_elems(handle)
634 },
635 TagToken(Tag {
636 kind: EmptyTag,
637 name,
638 attrs,
639 }) => {
640 let tag = {
641 let mut tag = Tag {
642 kind: EmptyTag,
643 name: name,
644 attrs: attrs,
645 };
646 self.process_namespaces(&mut tag);
647 tag
648 };
649 self.phase = EndPhase;
650 let handle = self.append_tag_to_doc(tag);
651 self.sink.pop(&handle);
652 Done
653 },
654 CommentToken(comment) => self.append_comment_to_doc(comment),
655 PIToken(pi) => self.append_pi_to_doc(pi),
656 CharacterTokens(ref chars) if !any_not_whitespace(chars) => Done,
657 EOFToken => {
658 self.sink
659 .parse_error(Borrowed("Unexpected EOF in start phase"));
660 Reprocess(EndPhase, EOFToken)
661 },
662 DoctypeToken(d) => {
663 self.append_doctype_to_doc(d);
664 Done
665 },
666 _ => {
667 self.sink
668 .parse_error(Borrowed("Unexpected element in start phase"));
669 Done
670 },
671 },
672 MainPhase => match token {
673 CharacterTokens(chs) => self.append_text(chs),
674 TagToken(Tag {
675 kind: StartTag,
676 name,
677 attrs,
678 }) => {
679 let tag = {
680 let mut tag = Tag {
681 kind: StartTag,
682 name: name,
683 attrs: attrs,
684 };
685 self.process_namespaces(&mut tag);
686 tag
687 };
688 self.insert_tag(tag)
689 },
690 TagToken(Tag {
691 kind: EmptyTag,
692 name,
693 attrs,
694 }) => {
695 let tag = {
696 let mut tag = Tag {
697 kind: EmptyTag,
698 name: name,
699 attrs: attrs,
700 };
701 self.process_namespaces(&mut tag);
702 tag
703 };
704 if tag.name.local == local_name!("script") {
705 self.insert_tag(tag.clone());
706 self.complete_script();
707 self.close_tag(tag)
708 } else {
709 self.append_tag(tag)
710 }
711 },
712 TagToken(Tag {
713 kind: EndTag,
714 name,
715 attrs,
716 }) => {
717 let tag = {
718 let mut tag = Tag {
719 kind: EndTag,
720 name: name,
721 attrs: attrs,
722 };
723 self.process_namespaces(&mut tag);
724 tag
725 };
726 if tag.name.local == local_name!("script") {
727 self.complete_script();
728 }
729 let retval = self.close_tag(tag);
730 if self.no_open_elems() {
731 self.phase = EndPhase;
732 }
733 retval
734 },
735 TagToken(Tag { kind: ShortTag, .. }) => {
736 self.pop();
737 if self.no_open_elems() {
738 self.phase = EndPhase;
739 }
740 Done
741 },
742 CommentToken(comment) => self.append_comment_to_tag(comment),
743 PIToken(pi) => self.append_pi_to_tag(pi),
744 EOFToken | NullCharacterToken => Reprocess(EndPhase, EOFToken),
745 DoctypeToken(_) => {
746 self.sink
747 .parse_error(Borrowed("Unexpected element in main phase"));
748 Done
749 },
750 },
751 EndPhase => match token {
752 CommentToken(comment) => self.append_comment_to_doc(comment),
753 PIToken(pi) => self.append_pi_to_doc(pi),
754 CharacterTokens(ref chars) if !any_not_whitespace(chars) => Done,
755 EOFToken => self.stop_parsing(),
756 _ => {
757 self.sink
758 .parse_error(Borrowed("Unexpected element in end phase"));
759 Done
760 },
761 },
762 }
763 }
764 }
765