mf_core/schema_parser/
parser.rs

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
25/// XML Schema 解析器
26pub struct XmlSchemaParser;
27
28/// 多文件解析上下文
29#[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}