Skip to main content

xsd_schema/parser/frames/
facets.rs

1// ============================================================================
2// Facet Frame
3// ============================================================================
4
5/// Frame for facet elements (enumeration, pattern, etc.)
6pub struct FacetFrame {
7    kind: FacetKind,
8    value: String,
9    fixed: bool,
10    #[allow(dead_code)]
11    id: Option<String>,
12    /// XSD 1.1 assertion: xpathDefaultNamespace attribute (raw string)
13    xpath_default_namespace: Option<String>,
14    /// XSD 1.1 assertion: namespace bindings snapshot for XPath prefix resolution
15    ns_snapshot: Option<NamespaceContextSnapshot>,
16    annotation: Option<Annotation>,
17    source: Option<SourceRef>,
18    foreign_attributes: Vec<ForeignAttribute>,
19}
20
21impl FacetFrame {
22    pub fn new(
23        kind: FacetKind,
24        attrs: &AttributeMap,
25        name_table: &NameTable,
26        source: Option<SourceRef>,
27        ns_snapshot: Option<NamespaceContextSnapshot>,
28    ) -> SchemaResult<Self> {
29        // For assertion facets, read 'test' attribute instead of 'value'
30        let value = if kind == FacetKind::Assertion {
31            attrs
32                .get_value_by_name(name_table, "test")
33                .map(String::from)
34                .unwrap_or_default()
35        } else {
36            attrs
37                .get_value_by_name(name_table, "value")
38                .map(String::from)
39                .unwrap_or_default()
40        };
41
42        let fixed = parse_bool_attr_default(attrs, name_table, "fixed", false)?;
43
44        let id = attrs
45            .get_value_by_name(name_table, "id")
46            .map(String::from);
47
48        // For assertion facets, read xpathDefaultNamespace
49        let xpath_default_namespace = if kind == FacetKind::Assertion {
50            attrs
51                .get_value_by_name(name_table, "xpathDefaultNamespace")
52                .map(String::from)
53        } else {
54            None
55        };
56
57        Ok(Self {
58            kind,
59            value,
60            fixed,
61            id,
62            xpath_default_namespace,
63            ns_snapshot,
64            annotation: None,
65            source,
66            foreign_attributes: Vec::new(),
67        })
68    }
69}
70
71impl Frame for FacetFrame {
72    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
73        matches!(local_name, xsd_names::ANNOTATION)
74    }
75
76    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
77        if self.kind == FacetKind::Assertion {
78            matches!(local_name, "test" | "xpathDefaultNamespace" | "id")
79        } else {
80            matches!(local_name, "value" | "fixed" | "id")
81        }
82    }
83
84    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
85
86    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
87        if let FrameResult::Annotation(ann) = child {
88            self.annotation = Some(ann);
89        }
90        Ok(())
91    }
92
93    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
94        let annotation = merge_foreign_attributes(
95            self.annotation,
96            self.foreign_attributes,
97            self.source.clone(),
98        );
99        Ok(FrameResult::Facet(FacetResult {
100            kind: self.kind,
101            value: self.value,
102            fixed: self.fixed,
103            annotation,
104            source: self.source,
105            xpath_default_namespace: self.xpath_default_namespace,
106            ns_snapshot: self.ns_snapshot,
107        }))
108    }
109
110    fn has_annotation(&self) -> bool {
111        self.annotation.is_some()
112    }
113
114    fn source(&self) -> Option<&SourceRef> {
115        self.source.as_ref()
116    }
117
118    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
119        self.foreign_attributes = attrs;
120    }
121}