nom_xml/
processing_instruction.rs

1// processing_instruction.rs
2
3use crate::{parse::Parse, IResult, Name};
4use nom::{
5    bytes::complete::tag,
6    combinator::{map, map_res, opt, peek},
7    multi::many_till,
8    sequence::{preceded, tuple},
9};
10
11#[derive(Clone, PartialEq, Eq)]
12pub struct ProcessingInstruction {
13    pub target: Name,
14    pub data: Option<String>,
15}
16
17impl<'a> Parse<'a> for ProcessingInstruction {
18    type Args = ();
19    type Output = IResult<&'a str, Self>;
20
21    // [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
22    fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
23        map(
24            tuple((
25                tag("<?"),
26                Self::parse_target,
27                opt(preceded(
28                    Self::parse_multispace1,
29                    many_till(Self::parse_char, peek(tag("?>"))),
30                )),
31                tag("?>"),
32            )),
33            |(_open_tag, target, data_chars_opt, _close_tag)| {
34                let data = data_chars_opt.map(|(chars, _)| chars.into_iter().collect::<String>());
35                ProcessingInstruction { target, data }
36            },
37        )(input)
38    }
39}
40
41impl ProcessingInstruction {
42    //[17] PITarget	::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
43    fn parse_target(input: &str) -> IResult<&str, Name> {
44        map_res(Self::parse_name, |name| {
45            if name.local_part.eq_ignore_ascii_case("xml") {
46                Err(nom::Err::Failure(nom::error::Error::new(
47                    input,
48                    nom::error::ErrorKind::Tag,
49                )))
50            } else {
51                Ok(name)
52            }
53        })(input)
54    }
55}