1use std::collections::HashMap;
2
3use mf_model::{
4 mark_type::MarkSpec,
5 node_type::NodeSpec,
6 schema::{AttributeSpec, SchemaSpec},
7};
8use serde_json::Value;
9
10use crate::{
11 extension::Extension,
12 mark::Mark,
13 node::Node,
14 types::{Extensions, GlobalAttributeItem},
15};
16
17use super::error::{XmlSchemaError, XmlSchemaResult};
18use super::types::{
19 deserialize_optional_bool, deserialize_optional_value, XmlAttr, XmlAttrs,
20 XmlGlobalAttribute, XmlGlobalAttributes, XmlInclude, XmlIncludes,
21 XmlImport, XmlImports, XmlMark, XmlMarks, XmlNode, XmlNodes, XmlSchema,
22 XmlSchemaWithReferences,
23};
24
25pub struct XmlSchemaParser;
27
28#[derive(Debug, Clone)]
30pub struct MultiFileParseContext {
31 pub base_path: std::path::PathBuf,
32 pub parsed_files: std::collections::HashSet<std::path::PathBuf>,
33 pub max_depth: usize,
34 pub current_depth: usize,
35}
36
37impl XmlSchemaParser {
38 pub fn parse_from_str(xml_content: &str) -> XmlSchemaResult<SchemaSpec> {
39 let xml_schema: XmlSchema = quick_xml::de::from_str(xml_content)?;
40 Self::convert_to_schema_spec(xml_schema)
41 }
42
43 pub fn parse_from_file(file_path: &str) -> XmlSchemaResult<SchemaSpec> {
44 let xml_content = std::fs::read_to_string(file_path).map_err(|e| {
45 XmlSchemaError::XmlParseError(quick_xml::Error::Io(e.into()))
46 })?;
47 Self::parse_from_str(&xml_content)
48 }
49
50 pub fn parse_to_extensions(
51 xml_content: &str
52 ) -> XmlSchemaResult<Vec<Extensions>> {
53 if let Ok(xml_schema_with_refs) =
54 quick_xml::de::from_str::<XmlSchemaWithReferences>(xml_content)
55 {
56 Self::convert_xml_schema_with_refs_to_extensions(
57 xml_schema_with_refs,
58 )
59 } else {
60 let xml_schema: XmlSchema = quick_xml::de::from_str(xml_content)?;
61 Self::convert_to_extensions(xml_schema)
62 }
63 }
64
65 pub fn parse_extensions_from_file(
66 file_path: &str
67 ) -> XmlSchemaResult<Vec<Extensions>> {
68 let xml_content = std::fs::read_to_string(file_path).map_err(|e| {
69 XmlSchemaError::XmlParseError(quick_xml::Error::Io(e.into()))
70 })?;
71 Self::parse_to_extensions(&xml_content)
72 }
73
74 pub fn parse_multi_file(file_path: &str) -> XmlSchemaResult<SchemaSpec> {
75 let root_path =
76 std::path::Path::new(file_path).canonicalize().map_err(|e| {
77 XmlSchemaError::FileNotFound(format!(
78 "无法找到文件 {}: {}",
79 file_path, e
80 ))
81 })?;
82
83 let mut context = MultiFileParseContext {
84 base_path: root_path
85 .parent()
86 .unwrap_or_else(|| std::path::Path::new("."))
87 .to_path_buf(),
88 parsed_files: std::collections::HashSet::new(),
89 max_depth: 10,
90 current_depth: 0,
91 };
92
93 Self::parse_file_with_context_new(&root_path, &mut context)
94 }
95
96 fn parse_file_with_context_new(
97 file_path: &std::path::Path,
98 context: &mut MultiFileParseContext,
99 ) -> XmlSchemaResult<SchemaSpec> {
100 if context.current_depth >= context.max_depth {
101 return Err(XmlSchemaError::CircularReference(format!(
102 "解析深度超过限制: {}",
103 context.max_depth
104 )));
105 }
106
107 let canonical_path = file_path.canonicalize().map_err(|e| {
108 XmlSchemaError::FileNotFound(format!(
109 "无法解析文件路径 {:?}: {}",
110 file_path, e
111 ))
112 })?;
113
114 if context.parsed_files.contains(&canonical_path) {
115 return Err(XmlSchemaError::CircularReference(format!(
116 "检测到循环引用: {:?}",
117 canonical_path
118 )));
119 }
120
121 context.parsed_files.insert(canonical_path.clone());
122 context.current_depth += 1;
123
124 let xml_content =
125 std::fs::read_to_string(&canonical_path).map_err(|e| {
126 XmlSchemaError::FileNotFound(format!(
127 "无法读取文件 {:?}: {}",
128 canonical_path, e
129 ))
130 })?;
131
132 let xml_schema: XmlSchemaWithReferences =
133 quick_xml::de::from_str(&xml_content)?;
134
135 let mut merged_spec = SchemaSpec {
136 nodes: HashMap::new(),
137 marks: HashMap::new(),
138 top_node: xml_schema.top_node.clone(),
139 };
140
141 let old_base_path = context.base_path.clone();
142 if let Some(parent) = canonical_path.parent() {
143 context.base_path = parent.to_path_buf();
144 }
145
146 if let Some(imports) = xml_schema.imports {
147 for import in imports.imports {
148 let import_path = Self::resolve_relative_path(
149 &context.base_path,
150 &import.src,
151 )?;
152 let imported_spec =
153 Self::parse_file_with_context_new(&import_path, context)?;
154 Self::merge_schema_spec(
155 &mut merged_spec,
156 imported_spec,
157 false,
158 )?;
159 }
160 }
161
162 if let Some(includes) = xml_schema.includes {
163 for include in includes.includes {
164 let include_path = Self::resolve_relative_path(
165 &context.base_path,
166 &include.src,
167 )?;
168 let included_spec =
169 Self::parse_file_with_context_new(&include_path, context)?;
170 Self::merge_schema_spec(&mut merged_spec, included_spec, true)?;
171 }
172 }
173
174 context.base_path = old_base_path;
175
176 let current_spec = Self::convert_xml_schema_to_spec(XmlSchema {
177 top_node: xml_schema.top_node,
178 nodes: xml_schema.nodes,
179 marks: xml_schema.marks,
180 })?;
181
182 Self::merge_schema_spec(&mut merged_spec, current_spec, true)?;
183
184 context.current_depth -= 1;
185 Ok(merged_spec)
186 }
187
188 fn resolve_relative_path(
189 base_path: &std::path::Path,
190 relative_path: &str,
191 ) -> XmlSchemaResult<std::path::PathBuf> {
192 let path = if std::path::Path::new(relative_path).is_absolute() {
193 std::path::PathBuf::from(relative_path)
194 } else {
195 base_path.join(relative_path)
196 };
197
198 path.canonicalize().map_err(|e| {
199 XmlSchemaError::PathResolutionError(format!(
200 "无法解析路径 {} (基于 {:?}): {}",
201 relative_path, base_path, e
202 ))
203 })
204 }
205
206 pub fn parse_multi_file_to_extensions(
207 file_path: &str
208 ) -> XmlSchemaResult<Vec<Extensions>> {
209 let root_path =
210 std::path::Path::new(file_path).canonicalize().map_err(|e| {
211 XmlSchemaError::FileNotFound(format!(
212 "无法找到文件 {}: {}",
213 file_path, e
214 ))
215 })?;
216
217 let mut context = MultiFileParseContext {
218 base_path: root_path
219 .parent()
220 .unwrap_or_else(|| std::path::Path::new("."))
221 .to_path_buf(),
222 parsed_files: std::collections::HashSet::new(),
223 max_depth: 10,
224 current_depth: 0,
225 };
226
227 Self::parse_file_to_extensions_with_context_new(
228 &root_path,
229 &mut context,
230 )
231 }
232
233 fn parse_file_to_extensions_with_context_new(
234 file_path: &std::path::Path,
235 context: &mut MultiFileParseContext,
236 ) -> XmlSchemaResult<Vec<Extensions>> {
237 if context.current_depth >= context.max_depth {
238 return Err(XmlSchemaError::CircularReference(format!(
239 "解析深度超过限制: {}",
240 context.max_depth
241 )));
242 }
243
244 let canonical_path = file_path.canonicalize().map_err(|e| {
245 XmlSchemaError::FileNotFound(format!(
246 "无法解析文件路径 {:?}: {}",
247 file_path, e
248 ))
249 })?;
250
251 if context.parsed_files.contains(&canonical_path) {
252 return Err(XmlSchemaError::CircularReference(format!(
253 "检测到循环引用: {:?}",
254 canonical_path
255 )));
256 }
257
258 context.parsed_files.insert(canonical_path.clone());
259 context.current_depth += 1;
260
261 let xml_content =
262 std::fs::read_to_string(&canonical_path).map_err(|e| {
263 XmlSchemaError::FileNotFound(format!(
264 "无法读取文件 {:?}: {}",
265 canonical_path, e
266 ))
267 })?;
268
269 let xml_schema: XmlSchemaWithReferences =
270 quick_xml::de::from_str(&xml_content)?;
271
272 let mut all_extensions = Vec::new();
273
274 let old_base_path = context.base_path.clone();
275 if let Some(parent) = canonical_path.parent() {
276 context.base_path = parent.to_path_buf();
277 }
278
279 if let Some(imports) = &xml_schema.imports {
280 for import in &imports.imports {
281 let import_path = Self::resolve_relative_path(
282 &context.base_path,
283 &import.src,
284 )?;
285 let imported_extensions =
286 Self::parse_file_to_extensions_with_context_new(
287 &import_path,
288 context,
289 )?;
290 all_extensions.extend(imported_extensions);
291 }
292 }
293
294 if let Some(includes) = &xml_schema.includes {
295 for include in &includes.includes {
296 let include_path = Self::resolve_relative_path(
297 &context.base_path,
298 &include.src,
299 )?;
300 let included_extensions =
301 Self::parse_file_to_extensions_with_context_new(
302 &include_path,
303 context,
304 )?;
305 all_extensions.extend(included_extensions);
306 }
307 }
308
309 context.base_path = old_base_path;
310
311 let current_schema = XmlSchema {
312 top_node: xml_schema.top_node,
313 nodes: xml_schema.nodes,
314 marks: xml_schema.marks,
315 };
316 let current_extensions = Self::convert_to_extensions(current_schema)?;
317 all_extensions.extend(current_extensions);
318
319 if let Some(xml_global_attrs) = &xml_schema.global_attributes {
320 let mut extension = Extension::new();
321 for xml_global_attr in &xml_global_attrs.global_attributes {
322 let global_attr_item =
323 Self::convert_xml_global_attribute_to_item(
324 xml_global_attr.clone(),
325 )?;
326 extension.add_global_attribute(global_attr_item);
327 }
328 all_extensions.push(Extensions::E(extension));
329 }
330
331 context.current_depth -= 1;
332 Ok(all_extensions)
333 }
334
335 pub fn parse_file_to_extensions_with_context(
336 file_path: &str,
337 context: &mut MultiFileParseContext,
338 ) -> XmlSchemaResult<Vec<Extensions>> {
339 if context.current_depth >= context.max_depth {
340 return Err(XmlSchemaError::CircularReference(format!(
341 "解析深度超过限制: {}",
342 context.max_depth
343 )));
344 }
345
346 let file_path_buf = if std::path::Path::new(file_path).is_absolute() {
347 std::path::PathBuf::from(file_path)
348 } else {
349 context.base_path.join(file_path)
350 };
351
352 let canonical_path = file_path_buf.canonicalize().map_err(|e| {
353 XmlSchemaError::FileNotFound(format!(
354 "无法解析文件路径 {}: {}",
355 file_path, e
356 ))
357 })?;
358
359 if context.parsed_files.contains(&canonical_path) {
360 return Err(XmlSchemaError::CircularReference(format!(
361 "检测到循环引用: {:?}",
362 canonical_path
363 )));
364 }
365
366 context.parsed_files.insert(canonical_path.clone());
367 context.current_depth += 1;
368
369 let xml_content =
370 std::fs::read_to_string(&canonical_path).map_err(|e| {
371 XmlSchemaError::FileNotFound(format!(
372 "无法读取文件 {:?}: {}",
373 canonical_path, e
374 ))
375 })?;
376
377 let xml_schema: XmlSchemaWithReferences =
378 quick_xml::de::from_str(&xml_content)?;
379
380 let mut all_extensions = Vec::new();
381
382 let old_base_path = context.base_path.clone();
383 if let Some(parent) = canonical_path.parent() {
384 context.base_path = parent.to_path_buf();
385 }
386
387 if let Some(imports) = &xml_schema.imports {
388 for import in &imports.imports {
389 let imported_extensions =
390 Self::parse_file_to_extensions_with_context(
391 &import.src,
392 context,
393 )?;
394 all_extensions.extend(imported_extensions);
395 }
396 }
397
398 if let Some(includes) = &xml_schema.includes {
399 for include in &includes.includes {
400 let included_extensions =
401 Self::parse_file_to_extensions_with_context(
402 &include.src,
403 context,
404 )?;
405 all_extensions.extend(included_extensions);
406 }
407 }
408
409 context.base_path = old_base_path;
410
411 let current_schema = XmlSchema {
412 top_node: xml_schema.top_node,
413 nodes: xml_schema.nodes,
414 marks: xml_schema.marks,
415 };
416 let current_extensions = Self::convert_to_extensions(current_schema)?;
417 all_extensions.extend(current_extensions);
418
419 if let Some(xml_global_attrs) = &xml_schema.global_attributes {
420 let mut extension = Extension::new();
421 for xml_global_attr in &xml_global_attrs.global_attributes {
422 let global_attr_item =
423 Self::convert_xml_global_attribute_to_item(
424 xml_global_attr.clone(),
425 )?;
426 extension.add_global_attribute(global_attr_item);
427 }
428 all_extensions.push(Extensions::E(extension));
429 }
430
431 context.current_depth -= 1;
432 Ok(all_extensions)
433 }
434
435 pub fn parse_file_with_context(
436 file_path: &str,
437 context: &mut MultiFileParseContext,
438 ) -> XmlSchemaResult<SchemaSpec> {
439 if context.current_depth >= context.max_depth {
440 return Err(XmlSchemaError::CircularReference(format!(
441 "解析深度超过限制: {}",
442 context.max_depth
443 )));
444 }
445
446 let file_path_buf = if std::path::Path::new(file_path).is_absolute() {
447 std::path::PathBuf::from(file_path)
448 } else {
449 context.base_path.join(file_path)
450 };
451
452 let canonical_path = file_path_buf.canonicalize().map_err(|e| {
453 XmlSchemaError::FileNotFound(format!(
454 "无法解析文件路径 {}: {}",
455 file_path, e
456 ))
457 })?;
458
459 if context.parsed_files.contains(&canonical_path) {
460 return Err(XmlSchemaError::CircularReference(format!(
461 "检测到循环引用: {:?}",
462 canonical_path
463 )));
464 }
465
466 context.parsed_files.insert(canonical_path.clone());
467 context.current_depth += 1;
468
469 let xml_content =
470 std::fs::read_to_string(&canonical_path).map_err(|e| {
471 XmlSchemaError::FileNotFound(format!(
472 "无法读取文件 {:?}: {}",
473 canonical_path, e
474 ))
475 })?;
476
477 let xml_schema: XmlSchemaWithReferences =
478 quick_xml::de::from_str(&xml_content)?;
479
480 let mut merged_spec = SchemaSpec {
481 nodes: HashMap::new(),
482 marks: HashMap::new(),
483 top_node: xml_schema.top_node.clone(),
484 };
485
486 let old_base_path = context.base_path.clone();
487 if let Some(parent) = canonical_path.parent() {
488 context.base_path = parent.to_path_buf();
489 }
490
491 if let Some(imports) = xml_schema.imports {
492 for import in imports.imports {
493 let imported_spec =
494 Self::parse_file_with_context(&import.src, context)?;
495 Self::merge_schema_spec(
496 &mut merged_spec,
497 imported_spec,
498 false,
499 )?;
500 }
501 }
502
503 if let Some(includes) = xml_schema.includes {
504 for include in includes.includes {
505 let included_spec =
506 Self::parse_file_with_context(&include.src, context)?;
507 Self::merge_schema_spec(&mut merged_spec, included_spec, true)?;
508 }
509 }
510
511 context.base_path = old_base_path;
512
513 let current_spec = Self::convert_xml_schema_to_spec(XmlSchema {
514 top_node: xml_schema.top_node,
515 nodes: xml_schema.nodes,
516 marks: xml_schema.marks,
517 })?;
518 Self::merge_schema_spec(&mut merged_spec, current_spec, true)?;
519
520 context.current_depth -= 1;
521 Ok(merged_spec)
522 }
523
524 pub fn convert_to_extensions_from_spec(
525 schema_spec: SchemaSpec
526 ) -> XmlSchemaResult<Vec<Extensions>> {
527 let xml_schema = XmlSchema {
528 top_node: schema_spec.top_node,
529 nodes: Some(XmlNodes {
530 nodes: schema_spec
531 .nodes
532 .into_iter()
533 .map(|(name, spec)| XmlNode {
534 name,
535 group: spec.group,
536 desc: spec.desc,
537 content: spec.content,
538 marks: spec.marks,
539 attrs: spec.attrs.map(|attrs| XmlAttrs {
540 attrs: attrs
541 .into_iter()
542 .map(|(name, attr_spec)| XmlAttr {
543 name,
544 default: attr_spec.default,
545 })
546 .collect(),
547 }),
548 })
549 .collect(),
550 }),
551 marks: Some(XmlMarks {
552 marks: schema_spec
553 .marks
554 .into_iter()
555 .map(|(name, spec)| XmlMark {
556 name,
557 group: spec.group,
558 desc: spec.desc,
559 excludes: spec.excludes,
560 spanning: spec.spanning,
561 attrs: spec.attrs.map(|attrs| XmlAttrs {
562 attrs: attrs
563 .into_iter()
564 .map(|(name, attr_spec)| XmlAttr {
565 name,
566 default: attr_spec.default,
567 })
568 .collect(),
569 }),
570 })
571 .collect(),
572 }),
573 };
574
575 Self::convert_to_extensions(xml_schema)
576 }
577
578 fn merge_schema_spec(
579 target: &mut SchemaSpec,
580 source: SchemaSpec,
581 allow_override: bool,
582 ) -> XmlSchemaResult<()> {
583 for (name, node_spec) in source.nodes {
584 if target.nodes.contains_key(&name) && !allow_override {
585 return Err(XmlSchemaError::DuplicateNodeName(format!(
586 "节点 '{}' 已存在,不允许覆盖",
587 name
588 )));
589 }
590 target.nodes.insert(name, node_spec);
591 }
592
593 for (name, mark_spec) in source.marks {
594 if target.marks.contains_key(&name) && !allow_override {
595 return Err(XmlSchemaError::DuplicateMarkName(format!(
596 "标记 '{}' 已存在,不允许覆盖",
597 name
598 )));
599 }
600 target.marks.insert(name, mark_spec);
601 }
602
603 if target.top_node.is_none() && source.top_node.is_some() {
604 target.top_node = source.top_node;
605 }
606
607 Ok(())
608 }
609
610 fn convert_xml_schema_to_spec(
611 xml_schema: XmlSchema
612 ) -> XmlSchemaResult<SchemaSpec> {
613 Self::convert_to_schema_spec(xml_schema)
614 }
615
616 fn convert_to_extensions(
617 xml_schema: XmlSchema
618 ) -> XmlSchemaResult<Vec<Extensions>> {
619 let mut extensions = Vec::new();
620
621 if let Some(xml_nodes) = xml_schema.nodes {
622 for xml_node in xml_nodes.nodes {
623 let mut node =
624 Node::create(&xml_node.name, NodeSpec::default());
625 if let Some(group) = xml_node.group {
626 node.r#type.group = Some(group);
627 }
628 if let Some(desc) = xml_node.desc {
629 node.set_desc(&desc);
630 }
631 if let Some(content) = xml_node.content {
632 node.set_content(&content);
633 }
634 if let Some(marks) = xml_node.marks {
635 node.set_marks(marks);
636 }
637 if let Some(xml_attrs) = xml_node.attrs {
638 let attrs =
639 Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?;
640 node.set_attrs(attrs);
641 }
642 extensions.push(Extensions::N(node));
643 }
644 }
645
646 if let Some(xml_marks) = xml_schema.marks {
647 for xml_mark in xml_marks.marks {
648 let mut mark = Mark::new(&xml_mark.name, MarkSpec::default());
649 if let Some(group) = xml_mark.group {
650 mark.r#type.group = Some(group);
651 }
652 if let Some(desc) = xml_mark.desc {
653 mark.set_desc(&desc);
654 }
655 if let Some(excludes) = xml_mark.excludes {
656 mark.r#type.excludes = Some(excludes);
657 }
658 if let Some(spanning) = xml_mark.spanning {
659 mark.r#type.spanning = Some(spanning);
660 }
661 if let Some(xml_attrs) = xml_mark.attrs {
662 let attrs =
663 Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?;
664 mark.set_attrs(attrs);
665 }
666 extensions.push(Extensions::M(mark));
667 }
668 }
669
670 let extension = Extension::new();
671 extensions.push(Extensions::E(extension));
672
673 Ok(extensions)
674 }
675
676 fn convert_xml_schema_with_refs_to_extensions(
677 xml_schema: XmlSchemaWithReferences
678 ) -> XmlSchemaResult<Vec<Extensions>> {
679 let mut extensions = Vec::new();
680
681 if let Some(xml_nodes) = xml_schema.nodes {
682 for xml_node in xml_nodes.nodes {
683 let mut node =
684 Node::create(&xml_node.name, NodeSpec::default());
685 if let Some(group) = xml_node.group {
686 node.r#type.group = Some(group);
687 }
688 if let Some(desc) = xml_node.desc {
689 node.set_desc(&desc);
690 }
691 if let Some(content) = xml_node.content {
692 node.set_content(&content);
693 }
694 if let Some(marks) = xml_node.marks {
695 node.set_marks(marks);
696 }
697 if let Some(xml_attrs) = xml_node.attrs {
698 let attrs =
699 Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?;
700 node.set_attrs(attrs);
701 }
702 extensions.push(Extensions::N(node));
703 }
704 }
705
706 if let Some(xml_marks) = xml_schema.marks {
707 for xml_mark in xml_marks.marks {
708 let mut mark = Mark::new(&xml_mark.name, MarkSpec::default());
709 if let Some(group) = xml_mark.group {
710 mark.r#type.group = Some(group);
711 }
712 if let Some(desc) = xml_mark.desc {
713 mark.set_desc(&desc);
714 }
715 if let Some(excludes) = xml_mark.excludes {
716 mark.r#type.excludes = Some(excludes);
717 }
718 if let Some(spanning) = xml_mark.spanning {
719 mark.r#type.spanning = Some(spanning);
720 }
721 if let Some(xml_attrs) = xml_mark.attrs {
722 let attrs =
723 Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?;
724 mark.set_attrs(attrs);
725 }
726 extensions.push(Extensions::M(mark));
727 }
728 }
729
730 if let Some(xml_global_attrs) = xml_schema.global_attributes {
731 let mut extension = Extension::new();
732 for xml_global_attr in xml_global_attrs.global_attributes {
733 let global_attr_item =
734 Self::convert_xml_global_attribute_to_item(
735 xml_global_attr,
736 )?;
737 extension.add_global_attribute(global_attr_item);
738 }
739 extensions.push(Extensions::E(extension));
740 } else {
741 let extension = Extension::new();
742 extensions.push(Extensions::E(extension));
743 }
744
745 Ok(extensions)
746 }
747
748 fn convert_to_schema_spec(
749 xml_schema: XmlSchema
750 ) -> XmlSchemaResult<SchemaSpec> {
751 let mut nodes = HashMap::new();
752 let mut marks = HashMap::new();
753
754 if let Some(xml_nodes) = xml_schema.nodes {
755 for xml_node in xml_nodes.nodes {
756 if nodes.contains_key(&xml_node.name) {
757 return Err(XmlSchemaError::DuplicateNodeName(
758 xml_node.name.clone(),
759 ));
760 }
761 let node_name = xml_node.name.clone();
762 let node_spec = Self::convert_xml_node_to_spec(xml_node)?;
763 nodes.insert(node_name, node_spec);
764 }
765 }
766
767 if let Some(xml_marks) = xml_schema.marks {
768 for xml_mark in xml_marks.marks {
769 if marks.contains_key(&xml_mark.name) {
770 return Err(XmlSchemaError::DuplicateMarkName(
771 xml_mark.name.clone(),
772 ));
773 }
774 let mark_name = xml_mark.name.clone();
775 let mark_spec = Self::convert_xml_mark_to_spec(xml_mark)?;
776 marks.insert(mark_name, mark_spec);
777 }
778 }
779
780 Ok(SchemaSpec { nodes, marks, top_node: xml_schema.top_node })
781 }
782
783 fn convert_xml_node_to_spec(
784 xml_node: XmlNode
785 ) -> XmlSchemaResult<NodeSpec> {
786 let attrs = if let Some(xml_attrs) = xml_node.attrs {
787 Some(Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?)
788 } else {
789 None
790 };
791
792 Ok(NodeSpec {
793 content: xml_node.content,
794 marks: xml_node.marks,
795 group: xml_node.group,
796 desc: xml_node.desc,
797 attrs,
798 })
799 }
800
801 fn convert_xml_mark_to_spec(
802 xml_mark: XmlMark
803 ) -> XmlSchemaResult<MarkSpec> {
804 let attrs = if let Some(xml_attrs) = xml_mark.attrs {
805 Some(Self::convert_xml_attrs_to_spec(xml_attrs.attrs)?)
806 } else {
807 None
808 };
809
810 Ok(MarkSpec {
811 attrs,
812 excludes: xml_mark.excludes,
813 group: xml_mark.group,
814 spanning: xml_mark.spanning,
815 desc: xml_mark.desc,
816 })
817 }
818
819 fn convert_xml_attrs_to_spec(
820 xml_attrs: Vec<XmlAttr>
821 ) -> XmlSchemaResult<HashMap<String, AttributeSpec>> {
822 let mut attrs = HashMap::new();
823 for xml_attr in xml_attrs {
824 let default_value = if let Some(default_value) = xml_attr.default {
825 Some(default_value)
826 } else {
827 None
828 };
829
830 attrs.insert(
831 xml_attr.name.clone(),
832 AttributeSpec { default: default_value },
833 );
834 }
835 Ok(attrs)
836 }
837
838 pub fn parse_attribute_value(value_str: &str) -> XmlSchemaResult<Value> {
839 if let Ok(json_value) = serde_json::from_str::<Value>(value_str) {
840 return Ok(json_value);
841 }
842 Ok(Value::String(value_str.to_string()))
843 }
844
845 fn convert_xml_global_attribute_to_item(
846 xml_global_attr: XmlGlobalAttribute
847 ) -> XmlSchemaResult<GlobalAttributeItem> {
848 let types = if xml_global_attr.types.trim() == "*" {
849 vec!["*".to_string()]
850 } else {
851 xml_global_attr
852 .types
853 .split_whitespace()
854 .map(|s| s.to_string())
855 .collect()
856 };
857
858 let attributes =
859 Self::convert_xml_attrs_to_spec(xml_global_attr.attrs)?;
860 Ok(GlobalAttributeItem { types, attributes })
861 }
862}
863
864#[cfg(test)]
865mod tests {
866 use super::*;
867
868 #[test]
869 fn test_parse_simple_schema() {
870 let xml = r#"
871 <?xml version=\"1.0\" encoding=\"UTF-8\"?>
872 <schema top_node=\"doc\">
873 <nodes>
874 <node name=\"doc\" desc=\"文档根节点\" content=\"paragraph+\"/>
875 <node name=\"paragraph\" desc=\"段落节点\" content=\"text*\"/>
876 <node name=\"text\" desc=\"文本节点\"/>
877 </nodes>
878 </schema>
879 "#;
880
881 let result = XmlSchemaParser::parse_from_str(xml);
882 assert!(result.is_ok());
883 let schema_spec = result.unwrap();
884 assert_eq!(schema_spec.top_node, Some("doc".to_string()));
885 assert_eq!(schema_spec.nodes.len(), 3);
886 assert!(schema_spec.nodes.contains_key("doc"));
887 assert!(schema_spec.nodes.contains_key("paragraph"));
888 assert!(schema_spec.nodes.contains_key("text"));
889 }
890}