xee_interpreter/atomic/
xpath_repr.rs1use xot::xmlname::NameStrInfo;
2
3use super::{Atomic, StringType};
4
5impl Atomic {
6 pub fn xpath_representation(&self) -> String {
8 match self {
9 Atomic::String(string_type, v) => match string_type {
10 StringType::String => string_literal(v),
11 _ => {
12 let schema_type = string_type.schema_type();
13 format!("xs:{}({})", schema_type.local_name(), string_literal(v))
14 }
15 },
16
17 Atomic::Boolean(v) => {
18 if *v {
19 "true()".to_string()
20 } else {
21 "false()".to_string()
22 }
23 }
24 Atomic::Decimal(_) | Atomic::Integer(_, _) | Atomic::Float(_) | Atomic::Double(_) => {
26 self.string_value()
27 }
28
29 Atomic::QName(v) => {
33 format!(
34 r#"fn:QName({}, {})"#,
35 string_literal(v.namespace()),
36 string_literal(v.local_name())
37 )
38 }
39 _ => self.canonical_xpath_representation(),
42 }
43 }
44
45 fn canonical_xpath_representation(&self) -> String {
46 format!(
47 "xs:{}({})",
48 self.schema_type().local_name(),
49 string_literal(&self.string_value())
50 )
51 }
52}
53
54fn string_literal(s: &str) -> String {
55 if s.contains('\"') {
56 if s.contains('\'') {
57 let s = s.replace('\"', r#""""#);
58 format!(r#""{}""#, s)
59 } else {
60 format!(r#"'{}'"#, s)
61 }
62 } else {
63 format!(r#""{}""#, s)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use ibig::IBig;
70 use rust_decimal_macros::dec;
71
72 use crate::atomic::{BinaryType, Duration, IntegerType};
73
74 use super::*;
75
76 #[test]
77 fn test_string_simple() {
78 let atomic: Atomic = "foo".into();
79 assert_eq!(atomic.xpath_representation(), r#""foo""#);
80 }
81
82 #[test]
83 fn test_string_with_single_quote() {
84 let atomic: Atomic = "foo'bar".into();
85 assert_eq!(atomic.xpath_representation(), r#""foo'bar""#);
86 }
87
88 #[test]
89 fn test_string_with_double_quote() {
90 let atomic: Atomic = r#"foo"bar"#.into();
91 assert_eq!(atomic.xpath_representation(), r#"'foo"bar'"#);
92 }
93
94 #[test]
95 fn test_string_with_both_quotes() {
96 let atomic: Atomic = r#"foo'bar"baz"#.into();
97 assert_eq!(atomic.xpath_representation(), r#""foo'bar""baz""#);
98 }
99
100 #[test]
101 fn test_normalized_string() {
102 let atomic = Atomic::String(StringType::NormalizedString, "foo".into());
103 assert_eq!(
104 atomic.xpath_representation(),
105 r#"xs:normalizedString("foo")"#
106 );
107 }
108
109 #[test]
110 fn test_untyped() {
111 let atomic = Atomic::Untyped("foo".into());
112 assert_eq!(atomic.xpath_representation(), r#"xs:untypedAtomic("foo")"#);
113 }
114
115 #[test]
116 fn test_boolean_true() {
117 let atomic = Atomic::Boolean(true);
118 assert_eq!(atomic.xpath_representation(), "true()");
119 }
120
121 #[test]
122 fn test_boolean_false() {
123 let atomic = Atomic::Boolean(false);
124 assert_eq!(atomic.xpath_representation(), "false()");
125 }
126
127 #[test]
128 fn test_decimal_left_right() {
129 let atomic = Atomic::Decimal(dec!(1.5).into());
130 assert_eq!(atomic.xpath_representation(), "1.5");
131 }
132
133 #[test]
134 fn test_decimal_is_integer() {
135 let atomic = Atomic::Decimal(dec!(1.0).into());
136 assert_eq!(atomic.xpath_representation(), "1");
137 }
138
139 #[test]
140 fn test_decimal_only_right() {
141 let atomic = Atomic::Decimal(dec!(0.5).into());
142 assert_eq!(atomic.xpath_representation(), "0.5");
143 }
144
145 #[test]
146 fn test_integer() {
147 let i: IBig = 1.into();
148 let atomic = Atomic::Integer(IntegerType::Integer, i.into());
149 assert_eq!(atomic.xpath_representation(), "1");
150 }
151
152 #[test]
153 fn test_qname() {
154 let name = xot::xmlname::OwnedName::new(
155 "foo".to_string(),
156 "http://example.com".to_string(),
157 "".to_string(),
158 );
159 let atomic = Atomic::QName(name.into());
160 assert_eq!(
161 atomic.xpath_representation(),
162 r#"fn:QName("http://example.com", "foo")"#
163 );
164 }
165
166 #[test]
167 fn test_hex_binary() {
168 let atomic = Atomic::Binary(BinaryType::Hex, vec![0xDE, 0xAD, 0xBE, 0xEF].into());
169 assert_eq!(atomic.xpath_representation(), "xs:hexBinary(\"DEADBEEF\")");
170 }
171
172 #[test]
173 fn test_base64_binary() {
174 let atomic = Atomic::Binary(BinaryType::Base64, vec![0xDE, 0xAD, 0xBE, 0xEF].into());
175 assert_eq!(
176 atomic.xpath_representation(),
177 "xs:base64Binary(\"3q2+7w==\")"
178 );
179 }
180
181 #[test]
182 fn test_duration() {
183 let duration = Duration::new(14, chrono::Duration::seconds(0));
184
185 let atomic = Atomic::Duration(duration.into());
186 assert_eq!(atomic.xpath_representation(), r#"xs:duration("P1Y2M")"#);
187 }
188
189 #[test]
190 fn test_day_time_duration() {
191 let atomic = Atomic::DayTimeDuration(chrono::Duration::seconds(641).into());
192 assert_eq!(
193 atomic.xpath_representation(),
194 r#"xs:dayTimeDuration("PT10M41S")"#
195 );
196 }
197}