Skip to content

Commit 10d1ff8

Browse files
committed
Add helper functions to resolve XML and HTML entities:
- `quick_xml::escape::resolve_predefined_entity` - `quick_xml::escape::resolve_xml_entity` - `quick_xml::escape::resolve_html5_entity`
1 parent dd1cb18 commit 10d1ff8

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ to get an offset of the error position. For `SyntaxError`s the range
3535
- [#722]: Allow to pass owned strings to `Writer::create_element`. This is breaking change!
3636
- [#275]: Added `ElementWriter::new_line()` which enables pretty printing elements with multiple attributes.
3737
- [#743]: Add `Deserializer::get_ref()` to get XML Reader from serde Deserializer
38+
- [#734]: Add helper functions to resolve predefined XML and HTML5 entities:
39+
- `quick_xml::escape::resolve_predefined_entity`
40+
- `quick_xml::escape::resolve_xml_entity`
41+
- `quick_xml::escape::resolve_html5_entity`
3842

3943
### Bug Fixes
4044

@@ -83,6 +87,7 @@ to get an offset of the error position. For `SyntaxError`s the range
8387
[#704]: https://github.com/tafia/quick-xml/pull/704
8488
[#705]: https://github.com/tafia/quick-xml/pull/705
8589
[#722]: https://github.com/tafia/quick-xml/pull/722
90+
[#734]: https://github.com/tafia/quick-xml/pull/734
8691
[#738]: https://github.com/tafia/quick-xml/pull/738
8792
[#743]: https://github.com/tafia/quick-xml/pull/743
8893
[#748]: https://github.com/tafia/quick-xml/pull/748

src/escape.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ where
221221
if let Some(entity) = pat.strip_prefix('#') {
222222
let codepoint = parse_number(entity, start..end)?;
223223
unescaped.push_str(codepoint.encode_utf8(&mut [0u8; 4]));
224-
} else if let Some(value) = named_entity(pat) {
224+
} else if let Some(value) = resolve_predefined_entity(pat) {
225225
unescaped.push_str(value);
226226
} else if let Some(value) = resolve_entity(pat) {
227227
unescaped.push_str(value);
@@ -248,10 +248,45 @@ where
248248
}
249249
}
250250

251-
#[cfg(not(feature = "escape-html"))]
252-
fn named_entity(name: &str) -> Option<&str> {
251+
/// Resolves predefined XML entities or all HTML5 entities depending on the feature
252+
/// [`escape-html`](https://docs.rs/quick-xml/latest/quick_xml/#escape-html).
253+
///
254+
/// Behaves like [`resolve_xml_entity`] if feature is not enabled and as
255+
/// [`resolve_html5_entity`] if enabled.
256+
#[inline]
257+
pub fn resolve_predefined_entity(entity: &str) -> Option<&'static str> {
258+
#[cfg(not(feature = "escape-html"))]
259+
{
260+
resolve_xml_entity(entity)
261+
}
262+
263+
#[cfg(feature = "escape-html")]
264+
{
265+
resolve_html5_entity(entity)
266+
}
267+
}
268+
269+
/// Resolves predefined XML entities. If specified entity is not a predefined XML
270+
/// entity, `None` is returned.
271+
///
272+
/// The complete list of predefined entities are defined in the [specification].
273+
///
274+
/// ```
275+
/// # use quick_xml::escape::resolve_xml_entity;
276+
/// # use pretty_assertions::assert_eq;
277+
/// assert_eq!(resolve_xml_entity("lt"), Some("<"));
278+
/// assert_eq!(resolve_xml_entity("gt"), Some(">"));
279+
/// assert_eq!(resolve_xml_entity("amp"), Some("&"));
280+
/// assert_eq!(resolve_xml_entity("apos"), Some("'"));
281+
/// assert_eq!(resolve_xml_entity("quot"), Some("\""));
282+
///
283+
/// assert_eq!(resolve_xml_entity("foo"), None);
284+
/// ```
285+
///
286+
/// [specification]: https://www.w3.org/TR/xml11/#sec-predefined-ent
287+
pub fn resolve_xml_entity(entity: &str) -> Option<&'static str> {
253288
// match over strings are not allowed in const functions
254-
let s = match name.as_bytes() {
289+
let s = match entity.as_bytes() {
255290
b"lt" => "<",
256291
b"gt" => ">",
257292
b"amp" => "&",
@@ -261,12 +296,13 @@ fn named_entity(name: &str) -> Option<&str> {
261296
};
262297
Some(s)
263298
}
264-
#[cfg(feature = "escape-html")]
265-
fn named_entity(name: &str) -> Option<&str> {
299+
300+
/// Resolves all HTML5 entities. For complete list see <https://dev.w3.org/html5/html-author/charref>.
301+
pub fn resolve_html5_entity(entity: &str) -> Option<&'static str> {
266302
// imported from https://dev.w3.org/html5/html-author/charref
267303
// match over strings are not allowed in const functions
268304
//TODO: automate up-to-dating using https://html.spec.whatwg.org/entities.json
269-
let s = match name.as_bytes() {
305+
let s = match entity.as_bytes() {
270306
b"Tab" => "\u{09}",
271307
b"NewLine" => "\u{0A}",
272308
b"excl" => "\u{21}",

0 commit comments

Comments
 (0)