Skip to main content

xrust/parser/xml/
qname.rs

1use crate::item::Node;
2use crate::parser::combinators::alt::alt2;
3use crate::parser::combinators::many::many1;
4use crate::parser::combinators::map::{map, map_with_state_and_result};
5use crate::parser::combinators::opt::opt;
6use crate::parser::combinators::pair::pair;
7use crate::parser::combinators::support::none_of;
8use crate::parser::combinators::tag::tag;
9use crate::parser::combinators::take::{take_one, take_while};
10use crate::parser::combinators::tuple::{tuple2, tuple3};
11//use crate::parser::combinators::debug::inspect;
12use crate::parser::combinators::wellformed::wellformed;
13use crate::parser::common::{is_namechar, is_namestartchar, is_ncnamechar, is_ncnamestartchar};
14use crate::parser::xml::dtd::pereference::petextreference;
15use crate::parser::{ParseError, ParseInput, StaticState};
16use qualname::{NamespacePrefix, NamespaceUri, NcName, QName};
17
18// QualifiedName, returning a QName
19pub(crate) fn qualname_to_qname<'a, N: Node, L>()
20-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, QName), ParseError>
21where
22    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
23{
24    alt2(prefixed_name_to_qname(), unprefixed_name_to_qname())
25}
26
27// QualifiedName, returning the pieces: (prefix, local-part)
28// NB. Cannot use NamespacePrefix or NcName since values can legitimately be invalid (empty string). E.g. xmlns=""
29pub(crate) fn qualname_to_parts<'a, N: Node, L>() -> impl Fn(
30    ParseInput<'a, N>,
31    &mut StaticState<L>,
32) -> Result<
33    (ParseInput<'a, N>, (Option<String>, String)),
34    ParseError,
35>
36where
37    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
38{
39    alt2(prefixed_name_to_parts(), unprefixed_name_to_parts())
40}
41
42// Expanded Qualified Name
43// EQName ::= QName | URIQualifiedName
44#[allow(dead_code)]
45pub(crate) fn eqname_to_qname<'a, N: Node, L>()
46-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, QName), ParseError>
47where
48    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
49{
50    alt2(uriqualname(), qualname_to_qname())
51}
52// URIQualifiedName ::= "Q" "{" [^{}]* "}" NCName
53#[allow(dead_code)]
54pub(crate) fn uriqualname<'a, N: Node, L>()
55-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, QName), ParseError>
56where
57    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
58{
59    map(
60        pair(
61            tuple3(
62                tag("Q{"),
63                map(many1(none_of("{}")), |v| {
64                    v.iter().fold(String::new(), |mut s, w| {
65                        s.push_str(w);
66                        s
67                    })
68                }),
69                //v.concat::<String>()),
70                //v.iter().collect::<String>()),
71                tag("}"),
72            ),
73            ncname(),
74        ),
75        |((_, uri, _), localpart)| {
76            QName::new_from_parts(
77                NcName::try_from(localpart.as_str()).expect("not a valid NcName"),
78                Some(NamespaceUri::try_from(uri.as_str()).expect("not a valid XML Namespace URI")),
79            )
80        },
81    )
82}
83
84fn unprefixed_name_to_qname<'a, N: Node, L>()
85-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, QName), ParseError>
86where
87    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
88{
89    map(alt2(petextreference(), ncname()), |localpart| {
90        QName::from_local_name(NcName::try_from(localpart.as_str()).expect("not a valid QName")) // TODO: should be able to use unchecked creation, since we've already parsed the NCName
91    })
92}
93fn unprefixed_name_to_parts<'a, N: Node, L>() -> impl Fn(
94    ParseInput<'a, N>,
95    &mut StaticState<L>,
96) -> Result<
97    (ParseInput<'a, N>, (Option<String>, String)),
98    ParseError,
99>
100where
101    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
102{
103    map(alt2(petextreference(), ncname()), |localpart| {
104        (None, localpart)
105    })
106}
107fn prefixed_name_to_parts<'a, N: Node, L>() -> impl Fn(
108    ParseInput<'a, N>,
109    &mut StaticState<L>,
110) -> Result<
111    (ParseInput<'a, N>, (Option<String>, String)),
112    ParseError,
113>
114where
115    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
116{
117    map(
118        tuple3(
119            alt2(petextreference(), ncname()),
120            tag(":"),
121            alt2(petextreference(), ncname()),
122        ),
123        |(prefix, _, localpart)| (Some(prefix), localpart),
124    )
125}
126fn prefixed_name_to_qname<'a, N: Node, L>()
127-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, QName), ParseError>
128where
129    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
130{
131    map_with_state_and_result(
132        tuple3(
133            alt2(petextreference::<N, L>(), ncname()),
134            tag(":"),
135            alt2(petextreference::<N, L>(), ncname()),
136        ),
137        |(prefix, _, localpart), _state, ss| {
138            if let Some(f) = &mut ss.namespace {
139                if let Ok(uri) = f(&NamespacePrefix::try_from(prefix.as_str()).unwrap()) {
140                    if let Ok(lp) = NcName::try_from(localpart.as_str()) {
141                        Ok(QName::new_from_parts(lp, Some(uri)))
142                    } else {
143                        Err(ParseError::NSResolveError(format!(
144                            "name \"{}\" is not valid",
145                            localpart
146                        )))
147                    }
148                } else {
149                    Err(ParseError::NSResolveError(format!(
150                        "namespace resolver failed on prefix \"{}\"",
151                        prefix
152                    )))
153                }
154            } else {
155                // No closure to resolve prefix
156                Err(ParseError::NSResolveError(String::from(
157                    "no closure to resolve prefix",
158                )))
159            }
160        },
161    )
162}
163
164// NCName ::= Name - (Char* ':' Char*)
165// Name ::= NameStartChar NameChar*
166// NameStartChar ::= ':' | [A-Z] | '_' | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
167// NameChar ::= NameStartChar | '-' | '.' | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
168pub(crate) fn ncname<'a, N: Node, L>()
169-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
170where
171    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
172{
173    map(
174        tuple2(
175            wellformed(
176                take_one(),
177                is_ncnamestartchar,
178                "invalid character in NcName",
179            ),
180            opt(take_while(|c| is_ncnamechar(&c))),
181        ),
182        |(a, b)| [a.to_string(), b.unwrap_or_default()].concat(),
183    )
184}
185
186/// XML 1.0 (Fifth Edition) [5] Name ::= NameStartChar ( NameChar )*
187pub(crate) fn name<'a, N: Node, L>()
188-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
189where
190    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
191{
192    map(
193        tuple2(
194            wellformed(take_one(), is_namestartchar, "invalid name start character"),
195            opt(take_while(|c| is_namechar(&c))),
196        ),
197        |(nsc, nc)| match nc {
198            None => nsc.to_string(),
199            Some(nc) => [nsc.to_string(), nc].concat(),
200        },
201    )
202}