mod attribute;
mod chardata;
mod dtd;
mod element;
mod misc;
pub mod qname;
mod reference;
mod strings;
mod xmldecl;
use crate::item::Node;
use crate::parser::combinators::map::map;
use crate::parser::combinators::opt::opt;
use crate::parser::combinators::tag::tag;
use crate::parser::combinators::tuple::tuple4;
use crate::parser::xml::dtd::doctypedecl;
use crate::parser::xml::element::element;
use crate::parser::xml::misc::misc;
use crate::parser::xml::xmldecl::xmldecl;
use crate::parser::{
ParseError, ParseInput, ParserState, ParserStateBuilder, StaticState, StaticStateBuilder,
};
use crate::xdmerror::{Error, ErrorKind};
use crate::xmldecl::XMLDecl;
use qualname::{NamespaceMap, NamespacePrefix, NamespaceUri};
pub fn parse_with_state<N: Node, L>(
input: &str,
ps: ParserState<N>,
mut ss: StaticState<L>,
) -> Result<N, Error>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
match document((input, ps), &mut ss) {
Ok(((_, _), xmldoc)) => Ok(xmldoc),
Err(err) => {
match err {
ParseError::Combinator(f) => Err(Error::new(
ErrorKind::ParseError,
format!(
"Unrecoverable parser error ({}) while parsing XML \"{}\"",
f,
input.chars().take(80).collect::<String>()
),
)),
ParseError::MissingGenEntity { .. } => Err(Error::new(
ErrorKind::ParseError,
"Missing Gen Entity.".to_string(),
)),
ParseError::MissingParamEntity { .. } => Err(Error::new(
ErrorKind::ParseError,
"Missing Param Entity.".to_string(),
)),
ParseError::EntityDepth { .. } => Err(Error::new(
ErrorKind::ParseError,
"Entity depth limit exceeded".to_string(),
)),
ParseError::Validation { .. } => Err(Error::new(
ErrorKind::ParseError,
"Validation error.".to_string(),
)),
ParseError::MissingNameSpace => Err(Error::new(
ErrorKind::ParseError,
"Missing namespace declaration.".to_string(),
)),
ParseError::NotWellFormed(s) => Err(Error::new(
ErrorKind::ParseError,
format!("XML document not well formed at \"{}\".", s),
)),
ParseError::ExtDTDLoadError => Err(Error::new(
ErrorKind::ParseError,
"Unable to open external DTD.".to_string(),
)),
ParseError::Notimplemented => Err(Error::new(
ErrorKind::ParseError,
"Unimplemented feature.".to_string(),
)),
_ => Err(Error::new(ErrorKind::Unknown, "Unknown error.".to_string())),
}
}
}
}
pub fn parse<L, N: Node>(doc: N, input: &str, r: Option<L>) -> Result<N, Error>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
let (xmldoc, _) = parse_with_ns(doc, input, r)?;
Ok(xmldoc)
}
pub fn parse_with_ns<L, N: Node>(
doc: N,
input: &str,
r: Option<L>,
) -> Result<(N, Option<NamespaceMap>), Error>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
let state = ParserStateBuilder::new().doc(doc).build();
let static_state = r.map_or(StaticState::new(), |f| {
StaticStateBuilder::new().namespace(f).build()
});
Ok((parse_with_state(input, state, static_state)?, None))
}
fn document<'a, N: Node, L>(
input: ParseInput<'a, N>,
ss: &mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, N), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
match tuple4(
opt(utf8bom()),
opt(prolog()),
element(),
opt(misc()),
"document",
)(input, ss)
{
Err(err) => Err(err),
Ok(((input1, state1), (_, p, e, m))) => {
if input1.is_empty() {
if state1.id_tracking {
for idref in ss.ids_pending.iter() {
if ss.ids_read.get(idref).is_none() {
return Err(ParseError::IDError(String::from("ID missing")));
}
}
}
let pr = p.unwrap_or((None, vec![]));
let mut d = state1.doc.clone().unwrap();
pr.1.iter()
.for_each(|n| d.push(n.clone()).expect("unable to add node"));
d.push(e).expect("unable to add node");
m.unwrap_or_default()
.iter()
.for_each(|n| d.push(n.clone()).expect("unable to add node"));
if let Some(x) = pr.0 {
let _ = d.set_xmldecl(x);
}
if !state1.dtd.patterns.is_empty() {
let _ = d.set_dtd(state1.dtd.clone());
};
Ok((
(input1, state1.clone()),
state1.doc.clone().unwrap().clone(),
))
} else {
Err(ParseError::NotWellFormed(format!(
"unexpected extra characters: \"{}\"",
input1
)))
}
}
}
}
fn prolog<'a, N: Node, L>() -> impl Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<
(ParseInput<'a, N>, (Option<XMLDecl>, Vec<N>)),
ParseError,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
map(
tuple4(opt(xmldecl()), misc(), opt(doctypedecl()), misc(), "prolog"),
|(xmld, mut m1, _dtd, mut m2)| {
m1.append(&mut m2);
(xmld, m1)
},
)
}
fn utf8bom<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, ()), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
tag("\u{feff}")
}