1use crate::{parse::Parse, IResult};
2use nom::{
3 branch::alt,
4 bytes::complete::tag,
5 character::complete::{alpha1, alphanumeric1, digit1},
6 combinator::{map, opt},
7 error::ErrorKind,
8 multi::many0,
9 sequence::{delimited, pair, preceded, tuple},
10};
11use std::str::FromStr;
12
13#[derive(Clone, PartialEq, Eq)]
14pub enum Standalone {
15 Yes,
16 No,
17}
18
19impl FromStr for Standalone {
20 type Err = nom::Err<nom::error::Error<&'static str>>;
21
22 fn from_str(s: &str) -> Result<Self, Self::Err> {
23 match s {
24 "yes" => Ok(Standalone::Yes),
25 "no" => Ok(Standalone::No),
26 _ => Err(nom::Err::Error(nom::error::Error::new("", ErrorKind::Alt))),
27 }
28 }
29}
30
31#[derive(Clone, PartialEq, Eq)]
32pub struct XmlDecl {
33 pub version: String,
34 pub encoding: Option<String>,
35 pub standalone: Option<Standalone>,
36}
37impl<'a> Parse<'a> for XmlDecl {
38 type Args = ();
39 type Output = IResult<&'a str, Self>;
40 fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
42 map(
43 tuple((
44 tag("<?xml"),
45 Self::parse_version_info,
46 opt(Self::parse_encoding_decl),
47 opt(Self::parse_sd_decl),
48 Self::parse_multispace0,
49 tag("?>"),
50 )),
51 |(_start, version, encoding, standalone, _whitespace, _end)| Self {
52 version,
53 encoding,
54 standalone,
55 },
56 )(input)
57 }
58}
59
60impl XmlDecl {
61 fn parse_version_info(input: &str) -> IResult<&str, String> {
63 map(
64 tuple((
65 Self::parse_multispace1,
66 tag("version"),
67 Self::parse_eq,
68 alt((
69 delimited(tag("'"), Self::parse_version_num, tag("'")),
70 delimited(tag("\""), Self::parse_version_num, tag("\"")),
71 )),
72 )),
73 |(_whitespace, _version_literal, _eq, version)| version,
74 )(input)
75 }
76
77 fn parse_version_num(input: &str) -> IResult<&str, String> {
79 map(preceded(tag("1."), digit1), |version| {
80 format!("1.{}", version)
81 })(input)
82 }
83 fn parse_encoding_decl(input: &str) -> IResult<&str, String> {
85 map(
86 tuple((
87 Self::parse_multispace1,
88 tag("encoding"),
89 Self::parse_eq,
90 alt((
91 delimited(tag("'"), Self::parse_enc_name, tag("'")),
92 delimited(tag("\""), Self::parse_enc_name, tag("\"")),
93 )),
94 )),
95 |(_whitespace, _encoding_literal, _eq, encoding)| encoding,
96 )(input)
97 }
98
99 fn parse_enc_name(input: &str) -> IResult<&str, String> {
101 map(
102 pair(
103 alt((alpha1, tag("-"))),
104 many0(alt((alphanumeric1, tag("."), tag("_"), tag("-")))),
105 ),
106 |(first, rest)| format!("{}{}", first, rest.join("")),
107 )(input)
108 }
109
110 fn parse_sd_decl(input: &str) -> IResult<&str, Standalone> {
112 map(
113 tuple((
114 Self::parse_multispace1,
115 tag("standalone"),
116 Self::parse_eq,
117 alt((
118 delimited(tag("'"), alt((tag("yes"), tag("no"))), tag("'")),
119 delimited(tag("\""), alt((tag("yes"), tag("no"))), tag("\"")),
120 )),
121 )),
122 |(_whtiespace, _standalone_literal, _eq, standalone)| {
123 Standalone::from_str(standalone).unwrap()
124 },
125 )(input)
126 }
127}