r"""Visually escape invalid XML characters. For example, transforms 'hello\aworld\b' into 'hello#x07world#x08' Note that the #xABs are *not* XML escapes - missing the ampersand «. The idea is to escape visually for the user rather than for XML itself.
(arg: object)
| 35 | |
| 36 | |
| 37 | def bin_xml_escape(arg: object) -> str: |
| 38 | r"""Visually escape invalid XML characters. |
| 39 | |
| 40 | For example, transforms |
| 41 | 'hello\aworld\b' |
| 42 | into |
| 43 | 'hello#x07world#x08' |
| 44 | Note that the #xABs are *not* XML escapes - missing the ampersand «. |
| 45 | The idea is to escape visually for the user rather than for XML itself. |
| 46 | """ |
| 47 | |
| 48 | def repl(matchobj: re.Match[str]) -> str: |
| 49 | i = ord(matchobj.group()) |
| 50 | if i <= 0xFF: |
| 51 | return f"#x{i:02X}" |
| 52 | else: |
| 53 | return f"#x{i:04X}" |
| 54 | |
| 55 | # The spec range of valid chars is: |
| 56 | # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] |
| 57 | # For an unknown(?) reason, we disallow #x7F (DEL) as well. |
| 58 | illegal_xml_re = "[^\u0009\u000a\u000d\u0020-\u007e\u0080-\ud7ff\ue000-\ufffd\U00010000-\U0010ffff]" |
| 59 | return re.sub(illegal_xml_re, repl, str(arg)) |
| 60 | |
| 61 | |
| 62 | def merge_family(left, right) -> None: |
no outgoing calls