stb_parser/
lib.rs

1use std::fs::File;
2use std::io::prelude::*;
3use std::str::FromStr;
4
5use crate::st_bridge::stb_common::StbCommon;
6use crate::st_bridge::stb_extensions::StbExtension;
7use crate::st_bridge::stb_extensions::StbExtensions;
8use crate::st_bridge::stb_model::stb_axes_and_stories::StbAxes;
9use crate::st_bridge::stb_model::stb_axes_and_stories::StbNodeId;
10use crate::st_bridge::stb_model::stb_axes_and_stories::StbNodeIdList;
11use crate::st_bridge::stb_model::stb_axes_and_stories::StbStories;
12use crate::st_bridge::stb_model::stb_axes_and_stories::StbStory;
13use crate::st_bridge::stb_model::stb_axes_and_stories::StbStoryKind;
14use crate::st_bridge::stb_model::stb_axes_and_stories::StbXAxis;
15use crate::st_bridge::stb_model::stb_axes_and_stories::StbYAxis;
16use crate::st_bridge::stb_model::stb_members::HaunchType;
17use crate::st_bridge::stb_model::stb_members::StbBeam;
18use crate::st_bridge::stb_model::stb_members::StbBeams;
19use crate::st_bridge::stb_model::stb_members::StbBrace;
20use crate::st_bridge::stb_model::stb_members::StbBraces;
21use crate::st_bridge::stb_model::stb_members::StbColumn;
22use crate::st_bridge::stb_model::stb_members::StbColumns;
23use crate::st_bridge::stb_model::stb_members::StbGirder;
24use crate::st_bridge::stb_model::stb_members::StbGirders;
25use crate::st_bridge::stb_model::stb_members::StbMembers;
26use crate::st_bridge::stb_model::stb_members::StbPost;
27use crate::st_bridge::stb_model::stb_members::StbPosts;
28use crate::st_bridge::stb_model::stb_members::StbSlab;
29use crate::st_bridge::stb_model::stb_members::StbSlabs;
30use crate::st_bridge::stb_model::stb_nodes::StbNode;
31use crate::st_bridge::stb_model::stb_nodes::StbNodes;
32use crate::st_bridge::stb_model::stb_sections::StbSec1WaySlab1;
33use crate::st_bridge::stb_model::stb_sections::StbSecBarArrangementBeam;
34use crate::st_bridge::stb_model::stb_sections::StbSecBarArrangementSlab;
35use crate::st_bridge::stb_model::stb_sections::StbSecBeamRC;
36use crate::st_bridge::stb_model::stb_sections::StbSecBeamS;
37use crate::st_bridge::stb_model::stb_sections::StbSecBeamSameSection;
38use crate::st_bridge::stb_model::stb_sections::StbSecBeamStartCenterEndSection;
39use crate::st_bridge::stb_model::stb_sections::StbSecBraceS;
40use crate::st_bridge::stb_model::stb_sections::StbSecBuildBox;
41use crate::st_bridge::stb_model::stb_sections::StbSecBuildH;
42use crate::st_bridge::stb_model::stb_sections::StbSecColumnS;
43use crate::st_bridge::stb_model::stb_sections::StbSecFigureBeam;
44use crate::st_bridge::stb_model::stb_sections::StbSecFigureSlab;
45use crate::st_bridge::stb_model::stb_sections::StbSecHaunch;
46use crate::st_bridge::stb_model::stb_sections::StbSecPipe;
47use crate::st_bridge::stb_model::stb_sections::StbSecRollBox;
48use crate::st_bridge::stb_model::stb_sections::StbSecRollH;
49use crate::st_bridge::stb_model::stb_sections::StbSecRollL;
50use crate::st_bridge::stb_model::stb_sections::StbSecSlabRC;
51use crate::st_bridge::stb_model::stb_sections::StbSecSteel;
52use crate::st_bridge::stb_model::stb_sections::StbSecSteelBeam;
53use crate::st_bridge::stb_model::stb_sections::StbSecSteelBrace;
54use crate::st_bridge::stb_model::stb_sections::StbSecSteelColumn;
55use crate::st_bridge::stb_model::stb_sections::StbSecStraightBeam;
56use crate::st_bridge::stb_model::stb_sections::StbSecStraightSlab;
57use crate::st_bridge::stb_model::stb_sections::StbSections;
58use crate::st_bridge::stb_model::StbModel;
59use crate::st_bridge::StBridge;
60
61pub mod st_bridge;
62
63pub fn read_st_bridge(file_name: &str) -> StBridge {
64    let contents = get_contents(file_name);
65
66    let document = roxmltree::Document::parse(&contents).unwrap();
67
68    let root_node = document.root_element();
69
70    let version = root_node.attribute("version").unwrap().to_string();
71
72    let stb_common = extract_stb_common(root_node);
73
74    let stb_model = extract_stb_model(root_node);
75
76    let stb_extensions = extract_stb_extensions(root_node);
77
78    StBridge {
79        version,
80        stb_common,
81        stb_model,
82        stb_extensions,
83    }
84}
85
86pub fn get_contents(filename: &str) -> String {
87    let mut f = File::open(filename).expect("File not found.");
88
89    let mut contents = String::new();
90
91    f.read_to_string(&mut contents)
92        .expect("something went wrong reading the file");
93
94    return contents;
95}
96
97pub fn extract_node<'a>(
98    name: &str,
99    parent: roxmltree::Node<'a, '_>,
100) -> Option<roxmltree::Node<'a, 'a>> {
101    let child_elements = parent.children().filter(|n| n.is_element());
102
103    for node in child_elements {
104        let tag_name = node.tag_name().name();
105
106        if tag_name == name {
107            return Some(node);
108        }
109    }
110
111    None
112}
113
114pub fn extract_stb_common<'a>(root_node: roxmltree::Node<'a, 'a>) -> StbCommon {
115    let stb_common_node = extract_node("StbCommon", root_node).unwrap();
116    let stb_reinforcement_strength_list =
117        extract_node("StbReinforcement_Strength_List", stb_common_node).unwrap();
118    let mut stb_common = StbCommon::new();
119
120    for node in stb_reinforcement_strength_list
121        .children()
122        .filter(|n| n.is_element())
123    {
124        let d = node.attribute("D").unwrap().to_string();
125        let sd = node.attribute("SD").unwrap().to_string();
126        stb_common.stb_reinforcement_strength_list.insert(d, sd);
127    }
128
129    return stb_common;
130}
131
132pub fn extract_stb_model(root_node: roxmltree::Node) -> StbModel {
133    let stb_model_node = extract_node("StbModel", root_node).unwrap();
134
135    let stb_nodes = extract_stb_nodes(stb_model_node);
136
137    let stb_axes = extract_stb_axes(stb_model_node);
138
139    let stb_stories = extract_stb_stories(stb_model_node);
140
141    let stb_members = extract_stb_members(stb_model_node);
142
143    let stb_sections = extract_stb_sections(stb_model_node);
144
145    StbModel {
146        stb_nodes,
147        stb_axes,
148        stb_stories,
149        stb_members,
150        stb_sections,
151    }
152}
153
154fn extract_stb_nodes(stb_model_node: roxmltree::Node) -> StbNodes {
155    let stb_nodes_node = extract_node("StbNodes", stb_model_node).unwrap();
156
157    let mut stb_nodes = StbNodes::new();
158
159    for node in stb_nodes_node.children().filter(|n| n.is_element()) {
160        let id_member = match node.attribute("id_member") {
161            Some(s) => Some(s.parse::<i32>().unwrap()),
162            None => None,
163        };
164
165        stb_nodes.insert(
166            parse_attribute("id", node).unwrap(),
167            StbNode {
168                x: parse_attribute("x", node).unwrap(),
169                y: parse_attribute("y", node).unwrap(),
170                z: parse_attribute("z", node).unwrap(),
171                kind: parse_enum_attribute("kind", node).unwrap(),
172                id_member,
173            },
174        );
175    }
176
177    stb_nodes
178}
179
180fn extract_stb_axes(stb_model_node: roxmltree::Node) -> StbAxes {
181    let stb_axes_node = extract_node("StbAxes", stb_model_node).unwrap();
182
183    let mut stb_axes = StbAxes::new();
184
185    for node in stb_axes_node.children().filter(|n| n.is_element()) {
186        let stb_node_id_list_node = extract_node("StbNodeid_List", node).unwrap();
187
188        let mut stb_node_id_list = Vec::new();
189
190        for children in stb_node_id_list_node.children().filter(|n| n.is_element()) {
191            let id = parse_attribute("id", children).unwrap();
192            stb_node_id_list.push(StbNodeId { id });
193        }
194
195        match node.tag_name().name() {
196            "StbX_Axis" => {
197                stb_axes.stb_x_axis_list.push(StbXAxis {
198                    id: parse_attribute("id", node).unwrap(),
199                    name: parse_attribute("name", node).unwrap(),
200                    distance: parse_attribute("distance", node).unwrap(),
201                    stb_node_id_list: StbNodeIdList {
202                        children: stb_node_id_list,
203                    },
204                });
205            }
206            "StbY_Axis" => {
207                stb_axes.stb_y_axis_list.push(StbYAxis {
208                    id: parse_attribute("id", node).unwrap(),
209                    name: parse_attribute("name", node).unwrap(),
210                    distance: parse_attribute("distance", node).unwrap(),
211                    stb_node_id_list: StbNodeIdList {
212                        children: stb_node_id_list,
213                    },
214                });
215            }
216            _ => {
217                panic!("Tag name {} is invalid.", node.tag_name().name());
218            }
219        }
220    }
221
222    stb_axes
223}
224
225fn extract_stb_stories(stb_model_node: roxmltree::Node) -> StbStories {
226    let stb_stories_node = extract_node("StbStories", stb_model_node).unwrap();
227
228    let mut stb_stories = StbStories::new();
229
230    for node in stb_stories_node.children().filter(|n| n.is_element()) {
231        let stb_node_id_list_node = extract_node("StbNodeid_List", node).unwrap();
232
233        let mut stb_node_id_list = Vec::new();
234
235        for children in stb_node_id_list_node.children().filter(|n| n.is_element()) {
236            let id = parse_attribute("id", children).unwrap();
237            stb_node_id_list.push(StbNodeId { id });
238        }
239
240        stb_stories.stb_story_list.push(StbStory {
241            id: parse_attribute("id", node).unwrap(),
242            name: parse_attribute("name", node).unwrap(),
243            height: parse_attribute("height", node).unwrap(),
244            kind: StbStoryKind::from_str(node.attribute("kind").unwrap()).unwrap(),
245            concrete_strength: node.attribute("concrete_strength").unwrap().to_string(),
246            stb_node_id_list: StbNodeIdList {
247                children: stb_node_id_list,
248            },
249        });
250    }
251
252    stb_stories
253}
254
255fn extract_stb_members(stb_model_node: roxmltree::Node) -> StbMembers {
256    let stb_members_node = extract_node("StbMembers", stb_model_node).unwrap();
257
258    let stb_columns = extract_stb_columns(stb_members_node);
259    let stb_posts = extract_stb_posts(stb_members_node);
260    let stb_girders = extract_stb_girders(stb_members_node);
261    let stb_beams = extract_stb_beams(stb_members_node);
262    let stb_braces = extract_stb_braces(stb_members_node);
263    let stb_slabs = extract_stb_slabs(stb_members_node);
264
265    StbMembers {
266        stb_columns,
267        stb_posts,
268        stb_girders,
269        stb_beams,
270        stb_braces,
271        stb_slabs,
272    }
273}
274
275fn extract_stb_columns(stb_members_node: roxmltree::Node) -> StbColumns {
276    let stb_columns_node = extract_node("StbColumns", stb_members_node).unwrap();
277
278    let mut stb_column_list: Vec<StbColumn> = Vec::new();
279
280    for node in stb_columns_node.children().filter(|n| n.is_element()) {
281        stb_column_list.push(StbColumn {
282            id: parse_attribute("id", node).unwrap(),
283            name: node.attribute("name").unwrap().to_string(),
284            id_node_bottom: parse_attribute("idNode_bottom", node).unwrap(),
285            id_node_top: parse_attribute("idNode_top", node).unwrap(),
286            rotate: parse_attribute("rotate", node).unwrap(),
287            id_section: parse_attribute("id_section", node).unwrap(),
288            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
289            offset_x: parse_attribute("offset_X", node).unwrap(),
290            offset_y: parse_attribute("offset_Y", node).unwrap(),
291            condition_bottom: parse_enum_attribute("condition_bottom", node).unwrap(),
292            condition_top: parse_enum_attribute("condition_top", node).unwrap(),
293        });
294    }
295
296    StbColumns { stb_column_list }
297}
298
299fn extract_stb_posts(stb_members_node: roxmltree::Node) -> StbPosts {
300    let stb_posts_node = extract_node("StbPosts", stb_members_node).unwrap();
301
302    let mut stb_post_list: Vec<StbPost> = Vec::new();
303
304    for node in stb_posts_node.children().filter(|n| n.is_element()) {
305        stb_post_list.push(StbPost {
306            id: parse_attribute("id", node).unwrap(),
307            name: node.attribute("name").unwrap().to_string(),
308            id_node_bottom: parse_attribute("idNode_bottom", node).unwrap(),
309            id_node_top: parse_attribute("idNode_top", node).unwrap(),
310            rotate: parse_attribute("rotate", node).unwrap(),
311            id_section: parse_attribute("id_section", node).unwrap(),
312            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
313            offset_x: parse_attribute("offset_X", node).unwrap(),
314            offset_y: parse_attribute("offset_Y", node).unwrap(),
315            offset_bottom_x: parse_attribute("offset_bottom_X", node).unwrap(),
316            offset_bottom_y: parse_attribute("offset_bottom_Y", node).unwrap(),
317            offset_bottom_z: parse_attribute("offset_bottom_Z", node).unwrap(),
318            offset_top_x: parse_attribute("offset_top_X", node).unwrap(),
319            offset_top_y: parse_attribute("offset_top_Y", node).unwrap(),
320            offset_top_z: parse_attribute("offset_top_Z", node).unwrap(),
321            condition_bottom: parse_enum_attribute("condition_bottom", node).unwrap(),
322            condition_top: parse_enum_attribute("condition_top", node).unwrap(),
323        });
324    }
325
326    StbPosts { stb_post_list }
327}
328
329fn extract_stb_girders(stb_members_node: roxmltree::Node) -> StbGirders {
330    let stb_girders_node = extract_node("StbGirders", stb_members_node).unwrap();
331
332    let mut stb_girder_list: Vec<StbGirder> = Vec::new();
333
334    for node in stb_girders_node.children().filter(|n| n.is_element()) {
335        stb_girder_list.push(StbGirder {
336            id: parse_attribute("id", node).unwrap(),
337            name: node.attribute("name").unwrap().to_string(),
338            id_node_start: parse_attribute("idNode_start", node).unwrap(),
339            id_node_end: parse_attribute("idNode_end", node).unwrap(),
340            rotate: parse_attribute("rotate", node).unwrap(),
341            id_section: parse_attribute("id_section", node).unwrap(),
342            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
343            is_foundation: parse_attribute("isFoundation", node).unwrap(),
344            offset: parse_attribute("offset", node).unwrap(),
345            level: parse_attribute("level", node).unwrap(),
346            type_haunch_h: match node.attribute("type_haunch_H") {
347                Some(s) => Some(HaunchType::from_str(s).unwrap()),
348                None => None,
349            },
350        });
351    }
352
353    StbGirders { stb_girder_list }
354}
355
356fn extract_stb_beams(stb_members_node: roxmltree::Node) -> StbBeams {
357    let stb_beams_node = extract_node("StbBeams", stb_members_node).unwrap();
358
359    let mut stb_beam_list: Vec<StbBeam> = Vec::new();
360
361    for node in stb_beams_node.children().filter(|n| n.is_element()) {
362        stb_beam_list.push(StbBeam {
363            id: parse_attribute("id", node).unwrap(),
364            name: node.attribute("name").unwrap().to_string(),
365            id_node_start: parse_attribute("idNode_start", node).unwrap(),
366            id_node_end: parse_attribute("idNode_end", node).unwrap(),
367            rotate: parse_attribute("rotate", node).unwrap(),
368            id_section: parse_attribute("id_section", node).unwrap(),
369            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
370            is_foundation: parse_attribute("isFoundation", node).unwrap(),
371            offset: parse_attribute("offset", node).unwrap(),
372            level: parse_attribute("level", node).unwrap(),
373        });
374    }
375
376    StbBeams { stb_beam_list }
377}
378
379fn extract_stb_braces(stb_members_node: roxmltree::Node) -> StbBraces {
380    let stb_braces_node = extract_node("StbBraces", stb_members_node).unwrap();
381
382    let mut stb_brace_list: Vec<StbBrace> = Vec::new();
383
384    for node in stb_braces_node.children().filter(|n| n.is_element()) {
385        stb_brace_list.push(StbBrace {
386            id: parse_attribute("id", node).unwrap(),
387            name: node.attribute("name").unwrap().to_string(),
388            id_node_start: parse_attribute("idNode_start", node).unwrap(),
389            id_node_end: parse_attribute("idNode_end", node).unwrap(),
390            rotate: parse_attribute("rotate", node).unwrap(),
391            id_section: parse_attribute("id_section", node).unwrap(),
392            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
393            offset_start_x: parse_attribute("offset_start_X", node).unwrap(),
394            offset_start_y: parse_attribute("offset_start_Y", node).unwrap(),
395            offset_start_z: parse_attribute("offset_start_Z", node).unwrap(),
396            offset_end_x: parse_attribute("offset_end_X", node).unwrap(),
397            offset_end_y: parse_attribute("offset_end_Y", node).unwrap(),
398            offset_end_z: parse_attribute("offset_end_Z", node).unwrap(),
399            condition_start: parse_enum_attribute("condition_start", node).unwrap(),
400            condition_end: parse_enum_attribute("condition_end", node).unwrap(),
401        });
402    }
403
404    StbBraces { stb_brace_list }
405}
406
407fn extract_stb_slabs(stb_members_node: roxmltree::Node) -> StbSlabs {
408    let stb_slabs_node = extract_node("StbSlabs", stb_members_node).unwrap();
409
410    let mut stb_slab_list: Vec<StbSlab> = Vec::new();
411
412    for node in stb_slabs_node.children().filter(|n| n.is_element()) {
413        stb_slab_list.push(StbSlab {
414            id: parse_attribute("id", node).unwrap(),
415            name: node.attribute("name").unwrap().to_string(),
416            id_section: parse_attribute("id_section", node).unwrap(),
417            kind_structure: parse_enum_attribute("kind_structure", node).unwrap(),
418            kind_slab: parse_enum_attribute("kind_slab", node).unwrap(),
419            level: parse_attribute("level", node).unwrap(),
420            is_foundation: parse_attribute("isFoundation", node).unwrap(),
421        });
422    }
423
424    StbSlabs { stb_slab_list }
425}
426
427fn extract_stb_sections(stb_model_node: roxmltree::Node) -> StbSections {
428    let stb_sections_node = extract_node("StbSections", stb_model_node).unwrap();
429
430    let mut stb_sections = StbSections::new();
431
432    for node in stb_sections_node.children().filter(|n| n.is_element()) {
433        let tag_name = node.tag_name().name();
434
435        match tag_name {
436            "StbSecColumn_RC" => unimplemented_panic(tag_name),
437            "StbSecColumn_S" => stb_sections
438                .children
439                .push(Box::new(extract_stb_sec_column_s(node))),
440            "StbSecColumn_SRC" => unimplemented_panic(tag_name),
441            "StbSecColumn_CFT" => unimplemented_panic(tag_name),
442            "StbSecBeam_RC" => stb_sections
443                .children
444                .push(Box::new(extract_stb_sec_beam_rc(node))),
445            "StbSecBeam_S" => stb_sections
446                .children
447                .push(Box::new(extract_stb_sec_beam_s(node))),
448            "StbSecBeam_SRC" => unimplemented_panic(tag_name),
449            "StbSecBrace_S" => stb_sections
450                .children
451                .push(Box::new(extract_stb_sec_brace_s(node))),
452            "StbSecSlab_RC" => stb_sections
453                .children
454                .push(Box::new(extract_stb_sec_slab_rc(node))),
455            "StbSecSlabDeck" => unimplemented_panic(tag_name),
456            "StbSecSlabPrecast" => unimplemented_panic(tag_name),
457            "StbSecWall_RC" => unimplemented_panic(tag_name),
458            "StbSecFoundation_RC" => unimplemented_panic(tag_name),
459            "StbSecPile_RC" => unimplemented_panic(tag_name),
460            "StbSecPile_S" => unimplemented_panic(tag_name),
461            "StbSecPileProduct" => unimplemented_panic(tag_name),
462            "StbSecOpen_RC" => unimplemented_panic(tag_name),
463            "StbSecParapet_RC" => unimplemented_panic(tag_name),
464            "StbSecSteel" => stb_sections.stb_sec_steel = extract_stb_sec_steel(node),
465            "StbSecUndefined" => unimplemented_panic(tag_name),
466            _ => {
467                panic!("Tag name {} is invalid.", tag_name)
468            }
469        };
470    }
471
472    stb_sections
473}
474
475fn extract_stb_sec_column_s(node: roxmltree::Node) -> StbSecColumnS {
476    let stb_sec_steel_column_node = extract_node("StbSecSteelColumn", node).unwrap();
477    StbSecColumnS {
478        id: parse_attribute("id", node).unwrap(),
479        name: parse_attribute("name", node).unwrap(),
480        floor: parse_attribute("floor", node).unwrap(),
481        kind_column: parse_enum_attribute("kind_column", node).unwrap(),
482        direction: parse_attribute("direction", node).unwrap(),
483        base_type: parse_enum_attribute("base_type", node).unwrap(),
484        stb_sec_steel_column: StbSecSteelColumn {
485            pos: parse_enum_attribute("pos", stb_sec_steel_column_node).unwrap(),
486            shape: parse_enum_attribute("shape", stb_sec_steel_column_node).unwrap(),
487            strength_main: parse_attribute("strength_web", stb_sec_steel_column_node).unwrap(),
488            strength_web: parse_attribute("strength_web", stb_sec_steel_column_node).unwrap(),
489        },
490    }
491}
492
493fn extract_stb_sec_beam_rc(node: roxmltree::Node) -> StbSecBeamRC {
494    let stb_sec_figure_node = extract_node("StbSecFigure", node).unwrap();
495    let stb_sec_figure = extract_stb_sec_figure_beam(stb_sec_figure_node);
496
497    let stb_sec_bar_arrangement_node = extract_node("StbSecBar_Arrangement", node).unwrap();
498    let stb_sec_bar_arrangement = extract_stb_sec_bar_arrangement(stb_sec_bar_arrangement_node);
499
500    StbSecBeamRC {
501        id: parse_attribute("id", node).unwrap(),
502        name: parse_attribute("name", node).unwrap(),
503        floor: parse_attribute("name", node).unwrap(),
504        kind_beam: parse_enum_attribute("kind_beam", node).unwrap(),
505        is_foundation: parse_attribute("isFoundation", node).unwrap(),
506        is_canti: parse_attribute("isCanti", node).unwrap(),
507        d_reinforcement_main: parse_attribute("D_reinforcement_main", node).unwrap(),
508        d_stirrup: parse_attribute("D_stirrup", node).unwrap(),
509        d_reinforcement_web: parse_attribute("D_reinforcement_web", node).unwrap(),
510        d_bar_spacing: parse_attribute("D_bar_spacing", node).unwrap(),
511        strength_concrete: match node.attribute("strength_concrete") {
512            Some(s) => Some(s.to_string()),
513            None => None,
514        },
515        strength_reinforcement_main: parse_attribute("strength_reinforcement_main", node).unwrap(),
516        strength_reinforcement_2nd_main: match node.attribute("strength_reinforcement_2nd_main") {
517            Some(s) => Some(s.to_string()),
518            None => None,
519        },
520        strength_stirrup: parse_attribute("strength_stirrup", node).unwrap(),
521        strength_reinforcement_web: parse_attribute("strength_reinforcement_web", node).unwrap(),
522        strength_bar_spacing: parse_attribute("strength_bar_spacing", node).unwrap(),
523        depth_cover_left: match node.attribute("depth_cover_left") {
524            Some(s) => Some(s.parse().unwrap()),
525            None => None,
526        },
527        depth_cover_right: match node.attribute("depth_cover_right") {
528            Some(s) => Some(s.parse().unwrap()),
529            None => None,
530        },
531        depth_cover_top: match node.attribute("depth_cover_top") {
532            Some(s) => Some(s.parse().unwrap()),
533            None => None,
534        },
535        depth_cover_bottom: match node.attribute("depth_cover_bottom") {
536            Some(s) => Some(s.parse().unwrap()),
537            None => None,
538        },
539        stb_sec_figure,
540        stb_sec_bar_arrangement,
541    }
542}
543
544fn extract_stb_sec_bar_arrangement(node: roxmltree::Node) -> StbSecBarArrangementBeam {
545    let stb_sec_beam_start_center_end_section_list = match extract_node("", node) {
546        Some(_) => {
547            let mut list = Vec::new();
548            for children in node.children().filter(|n| n.is_element()) {
549                list.push(extract_stb_sec_beam_start_center_end_section(children));
550            }
551            Some(list)
552        }
553        None => None,
554    };
555
556    let stb_sec_beam_same_section = match extract_node("", node) {
557        Some(n) => Some(extract_stb_sec_beam_same_section(n)),
558        None => None,
559    };
560
561    StbSecBarArrangementBeam {
562        stb_sec_beam_start_center_end_section_list,
563        stb_sec_beam_same_section,
564    }
565}
566
567fn extract_stb_sec_beam_start_center_end_section(
568    node: roxmltree::Node,
569) -> StbSecBeamStartCenterEndSection {
570    StbSecBeamStartCenterEndSection {
571        pos: parse_enum_attribute("pos", node).unwrap(),
572        count_main_top_1st: parse_attribute("count_main_top_1st", node).unwrap(),
573        count_main_bottom_1st: parse_attribute("count_main_bottom_1st", node).unwrap(),
574        count_stirrup: parse_attribute("count_stirrup", node).unwrap(),
575        pitch_stirrup: parse_attribute("pitch_stirrup", node).unwrap(),
576        count_web: parse_attribute("count_web", node).unwrap(),
577        count_bar_spacing: parse_attribute("count_bar_spacing", node).unwrap(),
578        pitch_bar_spacing: parse_attribute("pitch_bar_spacing", node).unwrap(),
579    }
580}
581
582fn extract_stb_sec_beam_same_section(node: roxmltree::Node) -> StbSecBeamSameSection {
583    StbSecBeamSameSection {
584        count_main_top_1st: parse_attribute("count_main_top_1st", node).unwrap(),
585        count_main_bottom_1st: parse_attribute("count_main_bottom_1st", node).unwrap(),
586        count_stirrup: parse_attribute("count_stirrup", node).unwrap(),
587        pitch_stirrup: parse_attribute("pitch_stirrup", node).unwrap(),
588        count_web: parse_attribute("count_web", node).unwrap(),
589        count_bar_spacing: parse_attribute("count_bar_spacing", node).unwrap(),
590        pitch_bar_spacing: parse_attribute("pitch_bar_spacing", node).unwrap(),
591    }
592}
593
594fn extract_stb_sec_figure_beam(node: roxmltree::Node) -> StbSecFigureBeam {
595    let stb_sec_haunch = match extract_node("StbSecHaunch", node) {
596        Some(n) => Some(extract_stb_sec_haunch(n)),
597        None => None,
598    };
599
600    let stb_sec_straight = match extract_node("StbSecStraight", node) {
601        Some(n) => Some(extract_stb_sec_straight(n)),
602        None => None,
603    };
604
605    StbSecFigureBeam {
606        stb_sec_haunch,
607        stb_sec_straight,
608    }
609}
610
611fn extract_stb_sec_haunch(node: roxmltree::Node) -> StbSecHaunch {
612    StbSecHaunch {
613        width_start: parse_attribute("width_start", node).unwrap(),
614        depth_start: parse_attribute("depth_start", node).unwrap(),
615        width_center: parse_attribute("width_center", node).unwrap(),
616        depth_center: parse_attribute("depth_center", node).unwrap(),
617        width_end: parse_attribute("width_end", node).unwrap(),
618        depth_end: parse_attribute("depth_end", node).unwrap(),
619    }
620}
621
622fn extract_stb_sec_straight(node: roxmltree::Node) -> StbSecStraightBeam {
623    StbSecStraightBeam {
624        depth: parse_attribute("depth", node).unwrap(),
625    }
626}
627
628fn extract_stb_sec_beam_s(node: roxmltree::Node) -> StbSecBeamS {
629    let stb_sec_steel_beam_node = extract_node("StbSecSteelBeam", node).unwrap();
630    let stb_sec_steel_beam = extract_stb_sec_steel_beam(stb_sec_steel_beam_node);
631
632    StbSecBeamS {
633        id: parse_attribute("id", node).unwrap(),
634        name: parse_attribute("name", node).unwrap(),
635        floor: parse_attribute("floor", node).unwrap(),
636        kind_beam: parse_enum_attribute("kind_beam", node).unwrap(),
637        is_canti: parse_attribute("isCanti", node).unwrap(),
638        stb_sec_steel_beam,
639    }
640}
641
642fn extract_stb_sec_steel_beam(node: roxmltree::Node) -> StbSecSteelBeam {
643    StbSecSteelBeam {
644        pos: parse_enum_attribute("pos", node).unwrap(),
645        shape: parse_attribute("shape", node).unwrap(),
646        strength_main: parse_attribute("strength_main", node).unwrap(),
647        strength_web: parse_attribute("strength_web", node).unwrap(),
648    }
649}
650
651fn extract_stb_sec_brace_s(node: roxmltree::Node) -> StbSecBraceS {
652    let stb_sec_steel_brace_node = extract_node("StbSecSteelBrace", node).unwrap();
653    let stb_sec_steel_brace = StbSecSteelBrace {
654        pos: parse_enum_attribute("pos", stb_sec_steel_brace_node).unwrap(),
655        shape: parse_attribute("shape", stb_sec_steel_brace_node).unwrap(),
656        strength_main: parse_attribute("strength_main", stb_sec_steel_brace_node).unwrap(),
657        strength_web: parse_attribute("strength_web", stb_sec_steel_brace_node).unwrap(),
658    };
659
660    StbSecBraceS {
661        id: parse_attribute("id", node).unwrap(),
662        name: parse_attribute("name", node).unwrap(),
663        floor: parse_attribute("floor", node).unwrap(),
664        kind_brace: parse_enum_attribute("kind_brace", node).unwrap(),
665        stb_sec_steel_brace,
666    }
667}
668
669fn extract_stb_sec_slab_rc(node: roxmltree::Node) -> StbSecSlabRC {
670    let stb_sec_figure_node = extract_node("StbSecFigure", node).unwrap();
671    let stb_sec_straight_node = extract_node("StbSecStraight", stb_sec_figure_node).unwrap();
672    let stb_sec_straight = StbSecStraightSlab {
673        depth: parse_attribute("depth", stb_sec_straight_node).unwrap(),
674    };
675    let stb_sec_figure = StbSecFigureSlab { stb_sec_straight };
676
677    let stb_sec_bar_arrangement_node = extract_node("StbSecBar_Arrangement", node).unwrap();
678    let mut stb_sec_1way_slab_1_list = Vec::new();
679
680    for children in stb_sec_bar_arrangement_node
681        .children()
682        .filter(|n| n.is_element())
683    {
684        stb_sec_1way_slab_1_list.push(StbSec1WaySlab1 {
685            pos: parse_enum_attribute("pos", children).unwrap(),
686            strength: parse_attribute("strength", children).unwrap(),
687            d: parse_attribute("D", children).unwrap(),
688            pitch: parse_attribute("pitch", children).unwrap(),
689        });
690    }
691
692    let stb_sec_bar_arrangement = StbSecBarArrangementSlab {
693        stb_sec_1way_slab_1_list,
694    };
695
696    StbSecSlabRC {
697        id: parse_attribute("id", node).unwrap(),
698        name: parse_attribute("name", node).unwrap(),
699        is_foundation: parse_attribute("isFoundation", node).unwrap(),
700        is_canti: parse_attribute("isCanti", node).unwrap(),
701        strength_concrete: parse_attribute("strength_concrete", node).unwrap(),
702        stb_sec_figure,
703        stb_sec_bar_arrangement,
704    }
705}
706
707fn extract_stb_sec_steel(stb_sec_steel_node: roxmltree::Node) -> StbSecSteel {
708    let mut stb_sec_steel = StbSecSteel::new();
709
710    for node in stb_sec_steel_node.children().filter(|n| n.is_element()) {
711        let tag_name = node.tag_name().name();
712        match tag_name {
713            "StbSecRoll-H" => stb_sec_steel
714                .children
715                .push(Box::new(extract_stb_sec_roll_h(node))),
716            "StbSecBuild-H" => stb_sec_steel
717                .children
718                .push(Box::new(extract_stb_sec_build_h(node))),
719            "StbSecRoll-BOX" => stb_sec_steel
720                .children
721                .push(Box::new(extract_stb_sec_roll_box(node))),
722            "StbSecBuild-BOX" => stb_sec_steel
723                .children
724                .push(Box::new(extract_stb_sec_build_box(node))),
725            "StbSecPipe" => stb_sec_steel
726                .children
727                .push(Box::new(extract_stb_sec_pipe(node))),
728            "StbSecRoll-T" => unimplemented_panic(tag_name),
729            "StbSecRoll-C" => unimplemented_panic(tag_name),
730            "StbSecRoll-L" => stb_sec_steel
731                .children
732                .push(Box::new(extract_stb_sec_roll_l(node))),
733            "StbSecLipC" => unimplemented_panic(tag_name),
734            "StbSecFlatBar" => unimplemented_panic(tag_name),
735            "StbSecRoundBar" => unimplemented_panic(tag_name),
736            "StbSecSteelProduct" => unimplemented_panic(tag_name),
737            "StbSecSteelUndefined" => unimplemented_panic(tag_name),
738            _ => panic!("Tag name {} is invalid.", tag_name),
739        }
740    }
741
742    stb_sec_steel
743}
744
745fn extract_stb_sec_roll_h(node: roxmltree::Node) -> StbSecRollH {
746    StbSecRollH {
747        name: parse_attribute("name", node).unwrap(),
748        sec_type: parse_enum_attribute("type", node).unwrap(),
749        a: parse_attribute("A", node).unwrap(),
750        b: parse_attribute("B", node).unwrap(),
751        t1: parse_attribute("t1", node).unwrap(),
752        t2: parse_attribute("t2", node).unwrap(),
753        r: parse_attribute("r", node).unwrap(),
754    }
755}
756
757fn extract_stb_sec_build_h(node: roxmltree::Node) -> StbSecBuildH {
758    StbSecBuildH {
759        name: parse_attribute("name", node).unwrap(),
760        a: parse_attribute("A", node).unwrap(),
761        b: parse_attribute("B", node).unwrap(),
762        t1: parse_attribute("t1", node).unwrap(),
763        t2: parse_attribute("t2", node).unwrap(),
764    }
765}
766
767fn extract_stb_sec_roll_box(node: roxmltree::Node) -> StbSecRollBox {
768    StbSecRollBox {
769        name: parse_attribute("name", node).unwrap(),
770        sec_type: parse_enum_attribute("type", node).unwrap(),
771        a: parse_attribute("A", node).unwrap(),
772        b: parse_attribute("B", node).unwrap(),
773        t: parse_attribute("t", node).unwrap(),
774        r: parse_attribute("R", node).unwrap(),
775    }
776}
777
778fn extract_stb_sec_build_box(node: roxmltree::Node) -> StbSecBuildBox {
779    StbSecBuildBox {
780        name: parse_attribute("name", node).unwrap(),
781        a: parse_attribute("A", node).unwrap(),
782        b: parse_attribute("B", node).unwrap(),
783        t1: parse_attribute("t1", node).unwrap(),
784        t2: parse_attribute("t2", node).unwrap(),
785    }
786}
787
788fn extract_stb_sec_pipe(node: roxmltree::Node) -> StbSecPipe {
789    StbSecPipe {
790        name: parse_attribute("name", node).unwrap(),
791        d: parse_attribute("D", node).unwrap(),
792        t: parse_attribute("t", node).unwrap(),
793    }
794}
795
796fn extract_stb_sec_roll_l(node: roxmltree::Node) -> StbSecRollL {
797    StbSecRollL {
798        name: parse_attribute("name", node).unwrap(),
799        sec_type: parse_enum_attribute("type", node).unwrap(),
800        a: parse_attribute("A", node).unwrap(),
801        b: parse_attribute("B", node).unwrap(),
802        t1: parse_attribute("t1", node).unwrap(),
803        t2: parse_attribute("t2", node).unwrap(),
804        r1: parse_attribute("r1", node).unwrap(),
805        r2: parse_attribute("r2", node).unwrap(),
806        side: parse_attribute("side", node).unwrap(),
807    }
808}
809
810pub fn extract_stb_extensions(root_node: roxmltree::Node) -> StbExtensions {
811    let stb_extensions_node = extract_node("StbExtensions", root_node).unwrap();
812
813    let mut stb_extension_list = Vec::new();
814
815    for node in stb_extensions_node.children().filter(|n| n.is_element()) {
816        stb_extension_list.push(StbExtension {
817            identifier: parse_attribute("identifier", node).unwrap(),
818            description: parse_attribute("description", node).unwrap(),
819        });
820    }
821
822    StbExtensions { stb_extension_list }
823}
824
825fn parse_attribute<T: FromStr>(
826    name: &str,
827    node: roxmltree::Node,
828) -> Result<T, <T as FromStr>::Err> {
829    node.attribute(name).unwrap().to_lowercase().parse::<T>()
830}
831
832fn parse_enum_attribute<T: FromStr>(
833    name: &str,
834    node: roxmltree::Node,
835) -> Result<T, <T as FromStr>::Err> {
836    T::from_str(node.attribute(name).unwrap())
837}
838
839fn unimplemented_panic(what: &str) {
840    panic!("{} is unimplemented!", what);
841}