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 split: bool,
206}
207
208type Scan<T> = Result<T, Why>;
209
210const MORE: Why = Why::UnexpectedEnd;
212
213fn is_space(c: char) -> bool {
215 matches!(c, ' ' | '\t' | '\n' | '\r' | '\u{85}')
216}
217
218fn name_start(c: char) -> bool {
219 c.is_ascii_alphabetic() || c == '_' || c == ':' || c as u32 >= 0xC0
220}
221
222fn name_char(c: char) -> bool {
223 name_start(c) || c.is_ascii_digit() || c == '-' || c == '.' || c == '\u{B7}'
224}
225
226fn xml_char(c: u32) -> bool {
227 matches!(c, 0x9 | 0xA | 0xD | 0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF)
228}
229
230fn split(qualified: &str) -> (String, String) {
231 match qualified.split_once(':') {
232 Some((prefix, local)) => (prefix.to_owned(), local.to_owned()),
233 None => (String::new(), qualified.to_owned()),
234 }
235}
236
237impl<'r> Scanner<'r> {
238 pub fn new(segment: &str, representable: &'r dyn Fn(char) -> bool) -> Self {
241 Self {
242 buf: segment.chars().collect(),
243 at: 0,
244 consumed: 0,
245 place: Place::Start,
246 open: None,
247 elements: Vec::new(),
248 bindings: vec![("xml".into(), XML_NAMESPACE.into())],
249 pending: VecDeque::new(),
250 representable,
251 last_segment: false,
252 doctype: false,
253 standalone_no: false,
254 split: false,
255 }
256 }
257
258 pub fn feed(&mut self, segment: &str) {
260 self.consumed += self.at;
261 self.buf.drain(..self.at);
262 self.at = 0;
263 self.buf.extend(segment.chars());
264 }
265
266 pub fn finish(&mut self) {
268 self.last_segment = true;
269 }
270
271 fn peek(&self, ahead: usize) -> Option<char> {
272 self.buf.get(self.at + ahead).copied()
273 }
274
275 fn starts(&self, s: &str) -> bool {
276 let chars: Vec<char> = s.chars().collect();
277 self.buf[self.at..].starts_with(&chars)
278 }
279
280 fn could_start(&self, s: &str) -> bool {
282 let rest = &self.buf[self.at..];
283 rest.len() < s.chars().count() && s.chars().zip(rest).all(|(a, &b)| a == b)
284 }
285
286 fn find(&self, from: usize, s: &str) -> Option<usize> {
287 let chars: Vec<char> = s.chars().collect();
288 (from..=self.buf.len().saturating_sub(chars.len())).find(|&i| self.buf[i..].starts_with(&chars))
289 }
290
291 fn fail(&self, at: usize, why: Why) -> Step {
292 Step::Error(Malformed { offset: self.consumed + at, why })
293 }
294
295 pub fn advance(&mut self) -> Step {
296 if let Some(e) = self.pending.pop_front() {
297 return Step::Event(e);
298 }
299 if self.place == Place::Start {
300 self.place = Place::Prolog;
301 return Step::Event(Event::new(EventKind::StartOfDocument, ""));
302 }
303 if self.place == Place::Finished {
304 return Step::Done;
305 }
306 let before = self.at;
307 match self.step() {
308 Ok(()) => match self.pending.pop_front() {
309 Some(e) => Step::Event(e),
310 None if self.place == Place::Finished => Step::Event(Event::new(EventKind::EndOfDocument, "")),
311 None => self.advance(),
312 },
313 Err(MORE) => {
314 self.at = before;
315 self.at_end()
316 }
317 Err(why) => self.fail(self.at, why),
318 }
319 }
320
321 fn at_end(&mut self) -> Step {
323 if self.place == Place::Epilogue && self.buf[self.at..].iter().all(|&c| is_space(c)) {
324 self.at = self.buf.len();
325 self.place = Place::Finished;
326 return Step::Event(Event::new(EventKind::EndOfDocument, ""));
327 }
328 if !self.last_segment {
329 return Step::EndOfInput;
330 }
331 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 };
332 Step::Error(Malformed { offset: self.consumed + self.buf.len(), why })
333 }
334
335 fn step(&mut self) -> Scan<()> {
337 if let Some(open) = self.open.clone() {
338 return self.continue_open(open);
339 }
340 if self.split && self.peek(0) == Some('<') {
343 self.split = false;
344 self.pending.push_back(Event::characters(EventKind::ContentCharacters, String::new(), true));
345 return Ok(());
346 }
347 while self.place != Place::Content && self.peek(0).is_some_and(is_space) {
348 self.at += 1;
349 }
350 let Some(c) = self.peek(0) else { return Err(MORE) };
351 if c != '<' {
352 if self.place == Place::Content {
353 return self.content();
354 }
355 return Err(if self.place == Place::Epilogue { Why::ContentAfterRoot } else { Why::InvalidCharacter });
356 }
357 if self.starts("<?xml") && self.peek(5).is_some_and(|c| is_space(c) || c == '?') && self.consumed == 0 && self.at == 0 {
358 return self.declaration();
359 }
360 if self.could_start("<!--") || self.could_start("<![CDATA[") || self.could_start("<!DOCTYPE") || self.buf.len() - self.at < 2 {
361 return Err(MORE);
362 }
363 if self.starts("<!--") {
364 self.at += 4;
365 self.open = Some(Open::Comment);
366 return Ok(());
367 }
368 if self.starts("<![CDATA[") {
369 if self.place != Place::Content {
370 return Err(Why::InvalidCharacter);
371 }
372 if self.peek(9).is_none() {
373 return Err(MORE);
374 }
375 self.at += 9;
376 self.pending.push_back(Event::new(EventKind::StartOfCdataSection, ""));
377 self.open = Some(Open::Cdata);
378 return Ok(());
379 }
380 if self.starts("<!DOCTYPE") {
381 return self.doctype();
382 }
383 if self.starts("<?") {
384 return self.instruction();
385 }
386 if self.starts("</") {
387 return self.end_tag();
388 }
389 if self.place == Place::Epilogue {
390 return Err(Why::SecondRoot);
391 }
392 self.start_tag()
393 }
394
395 fn name(&mut self) -> Scan<String> {
396 let start = self.at;
397 match self.peek(0) {
398 None => return Err(MORE),
399 Some(c) if !name_start(c) => return Err(Why::InvalidCharacter),
400 _ => {}
401 }
402 while self.peek(0).is_some_and(name_char) {
403 self.at += 1;
404 }
405 if self.at == self.buf.len() {
406 return Err(MORE);
407 }
408 let name: String = self.buf[start..self.at].iter().collect();
409 if name.matches(':').count() > 1 || name.starts_with(':') || name.ends_with(':') {
410 self.at = start;
411 return Err(Why::InvalidCharacter);
412 }
413 Ok(name)
414 }
415
416 fn spaces(&mut self) -> bool {
417 let start = self.at;
418 while self.peek(0).is_some_and(is_space) {
419 self.at += 1;
420 }
421 self.at > start
422 }
423
424 fn expect(&mut self, c: char) -> Scan<()> {
425 match self.peek(0) {
426 None => Err(MORE),
427 Some(d) if d == c => {
428 self.at += 1;
429 Ok(())
430 }
431 Some(_) => Err(Why::InvalidCharacter),
432 }
433 }
434
435 fn reference(&mut self) -> Scan<Result<char, String>> {
438 let end = self.find(self.at, ";").ok_or(MORE)?;
439 let body: String = self.buf[self.at + 1..end].iter().collect();
440 let value = if let Some(hex) = body.strip_prefix("#x") {
441 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)?
442 } else if let Some(dec) = body.strip_prefix('#') {
443 dec.parse::<u32>().ok().filter(|&v| xml_char(v)).and_then(char::from_u32).map(Ok).ok_or(Why::BadReference)?
444 } else {
445 match body.as_str() {
446 "lt" => Ok('<'),
447 "gt" => Ok('>'),
448 "amp" => Ok('&'),
449 "apos" => Ok('\''),
450 "quot" => Ok('"'),
451 name if !name.is_empty() && name.chars().next().is_some_and(name_start) && name.chars().all(name_char) => Err(name.to_owned()),
452 _ => return Err(Why::BadReference),
453 }
454 };
455 self.at = end + 1;
456 Ok(value)
457 }
458
459 fn declaration(&mut self) -> Scan<()> {
460 let end = self.find(self.at, "?>").ok_or(MORE)?;
461 self.at += 5;
462 let mut seen = Vec::new();
463 loop {
464 self.spaces();
465 if self.at >= end {
466 break;
467 }
468 let name = self.name().map_err(|_| Why::BadDeclaration)?;
469 self.spaces();
470 self.expect('=').map_err(|_| Why::BadDeclaration)?;
471 self.spaces();
472 let quote = self.peek(0).filter(|&q| q == '"' || q == '\'').ok_or(Why::BadDeclaration)?;
473 let close = self.find(self.at + 1, "e.to_string()).filter(|&c| c < end).ok_or(Why::BadDeclaration)?;
474 let value: String = self.buf[self.at + 1..close].iter().collect();
475 self.at = close + 1;
476 let kind = match name.as_str() {
477 "version" if seen.is_empty() => EventKind::VersionInformation,
478 "encoding" if seen == [EventKind::VersionInformation] => EventKind::EncodingDeclaration,
479 "standalone" if seen.first() == Some(&EventKind::VersionInformation) && !seen.contains(&EventKind::StandaloneDeclaration) && (value == "yes" || value == "no") => {
480 self.standalone_no = value == "no";
481 EventKind::StandaloneDeclaration
482 }
483 _ => return Err(Why::BadDeclaration),
484 };
485 seen.push(kind);
486 self.pending.push_back(Event::new(kind, value));
487 }
488 if seen.first() != Some(&EventKind::VersionInformation) {
489 return Err(Why::BadDeclaration);
490 }
491 self.at = end + 2;
492 Ok(())
493 }
494
495 fn doctype(&mut self) -> Scan<()> {
496 if self.place != Place::Prolog || self.doctype {
497 return Err(Why::InvalidCharacter);
498 }
499 let mut depth = 0i32;
500 let mut quote = None;
501 let mut i = self.at + 9;
502 let end = loop {
503 let c = *self.buf.get(i).ok_or(MORE)?;
504 match (quote, c) {
505 (Some(q), c) if c == q => quote = None,
506 (Some(_), _) => {}
507 (None, '"' | '\'') => quote = Some(c),
508 (None, '[') => depth += 1,
509 (None, ']') => depth -= 1,
510 (None, '>') if depth == 0 => break i,
511 _ => {}
512 }
513 i += 1;
514 };
515 self.at += 9;
516 if !self.spaces() {
517 return Err(Why::InvalidCharacter);
518 }
519 let root = self.name()?;
520 self.at = end + 1;
521 self.doctype = true;
522 self.pending.push_back(Event::new(EventKind::DocumentTypeDeclaration, root));
523 Ok(())
524 }
525
526 fn instruction(&mut self) -> Scan<()> {
527 self.at += 2;
528 let start = self.at;
529 let target = self.name()?;
530 if target.eq_ignore_ascii_case("xml") {
531 self.at = start;
532 return Err(Why::BadDeclaration);
533 }
534 match self.peek(0) {
535 None => return Err(MORE),
536 Some('?') if self.peek(1).is_none() => return Err(MORE),
537 Some('?') if self.peek(1) == Some('>') => {}
538 Some(c) if is_space(c) => {}
539 Some(_) => return Err(Why::InvalidCharacter),
540 }
541 self.spaces();
542 self.open = Some(Open::Instruction(target.clone(), false));
543 self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target));
544 Ok(())
545 }
546
547 fn open_text(&mut self, terminator: &str) -> (String, bool) {
550 match self.find(self.at, terminator) {
551 Some(end) => {
552 let text: String = self.buf[self.at..end].iter().collect();
553 self.at = end + terminator.chars().count();
554 (text, true)
555 }
556 None => {
557 let rest = &self.buf[self.at..];
558 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);
559 let end = self.buf.len() - keep;
560 let text: String = self.buf[self.at..end].iter().collect();
561 self.at = end;
562 (text, false)
563 }
564 }
565 }
566
567 fn continue_open(&mut self, open: Open) -> Scan<()> {
568 let (terminator, kind) = match &open {
569 Open::Comment => ("-->", EventKind::Comment),
570 Open::Instruction(..) => ("?>", EventKind::ProcessingInstructionData),
571 Open::Cdata => ("]]>", EventKind::ContentCharacters),
572 };
573 let (text, complete) = self.open_text(terminator);
574 if open == Open::Comment && text.contains("--") {
575 return Err(Why::BadComment);
576 }
577 if !complete && text.is_empty() {
578 return Err(MORE);
579 }
580 if let Open::Instruction(target, true) = &open {
581 self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target.clone()));
582 }
583 if kind == EventKind::ContentCharacters {
584 if !text.is_empty() || std::mem::take(&mut self.split) {
585 self.pending.push_back(Event::characters(kind, text, complete));
586 }
587 self.split = !complete;
588 } else if !text.is_empty() || kind == EventKind::Comment || kind == EventKind::ProcessingInstructionData {
589 self.pending.push_back(Event::new(kind, text));
590 }
591 if complete {
592 self.open = None;
593 if open == Open::Cdata {
594 self.pending.push_back(Event::new(EventKind::EndOfCdataSection, ""));
595 }
596 } else if let Open::Instruction(target, _) = open {
597 self.open = Some(Open::Instruction(target, true));
598 }
599 Ok(())
600 }
601
602 fn content(&mut self) -> Scan<()> {
604 let mut run = String::new();
605 while let Some(c) = self.peek(0) {
606 match c {
607 '<' => break,
608 '&' => {
609 let mark = self.at;
610 match self.reference() {
611 Ok(Ok(ch)) if (self.representable)(ch) || ch.is_ascii() => run.push(ch),
612 Ok(Ok(ch)) => {
613 if !run.is_empty() {
614 self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
615 }
616 self.pending.push_back(Event::new(EventKind::ContentNationalCharacter, ch.to_string()));
617 }
618 Ok(Err(name)) if self.doctype && self.standalone_no => {
619 if !run.is_empty() {
620 self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
621 }
622 self.pending.push_back(Event::new(EventKind::UnresolvedReference, name));
623 }
624 Ok(Err(_)) => {
625 self.at = mark;
626 return Err(Why::UndeclaredEntity);
627 }
628 Err(MORE) => {
629 self.at = mark;
630 break;
631 }
632 Err(why) => {
633 self.at = mark;
634 return Err(why);
635 }
636 }
637 }
638 '\r' => {
639 run.push('\n');
640 self.at += 1;
641 if self.peek(0) == Some('\n') {
642 self.at += 1;
643 }
644 }
645 c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
646 c => {
647 run.push(c);
648 self.at += 1;
649 }
650 }
651 }
652 let complete = self.peek(0) == Some('<');
653 if run.is_empty() && self.pending.is_empty() {
654 return Err(MORE);
655 }
656 if !run.is_empty() {
657 self.pending.push_back(Event::characters(EventKind::ContentCharacters, run, complete));
658 self.split = !complete;
659 }
660 Ok(())
661 }
662
663 fn bound(&self, prefix: &str) -> Option<&str> {
664 self.bindings.iter().rev().find(|(p, _)| p == prefix).map(|(_, uri)| uri.as_str())
665 }
666
667 fn start_tag(&mut self) -> Scan<()> {
668 self.at += 1;
669 let qualified = self.name()?;
670 let mut attributes: Vec<(String, usize, String, Vec<Event>)> = Vec::new();
671 let empty = loop {
672 let spaced = self.spaces();
673 match self.peek(0) {
674 None => return Err(MORE),
675 Some('>') => {
676 self.at += 1;
677 break false;
678 }
679 Some('/') => {
680 self.at += 1;
681 self.expect('>')?;
682 break true;
683 }
684 Some(_) if !spaced => return Err(Why::InvalidCharacter),
685 Some(_) => {}
686 }
687 let name_at = self.at;
688 let name = self.name()?;
689 self.spaces();
690 self.expect('=')?;
691 self.spaces();
692 let quote = match self.peek(0) {
693 None => return Err(MORE),
694 Some(q @ ('"' | '\'')) => q,
695 Some(_) => return Err(Why::InvalidCharacter),
696 };
697 self.at += 1;
698 let (value, parts) = self.attribute_value(quote)?;
699 if attributes.iter().any(|(n, ..)| *n == name) {
700 return Err(Why::DuplicateAttribute);
701 }
702 attributes.push((name, name_at, value, parts));
703 };
704 let scope = self.bindings.len();
705 let mut declarations = Vec::new();
706 for (name, _, value, _) in &attributes {
707 let prefix = match name.as_str() {
708 "xmlns" => Some(String::new()),
709 n => n.strip_prefix("xmlns:").map(str::to_owned),
710 };
711 if let Some(prefix) = prefix {
712 self.bindings.push((prefix.clone(), value.clone()));
713 declarations.push(Event { namespace: value.clone(), prefix, ..Event::new(EventKind::NamespaceDeclaration, "") });
714 }
715 }
716 let (prefix, local) = split(&qualified);
717 let mut events = Vec::new();
718 let namespace = match self.bound(&prefix) {
719 Some(uri) => uri.to_owned(),
720 None => {
721 if !prefix.is_empty() {
722 events.push(Event::undeclared(Why::UndeclaredElementPrefix, &qualified));
723 }
724 String::new()
725 }
726 };
727 events.push(Event { namespace: namespace.clone(), prefix: prefix.clone(), ..Event::new(EventKind::StartOfElement, local.clone()) });
728 events.extend(declarations);
729 for (name, _, _, parts) in attributes {
730 if name == "xmlns" || name.starts_with("xmlns:") {
731 continue;
732 }
733 let (attribute_prefix, attribute_local) = split(&name);
734 let attribute_namespace = if attribute_prefix.is_empty() {
735 String::new()
736 } else {
737 match self.bound(&attribute_prefix) {
738 Some(uri) => uri.to_owned(),
739 None => {
740 events.push(Event::undeclared(Why::UndeclaredAttributePrefix, &name));
741 String::new()
742 }
743 }
744 };
745 events.push(Event { namespace: attribute_namespace, prefix: attribute_prefix, ..Event::new(EventKind::AttributeName, attribute_local) });
746 events.extend(parts);
747 }
748 if self.place == Place::Epilogue {
749 return Err(Why::ContentAfterRoot);
750 }
751 self.place = Place::Content;
752 if empty {
753 events.push(Event { namespace, prefix, ..Event::new(EventKind::EndOfElement, local) });
754 self.bindings.truncate(scope);
755 if self.elements.is_empty() {
756 self.place = Place::Epilogue;
757 }
758 } else {
759 self.elements.push(Element { qualified, local, prefix, namespace, bindings: scope });
760 }
761 self.pending.extend(events);
762 Ok(())
763 }
764
765 fn attribute_value(&mut self, quote: char) -> Scan<(String, Vec<Event>)> {
768 let (mut value, mut run, mut parts) = (String::new(), String::new(), Vec::new());
769 loop {
770 let Some(c) = self.peek(0) else { return Err(MORE) };
771 match c {
772 c if c == quote => {
773 self.at += 1;
774 break;
775 }
776 '<' => return Err(Why::LessThanInAttribute),
777 '&' => match self.reference()? {
778 Ok(ch) if (self.representable)(ch) || ch.is_ascii() => {
779 run.push(ch);
780 value.push(ch);
781 }
782 Ok(ch) => {
783 if !run.is_empty() {
784 parts.push(Event::characters(EventKind::AttributeCharacters, std::mem::take(&mut run), true));
785 }
786 parts.push(Event::new(EventKind::AttributeNationalCharacter, ch.to_string()));
787 value.push(ch);
788 }
789 Err(_) => return Err(Why::UndeclaredEntity),
790 },
791 '\t' | '\n' | '\r' => {
792 run.push(' ');
793 value.push(' ');
794 self.at += 1;
795 }
796 c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
797 c => {
798 run.push(c);
799 value.push(c);
800 self.at += 1;
801 }
802 }
803 }
804 if !run.is_empty() || parts.is_empty() {
805 parts.push(Event::characters(EventKind::AttributeCharacters, run, true));
806 }
807 Ok((value, parts))
808 }
809
810 fn end_tag(&mut self) -> Scan<()> {
811 let start = self.at;
812 self.at += 2;
813 let qualified = self.name()?;
814 self.spaces();
815 self.expect('>')?;
816 match self.elements.last() {
817 Some(e) if e.qualified == qualified => {}
818 _ => {
819 self.at = start;
820 return Err(Why::MismatchedEndTag);
821 }
822 }
823 let e = self.elements.pop().expect("checked above");
824 self.bindings.truncate(e.bindings);
825 self.pending.push_back(Event { namespace: e.namespace, prefix: e.prefix, ..Event::new(EventKind::EndOfElement, e.local) });
826 if self.elements.is_empty() {
827 self.place = Place::Epilogue;
828 }
829 Ok(())
830 }
831}
832
833#[cfg(test)]
834mod tests;