nom_xml/prolog/
declaration_content.rs

1use crate::{namespaces::ParseNamespace, parse::Parse, ConditionalState, IResult, Name};
2use nom::{
3    branch::alt,
4    bytes::complete::tag,
5    combinator::{map, opt},
6    multi::many1,
7    sequence::{preceded, tuple},
8};
9
10use super::content_particle::ContentParticle;
11
12#[derive(Clone, PartialEq, Eq)]
13pub enum DeclarationContent {
14    Mixed(Mixed),
15    Children(ContentParticle),
16    Empty,
17    Any,
18}
19
20impl<'a> Parse<'a> for DeclarationContent {
21    type Args = ();
22    type Output = IResult<&'a str, Self>;
23    // [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
24    fn parse(input: &'a str, args: Self::Args) -> Self::Output {
25        alt((
26            map(tag("EMPTY"), |_| Self::Empty),
27            map(tag("ANY"), |_| Self::Any),
28            map(|i| Mixed::parse(i, args), Self::Mixed),
29            map(Self::parse_children, Self::Children),
30        ))(input)
31    }
32}
33impl<'a> ParseNamespace<'a> for DeclarationContent {}
34impl DeclarationContent {
35    // [47] children ::= (choice | seq) ('?' | '*' | '+')?
36    fn parse_children(input: &str) -> IResult<&str, ContentParticle> {
37        let (input, particle) = alt((
38            map(
39                tuple((
40                    ContentParticle::parse_choice,
41                    opt(|i| ConditionalState::parse(i, ())),
42                )),
43                |(choice, state)| {
44                    ContentParticle::Choice(choice, state.unwrap_or(ConditionalState::None))
45                },
46            ),
47            map(
48                tuple((
49                    ContentParticle::parse_sequence,
50                    opt(|i| ConditionalState::parse(i, ())),
51                )),
52                |(seq, state)| {
53                    ContentParticle::Sequence(seq, state.unwrap_or(ConditionalState::None))
54                },
55            ),
56        ))(input)?;
57        Ok((input, particle))
58    }
59}
60
61#[derive(Clone, PartialEq, Eq)]
62pub enum Mixed {
63    PCDATA,
64    Names(Vec<Name>),
65}
66
67impl<'a> ParseNamespace<'a> for Mixed {}
68impl<'a> Parse<'a> for Mixed {
69    type Args = ();
70    type Output = IResult<&'a str, Self>;
71    // [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')'
72    // Namespaces (Third Edition) [19] Mixed ::= '(' S? '#PCDATA' (S? '|' S? QName)* S? ')*' | '(' S? '#PCDATA' S? ')'
73
74    fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
75        alt((
76            map(
77                tuple((
78                    tag("("),
79                    Self::parse_multispace0,
80                    tag("#PCDATA"),
81                    many1(preceded(
82                        tuple((Self::parse_multispace0, tag("|"), Self::parse_multispace0)),
83                        alt((Self::parse_name, Self::parse_qualified_name)),
84                    )),
85                    Self::parse_multispace0,
86                    tag(")*"),
87                )),
88                |(_, _, _, names, _, _)| Mixed::Names(names),
89            ),
90            map(
91                tuple((
92                    tag("("),
93                    Self::parse_multispace0,
94                    tag("#PCDATA"),
95                    Self::parse_multispace0,
96                    tag(")"),
97                )),
98                |_| Mixed::PCDATA,
99            ),
100        ))(input)
101    }
102}