1use std::collections::VecDeque;
7
8pub mod generate;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum EventKind {
12 StartOfDocument,
13 VersionInformation,
14 EncodingDeclaration,
15 StandaloneDeclaration,
16 DocumentTypeDeclaration,
17 Comment,
18 ProcessingInstructionTarget,
19 ProcessingInstructionData,
20 StartOfElement,
21 NamespaceDeclaration,
22 AttributeName,
23 AttributeCharacters,
24 AttributeNationalCharacter,
25 ContentCharacters,
26 ContentNationalCharacter,
27 StartOfCdataSection,
28 EndOfCdataSection,
29 EndOfElement,
30 UnresolvedReference,
31 EndOfInput,
32 EndOfDocument,
33 Exception,
34}
35
36impl EventKind {
37 pub fn name(self) -> &'static str {
39 match self {
40 Self::StartOfDocument => "START-OF-DOCUMENT",
41 Self::VersionInformation => "VERSION-INFORMATION",
42 Self::EncodingDeclaration => "ENCODING-DECLARATION",
43 Self::StandaloneDeclaration => "STANDALONE-DECLARATION",
44 Self::DocumentTypeDeclaration => "DOCUMENT-TYPE-DECLARATION",
45 Self::Comment => "COMMENT",
46 Self::ProcessingInstructionTarget => "PROCESSING-INSTRUCTION-TARGET",
47 Self::ProcessingInstructionData => "PROCESSING-INSTRUCTION-DATA",
48 Self::StartOfElement => "START-OF-ELEMENT",
49 Self::NamespaceDeclaration => "NAMESPACE-DECLARATION",
50 Self::AttributeName => "ATTRIBUTE-NAME",
51 Self::AttributeCharacters => "ATTRIBUTE-CHARACTERS",
52 Self::AttributeNationalCharacter => "ATTRIBUTE-NATIONAL-CHARACTER",
53 Self::ContentCharacters => "CONTENT-CHARACTERS",
54 Self::ContentNationalCharacter => "CONTENT-NATIONAL-CHARACTER",
55 Self::StartOfCdataSection => "START-OF-CDATA-SECTION",
56 Self::EndOfCdataSection => "END-OF-CDATA-SECTION",
57 Self::EndOfElement => "END-OF-ELEMENT",
58 Self::UnresolvedReference => "UNRESOLVED-REFERENCE",
59 Self::EndOfInput => "END-OF-INPUT",
60 Self::EndOfDocument => "END-OF-DOCUMENT",
61 Self::Exception => "EXCEPTION",
62 }
63 }
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
67pub struct Event {
68 pub kind: EventKind,
69 pub text: String,
71 pub namespace: String,
73 pub prefix: String,
75 pub information: i32,
78 pub code: i32,
81}
82
83impl Event {
84 fn new(kind: EventKind, text: impl Into<String>) -> Self {
85 Self { kind, text: text.into(), namespace: String::new(), prefix: String::new(), information: 0, code: 0 }
86 }
87
88 fn undeclared(why: Why, qualified: &str) -> Self {
91 Self { code: why.code(), ..Self::new(EventKind::Exception, qualified) }
92 }
93
94 fn characters(kind: EventKind, text: String, complete: bool) -> Self {
95 Self { information: if complete { 1 } else { 2 }, ..Self::new(kind, text) }
96 }
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100pub enum Why {
101 UnexpectedEnd,
102 InvalidCharacter,
103 MismatchedEndTag,
104 DuplicateAttribute,
105 UndeclaredElementPrefix,
106 UndeclaredAttributePrefix,
107 UndeclaredEntity,
108 BadReference,
109 ContentAfterRoot,
110 SecondRoot,
111 NoRoot,
112 BadDeclaration,
113 BadComment,
114 LessThanInAttribute,
115}
116
117impl Why {
118 pub fn code(self) -> i32 {
123 let not_well_formed = |reason: i32| 0x000C_0000 | reason;
124 match self {
125 Why::UnexpectedEnd => not_well_formed(0x2004),
126 Why::NoRoot => not_well_formed(0x2019),
127 Why::DuplicateAttribute => not_well_formed(0x3000),
128 Why::BadComment => not_well_formed(0x3008),
129 Why::LessThanInAttribute => not_well_formed(0x3022),
130 Why::BadReference => not_well_formed(0x3028),
131 Why::MismatchedEndTag => not_well_formed(0x3035),
132 Why::BadDeclaration => not_well_formed(0x3060),
133 Why::UndeclaredEntity => not_well_formed(0x3061),
134 Why::InvalidCharacter | Why::ContentAfterRoot => not_well_formed(0x3062),
135 Why::SecondRoot => not_well_formed(0x3065),
136 Why::UndeclaredAttributePrefix => 0x0004_0800,
137 Why::UndeclaredElementPrefix => 0x0004_0801,
138 }
139 }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145pub struct Malformed {
146 pub offset: usize,
147 pub why: Why,
148}
149
150#[derive(Clone, Debug, PartialEq, Eq)]
151pub enum Step {
152 Event(Event),
153 EndOfInput,
155 Error(Malformed),
156 Done,
158}
159
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161enum Place {
162 Start,
163 Prolog,
164 Content,
165 Epilogue,
166 Finished,
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
171enum Open {
172 Comment,
173 Instruction(String, bool),
176 Cdata,
177}
178
179struct Element {
180 qualified: String,
181 local: String,
182 prefix: String,
183 namespace: String,
184 bindings: usize,
185}
186
187pub const XML_NAMESPACE: &str = "http://www.w3.org/XML/1998/namespace";
188
189pub struct Scanner<'r> {
190 buf: Vec<char>,
191 at: usize,
192 consumed: usize,
193 place: Place,
194 open: Option<Open>,
195 elements: Vec<Element>,
196 bindings: Vec<(String, String)>,
198 pending: VecDeque<Event>,
199 representable: &'r dyn Fn(char) -> bool,
200 last_segment: bool,
201 doctype: bool,
202 standalone_no: bool,
203}
204
205type Scan<T> = Result<T, Why>;
206
207const MORE: Why = Why::UnexpectedEnd;
209
210fn is_space(c: char) -> bool {
211 matches!(c, ' ' | '\t' | '\n' | '\r')
212}
213
214fn name_start(c: char) -> bool {
215 c.is_ascii_alphabetic() || c == '_' || c == ':' || c as u32 >= 0xC0
216}
217
218fn name_char(c: char) -> bool {
219 name_start(c) || c.is_ascii_digit() || c == '-' || c == '.' || c == '\u{B7}'
220}
221
222fn xml_char(c: u32) -> bool {
223 matches!(c, 0x9 | 0xA | 0xD | 0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF)
224}
225
226fn split(qualified: &str) -> (String, String) {
227 match qualified.split_once(':') {
228 Some((prefix, local)) => (prefix.to_owned(), local.to_owned()),
229 None => (String::new(), qualified.to_owned()),
230 }
231}
232
233impl<'r> Scanner<'r> {
234 pub fn new(segment: &str, representable: &'r dyn Fn(char) -> bool) -> Self {
237 Self {
238 buf: segment.chars().collect(),
239 at: 0,
240 consumed: 0,
241 place: Place::Start,
242 open: None,
243 elements: Vec::new(),
244 bindings: vec![("xml".into(), XML_NAMESPACE.into())],
245 pending: VecDeque::new(),
246 representable,
247 last_segment: false,
248 doctype: false,
249 standalone_no: false,
250 }
251 }
252
253 pub fn feed(&mut self, segment: &str) {
255 self.consumed += self.at;
256 self.buf.drain(..self.at);
257 self.at = 0;
258 self.buf.extend(segment.chars());
259 }
260
261 pub fn finish(&mut self) {
263 self.last_segment = true;
264 }
265
266 fn peek(&self, ahead: usize) -> Option<char> {
267 self.buf.get(self.at + ahead).copied()
268 }
269
270 fn starts(&self, s: &str) -> bool {
271 let chars: Vec<char> = s.chars().collect();
272 self.buf[self.at..].starts_with(&chars)
273 }
274
275 fn could_start(&self, s: &str) -> bool {
277 let rest = &self.buf[self.at..];
278 rest.len() < s.chars().count() && s.chars().zip(rest).all(|(a, &b)| a == b)
279 }
280
281 fn find(&self, from: usize, s: &str) -> Option<usize> {
282 let chars: Vec<char> = s.chars().collect();
283 (from..=self.buf.len().saturating_sub(chars.len())).find(|&i| self.buf[i..].starts_with(&chars))
284 }
285
286 fn fail(&self, at: usize, why: Why) -> Step {
287 Step::Error(Malformed { offset: self.consumed + at, why })
288 }
289
290 pub fn advance(&mut self) -> Step {
291 if let Some(e) = self.pending.pop_front() {
292 return Step::Event(e);
293 }
294 if self.place == Place::Start {
295 self.place = Place::Prolog;
296 return Step::Event(Event::new(EventKind::StartOfDocument, ""));
297 }
298 if self.place == Place::Finished {
299 return Step::Done;
300 }
301 let before = self.at;
302 match self.step() {
303 Ok(()) => match self.pending.pop_front() {
304 Some(e) => Step::Event(e),
305 None if self.place == Place::Finished => Step::Event(Event::new(EventKind::EndOfDocument, "")),
306 None => self.advance(),
307 },
308 Err(MORE) => {
309 self.at = before;
310 self.at_end()
311 }
312 Err(why) => self.fail(self.at, why),
313 }
314 }
315
316 fn at_end(&mut self) -> Step {
318 if self.place == Place::Epilogue && self.buf[self.at..].iter().all(|&c| is_space(c)) {
319 self.at = self.buf.len();
320 self.place = Place::Finished;
321 return Step::Event(Event::new(EventKind::EndOfDocument, ""));
322 }
323 if !self.last_segment {
324 return Step::EndOfInput;
325 }
326 let why = if self.place == Place::Prolog && self.open.is_none() && self.buf[self.at..].iter().all(|&c| is_space(c)) { Why::NoRoot } else { Why::UnexpectedEnd };
327 Step::Error(Malformed { offset: self.consumed + self.buf.len(), why })
328 }
329
330 fn step(&mut self) -> Scan<()> {
332 if let Some(open) = self.open.clone() {
333 return self.continue_open(open);
334 }
335 while self.place != Place::Content && self.peek(0).is_some_and(is_space) {
336 self.at += 1;
337 }
338 let Some(c) = self.peek(0) else { return Err(MORE) };
339 if c != '<' {
340 if self.place == Place::Content {
341 return self.content();
342 }
343 return Err(if self.place == Place::Epilogue { Why::ContentAfterRoot } else { Why::InvalidCharacter });
344 }
345 if self.starts("<?xml") && self.peek(5).is_some_and(|c| is_space(c) || c == '?') && self.consumed == 0 && self.at == 0 {
346 return self.declaration();
347 }
348 if self.could_start("<!--") || self.could_start("<![CDATA[") || self.could_start("<!DOCTYPE") || self.buf.len() - self.at < 2 {
349 return Err(MORE);
350 }
351 if self.starts("<!--") {
352 self.at += 4;
353 self.open = Some(Open::Comment);
354 return Ok(());
355 }
356 if self.starts("<![CDATA[") {
357 if self.place != Place::Content {
358 return Err(Why::InvalidCharacter);
359 }
360 if self.peek(9).is_none() {
361 return Err(MORE);
362 }
363 self.at += 9;
364 self.pending.push_back(Event::new(EventKind::StartOfCdataSection, ""));
365 self.open = Some(Open::Cdata);
366 return Ok(());
367 }
368 if self.starts("<!DOCTYPE") {
369 return self.doctype();
370 }
371 if self.starts("<?") {
372 return self.instruction();
373 }
374 if self.starts("</") {
375 return self.end_tag();
376 }
377 if self.place == Place::Epilogue {
378 return Err(Why::SecondRoot);
379 }
380 self.start_tag()
381 }
382
383 fn name(&mut self) -> Scan<String> {
384 let start = self.at;
385 match self.peek(0) {
386 None => return Err(MORE),
387 Some(c) if !name_start(c) => return Err(Why::InvalidCharacter),
388 _ => {}
389 }
390 while self.peek(0).is_some_and(name_char) {
391 self.at += 1;
392 }
393 if self.at == self.buf.len() {
394 return Err(MORE);
395 }
396 let name: String = self.buf[start..self.at].iter().collect();
397 if name.matches(':').count() > 1 || name.starts_with(':') || name.ends_with(':') {
398 self.at = start;
399 return Err(Why::InvalidCharacter);
400 }
401 Ok(name)
402 }
403
404 fn spaces(&mut self) -> bool {
405 let start = self.at;
406 while self.peek(0).is_some_and(is_space) {
407 self.at += 1;
408 }
409 self.at > start
410 }
411
412 fn expect(&mut self, c: char) -> Scan<()> {
413 match self.peek(0) {
414 None => Err(MORE),
415 Some(d) if d == c => {
416 self.at += 1;
417 Ok(())
418 }
419 Some(_) => Err(Why::InvalidCharacter),
420 }
421 }
422
423 fn reference(&mut self) -> Scan<Result<char, String>> {
426 let end = self.find(self.at, ";").ok_or(MORE)?;
427 let body: String = self.buf[self.at + 1..end].iter().collect();
428 let value = if let Some(hex) = body.strip_prefix("#x") {
429 u32::from_str_radix(hex, 16).ok().filter(|&v| xml_char(v) && !hex.is_empty()).and_then(char::from_u32).map(Ok).ok_or(Why::BadReference)?
430 } else if let Some(dec) = body.strip_prefix('#') {
431 dec.parse::<u32>().ok().filter(|&v| xml_char(v)).and_then(char::from_u32).map(Ok).ok_or(Why::BadReference)?
432 } else {
433 match body.as_str() {
434 "lt" => Ok('<'),
435 "gt" => Ok('>'),
436 "amp" => Ok('&'),
437 "apos" => Ok('\''),
438 "quot" => Ok('"'),
439 name if !name.is_empty() && name.chars().next().is_some_and(name_start) && name.chars().all(name_char) => Err(name.to_owned()),
440 _ => return Err(Why::BadReference),
441 }
442 };
443 self.at = end + 1;
444 Ok(value)
445 }
446
447 fn declaration(&mut self) -> Scan<()> {
448 let end = self.find(self.at, "?>").ok_or(MORE)?;
449 self.at += 5;
450 let mut seen = Vec::new();
451 loop {
452 self.spaces();
453 if self.at >= end {
454 break;
455 }
456 let name = self.name().map_err(|_| Why::BadDeclaration)?;
457 self.spaces();
458 self.expect('=').map_err(|_| Why::BadDeclaration)?;
459 self.spaces();
460 let quote = self.peek(0).filter(|&q| q == '"' || q == '\'').ok_or(Why::BadDeclaration)?;
461 let close = self.find(self.at + 1, "e.to_string()).filter(|&c| c < end).ok_or(Why::BadDeclaration)?;
462 let value: String = self.buf[self.at + 1..close].iter().collect();
463 self.at = close + 1;
464 let kind = match name.as_str() {
465 "version" if seen.is_empty() => EventKind::VersionInformation,
466 "encoding" if seen == [EventKind::VersionInformation] => EventKind::EncodingDeclaration,
467 "standalone" if seen.first() == Some(&EventKind::VersionInformation) && !seen.contains(&EventKind::StandaloneDeclaration) && (value == "yes" || value == "no") => {
468 self.standalone_no = value == "no";
469 EventKind::StandaloneDeclaration
470 }
471 _ => return Err(Why::BadDeclaration),
472 };
473 seen.push(kind);
474 self.pending.push_back(Event::new(kind, value));
475 }
476 if seen.first() != Some(&EventKind::VersionInformation) {
477 return Err(Why::BadDeclaration);
478 }
479 self.at = end + 2;
480 Ok(())
481 }
482
483 fn doctype(&mut self) -> Scan<()> {
484 if self.place != Place::Prolog || self.doctype {
485 return Err(Why::InvalidCharacter);
486 }
487 let mut depth = 0i32;
488 let mut quote = None;
489 let mut i = self.at + 9;
490 let end = loop {
491 let c = *self.buf.get(i).ok_or(MORE)?;
492 match (quote, c) {
493 (Some(q), c) if c == q => quote = None,
494 (Some(_), _) => {}
495 (None, '"' | '\'') => quote = Some(c),
496 (None, '[') => depth += 1,
497 (None, ']') => depth -= 1,
498 (None, '>') if depth == 0 => break i,
499 _ => {}
500 }
501 i += 1;
502 };
503 self.at += 9;
504 if !self.spaces() {
505 return Err(Why::InvalidCharacter);
506 }
507 let root = self.name()?;
508 self.at = end + 1;
509 self.doctype = true;
510 self.pending.push_back(Event::new(EventKind::DocumentTypeDeclaration, root));
511 Ok(())
512 }
513
514 fn instruction(&mut self) -> Scan<()> {
515 self.at += 2;
516 let start = self.at;
517 let target = self.name()?;
518 if target.eq_ignore_ascii_case("xml") {
519 self.at = start;
520 return Err(Why::BadDeclaration);
521 }
522 match self.peek(0) {
523 None => return Err(MORE),
524 Some('?') if self.peek(1).is_none() => return Err(MORE),
525 Some('?') if self.peek(1) == Some('>') => {}
526 Some(c) if is_space(c) => {}
527 Some(_) => return Err(Why::InvalidCharacter),
528 }
529 self.spaces();
530 self.open = Some(Open::Instruction(target.clone(), false));
531 self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target));
532 Ok(())
533 }
534
535 fn open_text(&mut self, terminator: &str) -> (String, bool) {
538 match self.find(self.at, terminator) {
539 Some(end) => {
540 let text: String = self.buf[self.at..end].iter().collect();
541 self.at = end + terminator.chars().count();
542 (text, true)
543 }
544 None => {
545 let rest = &self.buf[self.at..];
546 let keep = (1..terminator.chars().count()).rev().find(|&n| n <= rest.len() && terminator.chars().take(n).eq(rest[rest.len() - n..].iter().copied())).unwrap_or(0);
547 let end = self.buf.len() - keep;
548 let text: String = self.buf[self.at..end].iter().collect();
549 self.at = end;
550 (text, false)
551 }
552 }
553 }
554
555 fn continue_open(&mut self, open: Open) -> Scan<()> {
556 let (terminator, kind) = match &open {
557 Open::Comment => ("-->", EventKind::Comment),
558 Open::Instruction(..) => ("?>", EventKind::ProcessingInstructionData),
559 Open::Cdata => ("]]>", EventKind::ContentCharacters),
560 };
561 let (text, complete) = self.open_text(terminator);
562 if open == Open::Comment && text.contains("--") {
563 return Err(Why::BadComment);
564 }
565 if !complete && text.is_empty() {
566 return Err(MORE);
567 }
568 if let Open::Instruction(target, true) = &open {
569 self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target.clone()));
570 }
571 if !text.is_empty() || kind == EventKind::Comment || kind == EventKind::ProcessingInstructionData {
572 let mut event = Event::new(kind, text);
573 if kind == EventKind::ContentCharacters {
574 event.information = if complete { 1 } else { 2 };
575 }
576 self.pending.push_back(event);
577 }
578 if complete {
579 self.open = None;
580 if open == Open::Cdata {
581 self.pending.push_back(Event::new(EventKind::EndOfCdataSection, ""));
582 }
583 } else if let Open::Instruction(target, _) = open {
584 self.open = Some(Open::Instruction(target, true));
585 }
586 Ok(())
587 }
588
589 fn content(&mut self) -> Scan<()> {
591 let mut run = String::new();
592 while let Some(c) = self.peek(0) {
593 match c {
594 '<' => break,
595 '&' => {
596 let mark = self.at;
597 match self.reference() {
598 Ok(Ok(ch)) if (self.representable)(ch) || ch.is_ascii() => run.push(ch),
599 Ok(Ok(ch)) => {
600 if !run.is_empty() {
601 self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
602 }
603 self.pending.push_back(Event::new(EventKind::ContentNationalCharacter, ch.to_string()));
604 }
605 Ok(Err(name)) if self.doctype && self.standalone_no => {
606 if !run.is_empty() {
607 self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
608 }
609 self.pending.push_back(Event::new(EventKind::UnresolvedReference, name));
610 }
611 Ok(Err(_)) => {
612 self.at = mark;
613 return Err(Why::UndeclaredEntity);
614 }
615 Err(MORE) => {
616 self.at = mark;
617 break;
618 }
619 Err(why) => {
620 self.at = mark;
621 return Err(why);
622 }
623 }
624 }
625 '\r' => {
626 run.push('\n');
627 self.at += 1;
628 if self.peek(0) == Some('\n') {
629 self.at += 1;
630 }
631 }
632 c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
633 c => {
634 run.push(c);
635 self.at += 1;
636 }
637 }
638 }
639 let complete = self.peek(0) == Some('<');
640 if run.is_empty() && self.pending.is_empty() {
641 return Err(MORE);
642 }
643 if !run.is_empty() {
644 self.pending.push_back(Event::characters(EventKind::ContentCharacters, run, complete));
645 }
646 Ok(())
647 }
648
649 fn bound(&self, prefix: &str) -> Option<&str> {
650 self.bindings.iter().rev().find(|(p, _)| p == prefix).map(|(_, uri)| uri.as_str())
651 }
652
653 fn start_tag(&mut self) -> Scan<()> {
654 self.at += 1;
655 let qualified = self.name()?;
656 let mut attributes: Vec<(String, usize, String, Vec<Event>)> = Vec::new();
657 let empty = loop {
658 let spaced = self.spaces();
659 match self.peek(0) {
660 None => return Err(MORE),
661 Some('>') => {
662 self.at += 1;
663 break false;
664 }
665 Some('/') => {
666 self.at += 1;
667 self.expect('>')?;
668 break true;
669 }
670 Some(_) if !spaced => return Err(Why::InvalidCharacter),
671 Some(_) => {}
672 }
673 let name_at = self.at;
674 let name = self.name()?;
675 self.spaces();
676 self.expect('=')?;
677 self.spaces();
678 let quote = match self.peek(0) {
679 None => return Err(MORE),
680 Some(q @ ('"' | '\'')) => q,
681 Some(_) => return Err(Why::InvalidCharacter),
682 };
683 self.at += 1;
684 let (value, parts) = self.attribute_value(quote)?;
685 if attributes.iter().any(|(n, ..)| *n == name) {
686 self.at = name_at;
687 return Err(Why::DuplicateAttribute);
688 }
689 attributes.push((name, name_at, value, parts));
690 };
691 let scope = self.bindings.len();
692 let mut declarations = Vec::new();
693 for (name, _, value, _) in &attributes {
694 let prefix = match name.as_str() {
695 "xmlns" => Some(String::new()),
696 n => n.strip_prefix("xmlns:").map(str::to_owned),
697 };
698 if let Some(prefix) = prefix {
699 self.bindings.push((prefix.clone(), value.clone()));
700 declarations.push(Event { namespace: value.clone(), prefix, ..Event::new(EventKind::NamespaceDeclaration, "") });
701 }
702 }
703 let (prefix, local) = split(&qualified);
704 let mut events = Vec::new();
705 let namespace = match self.bound(&prefix) {
706 Some(uri) => uri.to_owned(),
707 None => {
708 if !prefix.is_empty() {
709 events.push(Event::undeclared(Why::UndeclaredElementPrefix, &qualified));
710 }
711 String::new()
712 }
713 };
714 events.push(Event { namespace: namespace.clone(), prefix: prefix.clone(), ..Event::new(EventKind::StartOfElement, local.clone()) });
715 events.extend(declarations);
716 for (name, _, _, parts) in attributes {
717 if name == "xmlns" || name.starts_with("xmlns:") {
718 continue;
719 }
720 let (attribute_prefix, attribute_local) = split(&name);
721 let attribute_namespace = if attribute_prefix.is_empty() {
722 String::new()
723 } else {
724 match self.bound(&attribute_prefix) {
725 Some(uri) => uri.to_owned(),
726 None => {
727 events.push(Event::undeclared(Why::UndeclaredAttributePrefix, &name));
728 String::new()
729 }
730 }
731 };
732 events.push(Event { namespace: attribute_namespace, prefix: attribute_prefix, ..Event::new(EventKind::AttributeName, attribute_local) });
733 events.extend(parts);
734 }
735 if self.place == Place::Epilogue {
736 return Err(Why::ContentAfterRoot);
737 }
738 self.place = Place::Content;
739 if empty {
740 events.push(Event { namespace, prefix, ..Event::new(EventKind::EndOfElement, local) });
741 self.bindings.truncate(scope);
742 if self.elements.is_empty() {
743 self.place = Place::Epilogue;
744 }
745 } else {
746 self.elements.push(Element { qualified, local, prefix, namespace, bindings: scope });
747 }
748 self.pending.extend(events);
749 Ok(())
750 }
751
752 fn attribute_value(&mut self, quote: char) -> Scan<(String, Vec<Event>)> {
755 let (mut value, mut run, mut parts) = (String::new(), String::new(), Vec::new());
756 loop {
757 let Some(c) = self.peek(0) else { return Err(MORE) };
758 match c {
759 c if c == quote => {
760 self.at += 1;
761 break;
762 }
763 '<' => return Err(Why::LessThanInAttribute),
764 '&' => match self.reference()? {
765 Ok(ch) if (self.representable)(ch) || ch.is_ascii() => {
766 run.push(ch);
767 value.push(ch);
768 }
769 Ok(ch) => {
770 if !run.is_empty() {
771 parts.push(Event::characters(EventKind::AttributeCharacters, std::mem::take(&mut run), true));
772 }
773 parts.push(Event::new(EventKind::AttributeNationalCharacter, ch.to_string()));
774 value.push(ch);
775 }
776 Err(_) => return Err(Why::UndeclaredEntity),
777 },
778 '\t' | '\n' | '\r' => {
779 run.push(' ');
780 value.push(' ');
781 self.at += 1;
782 }
783 c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
784 c => {
785 run.push(c);
786 value.push(c);
787 self.at += 1;
788 }
789 }
790 }
791 if !run.is_empty() || parts.is_empty() {
792 parts.push(Event::characters(EventKind::AttributeCharacters, run, true));
793 }
794 Ok((value, parts))
795 }
796
797 fn end_tag(&mut self) -> Scan<()> {
798 let start = self.at;
799 self.at += 2;
800 let qualified = self.name()?;
801 self.spaces();
802 self.expect('>')?;
803 match self.elements.last() {
804 Some(e) if e.qualified == qualified => {}
805 _ => {
806 self.at = start;
807 return Err(Why::MismatchedEndTag);
808 }
809 }
810 let e = self.elements.pop().expect("checked above");
811 self.bindings.truncate(e.bindings);
812 self.pending.push_back(Event { namespace: e.namespace, prefix: e.prefix, ..Event::new(EventKind::EndOfElement, e.local) });
813 if self.elements.is_empty() {
814 self.place = Place::Epilogue;
815 }
816 Ok(())
817 }
818}
819
820#[cfg(test)]
821mod tests;