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