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 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 let subjects_property = self.objects_with_predicate(Self::sh_property())?;
99
100 let sh_or_values = self.get_sh_or_values()?;
102
103 let sh_xone_values = self.get_sh_xone_values()?;
105
106 let sh_and_values = self.get_sh_and_values()?;
108
109 let sh_not_values = self.get_sh_not_values()?;
111
112 let sh_node_values = self.get_sh_node_values()?;
114
115 let property_shapes_instances = HashSet::new();
117
118 let shape_instances = HashSet::new();
120
121 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 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
429fn path<RDF>() -> impl RDFNodeParse<RDF, Output = SHACLPath>
431where
432 RDF: FocusRDF,
433{
434 property_value(&SH_PATH).then(shacl_path)
435}
436
437fn 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 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}