1use stacksafe::stacksafe;
14
15use crate::item::{Node, Sequence};
16use crate::output::OutputDefinition;
17#[allow(unused_imports)]
18use crate::pattern::Pattern;
19use crate::security::{Policy, SecurityResult};
20use crate::transform::booleans::*;
21use crate::transform::callable::{ActualParameters, Callable, invoke};
22use crate::transform::construct::*;
23use crate::transform::controlflow::*;
24use crate::transform::datetime::*;
25use crate::transform::functions::*;
26use crate::transform::grouping::*;
27use crate::transform::keys::{key, populate_key_values};
28use crate::transform::logic::*;
29use crate::transform::misc::*;
30use crate::transform::navigate::*;
31use crate::transform::numbers::*;
32use crate::transform::strings::*;
33use crate::transform::template::{Template, apply_imports, apply_templates, next_match};
34use crate::transform::variables::{declare_variable, reference_variable};
35use crate::transform::{MAXDEPTH, Transform};
36use crate::xdmerror::Error;
37use crate::{ErrorKind, Item, SequenceTrait, Value};
38use qualname::{NamespaceMap, NamespaceUri, NcName, QName};
39use std::cmp::Ordering;
40use std::collections::HashMap;
41use std::rc::Rc;
42use std::sync::LazyLock;
43use url::Url;
44
45#[derive(Clone, Debug)]
59pub struct Context<N: Node> {
60 pub(crate) context: Sequence<N>, pub(crate) i: usize, pub(crate) context_item: Option<Item<N>>, pub(crate) last: Option<usize>,
68 pub(crate) current: Sequence<N>,
69 pub(crate) current_item: Option<Item<N>>, pub(crate) depth: usize, pub(crate) max_depth: Option<usize>, pub(crate) rd: Option<N>, pub(crate) templates: Vec<Rc<Template<N>>>,
76 pub(crate) current_templates: Vec<Rc<Template<N>>>,
77 pub(crate) callables: HashMap<QName, Callable<N>>,
79 pub(crate) vars: HashMap<String, Vec<Sequence<N>>>,
81 pub(crate) pre_vars: Vec<(String, Transform<N>)>,
84 pub(crate) current_grouping_key: Option<Rc<Value>>,
86 pub(crate) current_group: Sequence<N>,
87 pub(crate) keys: HashMap<String, Vec<(Pattern<N>, Transform<N>)>>,
91 pub(crate) key_values: HashMap<String, HashMap<String, Vec<N>>>,
93 pub(crate) od: OutputDefinition,
95 pub(crate) base_url: Option<Url>,
96 pub(crate) namespaces: Option<Rc<NamespaceMap>>,
100 policy: Option<Rc<Policy<N>>>,
102}
103impl<N: Node> Default for Context<N> {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl<N: Node> Context<N> {
110 pub fn new() -> Self {
111 Context {
112 context: Sequence::new(),
113 current: Sequence::new(),
114 i: 0,
115 context_item: None,
116 last: None,
117 current_item: None,
118 depth: 0,
119 max_depth: Some(MAXDEPTH),
120 rd: None,
121 templates: vec![],
122 current_templates: vec![],
123 callables: HashMap::new(),
124 vars: HashMap::new(),
125 pre_vars: Vec::new(),
126 current_grouping_key: None,
127 current_group: Sequence::new(),
128 keys: HashMap::new(),
129 key_values: HashMap::new(),
130 od: OutputDefinition::new(),
131 base_url: None,
132 namespaces: None,
133 policy: None,
134 }
135 }
136 pub fn context(&mut self, s: Sequence<N>, i: usize) {
138 self.context_item = Some(s[i].clone());
139 self.context = s;
140 self.i = i;
141 }
142 pub fn context_item(&mut self, i: Option<Item<N>>) {
144 self.context_item = i;
145 }
146 pub fn current_item(&mut self, i: Item<N>) {
148 self.current_item = Some(i);
149 }
150 pub fn current(&mut self, s: Sequence<N>) {
152 self.current = s;
153 }
154 pub fn result_document(&mut self, rd: N) {
156 self.rd = Some(rd);
157 }
158 pub fn declare_key(&mut self, name: String, m: Pattern<N>, u: Transform<N>) {
160 if let Some(v) = self.keys.get_mut(&name) {
161 v.push((m, u))
162 } else {
163 self.keys.insert(name.clone(), vec![(m, u)]);
164 }
165 if self.key_values.get_mut(&name).is_some() {
167 } else {
169 self.key_values.insert(name, HashMap::new());
170 }
171 }
172 pub fn populate_key_values<
174 F: FnMut(&str) -> Result<(), Error>,
175 G: FnMut(&str) -> Result<N, Error>,
176 H: FnMut(&Url) -> Result<String, Error>,
177 >(
178 &mut self,
179 stctxt: &mut StaticContext<N, F, G, H>,
180 sd: N,
181 ) -> Result<(), Error> {
182 populate_key_values(self, stctxt, sd)
183 }
184 pub fn dump_key_values(&self) {
185 self.key_values.iter().for_each(|(k, v)| {
186 println!("key \"{}\":", k);
187 v.iter()
188 .for_each(|(kk, vv)| println!("\tvalue \"{}\" {} nodes", kk, vv.len()))
189 })
190 }
191 pub fn attribute_set(&mut self, _name: QName, _body: Vec<Transform<N>>) {}
193 pub fn var_push(&mut self, name: String, value: Sequence<N>) {
195 match self.vars.get_mut(name.as_str()) {
196 Some(u) => {
197 u.push(value);
199 }
200 None => {
201 self.vars.insert(name, vec![value]);
203 }
204 }
205 }
206 #[allow(dead_code)]
208 fn var_pop(&mut self, name: String) {
209 self.vars.get_mut(name.as_str()).map(|u| u.pop());
210 }
211 #[allow(dead_code)]
212 pub(crate) fn dump_vars(&self) -> String {
213 self.vars.iter().fold(String::new(), |mut acc, (k, v)| {
214 acc.push_str(format!("{}==\"{}\", ", k, v[0].to_string()).as_str());
215 acc
216 })
217 }
218 pub fn pre_var_push(&mut self, name: String, x: Transform<N>) {
220 self.pre_vars.push((name, x));
221 }
222
223 pub fn callable_push(&mut self, qn: QName, c: Callable<N>) {
225 self.callables.insert(qn, c);
226 }
227 pub fn callable_get(&self, qn: &QName) -> Option<Callable<N>> {
229 self.callables.get(qn).cloned()
230 }
231
232 #[allow(dead_code)]
234 fn baseurl(&self) -> Option<Url> {
235 self.base_url.clone()
236 }
237 #[allow(dead_code)]
239 fn set_baseurl(&mut self, url: Url) {
240 self.base_url = Some(url);
241 }
242
243 pub fn policy(&mut self, policy: Rc<Policy<N>>) -> Result<(), Error> {
246 calculate_features(self, &policy)?;
248
249 self.policy = Some(policy);
250
251 Ok(())
252 }
253 pub fn security_feature(
257 &self,
258 f: &QName,
259 a: ActualParameters<N>,
260 ) -> Result<SecurityResult, Error> {
261 if *f == *MAXDEPTH_QNAME {
262 self.policy
263 .as_ref()
264 .map_or_else(|| Ok(SecurityResult::NotPermitted), |p| p.get(f, a))
265 } else {
266 Ok(SecurityResult::NotPermitted)
268 }
269 }
270
271 pub(crate) fn evaluate_internal<
274 F: FnMut(&str) -> Result<(), Error>,
275 G: FnMut(&str) -> Result<N, Error>,
276 H: FnMut(&Url) -> Result<String, Error>,
277 >(
278 &self,
279 stctxt: &mut StaticContext<N, F, G, H>,
280 ) -> Result<Sequence<N>, Error> {
281 if self.context.is_empty() {
282 Ok(Sequence::new())
283 } else {
284 self.context_item.as_ref().map_or_else(
285 || {
286 Err(Error::new(
287 ErrorKind::DynamicAbsent,
288 String::from("no context item"),
289 ))
290 },
291 |i| {
292 let templates = self.find_templates(stctxt, i, &None)?;
296 match templates.len() {
297 0 => Err(Error::new(
298 ErrorKind::DynamicAbsent,
299 String::from("no matching template"),
300 )),
301 1 => self.dispatch(stctxt, &templates[0].body),
302 _ => {
303 if templates[0].priority == templates[1].priority
304 && templates[0].import.len() == templates[1].import.len()
305 {
306 let mut candidates: Vec<Rc<Template<N>>> = templates
307 .iter()
308 .take_while(|t| {
309 t.priority == templates[0].priority
310 && t.import.len() == templates[0].import.len()
311 })
312 .cloned()
313 .collect();
314 candidates.sort_unstable_by(|a, b| {
315 a.document_order.map_or(Ordering::Greater, |v| {
316 b.document_order.map_or(Ordering::Less, |u| v.cmp(&u))
317 })
318 });
319 self.dispatch(stctxt, &candidates.last().unwrap().body)
320 } else {
321 self.dispatch(stctxt, &templates[0].body)
322 }
323 }
324 }
325 },
326 )
327 }
328 }
329 pub fn evaluate<
370 F: FnMut(&str) -> Result<(), Error>,
371 G: FnMut(&str) -> Result<N, Error>,
372 H: FnMut(&Url) -> Result<String, Error>,
373 >(
374 &self,
375 stctxt: &mut StaticContext<N, F, G, H>,
376 ) -> Result<Sequence<N>, Error> {
377 if self.context.is_empty() {
379 Ok(Sequence::new())
381 } else {
382 let mut ctxt = self.clone();
383 ctxt.context(
386 self.context.get(self.i).map_or_else(Vec::new, |i| {
387 if let Item::Node(n) = i {
388 vec![Item::Node(n.owner_document())]
389 } else {
390 vec![]
391 }
392 }),
393 0,
394 );
395 for (name, x) in &self.pre_vars {
398 ctxt.var_push(name.clone(), ctxt.dispatch(stctxt, x)?);
399 }
400 let result = ctxt.evaluate_internal(stctxt)?;
401 if let Some(mut rd) = ctxt.rd {
403 Ok(result
404 .into_iter()
405 .map(|i| {
406 if let Item::Node(ref n) = i {
407 if n.owner_document().is_same(&rd) {
408 if n.is_unattached() {
409 rd.push(n.clone())
411 .expect("unable to attach to result document");
412 i
414 } else {
415 i
418 }
419 } else {
420 let cp = n.deep_copy().expect("unable to copy node");
424 rd.push(cp.clone())
425 .expect("unable to attach to result document");
426 Item::Node(cp)
428 }
429 } else {
430 i
432 }
433 })
434 .collect())
435 } else {
436 Ok(result)
437 }
438 }
439 }
440
441 pub fn find_templates<
443 F: FnMut(&str) -> Result<(), Error>,
444 G: FnMut(&str) -> Result<N, Error>,
445 H: FnMut(&Url) -> Result<String, Error>,
446 >(
447 &self,
448 stctxt: &mut StaticContext<N, F, G, H>,
449 i: &Item<N>,
450 m: &Option<QName>,
451 ) -> Result<Vec<Rc<Template<N>>>, Error> {
452 let mut candidates =
453 self.templates
454 .iter()
455 .filter(|t| t.mode == *m)
456 .try_fold(vec![], |mut cand, t| {
457 let e = t.pattern.matches(self, stctxt, i);
458 if e {
459 cand.push(t.clone())
460 }
461 Ok(cand)
462 })?;
463 if !candidates.is_empty() {
464 candidates.sort_unstable_by(|a, b| (*a).cmp(b));
467 Ok(candidates)
468 } else {
469 Err(Error::new(
470 ErrorKind::Unknown,
471 format!("no matching template for item {:?} in mode \"{:?}\"", i, m),
472 ))
473 }
474 }
475
476 #[stacksafe]
511 pub fn dispatch<
512 F: FnMut(&str) -> Result<(), Error>,
513 G: FnMut(&str) -> Result<N, Error>,
514 H: FnMut(&Url) -> Result<String, Error>,
515 >(
517 &self,
518 stctxt: &mut StaticContext<N, F, G, H>,
519 t: &Transform<N>,
520 ) -> Result<Sequence<N>, Error> {
521 match t {
522 Transform::Root => root(self),
523 Transform::ContextItem => context(self),
524 Transform::CurrentItem => current(self),
525 Transform::Compose(v) => compose(self, stctxt, v),
526 Transform::Step(nm) => step(self, nm),
527 Transform::StepPredicated(nm, preds) => step_predicated(self, stctxt, nm, preds),
528 Transform::Filter(t) => filter(self, stctxt, t),
529 Transform::Empty => empty(self),
530 Transform::Literal(v) => literal(self, v),
531 Transform::LiteralElement(qn, t) => literal_element(self, stctxt, qn, t),
532 Transform::Element(qn, t) => element(self, stctxt, qn, t),
533 Transform::LiteralText(t, b) => literal_text(self, stctxt, t, b),
534 Transform::LiteralAttribute(qn, t) => literal_attribute(self, stctxt, qn, t),
535 Transform::LiteralComment(t) => literal_comment(self, stctxt, t),
536 Transform::LiteralProcessingInstruction(n, t) => {
537 literal_processing_instruction(self, stctxt, n, t)
538 }
539 Transform::NamespaceDeclaration(p, u, s) => {
540 namespace_declaration(self, stctxt, p, u, s)
541 }
542 Transform::SetAttribute(qn, v) => set_attribute(self, stctxt, qn, v),
543 Transform::SequenceItems(v) => make_sequence(self, stctxt, v),
544 Transform::Copy(f, t) => copy(self, stctxt, f, t),
545 Transform::DeepCopy(d) => deep_copy(self, stctxt, d),
546 Transform::Or(v) => tr_or(self, stctxt, v),
547 Transform::And(v) => tr_and(self, stctxt, v),
548 Transform::Union(b) => union(self, stctxt, b),
549 Transform::GeneralComparison(o, l, r) => general_comparison(self, stctxt, o, l, r),
550 Transform::ValueComparison(o, l, r) => value_comparison(self, stctxt, o, l, r),
551 Transform::Concat(v) => tr_concat(self, stctxt, v),
552 Transform::Range(s, e) => tr_range(self, stctxt, s, e),
553 Transform::Arithmetic(v) => arithmetic(self, stctxt, v),
554 Transform::Loop(v, b) => tr_loop(self, stctxt, v, b),
555 Transform::Switch(c, o) => switch(self, stctxt, c, o),
556 Transform::ForEach(g, s, b, o) => for_each(self, stctxt, g, s, b, o),
557 Transform::ApplyTemplates(s, m, o) => apply_templates(self, stctxt, s, m, o),
558 Transform::ApplyImports => apply_imports(self, stctxt),
559 Transform::NextMatch => next_match(self, stctxt),
560 Transform::VariableDeclaration(n, v, f, _) => {
561 declare_variable(self, stctxt, n.clone(), v, f)
562 }
563 Transform::VariableReference(n, _) => reference_variable(self, n),
564 Transform::Position => position(self),
565 Transform::Last => last(self),
566 Transform::Count(s) => tr_count(self, stctxt, s),
567 Transform::LocalName(s) => local_name(self, stctxt, s),
568 Transform::Name(s) => name(self, stctxt, s),
569 Transform::String(s) => string(self, stctxt, s),
570 Transform::StartsWith(s, t) => starts_with(self, stctxt, s, t),
571 Transform::EndsWith(s, t) => ends_with(self, stctxt, s, t),
572 Transform::Contains(s, t) => contains(self, stctxt, s, t),
573 Transform::Substring(s, t, l) => substring(self, stctxt, s, t, l),
574 Transform::SubstringBefore(s, t) => substring_before(self, stctxt, s, t),
575 Transform::SubstringAfter(s, t) => substring_after(self, stctxt, s, t),
576 Transform::NormalizeSpace(s) => normalize_space(self, stctxt, s),
577 Transform::Translate(s, m, t) => translate(self, stctxt, s, m, t),
578 Transform::GenerateId(s) => generate_id(self, stctxt, s),
579 Transform::Boolean(b) => boolean(self, stctxt, b),
580 Transform::Not(b) => not(self, stctxt, b),
581 Transform::True => tr_true(self),
582 Transform::False => tr_false(self),
583 Transform::Number(n) => number(self, stctxt, n),
584 Transform::Sum(s) => sum(self, stctxt, s),
585 Transform::Avg(s) => avg(self, stctxt, s),
586 Transform::Min(s) => min(self, stctxt, s),
587 Transform::Max(s) => max(self, stctxt, s),
588 Transform::Floor(n) => floor(self, stctxt, n),
589 Transform::Ceiling(n) => ceiling(self, stctxt, n),
590 Transform::Round(n, p) => round(self, stctxt, n, p),
591 Transform::CurrentGroup => current_group(self),
592 Transform::CurrentGroupingKey => current_grouping_key(self),
593 Transform::CurrentDateTime => current_date_time(self),
594 Transform::CurrentDate => current_date(self),
595 Transform::CurrentTime => current_time(self),
596 Transform::FormatDateTime(t, p, l, c, q) => {
597 format_date_time(self, stctxt, t, p, l, c, q)
598 }
599 Transform::FormatDate(t, p, l, c, q) => format_date(self, stctxt, t, p, l, c, q),
600 Transform::FormatTime(t, p, l, c, q) => format_time(self, stctxt, t, p, l, c, q),
601 Transform::FormatNumber(v, p, d) => format_number(self, stctxt, v, p, d),
602 Transform::FormatInteger(i, s) => format_integer(self, stctxt, i, s),
603 Transform::GenerateIntegers(start_at, select, n) => {
604 generate_integers(self, stctxt, start_at, select, n)
605 }
606 Transform::Key(n, v, _, _) => key(self, stctxt, n, v),
607 Transform::SystemProperty(p, ns) => system_property(self, stctxt, p, ns),
608 Transform::AvailableSystemProperties => available_system_properties(),
609 Transform::Document(uris, base) => document(self, stctxt, uris, base),
610 Transform::Invoke(qn, a, ns) => invoke(self, stctxt, qn, a, ns),
611 Transform::Message(b, s, e, t) => message(self, stctxt, b, s, e, t),
612 Transform::Error(k, m) => tr_error(self, k, m),
613 Transform::NotImplemented(s) => not_implemented(self, s),
614 _ => Err(Error::new(
615 ErrorKind::NotImplemented,
616 "not implemented".to_string(),
617 )),
618 }
619 }
620}
621
622fn calculate_features<N: Node>(ctxt: &mut Context<N>, policy: &Rc<Policy<N>>) -> Result<(), Error> {
623 match policy.get(&*MAXDEPTH_QNAME, ActualParameters::Named(vec![]))? {
624 SecurityResult::NotPermitted => ctxt.max_depth = Some(MAXDEPTH),
625 SecurityResult::Permitted(None) => ctxt.max_depth = None,
626 SecurityResult::Permitted(Some(v)) => {
627 ctxt.max_depth = Some(
628 v.parse::<usize>()
629 .map_err(|_| Error::new(ErrorKind::ParseError, "not a number"))?,
630 )
631 }
632 }
633 Ok(())
634}
635
636impl<N: Node> From<Sequence<N>> for Context<N> {
637 fn from(value: Sequence<N>) -> Self {
638 let ci = if value.is_empty() {
639 None
640 } else {
641 Some(value[0].clone())
642 };
643 Context {
644 context_item: ci,
645 context: value,
646 i: 0,
647 last: None,
648 current_item: None,
649 current: Sequence::new(),
650 depth: 0,
651 max_depth: Some(MAXDEPTH),
652 rd: None,
653 templates: vec![],
654 current_templates: vec![],
655 callables: HashMap::new(),
656 vars: HashMap::new(),
657 pre_vars: Vec::new(),
658 keys: HashMap::new(),
659 key_values: HashMap::new(),
660 current_grouping_key: None,
661 current_group: Sequence::new(),
662 od: OutputDefinition::new(),
663 base_url: None,
664 namespaces: None,
665 policy: None,
666 }
667 }
668}
669
670pub struct ContextBuilder<N: Node>(Context<N>);
672
673impl<N: Node> Default for ContextBuilder<N> {
674 fn default() -> Self {
675 Self::new()
676 }
677}
678
679impl<N: Node> ContextBuilder<N> {
680 pub fn new() -> Self {
681 ContextBuilder(Context::new())
682 }
683 pub fn context(mut self, s: Sequence<N>) -> Self {
685 if !s.is_empty() {
686 self.0.context_item = Some(s[0].clone());
687 }
688 self.0.context = s;
689 self.0.i = 0;
690 self.0.last = None;
691 self
692 }
693 pub fn last(mut self, n: usize) -> Self {
696 self.0.last = Some(n);
697 self
698 }
699 pub fn index(mut self, i: usize) -> Self {
703 self.0.i = i;
704 self
705 }
706 pub fn context_item(mut self, c: Option<Item<N>>) -> Self {
708 self.0.context_item = c;
709 self
710 }
711 pub fn current_item(mut self, i: Option<Item<N>>) -> Self {
712 self.0.current_item = i;
713 self
714 }
715 pub fn current(mut self, s: Sequence<N>) -> Self {
716 self.0.current = s;
717 self
718 }
719 pub fn depth(mut self, d: usize) -> Self {
720 self.0.depth = d;
721 self
722 }
723 pub fn maximum_depth(mut self, m: Option<usize>) -> Self {
725 self.0.max_depth = m;
726 self
727 }
728 pub fn variable(mut self, n: String, v: Sequence<N>) -> Self {
729 self.0.var_push(n, v);
730 self
731 }
732 pub fn variables(mut self, v: HashMap<String, Vec<Sequence<N>>>) -> Self {
733 self.0.vars = v;
734 self
735 }
736 pub fn result_document(mut self, rd: N) -> Self {
737 self.0.rd = Some(rd);
738 self
739 }
740 pub fn template(mut self, t: Template<N>) -> Self {
741 self.0.templates.push(Rc::new(t));
742 self
743 }
744 pub fn template_all(mut self, v: Vec<Template<N>>) -> Self {
745 for t in v {
746 self.0.templates.push(Rc::new(t))
747 }
748 self
749 }
750 pub fn current_templates(mut self, c: Vec<Rc<Template<N>>>) -> Self {
751 self.0.current_templates = c;
752 self
753 }
754 pub fn current_group(mut self, c: Sequence<N>) -> Self {
755 self.0.current_group = c;
756 self
757 }
758 pub fn current_grouping_key(mut self, k: Rc<Value>) -> Self {
759 self.0.current_grouping_key = Some(k);
760 self
761 }
762 pub fn output_definition(mut self, od: OutputDefinition) -> Self {
763 self.0.od = od;
764 self
765 }
766 pub fn base_url(mut self, b: Url) -> Self {
767 self.0.base_url = Some(b);
768 self
769 }
770 pub fn callable(mut self, qn: QName, c: Callable<N>) -> Self {
771 self.0.callables.insert(qn, c);
772 self
773 }
774 pub fn namespaces(mut self, nm: NamespaceMap) -> Self {
775 self.0.namespaces = Some(Rc::new(nm));
776 self
777 }
778 pub fn policy(mut self, p: Rc<Policy<N>>) -> Result<Self, Error> {
780 calculate_features(&mut self.0, &p)?;
781 self.0.policy = Some(p);
782 Ok(self)
783 }
784 pub fn build(self) -> Context<N> {
785 self.0
786 }
787}
788
789impl<N: Node> From<&Context<N>> for ContextBuilder<N> {
791 fn from(c: &Context<N>) -> Self {
792 c.context_item.as_ref().map_or_else(
793 || ContextBuilder(c.clone()).current(vec![]).current_item(None),
794 |i| {
795 ContextBuilder(c.clone())
796 .current(c.context.clone())
797 .current_item(Some(i.clone()))
798 },
799 )
800 }
801}
802
803pub struct StaticContext<N: Node, F, G, H>
807where
808 F: FnMut(&str) -> Result<(), Error>,
809 G: FnMut(&str) -> Result<N, Error>, H: FnMut(&Url) -> Result<String, Error>, {
812 pub(crate) message: Option<F>,
813 pub(crate) parser: Option<G>,
814 pub(crate) fetcher: Option<H>,
815}
816impl<N: Node, F, G, H> Default for StaticContext<N, F, G, H>
817where
818 F: FnMut(&str) -> Result<(), Error>,
819 G: FnMut(&str) -> Result<N, Error>,
820 H: FnMut(&Url) -> Result<String, Error>,
821{
822 fn default() -> Self {
823 Self::new()
824 }
825}
826
827impl<N: Node, F, G, H> StaticContext<N, F, G, H>
828where
829 F: FnMut(&str) -> Result<(), Error>,
830 G: FnMut(&str) -> Result<N, Error>,
831 H: FnMut(&Url) -> Result<String, Error>,
832{
833 pub fn new() -> Self {
834 StaticContext {
835 message: None,
836 parser: None,
837 fetcher: None,
838 }
839 }
840}
841
842pub struct StaticContextBuilder<
881 N: Node,
882 F: FnMut(&str) -> Result<(), Error>,
883 G: FnMut(&str) -> Result<N, Error>,
884 H: FnMut(&Url) -> Result<String, Error>,
885>(StaticContext<N, F, G, H>);
886
887impl<N: Node, F, G, H> Default for StaticContextBuilder<N, F, G, H>
888where
889 F: FnMut(&str) -> Result<(), Error>,
890 G: FnMut(&str) -> Result<N, Error>,
891 H: FnMut(&Url) -> Result<String, Error>,
892{
893 fn default() -> Self {
894 Self::new()
895 }
896}
897
898impl<N: Node, F, G, H> StaticContextBuilder<N, F, G, H>
899where
900 F: FnMut(&str) -> Result<(), Error>,
901 G: FnMut(&str) -> Result<N, Error>,
902 H: FnMut(&Url) -> Result<String, Error>,
903{
904 pub fn new() -> Self {
905 StaticContextBuilder(StaticContext::new())
906 }
907 pub fn message(mut self, f: F) -> Self {
908 self.0.message = Some(f);
909 self
910 }
911 pub fn parser(mut self, p: G) -> Self {
912 self.0.parser = Some(p);
913 self
914 }
915 pub fn fetcher(mut self, f: H) -> Self {
916 self.0.fetcher = Some(f);
917 self
918 }
919 pub fn build(self) -> StaticContext<N, F, G, H> {
920 self.0
921 }
922}
923
924static TRANSFORMNS: LazyLock<Option<NamespaceUri>> = LazyLock::new(|| {
926 Some(
927 NamespaceUri::try_from("http://gitlab.gnome.org/World/Rust/markup-rs/xrust/transform")
928 .unwrap(),
929 )
930});
931static MAXDEPTH_QNAME: LazyLock<QName> = LazyLock::new(|| {
932 QName::new_from_parts(
933 NcName::try_from("maximum-depth").unwrap(),
934 TRANSFORMNS.clone(),
935 )
936});