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    XmlAttr, XmlAttrs, XmlGlobalAttribute, XmlMark, XmlMarks, XmlNode,
20    XmlNodes, XmlSchema, XmlSchemaWithReferences,
21};
22
23/// XML Schema 解析器
24pub struct XmlSchemaParser;
25
26/// 多文件解析上下文
27#[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                // 检查是否为顶级节点
624                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}