nom_xml/prolog/
id.rs

1use nom::{
2    branch::alt,
3    bytes::complete::{is_a, tag},
4    character::complete::alphanumeric1,
5    combinator::map,
6    multi::many0,
7    sequence::{delimited, pair, preceded},
8};
9
10use crate::{parse::Parse, IResult};
11
12use super::external_id::ExternalID;
13
14#[derive(Clone, PartialEq, Eq)]
15pub enum ID {
16    ExternalID(ExternalID),
17    PublicID(String),
18}
19
20impl<'a> Parse<'a> for ID {
21    type Args = ();
22    type Output = IResult<&'a str, Self>;
23    // [83] PublicID ::= 'PUBLIC' S PubidLiteral
24    fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
25        alt((
26            map(
27                preceded(
28                    pair(tag("PUBLIC"), Self::parse_multispace1),
29                    Self::parse_public_id_literal,
30                ),
31                ID::PublicID,
32            ),
33            map(|i| ExternalID::parse(i, ()), ID::ExternalID),
34        ))(input)
35    }
36}
37
38impl ID {
39    // [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
40    pub fn parse_public_id_literal(input: &str) -> IResult<&str, String> {
41        map(
42            alt((
43                delimited(
44                    tag("\""),
45                    many0(|i| Self::parse_pubid_char(i, false)),
46                    tag("\""),
47                ),
48                delimited(
49                    tag("'"),
50                    many0(|i| Self::parse_pubid_char(i, true)),
51                    tag("'"),
52                ),
53            )),
54            |pubid_literal: Vec<&str>| pubid_literal.concat(),
55        )(input)
56    }
57
58    // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
59    pub fn parse_pubid_char(input: &str, exclude_single_quote: bool) -> IResult<&str, &str> {
60        let chars = if exclude_single_quote {
61            " \r\n-()+,./:=?;!*#@$_%"
62        } else {
63            " \r\n-'()+,./:=?;!*#@$_%"
64        };
65
66        alt((tag(" "), tag("\r"), tag("\n"), alphanumeric1, is_a(chars)))(input)
67    }
68}