1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2026 oxml. All rights reserved.
//! Content for external entities and subsets, supplied by the caller.
//!
//! oxml never performs I/O. A document that references an external
//! entity or an external DTD subset names a *location*, and resolving
//! that location is the caller's decision -- they have the permission
//! model, the user, and the context to make it. See
//! [ADR 0003](https://github.com/sebastienrousseau/oxml/blob/main/doc/adr/0003-no-external-entities.md).
//!
//! Without a source, an external reference expands to nothing and the
//! declarations in an external subset are unknown, which is what
//! [`crate::parse`] does. With one, the same parse can check the rules
//! that only the external content can settle.
/// Somewhere the caller can look up external content.
///
/// Implemented for `&[(&str, &str)]`, which is enough for a test
/// fixture or a document whose parts are already in memory.
///
/// # Examples
///
/// ```
/// use oxml::{Limits, external::ExternalSource, parse_with_external};
///
/// // A slice of (system identifier, content) pairs is a source.
/// let parts: &[(&str, &str)] = &[("greeting.ent", "hello")];
/// assert_eq!(parts.fetch("greeting.ent", None), Some("hello"));
///
/// let doc = parse_with_external(
/// r#"<!DOCTYPE d [<!ENTITY g SYSTEM "greeting.ent">]><d>&g;</d>"#,
/// Limits::default(),
/// &parts,
/// )?;
/// assert_eq!(doc.text(doc.root()), "hello");
/// # Ok::<(), oxml::Error>(())
/// ```
/// Nothing is available.
///
/// The behaviour of [`crate::parse`], expressed as a source so that one
/// code path serves both.
pub ;