Skip to main content

ai_agent/utils/
xml.rs

1// Source: ~/claudecode/openclaudecode/src/utils/xml.rs
2
3/// Escape XML/HTML special characters for safe interpolation into element
4/// text content (between tags). Use when untrusted strings (process stdout,
5/// user input, external data) go inside `<tag>${here}</tag>`.
6pub fn escape_xml(s: &str) -> String {
7    s.replace('&', "&amp;")
8        .replace('<', "&lt;")
9        .replace('>', "&gt;")
10}
11
12/// Escape for interpolation into a double- or single-quoted attribute value:
13/// `<tag attr="${here}">`. Escapes quotes in addition to `& < >`.
14pub fn escape_xml_attr(s: &str) -> String {
15    escape_xml(s)
16        .replace('"', "&quot;")
17        .replace('\'', "&apos;")
18}
19
20#[cfg(test)]
21mod tests {
22    use super::*;
23
24    #[test]
25    fn test_escape_xml() {
26        assert_eq!(escape_xml("a & b"), "a &amp; b");
27        assert_eq!(escape_xml("<tag>"), "&lt;tag&gt;");
28        assert_eq!(escape_xml("a < b & c > d"), "a &lt; b &amp; c &gt; d");
29    }
30
31    #[test]
32    fn test_escape_xml_attr() {
33        assert_eq!(
34            escape_xml_attr("say \"hello\""),
35            "say &quot;hello&quot;"
36        );
37        assert_eq!(
38            escape_xml_attr("it's"),
39            "it&apos;s"
40        );
41        assert_eq!(
42            escape_xml_attr("<a href=\"test\">link</a>"),
43            "&lt;a href=&quot;test&quot;&gt;link&lt;/a&gt;"
44        );
45    }
46
47    #[test]
48    fn test_escape_empty() {
49        assert_eq!(escape_xml(""), "");
50        assert_eq!(escape_xml_attr(""), "");
51    }
52}