nom_xml/prolog/
textdecl.rs1use nom::{
2 branch::alt,
3 character::complete::{alpha1, alphanumeric1, digit1},
4 combinator::{map, opt},
5 multi::many0,
6 sequence::{delimited, pair, preceded, tuple},
7};
8
9use crate::{parse::Parse, tag, IResult};
10
11#[derive(Clone, PartialEq, Eq)]
12pub struct TextDecl {
13 pub version: Option<String>,
14 pub encoding: String,
15}
16impl<'a> Parse<'a> for TextDecl {
17 type Args = ();
18 type Output = IResult<&'a str, Self>;
19 fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
21 map(
22 tuple((
23 tag("<?xml"),
24 opt(Self::parse_version_info),
25 Self::parse_encoding_decl,
26 Self::parse_multispace0,
27 tag("?>"),
28 )),
29 |(_start, version, encoding, _whitespace, _end)| Self { version, encoding },
30 )(input)
31 }
32}
33
34impl TextDecl {
35 fn parse_version_info(input: &str) -> IResult<&str, String> {
37 map(
38 tuple((
39 Self::parse_multispace1,
40 tag("version"),
41 Self::parse_eq,
42 alt((
43 delimited(tag("'"), Self::parse_version_num, tag("'")),
44 delimited(tag("\""), Self::parse_version_num, tag("\"")),
45 )),
46 )),
47 |(_whitespace, _version_literal, _eq, version)| version,
48 )(input)
49 }
50
51 fn parse_version_num(input: &str) -> IResult<&str, String> {
53 map(preceded(tag("1."), digit1), |version| {
54 format!("1.{}", version)
55 })(input)
56 }
57 fn parse_encoding_decl(input: &str) -> IResult<&str, String> {
59 map(
60 tuple((
61 Self::parse_multispace1,
62 tag("encoding"),
63 Self::parse_eq,
64 alt((
65 delimited(tag("'"), Self::parse_enc_name, tag("'")),
66 delimited(tag("\""), Self::parse_enc_name, tag("\"")),
67 )),
68 )),
69 |(_whitespace, _encoding_literal, _eq, encoding)| encoding,
70 )(input)
71 }
72
73 fn parse_enc_name(input: &str) -> IResult<&str, String> {
75 map(
76 pair(
77 alt((alpha1, tag("-"))),
78 many0(alt((alphanumeric1, tag("."), tag("_"), tag("-")))),
79 ),
80 |(first, rest)| format!("{}{}", first, rest.join("")),
81 )(input)
82 }
83}