mf_core/schema_parser/
serializer.rs

1use quick_xml::events::{BytesEnd, BytesStart, Event};
2use quick_xml::Writer;
3use std::io::Cursor;
4use std::sync::Arc;
5
6use mf_model::schema::{AttributeSpec, SchemaSpec};
7
8use crate::{
9    mark::Mark,
10    node::Node,
11    types::{Extensions, GlobalAttributeItem},
12};
13
14use super::error::{XmlSchemaError, XmlSchemaResult};
15
16/// XML Schema 序列化器
17pub struct XmlSchemaSerializer;
18
19impl XmlSchemaSerializer {
20    /// 将 `SchemaSpec` 序列化为 XML 字符串(基础版本,不包含全局属性)
21    pub fn schema_spec_to_string(
22        schema: &SchemaSpec
23    ) -> XmlSchemaResult<String> {
24        let mut writer = Writer::new(Cursor::new(Vec::<u8>::new()));
25
26        // <schema>
27        let mut root = BytesStart::new("schema");
28        if let Some(top) = &schema.top_node {
29            root.push_attribute(("top_node", top.as_str()));
30        }
31        writer.write_event(Event::Start(root)).map_err(map_io)?;
32
33        // <nodes>
34        if !schema.nodes.is_empty() {
35            writer
36                .write_event(Event::Start(BytesStart::new("nodes")))
37                .map_err(map_io)?;
38
39            for (name, spec) in &schema.nodes {
40                let mut el = BytesStart::new("node");
41                el.push_attribute(("name", name.as_str()));
42                if let Some(group) = &spec.group {
43                    el.push_attribute(("group", group.as_str()));
44                }
45                if let Some(desc) = &spec.desc {
46                    el.push_attribute(("desc", desc.as_str()));
47                }
48                if let Some(content) = &spec.content {
49                    el.push_attribute(("content", content.as_str()));
50                }
51                if let Some(marks) = &spec.marks {
52                    el.push_attribute(("marks", marks.as_str()));
53                }
54
55                writer.write_event(Event::Start(el)).map_err(map_io)?;
56
57                if let Some(attrs) = &spec.attrs {
58                    writer
59                        .write_event(Event::Start(BytesStart::new("attrs")))
60                        .map_err(map_io)?;
61
62                    for (attr_name, attr_spec) in attrs {
63                        write_attr_element(&mut writer, attr_name, attr_spec)?;
64                    }
65
66                    writer
67                        .write_event(Event::End(BytesEnd::new("attrs")))
68                        .map_err(map_io)?;
69                }
70
71                writer
72                    .write_event(Event::End(BytesEnd::new("node")))
73                    .map_err(map_io)?;
74            }
75
76            writer
77                .write_event(Event::End(BytesEnd::new("nodes")))
78                .map_err(map_io)?;
79        }
80
81        // <marks>
82        if !schema.marks.is_empty() {
83            writer
84                .write_event(Event::Start(BytesStart::new("marks")))
85                .map_err(map_io)?;
86
87            for (name, spec) in &schema.marks {
88                let mut el = BytesStart::new("mark");
89                el.push_attribute(("name", name.as_str()));
90                if let Some(group) = &spec.group {
91                    el.push_attribute(("group", group.as_str()));
92                }
93                if let Some(desc) = &spec.desc {
94                    el.push_attribute(("desc", desc.as_str()));
95                }
96                if let Some(excludes) = &spec.excludes {
97                    el.push_attribute(("excludes", excludes.as_str()));
98                }
99                if let Some(spanning) = spec.spanning {
100                    if spanning {
101                        el.push_attribute(("spanning", "true"));
102                    }
103                }
104
105                writer.write_event(Event::Start(el)).map_err(map_io)?;
106
107                if let Some(attrs) = &spec.attrs {
108                    writer
109                        .write_event(Event::Start(BytesStart::new("attrs")))
110                        .map_err(map_io)?;
111
112                    for (attr_name, attr_spec) in attrs {
113                        write_attr_element(&mut writer, attr_name, attr_spec)?;
114                    }
115
116                    writer
117                        .write_event(Event::End(BytesEnd::new("attrs")))
118                        .map_err(map_io)?;
119                }
120
121                writer
122                    .write_event(Event::End(BytesEnd::new("mark")))
123                    .map_err(map_io)?;
124            }
125
126            writer
127                .write_event(Event::End(BytesEnd::new("marks")))
128                .map_err(map_io)?;
129        }
130
131        // </schema>
132        writer
133            .write_event(Event::End(BytesEnd::new("schema")))
134            .map_err(map_io)?;
135
136        let buf = writer.into_inner().into_inner();
137        let xml = String::from_utf8(buf).map_err(|e| {
138            XmlSchemaError::XmlParseError(quick_xml::Error::Io(Arc::new(
139                std::io::Error::new(
140                    std::io::ErrorKind::InvalidData,
141                    e.utf8_error().to_string(),
142                ),
143            )))
144        })?;
145        Ok(xml)
146    }
147
148    /// 将 `Extensions` 列表序列化为 XML 字符串(包含全局属性)
149    /// 可选传入 `top_node` 覆盖顶层节点名称
150    pub fn extensions_to_string(
151        extensions: &[Extensions],
152        top_node: Option<&str>,
153    ) -> XmlSchemaResult<String> {
154        let mut writer = Writer::new(Cursor::new(Vec::<u8>::new()));
155
156        let mut root = BytesStart::new("schema");
157        if let Some(top) = top_node {
158            root.push_attribute(("top_node", top));
159        }
160        writer.write_event(Event::Start(root)).map_err(map_io)?;
161
162        // 收集 nodes / marks / global_attributes
163        let mut nodes: Vec<&Node> = Vec::new();
164        let mut marks: Vec<&Mark> = Vec::new();
165        let mut global_attrs_sets: Vec<&[GlobalAttributeItem]> = Vec::new();
166
167        for ext in extensions {
168            match ext {
169                Extensions::N(n) => nodes.push(n),
170                Extensions::M(m) => marks.push(m),
171                Extensions::E(e) => {
172                    global_attrs_sets.push(e.get_global_attributes())
173                },
174            }
175        }
176
177        if !nodes.is_empty() {
178            writer
179                .write_event(Event::Start(BytesStart::new("nodes")))
180                .map_err(map_io)?;
181            for n in nodes {
182                let mut el = BytesStart::new("node");
183                el.push_attribute(("name", n.get_name()));
184                if let Some(group) = &n.r#type.group {
185                    el.push_attribute(("group", group.as_str()));
186                }
187                if let Some(desc) = &n.r#type.desc {
188                    el.push_attribute(("desc", desc.as_str()));
189                }
190                if let Some(content) = &n.r#type.content {
191                    el.push_attribute(("content", content.as_str()));
192                }
193                if let Some(marks_attr) = &n.r#type.marks {
194                    el.push_attribute(("marks", marks_attr.as_str()));
195                }
196                writer.write_event(Event::Start(el)).map_err(map_io)?;
197
198                if let Some(attrs) = &n.r#type.attrs {
199                    writer
200                        .write_event(Event::Start(BytesStart::new("attrs")))
201                        .map_err(map_io)?;
202                    for (attr_name, attr_spec) in attrs {
203                        write_attr_element(&mut writer, attr_name, attr_spec)?;
204                    }
205                    writer
206                        .write_event(Event::End(BytesEnd::new("attrs")))
207                        .map_err(map_io)?;
208                }
209
210                writer
211                    .write_event(Event::End(BytesEnd::new("node")))
212                    .map_err(map_io)?;
213            }
214            writer
215                .write_event(Event::End(BytesEnd::new("nodes")))
216                .map_err(map_io)?;
217        }
218
219        if !marks.is_empty() {
220            writer
221                .write_event(Event::Start(BytesStart::new("marks")))
222                .map_err(map_io)?;
223            for m in marks {
224                let mut el = BytesStart::new("mark");
225                el.push_attribute(("name", m.get_name()));
226                if let Some(group) = &m.r#type.group {
227                    el.push_attribute(("group", group.as_str()));
228                }
229                if let Some(desc) = &m.r#type.desc {
230                    el.push_attribute(("desc", desc.as_str()));
231                }
232                if let Some(excludes) = &m.r#type.excludes {
233                    el.push_attribute(("excludes", excludes.as_str()));
234                }
235                if let Some(spanning) = m.r#type.spanning {
236                    if spanning {
237                        el.push_attribute(("spanning", "true"));
238                    }
239                }
240                writer.write_event(Event::Start(el)).map_err(map_io)?;
241
242                if let Some(attrs) = &m.r#type.attrs {
243                    writer
244                        .write_event(Event::Start(BytesStart::new("attrs")))
245                        .map_err(map_io)?;
246                    for (attr_name, attr_spec) in attrs {
247                        write_attr_element(&mut writer, attr_name, attr_spec)?;
248                    }
249                    writer
250                        .write_event(Event::End(BytesEnd::new("attrs")))
251                        .map_err(map_io)?;
252                }
253
254                writer
255                    .write_event(Event::End(BytesEnd::new("mark")))
256                    .map_err(map_io)?;
257            }
258            writer
259                .write_event(Event::End(BytesEnd::new("marks")))
260                .map_err(map_io)?;
261        }
262
263        // <global_attributes>
264        let mut wrote_global = false;
265        for set in global_attrs_sets {
266            if set.is_empty() {
267                continue;
268            }
269            if !wrote_global {
270                writer
271                    .write_event(Event::Start(BytesStart::new(
272                        "global_attributes",
273                    )))
274                    .map_err(map_io)?;
275                wrote_global = true;
276            }
277            for item in set.iter() {
278                write_global_attribute(&mut writer, item)?;
279            }
280        }
281        if wrote_global {
282            writer
283                .write_event(Event::End(BytesEnd::new("global_attributes")))
284                .map_err(map_io)?;
285        }
286
287        writer
288            .write_event(Event::End(BytesEnd::new("schema")))
289            .map_err(map_io)?;
290
291        let buf = writer.into_inner().into_inner();
292        let xml = String::from_utf8(buf).map_err(|e| {
293            XmlSchemaError::XmlParseError(quick_xml::Error::Io(Arc::new(
294                std::io::Error::new(
295                    std::io::ErrorKind::InvalidData,
296                    e.utf8_error().to_string(),
297                ),
298            )))
299        })?;
300        Ok(xml)
301    }
302}
303
304fn write_attr_element(
305    writer: &mut Writer<Cursor<Vec<u8>>>,
306    name: &str,
307    attr: &AttributeSpec,
308) -> XmlSchemaResult<()> {
309    let mut el = BytesStart::new("attr");
310    el.push_attribute(("name", name));
311    if let Some(default) = &attr.default {
312        let s = value_to_attr_string(default);
313        el.push_attribute(("default", s.as_str()));
314    }
315    writer.write_event(Event::Empty(el)).map_err(map_io)?;
316    Ok(())
317}
318
319fn write_global_attribute(
320    writer: &mut Writer<Cursor<Vec<u8>>>,
321    item: &GlobalAttributeItem,
322) -> XmlSchemaResult<()> {
323    let mut el = BytesStart::new("global_attribute");
324    let types_value = if item.types.len() == 1 && item.types[0] == "*" {
325        "*".to_string()
326    } else {
327        item.types.join(" ")
328    };
329    el.push_attribute(("types", types_value.as_str()));
330    writer.write_event(Event::Start(el)).map_err(map_io)?;
331
332    if !item.attributes.is_empty() {
333        for (name, spec) in &item.attributes {
334            write_attr_element(writer, name, spec)?;
335        }
336    }
337
338    writer
339        .write_event(Event::End(BytesEnd::new("global_attribute")))
340        .map_err(map_io)?;
341    Ok(())
342}
343
344fn value_to_attr_string(value: &serde_json::Value) -> String {
345    match value {
346        serde_json::Value::Null => "null".to_string(),
347        serde_json::Value::Bool(b) => {
348            if *b { "true" } else { "false" }.to_string()
349        },
350        serde_json::Value::Number(n) => n.to_string(),
351        serde_json::Value::String(s) => s.clone(),
352        other => serde_json::to_string(other).unwrap_or_default(),
353    }
354}
355
356fn map_io(err: quick_xml::Error) -> XmlSchemaError {
357    XmlSchemaError::XmlParseError(err)
358}