1use crate::ast::{Pattern, QName, Schema};
7use crate::codegen::CodegenConfig;
8use std::collections::{HashMap, HashSet};
9use std::fmt::Write;
10
11pub fn generate_parsers(schema: &Schema, config: &CodegenConfig) -> String {
13 let mut g = ParserGenerator::new(schema, config);
14 g.run()
15}
16
17#[derive(Debug, Clone, Copy, PartialEq)]
19enum ParseStrategy {
20 FromXml,
22 TextFromStr,
24 TextString,
26 TextHexBinary,
28 TextBase64Binary,
30}
31
32struct ParserGenerator<'a> {
33 schema: &'a Schema,
34 config: &'a CodegenConfig,
35 output: String,
36 definitions: HashMap<&'a str, &'a Pattern>,
37 generated_names: HashSet<String>,
39}
40
41impl<'a> ParserGenerator<'a> {
42 fn new(schema: &'a Schema, config: &'a CodegenConfig) -> Self {
43 let definitions: HashMap<&str, &Pattern> = schema
44 .definitions
45 .iter()
46 .map(|d| (d.name.as_str(), &d.pattern))
47 .collect();
48
49 Self {
50 schema,
51 config,
52 output: String::new(),
53 definitions,
54 generated_names: HashSet::new(),
55 }
56 }
57
58 fn run(&mut self) -> String {
59 self.write_header();
60
61 for def in &self.schema.definitions {
63 if !def.name.contains("_ST_") && !self.is_simple_type(&def.pattern) {
64 if self.is_inline_attribute_ref(&def.name, &def.pattern) {
66 continue;
67 }
68 let rust_name = self.to_rust_type_name(&def.name);
70 if !self.generated_names.insert(rust_name) {
71 continue;
72 }
73 if def.name.contains("_EG_") && self.is_element_choice(&def.pattern) {
74 if let Some(code) = self.gen_element_group_parser(def) {
76 self.output.push_str(&code);
77 self.output.push('\n');
78 }
79 } else if !self.is_type_alias(&def.pattern) {
80 if let Some(code) = self.gen_struct_parser(def) {
82 self.output.push_str(&code);
83 self.output.push('\n');
84 }
85 }
86 }
87 }
88
89 std::mem::take(&mut self.output)
90 }
91
92 fn is_type_alias(&self, pattern: &Pattern) -> bool {
101 match pattern {
102 Pattern::Element { .. } => true,
104 Pattern::Datatype { .. } => true,
106 Pattern::Ref(name) => {
108 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
109 self.is_simple_type(def_pattern)
111 || self.is_type_alias(def_pattern)
113 } else {
114 false
117 }
118 }
119 _ => false,
120 }
121 }
122
123 fn is_inline_attribute_ref(&self, name: &str, pattern: &Pattern) -> bool {
126 !name.contains("_CT_") && matches!(pattern, Pattern::Attribute { .. })
127 }
128
129 fn write_header(&mut self) {
130 writeln!(self.output, "// Event-based parsers for generated types.").unwrap();
131 writeln!(
132 self.output,
133 "// ~3x faster than serde-based deserialization."
134 )
135 .unwrap();
136 writeln!(self.output).unwrap();
137 writeln!(self.output, "#![allow(unused_variables)]").unwrap();
138 writeln!(self.output, "#![allow(unused_imports)]").unwrap();
139 writeln!(self.output, "#![allow(clippy::single_match)]").unwrap();
140 writeln!(self.output, "#![allow(clippy::match_single_binding)]").unwrap();
141 writeln!(self.output, "#![allow(clippy::manual_is_multiple_of)]").unwrap();
142 writeln!(self.output).unwrap();
143 writeln!(self.output, "use super::generated::*;").unwrap();
144 for import in &self.config.cross_crate_imports {
146 writeln!(self.output, "use {};", import).unwrap();
147 }
148 writeln!(self.output, "use quick_xml::Reader;").unwrap();
149 writeln!(self.output, "use quick_xml::events::{{Event, BytesStart}};").unwrap();
150 writeln!(self.output, "use std::io::BufRead;").unwrap();
151 writeln!(self.output, "pub use ooxml_xml::{{FromXml, ParseError}};").unwrap();
153 writeln!(self.output, "#[cfg(feature = \"extra-children\")]").unwrap();
154 writeln!(
155 self.output,
156 "use ooxml_xml::{{PositionedNode, RawXmlElement, RawXmlNode}};"
157 )
158 .unwrap();
159 writeln!(self.output).unwrap();
160 writeln!(self.output, "#[allow(dead_code)]").unwrap();
162 writeln!(self.output, "/// Skip an element and all its children.").unwrap();
163 writeln!(
164 self.output,
165 "fn skip_element<R: BufRead>(reader: &mut Reader<R>) -> Result<(), ParseError> {{"
166 )
167 .unwrap();
168 writeln!(self.output, " let mut depth = 1u32;").unwrap();
169 writeln!(self.output, " let mut buf = Vec::new();").unwrap();
170 writeln!(self.output, " loop {{").unwrap();
171 writeln!(
172 self.output,
173 " match reader.read_event_into(&mut buf)? {{"
174 )
175 .unwrap();
176 writeln!(self.output, " Event::Start(_) => depth += 1,").unwrap();
177 writeln!(self.output, " Event::End(_) => {{").unwrap();
178 writeln!(self.output, " depth -= 1;").unwrap();
179 writeln!(self.output, " if depth == 0 {{ break; }}").unwrap();
180 writeln!(self.output, " }}").unwrap();
181 writeln!(self.output, " Event::Eof => break,").unwrap();
182 writeln!(self.output, " _ => {{}}").unwrap();
183 writeln!(self.output, " }}").unwrap();
184 writeln!(self.output, " buf.clear();").unwrap();
185 writeln!(self.output, " }}").unwrap();
186 writeln!(self.output, " Ok(())").unwrap();
187 writeln!(self.output, "}}").unwrap();
188 writeln!(self.output).unwrap();
189 writeln!(self.output, "#[allow(dead_code)]").unwrap();
191 writeln!(
192 self.output,
193 "/// Read the text content of an element until its end tag."
194 )
195 .unwrap();
196 writeln!(self.output, "fn read_text_content<R: BufRead>(reader: &mut Reader<R>) -> Result<String, ParseError> {{").unwrap();
197 writeln!(self.output, " let mut text = String::new();").unwrap();
198 writeln!(self.output, " let mut buf = Vec::new();").unwrap();
199 writeln!(self.output, " loop {{").unwrap();
200 writeln!(
201 self.output,
202 " match reader.read_event_into(&mut buf)? {{"
203 )
204 .unwrap();
205 writeln!(
206 self.output,
207 " Event::Text(e) => text.push_str(&e.decode().unwrap_or_default()),"
208 )
209 .unwrap();
210 writeln!(
211 self.output,
212 " Event::CData(e) => text.push_str(&e.decode().unwrap_or_default()),"
213 )
214 .unwrap();
215 writeln!(self.output, " Event::GeneralRef(e) => {{").unwrap();
218 writeln!(
219 self.output,
220 " let name = e.decode().unwrap_or_default();"
221 )
222 .unwrap();
223 writeln!(
224 self.output,
225 " if let Some(s) = quick_xml::escape::resolve_xml_entity(&name) {{"
226 )
227 .unwrap();
228 writeln!(self.output, " text.push_str(s);").unwrap();
229 writeln!(self.output, " }}").unwrap();
230 writeln!(self.output, " }},").unwrap();
231 writeln!(self.output, " Event::End(_) => break,").unwrap();
232 writeln!(self.output, " Event::Eof => break,").unwrap();
233 writeln!(self.output, " _ => {{}}").unwrap();
234 writeln!(self.output, " }}").unwrap();
235 writeln!(self.output, " buf.clear();").unwrap();
236 writeln!(self.output, " }}").unwrap();
237 writeln!(self.output, " Ok(text)").unwrap();
238 writeln!(self.output, "}}").unwrap();
239 writeln!(self.output).unwrap();
240 writeln!(self.output, "#[allow(dead_code)]").unwrap();
242 writeln!(self.output, "/// Decode a hex string to bytes.").unwrap();
243 writeln!(self.output, "fn decode_hex(s: &str) -> Option<Vec<u8>> {{").unwrap();
244 writeln!(self.output, " let s = s.trim();").unwrap();
245 writeln!(self.output, " if s.len() % 2 != 0 {{ return None; }}").unwrap();
246 writeln!(self.output, " (0..s.len())").unwrap();
247 writeln!(self.output, " .step_by(2)").unwrap();
248 writeln!(
249 self.output,
250 " .map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok())"
251 )
252 .unwrap();
253 writeln!(self.output, " .collect()").unwrap();
254 writeln!(self.output, "}}").unwrap();
255 writeln!(self.output).unwrap();
256
257 writeln!(self.output, "#[allow(dead_code)]").unwrap();
259 writeln!(self.output, "/// Decode a base64 string to bytes.").unwrap();
260 writeln!(
261 self.output,
262 "fn decode_base64(s: &str) -> Option<Vec<u8>> {{"
263 )
264 .unwrap();
265 writeln!(self.output, " use base64::Engine;").unwrap();
266 writeln!(
267 self.output,
268 " base64::engine::general_purpose::STANDARD.decode(s.trim()).ok()"
269 )
270 .unwrap();
271 writeln!(self.output, "}}").unwrap();
272 writeln!(self.output).unwrap();
273 }
274
275 fn is_simple_type(&self, pattern: &Pattern) -> bool {
276 match pattern {
277 Pattern::Choice(variants) => variants
278 .iter()
279 .all(|v| matches!(v, Pattern::StringLiteral(_))),
280 Pattern::StringLiteral(_) => true,
281 Pattern::Datatype { .. } => true,
282 Pattern::List(_) => true,
283 Pattern::Ref(name) => self
284 .definitions
285 .get(name.as_str())
286 .is_some_and(|p| self.is_simple_type(p)),
287 _ => false,
288 }
289 }
290
291 fn is_element_choice(&self, pattern: &Pattern) -> bool {
292 match pattern {
293 Pattern::Choice(variants) => variants.iter().any(Self::is_direct_element_variant),
294 _ => false,
295 }
296 }
297
298 fn is_direct_element_variant(pattern: &Pattern) -> bool {
299 match pattern {
300 Pattern::Element { .. } => true,
301 Pattern::Optional(inner) | Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => {
302 Self::is_direct_element_variant(inner)
303 }
304 _ => false,
305 }
306 }
307
308 fn has_xml_children_pattern(&self, pattern: &Pattern) -> bool {
310 match pattern {
311 Pattern::Empty => false,
312 Pattern::Attribute { .. } => false,
313 Pattern::Element { .. } => true,
314 Pattern::Ref(name) => {
315 if name.contains("_AG_") {
316 return false;
317 }
318 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
319 self.has_xml_children_pattern(def_pattern)
320 } else {
321 true
322 }
323 }
324 Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
325 items.iter().any(|i| self.has_xml_children_pattern(i))
326 }
327 Pattern::Optional(inner)
328 | Pattern::ZeroOrMore(inner)
329 | Pattern::OneOrMore(inner)
330 | Pattern::Group(inner)
331 | Pattern::Mixed(inner) => self.has_xml_children_pattern(inner),
332 Pattern::Text => true,
333 _ => false,
334 }
335 }
336
337 fn has_xml_attr_pattern(&self, pattern: &Pattern) -> bool {
339 match pattern {
340 Pattern::Attribute { .. } => true,
341 Pattern::Ref(name) if name.contains("_AG_") => true,
342 Pattern::Ref(name) => {
343 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
344 self.has_xml_attr_pattern(def_pattern)
345 } else {
346 false
347 }
348 }
349 Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
350 items.iter().any(|i| self.has_xml_attr_pattern(i))
351 }
352 Pattern::Optional(inner)
353 | Pattern::ZeroOrMore(inner)
354 | Pattern::OneOrMore(inner)
355 | Pattern::Group(inner) => self.has_xml_attr_pattern(inner),
356 _ => false,
357 }
358 }
359
360 fn eg_ref_to_field_name(&self, name: &str) -> String {
361 let spec_name = strip_namespace_prefix(name);
362 let short = spec_name.strip_prefix("EG_").unwrap_or(spec_name);
363 if let Some(mappings) = &self.config.name_mappings
365 && let Some(mapped) = mappings.resolve_field(&self.config.module_name, short)
366 {
367 return mapped.to_string();
368 }
369 to_snake_case(short)
370 }
371
372 fn is_eg_content_field(&self, field: &Field) -> bool {
373 if let Pattern::Ref(name) = &field.pattern
374 && name.contains("_EG_")
375 && let Some(pattern) = self.definitions.get(name.as_str())
376 {
377 return self.is_element_choice(pattern);
378 }
379 false
380 }
381
382 fn collect_element_variant_names(
384 &self,
385 pattern: &Pattern,
386 names: &mut Vec<String>,
387 visited: &mut std::collections::HashSet<String>,
388 ) {
389 match pattern {
390 Pattern::Element { name, .. } => {
391 names.push(name.local.clone());
392 }
393 Pattern::Optional(inner)
394 | Pattern::ZeroOrMore(inner)
395 | Pattern::OneOrMore(inner)
396 | Pattern::Group(inner) => {
397 self.collect_element_variant_names(inner, names, visited);
398 }
399 Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
400 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
401 self.collect_element_variant_names(def_pattern, names, visited);
402 }
403 }
404 Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
405 for item in items {
406 self.collect_element_variant_names(item, names, visited);
407 }
408 }
409 _ => {}
410 }
411 }
412
413 fn collect_eg_variants(
416 &self,
417 pattern: &Pattern,
418 variants: &mut Vec<(String, String, bool, bool)>,
419 visited: &mut std::collections::HashSet<String>,
420 ) {
421 match pattern {
422 Pattern::Element { name, pattern } => {
423 let (rust_type, needs_box) = self.pattern_to_rust_type(pattern, false);
425 let (actual_type, type_alias_has_box) =
428 self.resolve_from_xml_type_with_box(pattern);
429 let inner_type = actual_type.unwrap_or(rust_type);
430 variants.push((
431 name.local.clone(),
432 inner_type,
433 needs_box,
434 type_alias_has_box,
435 ));
436 }
437 Pattern::Optional(inner)
438 | Pattern::ZeroOrMore(inner)
439 | Pattern::OneOrMore(inner)
440 | Pattern::Group(inner) => {
441 self.collect_eg_variants(inner, variants, visited);
442 }
443 Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
444 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
445 self.collect_eg_variants(def_pattern, variants, visited);
446 }
447 }
448 Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
449 for item in items {
450 self.collect_eg_variants(item, variants, visited);
451 }
452 }
453 _ => {}
454 }
455 }
456
457 fn gen_element_group_parser(&self, def: &crate::ast::Definition) -> Option<String> {
458 let rust_name = self.to_rust_type_name(&def.name);
459
460 let Pattern::Choice(variants) = &def.pattern else {
461 return None;
462 };
463
464 let mut element_variants = Vec::new();
466 let mut visited = std::collections::HashSet::new();
467 visited.insert(def.name.clone());
468 for v in variants {
469 self.collect_eg_variants(v, &mut element_variants, &mut visited);
470 }
471 let mut seen = std::collections::HashSet::new();
473 element_variants.retain(|(name, _, _, _)| seen.insert(name.clone()));
474
475 if element_variants.is_empty() {
476 return None;
477 }
478
479 let mut code = String::new();
480 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
481 writeln!(
482 code,
483 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
484 )
485 .unwrap();
486 writeln!(code, " let tag = start_tag.local_name();").unwrap();
487 writeln!(code, " match tag.as_ref() {{").unwrap();
488
489 for (xml_name, inner_type, needs_box, type_alias_has_box) in &element_variants {
490 let variant_name = self.to_rust_variant_name(xml_name);
491 writeln!(code, " b\"{}\" => {{", xml_name).unwrap();
492 writeln!(
493 code,
494 " let inner = {}::from_xml(reader, start_tag, is_empty)?;",
495 inner_type
496 )
497 .unwrap();
498 let wrap_expr = match (*needs_box, *type_alias_has_box) {
502 (true, true) => "Box::new(Box::new(inner))",
503 (true, false) => "Box::new(inner)",
504 (false, true) => "Box::new(inner)",
505 (false, false) => "inner",
506 };
507 writeln!(
508 code,
509 " Ok(Self::{}({}))",
510 variant_name, wrap_expr
511 )
512 .unwrap();
513 writeln!(code, " }}").unwrap();
514 }
515
516 writeln!(code, " _ => Err(ParseError::UnexpectedElement(").unwrap();
517 writeln!(
518 code,
519 " String::from_utf8_lossy(start_tag.name().as_ref()).into_owned()"
520 )
521 .unwrap();
522 writeln!(code, " )),").unwrap();
523 writeln!(code, " }}").unwrap();
524 writeln!(code, " }}").unwrap();
525 writeln!(code, "}}").unwrap();
526
527 Some(code)
528 }
529
530 fn gen_struct_parser(&self, def: &crate::ast::Definition) -> Option<String> {
531 let rust_name = self.to_rust_type_name(&def.name);
532 let fields = self.extract_fields(&def.pattern);
533
534 if fields.is_empty() {
535 let has_unresolved_children = self.has_xml_children_pattern(&def.pattern);
536 let has_unresolved_attrs = self.has_xml_attr_pattern(&def.pattern);
537
538 let mut code = String::new();
539 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
540
541 if has_unresolved_children || has_unresolved_attrs {
542 writeln!(
544 code,
545 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
546 )
547 .unwrap();
548 if has_unresolved_attrs {
549 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
550 writeln!(
551 code,
552 " let mut extra_attrs = std::collections::HashMap::new();"
553 )
554 .unwrap();
555 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
556 writeln!(
557 code,
558 " for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
559 )
560 .unwrap();
561 writeln!(
562 code,
563 " let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
564 )
565 .unwrap();
566 writeln!(
567 code,
568 " let val = String::from_utf8_lossy(&attr.value).into_owned();"
569 )
570 .unwrap();
571 writeln!(code, " extra_attrs.insert(key, val);").unwrap();
572 writeln!(code, " }}").unwrap();
573 }
574 if has_unresolved_children {
575 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
576 writeln!(code, " let mut extra_children = Vec::new();").unwrap();
577 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
578 writeln!(code, " let mut child_idx: usize = 0;").unwrap();
579 }
580 writeln!(code, " if !is_empty {{").unwrap();
581 writeln!(code, " let mut buf = Vec::new();").unwrap();
582 writeln!(code, " loop {{").unwrap();
583 writeln!(
584 code,
585 " match reader.read_event_into(&mut buf)? {{"
586 )
587 .unwrap();
588 if has_unresolved_children {
589 writeln!(
590 code,
591 " #[cfg(feature = \"extra-children\")]"
592 )
593 .unwrap();
594 writeln!(code, " Event::Start(e) => {{").unwrap();
595 writeln!(
596 code,
597 " let elem = RawXmlElement::from_reader(reader, &e)?;"
598 )
599 .unwrap();
600 writeln!(
601 code,
602 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
603 )
604 .unwrap();
605 writeln!(code, " child_idx += 1;").unwrap();
606 writeln!(code, " }}").unwrap();
607 writeln!(
608 code,
609 " #[cfg(not(feature = \"extra-children\"))]"
610 )
611 .unwrap();
612 writeln!(
613 code,
614 " Event::Start(_) => {{ skip_element(reader)?; }}"
615 )
616 .unwrap();
617 writeln!(
618 code,
619 " #[cfg(feature = \"extra-children\")]"
620 )
621 .unwrap();
622 writeln!(code, " Event::Empty(e) => {{").unwrap();
623 writeln!(
624 code,
625 " let elem = RawXmlElement::from_empty(&e);"
626 )
627 .unwrap();
628 writeln!(
629 code,
630 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
631 )
632 .unwrap();
633 writeln!(code, " child_idx += 1;").unwrap();
634 writeln!(code, " }}").unwrap();
635 writeln!(
636 code,
637 " #[cfg(not(feature = \"extra-children\"))]"
638 )
639 .unwrap();
640 writeln!(code, " Event::Empty(_) => {{}}").unwrap();
641 } else {
642 writeln!(
643 code,
644 " Event::Start(_) => {{ skip_element(reader)?; }}"
645 )
646 .unwrap();
647 writeln!(code, " Event::Empty(_) => {{}}").unwrap();
648 }
649 writeln!(code, " Event::End(_) => break,").unwrap();
650 writeln!(code, " Event::Eof => break,").unwrap();
651 writeln!(code, " _ => {{}}").unwrap();
652 writeln!(code, " }}").unwrap();
653 writeln!(code, " buf.clear();").unwrap();
654 writeln!(code, " }}").unwrap();
655 writeln!(code, " }}").unwrap();
656 writeln!(code, " Ok(Self {{").unwrap();
657 if has_unresolved_attrs {
658 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
659 writeln!(code, " extra_attrs,").unwrap();
660 }
661 if has_unresolved_children {
662 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
663 writeln!(code, " extra_children,").unwrap();
664 }
665 writeln!(code, " }})").unwrap();
666 } else {
667 writeln!(
669 code,
670 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
671 )
672 .unwrap();
673 writeln!(code, " if !is_empty {{").unwrap();
674 writeln!(code, " let mut buf = Vec::new();").unwrap();
675 writeln!(code, " let mut depth = 1u32;").unwrap();
676 writeln!(code, " loop {{").unwrap();
677 writeln!(
678 code,
679 " match reader.read_event_into(&mut buf)? {{"
680 )
681 .unwrap();
682 writeln!(code, " Event::Start(_) => depth += 1,").unwrap();
683 writeln!(
684 code,
685 " Event::End(_) => {{ depth -= 1; if depth == 0 {{ break; }} }}"
686 )
687 .unwrap();
688 writeln!(code, " Event::Eof => break,").unwrap();
689 writeln!(code, " _ => {{}}").unwrap();
690 writeln!(code, " }}").unwrap();
691 writeln!(code, " buf.clear();").unwrap();
692 writeln!(code, " }}").unwrap();
693 writeln!(code, " }}").unwrap();
694 writeln!(code, " Ok(Self {{}})").unwrap();
695 }
696
697 writeln!(code, " }}").unwrap();
698 writeln!(code, "}}").unwrap();
699 return Some(code);
700 }
701
702 let mut code = String::new();
703 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
704 writeln!(
705 code,
706 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
707 )
708 .unwrap();
709
710 for field in &fields {
712 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
714 let base_name = base_name.trim_start_matches('_');
715 let var_name = format!("f_{}", base_name);
716
717 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
719 write!(code, " #[cfg(feature = \"{}\")] ", feature).unwrap();
720 } else {
721 write!(code, " ").unwrap();
722 }
723
724 if field.is_vec {
725 writeln!(code, "let mut {} = Vec::new();", var_name).unwrap();
726 } else if field.is_optional {
727 writeln!(code, "let mut {} = None;", var_name).unwrap();
728 } else {
729 let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, false);
731 let full_type = if needs_box {
732 format!("Box<{}>", rust_type)
733 } else {
734 rust_type
735 };
736 writeln!(code, "let mut {}: Option<{}> = None;", var_name, full_type).unwrap();
737 }
738 }
739
740 let attr_fields: Vec<_> = fields.iter().filter(|f| f.is_attribute).collect();
742 let has_attrs = !attr_fields.is_empty();
743 let elem_fields: Vec<_> = fields
744 .iter()
745 .filter(|f| !f.is_attribute && !f.is_text_content)
746 .collect();
747 let text_fields: Vec<_> = fields.iter().filter(|f| f.is_text_content).collect();
748 let has_children = !elem_fields.is_empty();
749 let has_parsing_loop = has_children || !text_fields.is_empty();
750 if has_attrs {
751 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
753 writeln!(
754 code,
755 " let mut extra_attrs = std::collections::HashMap::new();"
756 )
757 .unwrap();
758 }
759 if has_parsing_loop {
760 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
762 writeln!(code, " let mut extra_children = Vec::new();").unwrap();
763 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
764 writeln!(code, " let mut child_idx: usize = 0;").unwrap();
765 }
766 if has_attrs || has_parsing_loop {
767 writeln!(code).unwrap();
768 }
769 if has_attrs {
770 writeln!(code, " // Parse attributes").unwrap();
771 writeln!(
772 code,
773 " for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
774 )
775 .unwrap();
776 writeln!(
777 code,
778 " let val = String::from_utf8_lossy(&attr.value);"
779 )
780 .unwrap();
781 writeln!(code, " match attr.key.local_name().as_ref() {{").unwrap();
782 for field in &attr_fields {
783 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
784 let base_name = base_name.trim_start_matches('_');
785 let var_name = format!("f_{}", base_name);
786 let parse_expr = self.gen_attr_parse_expr(&field.pattern);
787
788 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
790 writeln!(code, " #[cfg(feature = \"{}\")]", feature).unwrap();
791 }
792 writeln!(code, " b\"{}\" => {{", field.xml_name).unwrap();
793 writeln!(code, " {} = {};", var_name, parse_expr).unwrap();
794 writeln!(code, " }}").unwrap();
795 }
796 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
798 writeln!(code, " unknown => {{").unwrap();
799 writeln!(
800 code,
801 " let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
802 )
803 .unwrap();
804 writeln!(
805 code,
806 " extra_attrs.insert(key, val.into_owned());"
807 )
808 .unwrap();
809 writeln!(code, " }}").unwrap();
810 writeln!(
811 code,
812 " #[cfg(not(feature = \"extra-attrs\"))]"
813 )
814 .unwrap();
815 writeln!(code, " _ => {{}}").unwrap();
816 writeln!(code, " }}").unwrap();
817 writeln!(code, " }}").unwrap();
818 }
819
820 if has_parsing_loop {
822 writeln!(code).unwrap();
823 writeln!(code, " // Parse child elements").unwrap();
824 writeln!(code, " if !is_empty {{").unwrap();
825 writeln!(code, " let mut buf = Vec::new();").unwrap();
826 writeln!(code, " loop {{").unwrap();
827 writeln!(
828 code,
829 " match reader.read_event_into(&mut buf)? {{"
830 )
831 .unwrap();
832 writeln!(code, " Event::Start(e) => {{").unwrap();
833 writeln!(
834 code,
835 " match e.local_name().as_ref() {{"
836 )
837 .unwrap();
838
839 let mut matched_names = std::collections::HashSet::new();
841 for field in &elem_fields {
842 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
843 let base_name = base_name.trim_start_matches('_');
844 let var_name = format!("f_{}", base_name);
845 let parse_expr = self.gen_element_parse_code(field, false);
846
847 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
849 writeln!(
850 code,
851 " #[cfg(feature = \"{}\")]",
852 feature
853 )
854 .unwrap();
855 }
856 if self.is_eg_content_field(field) {
857 let mut variant_names = Vec::new();
859 let mut visited = std::collections::HashSet::new();
860 if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
861 self.collect_element_variant_names(
862 def_pattern,
863 &mut variant_names,
864 &mut visited,
865 );
866 }
867 variant_names.retain(|n| matched_names.insert(n.clone()));
868 if !variant_names.is_empty() {
869 let arms: Vec<_> = variant_names
870 .iter()
871 .map(|n| format!("b\"{}\"", n))
872 .collect();
873 writeln!(
874 code,
875 " {} => {{",
876 arms.join(" | ")
877 )
878 .unwrap();
879 } else {
880 continue;
882 }
883 } else {
884 matched_names.insert(field.xml_name.clone());
885 writeln!(
886 code,
887 " b\"{}\" => {{",
888 field.xml_name
889 )
890 .unwrap();
891 }
892 if field.is_vec {
893 writeln!(
894 code,
895 " {}.push({});",
896 var_name, parse_expr
897 )
898 .unwrap();
899 } else {
900 writeln!(
901 code,
902 " {} = Some({});",
903 var_name, parse_expr
904 )
905 .unwrap();
906 }
907 writeln!(
908 code,
909 " #[cfg(feature = \"extra-children\")]"
910 )
911 .unwrap();
912 writeln!(
913 code,
914 " {{ child_idx += 1; }}"
915 )
916 .unwrap();
917 writeln!(code, " }}").unwrap();
918 }
919
920 writeln!(
922 code,
923 " #[cfg(feature = \"extra-children\")]"
924 )
925 .unwrap();
926 writeln!(code, " _ => {{").unwrap();
927 writeln!(
928 code,
929 " // Capture unknown element for roundtrip"
930 )
931 .unwrap();
932 writeln!(code, " let elem = RawXmlElement::from_reader(reader, &e)?;").unwrap();
933 writeln!(
934 code,
935 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
936 )
937 .unwrap();
938 writeln!(code, " child_idx += 1;").unwrap();
939 writeln!(code, " }}").unwrap();
940 writeln!(
941 code,
942 " #[cfg(not(feature = \"extra-children\"))]"
943 )
944 .unwrap();
945 writeln!(code, " _ => {{").unwrap();
946 writeln!(
947 code,
948 " // Skip unknown element"
949 )
950 .unwrap();
951 writeln!(
952 code,
953 " skip_element(reader)?;"
954 )
955 .unwrap();
956 writeln!(code, " }}").unwrap();
957 writeln!(code, " }}").unwrap();
958 writeln!(code, " }}").unwrap();
959 writeln!(code, " Event::Empty(e) => {{").unwrap();
960 writeln!(
961 code,
962 " match e.local_name().as_ref() {{"
963 )
964 .unwrap();
965
966 let mut matched_names_empty = std::collections::HashSet::new();
968 for field in &elem_fields {
969 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
970 let base_name = base_name.trim_start_matches('_');
971 let var_name = format!("f_{}", base_name);
972 let parse_expr = self.gen_element_parse_code(field, true);
973
974 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
976 writeln!(
977 code,
978 " #[cfg(feature = \"{}\")]",
979 feature
980 )
981 .unwrap();
982 }
983 if self.is_eg_content_field(field) {
984 let mut variant_names = Vec::new();
986 let mut visited = std::collections::HashSet::new();
987 if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
988 self.collect_element_variant_names(
989 def_pattern,
990 &mut variant_names,
991 &mut visited,
992 );
993 }
994 variant_names.retain(|n| matched_names_empty.insert(n.clone()));
995 if !variant_names.is_empty() {
996 let arms: Vec<_> = variant_names
997 .iter()
998 .map(|n| format!("b\"{}\"", n))
999 .collect();
1000 writeln!(
1001 code,
1002 " {} => {{",
1003 arms.join(" | ")
1004 )
1005 .unwrap();
1006 } else {
1007 continue;
1009 }
1010 } else {
1011 matched_names_empty.insert(field.xml_name.clone());
1012 writeln!(
1013 code,
1014 " b\"{}\" => {{",
1015 field.xml_name
1016 )
1017 .unwrap();
1018 }
1019 if field.is_vec {
1020 writeln!(
1021 code,
1022 " {}.push({});",
1023 var_name, parse_expr
1024 )
1025 .unwrap();
1026 } else {
1027 writeln!(
1028 code,
1029 " {} = Some({});",
1030 var_name, parse_expr
1031 )
1032 .unwrap();
1033 }
1034 writeln!(
1035 code,
1036 " #[cfg(feature = \"extra-children\")]"
1037 )
1038 .unwrap();
1039 writeln!(
1040 code,
1041 " {{ child_idx += 1; }}"
1042 )
1043 .unwrap();
1044 writeln!(code, " }}").unwrap();
1045 }
1046
1047 writeln!(
1049 code,
1050 " #[cfg(feature = \"extra-children\")]"
1051 )
1052 .unwrap();
1053 writeln!(code, " _ => {{").unwrap();
1054 writeln!(
1055 code,
1056 " // Capture unknown empty element for roundtrip"
1057 )
1058 .unwrap();
1059 writeln!(
1060 code,
1061 " let elem = RawXmlElement::from_empty(&e);"
1062 )
1063 .unwrap();
1064 writeln!(
1065 code,
1066 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
1067 )
1068 .unwrap();
1069 writeln!(code, " child_idx += 1;").unwrap();
1070 writeln!(code, " }}").unwrap();
1071 writeln!(
1072 code,
1073 " #[cfg(not(feature = \"extra-children\"))]"
1074 )
1075 .unwrap();
1076 writeln!(code, " _ => {{}}").unwrap();
1077 writeln!(code, " }}").unwrap();
1078 writeln!(code, " }}").unwrap();
1079
1080 if !text_fields.is_empty() {
1086 writeln!(code, " Event::Text(e) => {{").unwrap();
1087 writeln!(
1088 code,
1089 " let s = e.decode().unwrap_or_default();"
1090 )
1091 .unwrap();
1092 for field in &text_fields {
1093 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1094 let base_name = base_name.trim_start_matches('_');
1095 let var_name = format!("f_{}", base_name);
1096 writeln!(
1097 code,
1098 " {}.get_or_insert_with(String::new).push_str(&s);",
1099 var_name
1100 )
1101 .unwrap();
1102 }
1103 writeln!(code, " }}").unwrap();
1104 writeln!(code, " Event::GeneralRef(e) => {{").unwrap();
1105 writeln!(
1106 code,
1107 " let name = e.decode().unwrap_or_default();"
1108 )
1109 .unwrap();
1110 writeln!(code, " if let Some(s) = quick_xml::escape::resolve_xml_entity(&name) {{").unwrap();
1111 for field in &text_fields {
1112 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1113 let base_name = base_name.trim_start_matches('_');
1114 let var_name = format!("f_{}", base_name);
1115 writeln!(
1116 code,
1117 " {}.get_or_insert_with(String::new).push_str(s);",
1118 var_name
1119 ).unwrap();
1120 }
1121 writeln!(code, " }}").unwrap();
1122 writeln!(code, " }}").unwrap();
1123 }
1124
1125 writeln!(code, " Event::End(_) => break,").unwrap();
1126 writeln!(code, " Event::Eof => break,").unwrap();
1127 writeln!(code, " _ => {{}}").unwrap();
1128 writeln!(code, " }}").unwrap();
1129 writeln!(code, " buf.clear();").unwrap();
1130 writeln!(code, " }}").unwrap();
1131 writeln!(code, " }}").unwrap();
1132 } else {
1133 writeln!(code).unwrap();
1135 writeln!(code, " if !is_empty {{").unwrap();
1136 writeln!(code, " let mut buf = Vec::new();").unwrap();
1137 writeln!(code, " loop {{").unwrap();
1138 writeln!(
1139 code,
1140 " match reader.read_event_into(&mut buf)? {{"
1141 )
1142 .unwrap();
1143 writeln!(code, " Event::End(_) => break,").unwrap();
1144 writeln!(code, " Event::Eof => break,").unwrap();
1145 writeln!(code, " _ => {{}}").unwrap();
1146 writeln!(code, " }}").unwrap();
1147 writeln!(code, " buf.clear();").unwrap();
1148 writeln!(code, " }}").unwrap();
1149 writeln!(code, " }}").unwrap();
1150 }
1151
1152 writeln!(code).unwrap();
1154 writeln!(code, " Ok(Self {{").unwrap();
1155 for field in &fields {
1156 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1157 let base_name = base_name.trim_start_matches('_');
1158 let var_name = format!("f_{}", base_name);
1159
1160 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
1162 writeln!(code, " #[cfg(feature = \"{}\")]", feature).unwrap();
1163 }
1164
1165 let eg_needs_option =
1168 self.is_eg_content_field(field) && !field.is_optional && !field.is_vec;
1169
1170 if field.is_optional || field.is_vec || eg_needs_option {
1171 writeln!(code, " {}: {},", field.name, var_name).unwrap();
1172 } else {
1173 writeln!(
1175 code,
1176 " {}: {}.ok_or_else(|| ParseError::MissingAttribute(\"{}\".to_string()))?,",
1177 field.name, var_name, field.xml_name
1178 )
1179 .unwrap();
1180 }
1181 }
1182 if has_attrs {
1184 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
1185 writeln!(code, " extra_attrs,").unwrap();
1186 }
1187 if has_parsing_loop {
1189 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
1190 writeln!(code, " extra_children,").unwrap();
1191 }
1192 writeln!(code, " }})").unwrap();
1193 writeln!(code, " }}").unwrap();
1194 writeln!(code, "}}").unwrap();
1195
1196 Some(code)
1197 }
1198
1199 fn gen_attr_parse_expr(&self, pattern: &Pattern) -> String {
1200 match pattern {
1201 Pattern::Datatype { library, name, .. } if library == "xsd" => match name.as_str() {
1202 "boolean" => "Some(val == \"true\" || val == \"1\")".to_string(),
1203 "integer" | "int" | "long" | "short" | "byte" => "val.parse().ok()".to_string(),
1204 "unsignedInt" | "unsignedLong" | "unsignedShort" | "unsignedByte" => {
1205 "val.parse().ok()".to_string()
1206 }
1207 "double" | "float" | "decimal" => "val.parse().ok()".to_string(),
1208 "hexBinary" => "decode_hex(&val)".to_string(),
1209 "base64Binary" => "decode_base64(&val)".to_string(),
1210 _ => "Some(val.into_owned())".to_string(),
1211 },
1212 Pattern::Ref(name) => {
1213 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1215 return self.gen_attr_parse_expr(def_pattern);
1216 }
1217 if name.contains("_ST_") {
1219 "val.parse().ok()".to_string()
1220 } else {
1221 "Some(val.into_owned())".to_string()
1222 }
1223 }
1224 Pattern::Choice(variants)
1226 if variants
1227 .iter()
1228 .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1229 {
1230 "val.parse().ok()".to_string()
1231 }
1232 _ => "Some(val.into_owned())".to_string(),
1233 }
1234 }
1235
1236 fn extract_fields(&self, pattern: &Pattern) -> Vec<Field> {
1237 let mut fields = Vec::new();
1238 self.collect_fields(pattern, &mut fields, false);
1239 let mut seen = std::collections::HashSet::new();
1240 fields.retain(|f| seen.insert(f.name.clone()));
1241 fields
1242 }
1243
1244 fn collect_fields(&self, pattern: &Pattern, fields: &mut Vec<Field>, is_optional: bool) {
1245 match pattern {
1246 Pattern::Attribute { name, pattern } => {
1247 fields.push(Field {
1248 name: self.qname_to_field_name(name),
1249 xml_name: name.local.clone(),
1250 xml_prefix: name.prefix.clone(),
1251 pattern: pattern.as_ref().clone(),
1252 is_optional,
1253 is_attribute: true,
1254 is_vec: false,
1255 is_text_content: false,
1256 });
1257 }
1258 Pattern::Element { name, pattern } => {
1259 if name.local == "_any" {
1261 return;
1262 }
1263 fields.push(Field {
1264 name: self.qname_to_field_name(name),
1265 xml_name: name.local.clone(),
1266 xml_prefix: name.prefix.clone(),
1267 pattern: pattern.as_ref().clone(),
1268 is_optional,
1269 is_attribute: false,
1270 is_vec: false,
1271 is_text_content: false,
1272 });
1273 }
1274 Pattern::Sequence(items) | Pattern::Interleave(items) => {
1275 for item in items {
1276 self.collect_fields(item, fields, is_optional);
1277 }
1278 }
1279 Pattern::Optional(inner) => {
1280 self.collect_fields(inner, fields, true);
1281 }
1282 Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => match inner.as_ref() {
1283 Pattern::Element { name, pattern } if name.local != "_any" => {
1284 fields.push(Field {
1285 name: self.qname_to_field_name(name),
1286 xml_name: name.local.clone(),
1287 xml_prefix: name.prefix.clone(),
1288 pattern: pattern.as_ref().clone(),
1289 is_optional: false,
1290 is_attribute: false,
1291 is_vec: true,
1292 is_text_content: false,
1293 });
1294 }
1295 Pattern::Ref(name) if name.contains("_EG_") => {
1296 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1297 if self.is_element_choice(def_pattern) {
1298 fields.push(Field {
1300 name: self.eg_ref_to_field_name(name),
1301 xml_name: name.clone(),
1302 xml_prefix: None,
1303 pattern: Pattern::Ref(name.clone()),
1304 is_optional: false,
1305 is_attribute: false,
1306 is_vec: true,
1307 is_text_content: false,
1308 });
1309 } else {
1310 self.collect_fields(def_pattern, fields, true);
1312 }
1313 }
1314 }
1315 Pattern::Choice(alternatives) => {
1316 for alt in alternatives {
1318 self.collect_fields_as_vec(alt, fields);
1319 }
1320 }
1321 Pattern::Ref(_) => {
1322 self.collect_fields(inner, fields, false);
1323 }
1324 Pattern::Group(group_inner) => {
1325 if let Pattern::Choice(alternatives) = group_inner.as_ref() {
1328 for alt in alternatives {
1329 self.collect_fields_as_vec(alt, fields);
1330 }
1331 } else {
1332 self.collect_fields(group_inner, fields, false);
1333 }
1334 }
1335 _ => {}
1336 },
1337 Pattern::Group(inner) => {
1338 self.collect_fields(inner, fields, is_optional);
1339 }
1340 Pattern::Ref(name) => {
1341 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1342 if name.contains("_EG_") {
1343 if self.is_element_choice(def_pattern) {
1344 fields.push(Field {
1346 name: self.eg_ref_to_field_name(name),
1347 xml_name: name.clone(),
1348 xml_prefix: None,
1349 pattern: Pattern::Ref(name.clone()),
1350 is_optional,
1351 is_attribute: false,
1352 is_vec: false,
1353 is_text_content: false,
1354 });
1355 } else {
1356 self.collect_fields(def_pattern, fields, is_optional);
1358 }
1359 } else if name.contains("_AG_") {
1360 self.collect_fields(def_pattern, fields, is_optional);
1362 } else if self.is_string_type(def_pattern) {
1363 fields.push(Field {
1366 name: "text".to_string(),
1367 xml_name: "$text".to_string(),
1368 xml_prefix: None,
1369 pattern: Pattern::Datatype {
1370 library: "xsd".to_string(),
1371 name: "string".to_string(),
1372 params: vec![],
1373 },
1374 is_optional: true,
1375 is_attribute: false,
1376 is_vec: false,
1377 is_text_content: true,
1378 });
1379 } else {
1380 self.collect_fields(def_pattern, fields, is_optional);
1382 }
1383 }
1384 }
1385 Pattern::Choice(alternatives) => {
1386 for alt in alternatives {
1389 self.collect_fields(alt, fields, true);
1390 }
1391 }
1392 _ => {}
1393 }
1394 }
1395
1396 fn collect_fields_as_vec(&self, pattern: &Pattern, fields: &mut Vec<Field>) {
1399 match pattern {
1400 Pattern::Element {
1401 name,
1402 pattern: inner_pattern,
1403 } if name.local != "_any" => {
1404 fields.push(Field {
1405 name: self.qname_to_field_name(name),
1406 xml_name: name.local.clone(),
1407 xml_prefix: name.prefix.clone(),
1408 pattern: inner_pattern.as_ref().clone(),
1409 is_optional: false,
1410 is_attribute: false,
1411 is_vec: true,
1412 is_text_content: false,
1413 });
1414 }
1415 Pattern::Optional(inner) => {
1416 self.collect_fields(inner, fields, true);
1419 }
1420 Pattern::Group(inner) => {
1421 self.collect_fields_as_vec(inner, fields);
1422 }
1423 Pattern::Ref(name) => {
1424 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1426 if name.contains("_EG_") && self.is_element_choice(def_pattern) {
1427 fields.push(Field {
1429 name: self.eg_ref_to_field_name(name),
1430 xml_name: name.clone(),
1431 xml_prefix: None,
1432 pattern: Pattern::Ref(name.clone()),
1433 is_optional: false,
1434 is_attribute: false,
1435 is_vec: true,
1436 is_text_content: false,
1437 });
1438 } else if !name.contains("_AG_") && !name.contains("_CT_") {
1439 self.collect_fields_as_vec(def_pattern, fields);
1441 }
1442 }
1443 }
1444 _ => {}
1445 }
1446 }
1447
1448 fn is_string_type(&self, pattern: &Pattern) -> bool {
1450 match pattern {
1451 Pattern::Datatype { library, name, .. } => {
1452 library == "xsd" && (name == "string" || name == "token" || name == "NCName")
1453 }
1454 Pattern::Ref(name) => {
1455 self.definitions
1457 .get(name.as_str())
1458 .is_some_and(|p| self.is_string_type(p))
1459 }
1460 _ => false,
1461 }
1462 }
1463
1464 fn to_rust_type_name(&self, name: &str) -> String {
1465 let spec_name = strip_namespace_prefix(name);
1466 if let Some(mappings) = &self.config.name_mappings
1467 && let Some(mapped) = mappings.resolve_type(&self.config.module_name, spec_name)
1468 {
1469 return mapped.to_string();
1470 }
1471 to_pascal_case(spec_name)
1472 }
1473
1474 fn resolve_cross_crate_type(&self, name: &str) -> Option<String> {
1477 for (prefix, (crate_path, module_name)) in &self.config.cross_crate_type_prefix {
1478 if name.starts_with(prefix) {
1479 let spec_name = strip_namespace_prefix(name);
1481 let rust_type_name = if let Some(mappings) = &self.config.name_mappings
1482 && let Some(mapped) = mappings.resolve_type(module_name, spec_name)
1483 {
1484 mapped.to_string()
1485 } else {
1486 to_pascal_case(spec_name)
1487 };
1488 return Some(format!("{}{}", crate_path, rust_type_name));
1489 }
1490 }
1491 None
1492 }
1493
1494 fn to_rust_variant_name(&self, name: &str) -> String {
1495 if name.is_empty() {
1496 return "Empty".to_string();
1497 }
1498 if let Some(mappings) = &self.config.name_mappings
1499 && let Some(mapped) = mappings.resolve_variant(&self.config.module_name, name)
1500 {
1501 return mapped.to_string();
1502 }
1503 let name = to_pascal_case(name);
1504 if name.chars().next().is_some_and(|c| c.is_ascii_digit()) {
1505 format!("_{}", name)
1506 } else {
1507 name
1508 }
1509 }
1510
1511 fn qname_to_field_name(&self, qname: &QName) -> String {
1512 if let Some(mappings) = &self.config.name_mappings
1513 && let Some(mapped) = mappings.resolve_field(&self.config.module_name, &qname.local)
1514 {
1515 return mapped.to_string();
1516 }
1517 to_snake_case(&qname.local)
1518 }
1519
1520 fn get_field_feature(&self, struct_name: &str, xml_field_name: &str) -> Option<String> {
1523 self.config
1524 .feature_mappings
1525 .as_ref()
1526 .and_then(|fm| {
1527 fm.primary_feature(&self.config.module_name, struct_name, xml_field_name)
1528 })
1529 .map(|feature| format!("{}-{}", self.config.module_name, feature))
1530 }
1531
1532 fn is_element_wrapper_type_alias(&self, name: &str) -> bool {
1535 if let Some(def_pattern) = self.definitions.get(name) {
1536 matches!(def_pattern, Pattern::Element { pattern, .. } if matches!(pattern.as_ref(), Pattern::Ref(_)))
1537 } else {
1538 false
1539 }
1540 }
1541
1542 fn pattern_to_rust_type(&self, pattern: &Pattern, is_vec: bool) -> (String, bool) {
1545 match pattern {
1546 Pattern::Ref(name) => {
1547 if self.definitions.contains_key(name.as_str()) {
1548 let type_name = self.to_rust_type_name(name);
1549 let is_complex = name.contains("_CT_") || name.contains("_EG_");
1552 let is_already_boxed = self.is_element_wrapper_type_alias(name);
1553 let needs_box = is_complex && !is_vec && !is_already_boxed;
1554 (type_name, needs_box)
1555 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1556 let is_complex = name.contains("_CT_") || name.contains("_EG_");
1558 let needs_box = is_complex && !is_vec;
1559 (cross_crate, needs_box)
1560 } else {
1561 ("String".to_string(), false)
1562 }
1563 }
1564 Pattern::Datatype { library, name, .. } => {
1565 (xsd_to_rust(library, name).to_string(), false)
1566 }
1567 Pattern::Empty => ("()".to_string(), false),
1568 Pattern::StringLiteral(_) => ("String".to_string(), false),
1569 Pattern::Choice(_) => ("String".to_string(), false),
1570 _ => ("String".to_string(), false),
1571 }
1572 }
1573
1574 fn gen_element_parse_code(&self, field: &Field, is_empty_element: bool) -> String {
1577 let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, field.is_vec);
1579 let strategy = self.get_parse_strategy(&field.pattern);
1580
1581 let parse_expr = match strategy {
1582 ParseStrategy::FromXml => {
1583 let (actual_type, type_alias_has_box) =
1586 self.resolve_from_xml_type_with_box(&field.pattern);
1587 let final_type = actual_type.unwrap_or(rust_type.clone());
1588
1589 let mut expr = format!(
1590 "{}::from_xml(reader, &e, {})?",
1591 final_type, is_empty_element
1592 );
1593
1594 if type_alias_has_box {
1596 expr = format!("Box::new({})", expr);
1597 }
1598
1599 if needs_box {
1601 expr = format!("Box::new({})", expr);
1602 }
1603
1604 return expr;
1605 }
1606 ParseStrategy::TextFromStr => {
1607 if is_empty_element {
1608 "Default::default()".to_string()
1610 } else {
1611 "{ let text = read_text_content(reader)?; text.parse().map_err(|_| ParseError::InvalidValue(text))? }".to_string()
1612 }
1613 }
1614 ParseStrategy::TextString => {
1615 if is_empty_element {
1616 "String::new()".to_string()
1617 } else {
1618 "read_text_content(reader)?".to_string()
1619 }
1620 }
1621 ParseStrategy::TextHexBinary => {
1622 if is_empty_element {
1623 "Vec::new()".to_string()
1624 } else {
1625 "{ let text = read_text_content(reader)?; decode_hex(&text).unwrap_or_default() }".to_string()
1626 }
1627 }
1628 ParseStrategy::TextBase64Binary => {
1629 if is_empty_element {
1630 "Vec::new()".to_string()
1631 } else {
1632 "{ let text = read_text_content(reader)?; decode_base64(&text).unwrap_or_default() }".to_string()
1633 }
1634 }
1635 };
1636
1637 if strategy != ParseStrategy::FromXml && needs_box {
1639 format!("Box::new({})", parse_expr)
1640 } else {
1641 parse_expr
1642 }
1643 }
1644
1645 fn resolve_from_xml_type_with_box(&self, pattern: &Pattern) -> (Option<String>, bool) {
1650 match pattern {
1651 Pattern::Ref(name) => {
1652 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1654 if self.is_inline_attribute_ref(name, def_pattern) {
1656 return (None, false);
1657 }
1658 if let Pattern::Element { pattern: inner, .. } = def_pattern
1662 && let Some(inner_type) = self.resolve_from_xml_type_simple(inner)
1663 {
1664 let type_alias_has_box = if let Pattern::Ref(inner_name) = inner.as_ref() {
1666 inner_name.contains("_CT_") || inner_name.contains("_EG_")
1667 } else {
1668 false
1669 };
1670 return (Some(inner_type), type_alias_has_box);
1671 }
1672 if name.contains("_CT_") {
1676 return (Some(self.to_rust_type_name(name)), false);
1677 }
1678 if let Pattern::Ref(inner_name) = def_pattern
1681 && !self.definitions.contains_key(inner_name.as_str())
1682 {
1683 if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1685 return (Some(cross_crate), false);
1686 }
1687 return (None, false);
1689 } else if let Pattern::Ref(inner_name) = def_pattern {
1690 return self
1691 .resolve_from_xml_type_with_box(&Pattern::Ref(inner_name.clone()));
1692 }
1693 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1694 return (Some(cross_crate), false);
1696 }
1697 (Some(self.to_rust_type_name(name)), false)
1699 }
1700 _ => (None, false),
1701 }
1702 }
1703
1704 fn resolve_from_xml_type_simple(&self, pattern: &Pattern) -> Option<String> {
1706 match pattern {
1707 Pattern::Ref(name) => {
1708 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1709 if let Pattern::Element { pattern: inner, .. } = def_pattern {
1710 return self.resolve_from_xml_type_simple(inner);
1711 }
1712 if let Pattern::Ref(inner_name) = def_pattern {
1713 if !self.definitions.contains_key(inner_name.as_str()) {
1715 if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1717 return Some(cross_crate);
1718 }
1719 return None;
1721 }
1722 return self
1723 .resolve_from_xml_type_simple(&Pattern::Ref(inner_name.clone()));
1724 }
1725 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1726 return Some(cross_crate);
1728 }
1729 Some(self.to_rust_type_name(name))
1730 }
1731 _ => None,
1732 }
1733 }
1734
1735 fn get_parse_strategy(&self, pattern: &Pattern) -> ParseStrategy {
1737 match pattern {
1738 Pattern::Ref(name) => {
1739 if name.contains("_CT_") || name.contains("_EG_") {
1741 return ParseStrategy::FromXml;
1742 }
1743
1744 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1746 if let Pattern::Ref(inner_name) = def_pattern
1749 && !self.definitions.contains_key(inner_name.as_str())
1750 {
1751 if inner_name.contains("_CT_") || inner_name.contains("_EG_") {
1753 return ParseStrategy::FromXml;
1754 }
1755 return ParseStrategy::FromXml;
1758 }
1759 return self.get_parse_strategy(def_pattern);
1760 } else if self.resolve_cross_crate_type(name).is_some() {
1761 return ParseStrategy::FromXml;
1763 }
1764
1765 ParseStrategy::TextString
1767 }
1768 Pattern::Datatype { library, name, .. } => {
1769 if library == "xsd" {
1770 match name.as_str() {
1771 "string" | "token" | "NCName" | "ID" | "IDREF" | "anyURI" | "dateTime"
1772 | "date" | "time" => ParseStrategy::TextString,
1773 "hexBinary" => ParseStrategy::TextHexBinary,
1774 "base64Binary" => ParseStrategy::TextBase64Binary,
1775 _ => ParseStrategy::TextFromStr,
1777 }
1778 } else {
1779 ParseStrategy::TextString
1780 }
1781 }
1782 Pattern::Choice(variants)
1784 if variants
1785 .iter()
1786 .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1787 {
1788 ParseStrategy::TextFromStr
1789 }
1790 Pattern::StringLiteral(_) => ParseStrategy::TextString,
1791 Pattern::Empty => ParseStrategy::TextString,
1792 Pattern::List(_) => ParseStrategy::TextString,
1793 _ => ParseStrategy::FromXml,
1795 }
1796 }
1797}
1798
1799pub(crate) struct Field {
1800 pub name: String,
1801 pub xml_name: String,
1802 pub xml_prefix: Option<String>,
1803 pub pattern: Pattern,
1804 pub is_optional: bool,
1805 pub is_attribute: bool,
1806 pub is_vec: bool,
1807 pub is_text_content: bool,
1808}
1809
1810pub(crate) fn strip_namespace_prefix(name: &str) -> &str {
1811 for kind in ["CT_", "ST_", "EG_"] {
1812 if let Some(pos) = name.find(kind)
1813 && pos > 0
1814 {
1815 return &name[pos..];
1816 }
1817 }
1818 name
1819}
1820
1821pub(crate) fn to_pascal_case(s: &str) -> String {
1822 let mut result = String::new();
1823 let mut capitalize_next = true;
1824 for ch in s.chars() {
1825 if ch == '_' || ch == '-' {
1826 capitalize_next = true;
1827 } else if capitalize_next {
1828 result.extend(ch.to_uppercase());
1829 capitalize_next = false;
1830 } else {
1831 result.push(ch);
1832 }
1833 }
1834 result
1835}
1836
1837pub(crate) fn to_snake_case(s: &str) -> String {
1838 let mut result = String::new();
1839 for (i, ch) in s.chars().enumerate() {
1840 if ch.is_uppercase() && i > 0 {
1841 result.push('_');
1842 }
1843 result.extend(ch.to_lowercase());
1844 }
1845 match result.as_str() {
1846 "type" => "r#type".to_string(),
1848 "ref" => "r#ref".to_string(),
1849 "match" => "r#match".to_string(),
1850 "in" => "r#in".to_string(),
1851 "for" => "r#for".to_string(),
1852 "macro" => "r#macro".to_string(),
1853 "if" => "r#if".to_string(),
1854 "else" => "r#else".to_string(),
1855 "loop" => "r#loop".to_string(),
1856 "break" => "r#break".to_string(),
1857 "continue" => "r#continue".to_string(),
1858 "return" => "r#return".to_string(),
1859 "self" => "r#self".to_string(),
1860 "super" => "r#super".to_string(),
1861 "crate" => "r#crate".to_string(),
1862 "mod" => "r#mod".to_string(),
1863 "pub" => "r#pub".to_string(),
1864 "use" => "r#use".to_string(),
1865 "as" => "r#as".to_string(),
1866 "static" => "r#static".to_string(),
1867 "const" => "r#const".to_string(),
1868 "extern" => "r#extern".to_string(),
1869 "fn" => "r#fn".to_string(),
1870 "struct" => "r#struct".to_string(),
1871 "enum" => "r#enum".to_string(),
1872 "trait" => "r#trait".to_string(),
1873 "impl" => "r#impl".to_string(),
1874 "where" => "r#where".to_string(),
1875 "async" => "r#async".to_string(),
1876 "await" => "r#await".to_string(),
1877 "move" => "r#move".to_string(),
1878 "box" => "r#box".to_string(),
1879 "dyn" => "r#dyn".to_string(),
1880 "abstract" => "r#abstract".to_string(),
1881 "become" => "r#become".to_string(),
1882 "do" => "r#do".to_string(),
1883 "final" => "r#final".to_string(),
1884 "override" => "r#override".to_string(),
1885 "priv" => "r#priv".to_string(),
1886 "typeof" => "r#typeof".to_string(),
1887 "unsized" => "r#unsized".to_string(),
1888 "virtual" => "r#virtual".to_string(),
1889 "yield" => "r#yield".to_string(),
1890 "try" => "r#try".to_string(),
1891 _ => result,
1892 }
1893}
1894
1895pub(crate) fn xsd_to_rust(library: &str, name: &str) -> &'static str {
1896 if library == "xsd" {
1897 match name {
1898 "string" => "String",
1899 "integer" => "i64",
1900 "int" => "i32",
1901 "long" => "i64",
1902 "short" => "i16",
1903 "byte" => "i8",
1904 "unsignedInt" => "u32",
1905 "unsignedLong" => "u64",
1906 "unsignedShort" => "u16",
1907 "unsignedByte" => "u8",
1908 "boolean" => "bool",
1909 "double" => "f64",
1910 "float" => "f32",
1911 "decimal" => "f64",
1912 "hexBinary" | "base64Binary" => "Vec<u8>",
1913 _ => "String",
1914 }
1915 } else {
1916 "String"
1917 }
1918}