shacl_ast/converter/rdf_to_shacl/
shacl_parser.rs

1use iri_s::IriS;
2use prefixmap::{IriRef, PrefixMap};
3use srdf::{
4    combine_parsers, combine_vec, fail_msg, get_focus, has_type, instances_of, lang::Lang,
5    matcher::Any, not, ok, optional, parse_nodes, property_bool, property_value, property_values,
6    property_values_int, property_values_iri, property_values_non_empty, rdf_list, term, FocusRDF,
7    Iri as _, Literal, PResult, RDFNode, RDFNodeParse, RDFParseError, RDFParser, Rdf, SHACLPath,
8    Term, Triple, RDFS_CLASS, RDF_TYPE,
9};
10use std::collections::{HashMap, HashSet};
11
12use crate::{
13    component::Component, node_kind::NodeKind, node_shape::NodeShape,
14    property_shape::PropertyShape, schema::Schema, shape::Shape, target::Target, value::Value, *,
15};
16use std::fmt::Debug;
17
18use super::shacl_parser_error::ShaclParserError;
19
20type Result<A> = std::result::Result<A, ShaclParserError>;
21
22struct State {
23    pending: Vec<RDFNode>,
24}
25
26impl State {
27    fn from(pending: Vec<RDFNode>) -> Self {
28        State { pending }
29    }
30
31    fn pop_pending(&mut self) -> Option<RDFNode> {
32        self.pending.pop()
33    }
34}
35
36pub struct ShaclParser<RDF>
37where
38    RDF: FocusRDF + Debug,
39{
40    rdf_parser: RDFParser<RDF>,
41    shapes: HashMap<RDFNode, Shape>,
42    errors: Vec<ShaclParserError>,
43}
44
45impl<RDF> ShaclParser<RDF>
46where
47    RDF: FocusRDF + Debug,
48{
49    pub fn new(rdf: RDF) -> ShaclParser<RDF> {
50        ShaclParser {
51            rdf_parser: RDFParser::new(rdf),
52            shapes: HashMap::new(),
53            errors: Vec::new(),
54        }
55    }
56
57    pub fn errors(&self) -> &[ShaclParserError] {
58        &self.errors
59    }
60
61    pub fn parse(&mut self) -> Result<Schema> {
62        let prefixmap: PrefixMap = self.rdf_parser.prefixmap().unwrap_or_default();
63
64        let mut state = State::from(self.shapes_candidates()?);
65        while let Some(node) = state.pop_pending() {
66            if let std::collections::hash_map::Entry::Vacant(e) = self.shapes.entry(node.clone()) {
67                self.rdf_parser.rdf.set_focus(&node.clone().into());
68                match Self::shape(&mut state)
69                    .parse_impl(&mut self.rdf_parser.rdf)
70                    .map_err(|e| ShaclParserError::RDFParseError { err: e })
71                {
72                    Ok(shape) => {
73                        e.insert(shape);
74                    }
75                    Err(e) => {
76                        self.errors.push(e);
77                    }
78                };
79            }
80        }
81
82        Ok(Schema::new()
83            .with_prefixmap(prefixmap)
84            .with_shapes(self.shapes.clone()))
85    }
86
87    fn shapes_candidates(&mut self) -> Result<Vec<RDFNode>> {
88        // subjects with type `sh:NodeShape`
89        let node_shape_instances: HashSet<_> = self
90            .rdf_parser
91            .rdf
92            .triples_matching(Any, Self::rdf_type(), Self::sh_node_shape())
93            .map_err(|e| ShaclParserError::Custom { msg: e.to_string() })?
94            .map(Triple::into_subject)
95            .collect();
96
97        // subjects with property `sh:property`
98        let subjects_property = self.objects_with_predicate(Self::sh_property())?;
99
100        // elements of `sh:or` list
101        let sh_or_values = self.get_sh_or_values()?;
102
103        // elements of `sh:xone` list
104        let sh_xone_values = self.get_sh_xone_values()?;
105
106        // elements of `sh:and` list
107        let sh_and_values = self.get_sh_and_values()?;
108
109        // elements of `sh:not` list
110        let sh_not_values = self.get_sh_not_values()?;
111
112        // elements of `sh:not` list
113        let sh_node_values = self.get_sh_node_values()?;
114
115        // TODO: subjects with type `sh:PropertyShape`
116        let property_shapes_instances = HashSet::new();
117
118        // TODO: subjects with type `sh:Shape`
119        let shape_instances = HashSet::new();
120
121        // I would prefer a code like: node_shape_instances.union(subjects_property).union(...)
122        // But looking to the union API in HashSet, I think it can't be chained
123        let mut candidates = HashSet::new();
124        candidates.extend(node_shape_instances);
125        candidates.extend(subjects_property);
126        candidates.extend(sh_or_values);
127        candidates.extend(sh_xone_values);
128        candidates.extend(sh_and_values);
129        candidates.extend(sh_not_values);
130        candidates.extend(sh_node_values);
131        candidates.extend(property_shapes_instances);
132        candidates.extend(shape_instances);
133
134        let result: Vec<_> = candidates
135            .into_iter()
136            .map(|subject: RDF::Subject| subject.into())
137            .map(|term: RDF::Term| term.into())
138            .collect();
139
140        Ok(result)
141    }
142
143    fn get_sh_or_values(&mut self) -> Result<HashSet<RDF::Subject>> {
144        let mut rs = HashSet::new();
145        for subject in self.objects_with_predicate(Self::sh_or())? {
146            self.rdf_parser.set_focus(&subject.into());
147            let vs = rdf_list().parse_impl(&mut self.rdf_parser.rdf)?;
148            for v in vs {
149                if let Ok(subj) = v.clone().try_into() {
150                    rs.insert(subj);
151                } else {
152                    return Err(ShaclParserError::OrValueNoSubject {
153                        term: format!("{v}"),
154                    });
155                }
156            }
157        }
158        Ok(rs)
159    }
160
161    fn get_sh_xone_values(&mut self) -> Result<HashSet<RDF::Subject>> {
162        let mut rs = HashSet::new();
163        for subject in self.objects_with_predicate(Self::sh_xone())? {
164            self.rdf_parser.set_focus(&subject.into());
165            let vs = rdf_list().parse_impl(&mut self.rdf_parser.rdf)?;
166            for v in vs {
167                if let Ok(subj) = v.clone().try_into() {
168                    rs.insert(subj);
169                } else {
170                    return Err(ShaclParserError::XOneValueNoSubject {
171                        term: format!("{v}"),
172                    });
173                }
174            }
175        }
176        Ok(rs)
177    }
178
179    fn get_sh_and_values(&mut self) -> Result<HashSet<RDF::Subject>> {
180        let mut rs = HashSet::new();
181        for subject in self.objects_with_predicate(Self::sh_and())? {
182            self.rdf_parser.set_focus(&subject.into());
183            let vs = rdf_list().parse_impl(&mut self.rdf_parser.rdf)?;
184            for v in vs {
185                if let Ok(subj) = v.clone().try_into() {
186                    rs.insert(subj);
187                } else {
188                    return Err(ShaclParserError::AndValueNoSubject {
189                        term: format!("{v}"),
190                    });
191                }
192            }
193        }
194        Ok(rs)
195    }
196
197    fn get_sh_not_values(&mut self) -> Result<HashSet<RDF::Subject>> {
198        let mut rs = HashSet::new();
199        for s in self.objects_with_predicate(Self::sh_not())? {
200            rs.insert(s);
201        }
202        Ok(rs)
203    }
204
205    fn get_sh_node_values(&mut self) -> Result<HashSet<RDF::Subject>> {
206        let mut rs = HashSet::new();
207        for s in self.objects_with_predicate(Self::sh_node())? {
208            rs.insert(s);
209        }
210        Ok(rs)
211    }
212
213    fn objects_with_predicate(&self, pred: RDF::IRI) -> Result<HashSet<RDF::Subject>> {
214        let values_as_subjects = self
215            .rdf_parser
216            .rdf
217            .triples_with_predicate(pred)
218            .map_err(|e| ShaclParserError::Custom { msg: e.to_string() })?
219            .map(Triple::into_object)
220            .flat_map(TryInto::try_into)
221            .collect();
222        Ok(values_as_subjects)
223    }
224
225    /*fn values_of_list(&mut self, term: RDF::Term) -> Result<Vec<RDF::Term>> {
226        let values = set_focus(&term).with(rdf_list()).parse_impl(&mut self.rdf_parser.rdf)?;
227        Ok(values)
228    }*/
229
230    fn rdf_type() -> RDF::IRI {
231        RDF_TYPE.clone().into()
232    }
233
234    fn sh_node_shape() -> RDF::Term {
235        let iri: RDF::IRI = SH_NODE_SHAPE.clone().into();
236        iri.into()
237    }
238
239    fn sh_property() -> RDF::IRI {
240        SH_PROPERTY.clone().into()
241    }
242
243    fn sh_or() -> RDF::IRI {
244        SH_OR.clone().into()
245    }
246
247    fn sh_xone() -> RDF::IRI {
248        SH_XONE.clone().into()
249    }
250
251    fn sh_and() -> RDF::IRI {
252        SH_AND.clone().into()
253    }
254
255    fn sh_not() -> RDF::IRI {
256        SH_NOT.clone().into()
257    }
258
259    fn sh_node() -> RDF::IRI {
260        SH_NODE.clone().into()
261    }
262
263    fn shape<'a>(state: &'a mut State) -> impl RDFNodeParse<RDF, Output = Shape> + 'a
264    where
265        RDF: FocusRDF + 'a,
266    {
267        node_shape()
268            .then(move |ns| ok(&Shape::NodeShape(Box::new(ns))))
269            .or(property_shape(state).then(|ps| ok(&Shape::PropertyShape(ps))))
270    }
271}
272
273fn components<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
274where
275    RDF: FocusRDF,
276{
277    combine_parsers!(
278        min_count(),
279        max_count(),
280        in_component(),
281        datatype(),
282        node_kind(),
283        class(),
284        or(),
285        xone(),
286        and(),
287        not_parser(),
288        node(),
289        min_length(),
290        max_length(),
291        has_value(),
292        language_in()
293    )
294}
295
296fn property_shape<'a, RDF>(
297    _state: &'a mut State,
298) -> impl RDFNodeParse<RDF, Output = PropertyShape> + 'a
299where
300    RDF: FocusRDF + 'a,
301{
302    optional(has_type(SH_PROPERTY_SHAPE.clone()))
303        .with(
304            id().and(path())
305                .then(move |(id, path)| ok(&PropertyShape::new(id, path))),
306        )
307        .then(|ps| targets().flat_map(move |ts| Ok(ps.clone().with_targets(ts))))
308        .then(|ps| {
309            optional(closed()).flat_map(move |c| {
310                if let Some(true) = c {
311                    Ok(ps.clone().with_closed(true))
312                } else {
313                    Ok(ps.clone())
314                }
315            })
316        })
317        .then(|ps| {
318            property_shapes()
319                .flat_map(move |prop_shapes| Ok(ps.clone().with_property_shapes(prop_shapes)))
320        })
321        .then(move |ps| property_shape_components(ps))
322}
323
324fn property_shape_components<RDF>(
325    ps: PropertyShape,
326) -> impl RDFNodeParse<RDF, Output = PropertyShape>
327where
328    RDF: FocusRDF,
329{
330    components().flat_map(move |cs| Ok(ps.clone().with_components(cs)))
331}
332
333fn node_shape<RDF>() -> impl RDFNodeParse<RDF, Output = NodeShape>
334where
335    RDF: FocusRDF,
336{
337    not(property_values_non_empty(&SH_PATH)).with(
338        term()
339            .then(move |t: RDF::Term| ok(&NodeShape::new(t.into())))
340            .then(|ns| targets().flat_map(move |ts| Ok(ns.clone().with_targets(ts))))
341            .then(|ps| {
342                optional(closed()).flat_map(move |c| {
343                    if let Some(true) = c {
344                        Ok(ps.clone().with_closed(true))
345                    } else {
346                        Ok(ps.clone())
347                    }
348                })
349            })
350            .then(|ns| {
351                property_shapes().flat_map(move |ps| Ok(ns.clone().with_property_shapes(ps)))
352            })
353            .then(|ns| components().flat_map(move |cs| Ok(ns.clone().with_components(cs)))),
354    )
355}
356
357fn property_shapes<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Vec<RDFNode>> {
358    property_values(&SH_PROPERTY).flat_map(|ts| {
359        let nodes = ts.into_iter().map(Into::into).collect();
360        Ok(nodes)
361    })
362}
363
364fn parse_xone_values<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Component> {
365    rdf_list().flat_map(|ls| cnv_xone_list::<RDF>(ls))
366}
367
368fn cnv_xone_list<RDF>(ls: Vec<RDF::Term>) -> PResult<Component>
369where
370    RDF: Rdf,
371{
372    let shapes: Vec<_> = ls.into_iter().map(Into::into).collect();
373    Ok(Component::Xone { shapes })
374}
375
376fn parse_and_values<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Component> {
377    rdf_list().flat_map(|ls| cnv_and_list::<RDF>(ls))
378}
379
380fn cnv_and_list<RDF>(ls: Vec<RDF::Term>) -> PResult<Component>
381where
382    RDF: Rdf,
383{
384    let shapes: Vec<_> = ls.into_iter().map(Into::into).collect();
385    Ok(Component::And { shapes })
386}
387
388fn parse_not_value<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Component> {
389    term().flat_map(|t| cnv_not::<RDF>(t))
390}
391
392fn parse_node_value<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Component> {
393    term().flat_map(|t| cnv_node::<RDF>(t))
394}
395
396fn cnv_node<RDF>(t: RDF::Term) -> PResult<Component>
397where
398    RDF: Rdf,
399{
400    Ok(Component::Node { shape: t.into() })
401}
402
403fn cnv_not<RDF>(t: RDF::Term) -> PResult<Component>
404where
405    RDF: Rdf,
406{
407    Ok(Component::Not { shape: t.into() })
408}
409
410fn parse_or_values<RDF: FocusRDF>() -> impl RDFNodeParse<RDF, Output = Component> {
411    rdf_list().flat_map(|ls| cnv_or_list::<RDF>(ls))
412}
413
414fn cnv_or_list<RDF>(ls: Vec<RDF::Term>) -> PResult<Component>
415where
416    RDF: Rdf,
417{
418    let shapes: Vec<_> = ls.into_iter().map(Into::into).collect();
419    Ok(Component::Or { shapes })
420}
421
422fn id<RDF>() -> impl RDFNodeParse<RDF, Output = RDFNode>
423where
424    RDF: FocusRDF,
425{
426    term().then(move |t: RDF::Term| ok(&t.into()))
427}
428
429/// Parses the property value of the focus node as a SHACL path
430fn path<RDF>() -> impl RDFNodeParse<RDF, Output = SHACLPath>
431where
432    RDF: FocusRDF,
433{
434    property_value(&SH_PATH).then(shacl_path)
435}
436
437/// Parses the current focus node as a SHACL path
438fn shacl_path<RDF>(term: RDF::Term) -> impl RDFNodeParse<RDF, Output = SHACLPath>
439where
440    RDF: FocusRDF,
441{
442    if let Ok(iri) = term.try_into() {
443        let iri: RDF::IRI = iri;
444        let iri_string = iri.as_str();
445        let iri_s = IriS::new_unchecked(iri_string);
446        std::result::Result::Ok(ok(&SHACLPath::iri(iri_s)))
447    } else {
448        std::result::Result::Err(fail_msg(String::from("Only simple paths are supported")))
449    }
450}
451
452fn targets<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Target>>
453where
454    RDF: FocusRDF,
455{
456    combine_parsers!(
457        targets_class(),
458        targets_node(),
459        targets_implicit_class(),
460        targets_subjects_of(),
461        targets_objects_of()
462    )
463}
464
465fn closed<RDF>() -> impl RDFNodeParse<RDF, Output = bool>
466where
467    RDF: FocusRDF,
468{
469    property_bool(&SH_CLOSED)
470}
471
472fn min_count<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
473where
474    RDF: FocusRDF,
475{
476    property_values_int(&SH_MIN_COUNT)
477        .map(|ns| ns.iter().map(|n| Component::MinCount(*n)).collect())
478}
479
480fn max_count<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
481where
482    RDF: FocusRDF,
483{
484    property_values_int(&SH_MAX_COUNT)
485        .map(|ns| ns.iter().map(|n| Component::MaxCount(*n)).collect())
486}
487
488fn min_length<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
489where
490    RDF: FocusRDF,
491{
492    property_values_int(&SH_MIN_LENGTH)
493        .map(|ns| ns.iter().map(|n| Component::MinLength(*n)).collect())
494}
495
496fn max_length<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
497where
498    RDF: FocusRDF,
499{
500    property_values_int(&SH_MAX_LENGTH)
501        .map(|ns| ns.iter().map(|n| Component::MaxLength(*n)).collect())
502}
503
504fn datatype<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
505where
506    RDF: FocusRDF,
507{
508    property_values_iri(&SH_DATATYPE).map(|ns| {
509        ns.iter()
510            .map(|iri| Component::Datatype(IriRef::iri(iri.clone())))
511            .collect()
512    })
513}
514
515fn class<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
516where
517    RDF: FocusRDF,
518{
519    property_values(&SH_CLASS).map(|ns| {
520        ns.iter()
521            .map(|term: &RDF::Term| Component::Class(term.clone().into()))
522            .collect()
523    })
524}
525
526fn node_kind<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
527where
528    RDF: FocusRDF,
529{
530    property_values(&SH_NODE_KIND).flat_map(|ns| {
531        let nks: Vec<_> = ns
532            .iter()
533            .flat_map(|term| {
534                let nk = term_to_node_kind::<RDF>(term)?;
535                Ok::<Component, ShaclParserError>(Component::NodeKind(nk))
536            })
537            .collect();
538        Ok(nks)
539    })
540}
541
542fn has_value<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
543where
544    RDF: FocusRDF,
545{
546    property_values(&SH_HAS_VALUE).then(move |node_set| {
547        let nodes: Vec<_> = node_set.into_iter().collect();
548        parse_nodes(nodes, parse_has_value_values())
549    })
550}
551
552fn in_component<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
553where
554    RDF: FocusRDF,
555{
556    property_values(&SH_IN).then(move |node_set| {
557        let nodes: Vec<_> = node_set.into_iter().collect();
558        parse_nodes(nodes, parse_in_values())
559    })
560}
561
562fn language_in<R: FocusRDF>() -> impl RDFNodeParse<R, Output = Vec<Component>> {
563    property_values(&SH_LANGUAGE_IN).then(move |node_set| {
564        let nodes: Vec<_> = node_set.into_iter().collect();
565        parse_nodes(nodes, parse_language_in_values())
566    })
567}
568
569fn parse_in_values<RDF>() -> impl RDFNodeParse<RDF, Output = Component>
570where
571    RDF: FocusRDF,
572{
573    rdf_list().flat_map(cnv_in_list::<RDF>)
574}
575
576fn parse_has_value_values<RDF>() -> impl RDFNodeParse<RDF, Output = Component>
577where
578    RDF: FocusRDF,
579{
580    term().flat_map(cnv_has_value::<RDF>)
581}
582
583fn parse_language_in_values<R: FocusRDF>() -> impl RDFNodeParse<R, Output = Component> {
584    rdf_list().flat_map(cnv_language_in_list::<R>)
585}
586
587fn cnv_has_value<RDF>(term: RDF::Term) -> std::result::Result<Component, RDFParseError>
588where
589    RDF: Rdf,
590{
591    let value = term_to_value::<RDF>(&term)?;
592    Ok(Component::HasValue { value })
593}
594
595fn cnv_language_in_list<R: FocusRDF>(
596    terms: Vec<R::Term>,
597) -> std::result::Result<Component, RDFParseError> {
598    let langs: Vec<Lang> = terms.iter().flat_map(term_to_lang::<R>).collect();
599    Ok(Component::LanguageIn { langs })
600}
601
602fn term_to_value<RDF>(term: &RDF::Term) -> std::result::Result<Value, RDFParseError>
603where
604    RDF: Rdf,
605{
606    if term.is_blank_node() {
607        Err(RDFParseError::BlankNodeNoValue {
608            bnode: term.to_string(),
609        })
610    } else if let Ok(iri) = term.clone().try_into() {
611        let iri: RDF::IRI = iri;
612        let iri_string = iri.as_str();
613        let iri_s = IriS::new_unchecked(iri_string);
614        Ok(Value::Iri(IriRef::Iri(iri_s)))
615    } else if let Ok(literal) = term.clone().try_into() {
616        let literal: RDF::Literal = literal;
617        Ok(Value::Literal(literal.as_literal()))
618    } else {
619        todo!()
620    }
621}
622
623fn term_to_lang<R: FocusRDF>(term: &R::Term) -> std::result::Result<Lang, RDFParseError> {
624    if term.is_blank_node() {
625        Err(RDFParseError::BlankNodeNoValue {
626            bnode: term.to_string(),
627        })
628    } else if let Ok(literal) = term.clone().try_into() {
629        let literal: R::Literal = literal;
630        let lang = Lang::new(literal.lexical_form());
631        match lang {
632            Ok(lang) => Ok(lang),
633            Err(_) => todo!(),
634        }
635    } else {
636        todo!()
637    }
638}
639
640fn cnv_in_list<RDF>(ls: Vec<RDF::Term>) -> std::result::Result<Component, RDFParseError>
641where
642    RDF: Rdf,
643{
644    let values = ls.iter().flat_map(term_to_value::<RDF>).collect();
645    Ok(Component::In { values })
646}
647
648fn or<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
649where
650    RDF: FocusRDF,
651{
652    property_values(&SH_OR).then(move |terms_set| {
653        let terms: Vec<_> = terms_set.into_iter().collect();
654        parse_nodes(terms, parse_or_values())
655    })
656}
657
658fn xone<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
659where
660    RDF: FocusRDF,
661{
662    property_values(&SH_XONE).then(move |terms_set| {
663        let terms: Vec<_> = terms_set.into_iter().collect();
664        parse_nodes(terms, parse_xone_values())
665    })
666}
667
668fn and<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
669where
670    RDF: FocusRDF,
671{
672    property_values(&SH_AND).then(move |terms_set| {
673        let terms: Vec<_> = terms_set.into_iter().collect();
674        parse_nodes(terms, parse_and_values())
675    })
676}
677
678fn not_parser<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
679where
680    RDF: FocusRDF,
681{
682    property_values(&SH_NOT).then(move |terms_set| {
683        let terms: Vec<_> = terms_set.into_iter().collect();
684        parse_nodes(terms, parse_not_value())
685    })
686}
687
688fn node<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Component>>
689where
690    RDF: FocusRDF,
691{
692    property_values(&SH_NODE).then(move |terms_set| {
693        let terms: Vec<_> = terms_set.into_iter().collect();
694        parse_nodes(terms, parse_node_value())
695    })
696}
697
698fn term_to_node_kind<RDF>(term: &RDF::Term) -> Result<NodeKind>
699where
700    RDF: Rdf,
701{
702    let iri: RDF::IRI =
703        term.clone()
704            .try_into()
705            .map_err(|_| ShaclParserError::ExpectedNodeKind {
706                term: format!("{term}"),
707            })?;
708    match iri.as_str() {
709        SH_IRI_STR => Ok(NodeKind::Iri),
710        SH_LITERAL_STR => Ok(NodeKind::Literal),
711        SH_BLANKNODE_STR => Ok(NodeKind::BlankNode),
712        SH_BLANK_NODE_OR_IRI_STR => Ok(NodeKind::BlankNodeOrIri),
713        SH_BLANK_NODE_OR_LITERAL_STR => Ok(NodeKind::BlankNodeOrLiteral),
714        SH_IRI_OR_LITERAL_STR => Ok(NodeKind::IRIOrLiteral),
715        _ => Err(ShaclParserError::UnknownNodeKind {
716            term: format!("{term}"),
717        }),
718    }
719}
720
721fn targets_class<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Target>>
722where
723    RDF: FocusRDF,
724{
725    property_values(&SH_TARGET_CLASS).flat_map(move |ts| {
726        let result = ts
727            .into_iter()
728            .map(|t: RDF::Term| Target::TargetClass(t.into()))
729            .collect();
730        Ok(result)
731    })
732}
733
734fn targets_node<RDF>() -> impl RDFNodeParse<RDF, Output = Vec<Target>>
735where
736    RDF: FocusRDF,
737{
738    property_values(&SH_TARGET_NODE).flat_map(move |ts| {
739        let result = ts
740            .into_iter()
741            .map(|t: RDF::Term| Target::TargetNode(t.into()))
742            .collect();
743        Ok(result)
744    })
745}
746
747fn targets_implicit_class<R: FocusRDF>() -> impl RDFNodeParse<R, Output = Vec<Target>> {
748    // TODO: in general this can be improved
749    instances_of(&RDFS_CLASS)
750        .and(instances_of(&SH_PROPERTY_SHAPE))
751        .and(instances_of(&SH_NODE_SHAPE))
752        .and(get_focus())
753        .flat_map(
754            move |(((class, property_shapes), node_shapes), focus): (_, R::Term)| {
755                let result = class
756                    .into_iter()
757                    .filter(|t: &R::Subject| property_shapes.contains(t) || node_shapes.contains(t))
758                    .map(Into::into)
759                    .filter(|t: &R::Term| t.clone() == focus)
760                    .map(|t: R::Term| Target::TargetImplicitClass(t.into()))
761                    .collect();
762                Ok(result)
763            },
764        )
765}
766
767fn targets_objects_of<R: FocusRDF>() -> impl RDFNodeParse<R, Output = Vec<Target>> {
768    property_values_iri(&SH_TARGET_OBJECTS_OF).flat_map(move |ts| {
769        let result = ts
770            .into_iter()
771            .map(|t: IriS| Target::TargetObjectsOf(t.into()))
772            .collect();
773        Ok(result)
774    })
775}
776
777fn targets_subjects_of<R: FocusRDF>() -> impl RDFNodeParse<R, Output = Vec<Target>> {
778    property_values_iri(&SH_TARGET_SUBJECTS_OF).flat_map(move |ts| {
779        let result = ts
780            .into_iter()
781            .map(|t: IriS| Target::TargetSubjectsOf(t.into()))
782            .collect();
783        Ok(result)
784    })
785}
786
787#[cfg(test)]
788mod tests {
789    use iri_s::IriS;
790    use srdf::lang::Lang;
791    use srdf::Object;
792    use srdf::RDFFormat;
793    use srdf::ReaderMode;
794    use srdf::SRDFGraph;
795
796    use crate::shape::Shape;
797
798    use super::ShaclParser;
799
800    #[test]
801    fn test_language_in() {
802        let shape = r#"
803            @prefix :    <http://example.org/> .
804            @prefix sh:  <http://www.w3.org/ns/shacl#> .
805            @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
806
807            :TestShape a sh:NodeShape ;
808                sh:targetNode "Hello"@en ;
809                sh:languageIn ( "en" "fr" ) .
810        "#;
811
812        let rdf_format = RDFFormat::Turtle;
813        let reader_mode = ReaderMode::default();
814        let shape_id: Object = IriS::new_unchecked("http://example.org/TestShape").into();
815
816        let graph = SRDFGraph::from_str(shape, &rdf_format, None, &reader_mode).unwrap();
817        let schema = ShaclParser::new(graph).parse().unwrap();
818        let shape = match schema.get_shape(&shape_id).unwrap() {
819            Shape::NodeShape(ns) => ns,
820            _ => panic!("Shape is not a NodeShape"),
821        };
822
823        match shape.components().first().unwrap() {
824            crate::component::Component::LanguageIn { langs } => {
825                assert_eq!(langs.len(), 2);
826                assert_eq!(langs[0], Lang::new_unchecked("en"));
827                assert_eq!(langs[1], Lang::new_unchecked("fr"));
828            }
829            _ => panic!("Shape has not a LanguageIn component"),
830        }
831    }
832}