Coverage for gws-app/gws/lib/xmlx/util.py: 96%

27 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-05 13:35 +0200

1"""Value conversion and escaping for XML output.""" 

2 

3import gws.lib.datetimex as dtx 

4 

5 

6def atom_to_string(s) -> tuple[str, bool]: 

7 """Convert a primitive value to a string for XML output. 

8 

9 ``None`` becomes an empty string, numbers and booleans are lowercased (``true``, ``false``), 

10 datetimes and dates are written in ISO format. 

11 

12 Args: 

13 s: The value. 

14 

15 Returns: 

16 A tuple of the string and a flag that is ``False`` if the value is not a primitive value. 

17 """ 

18 

19 if s is None: 

20 return '', True 

21 

22 if isinstance(s, str): 

23 return s, True 

24 

25 if isinstance(s, (int, float, bool)): 

26 return str(s).lower(), True 

27 

28 if isinstance(s, dtx.dt.datetime): 

29 return dtx.to_iso_string(s, with_tz=':'), True 

30 

31 if isinstance(s, dtx.dt.date): 

32 return dtx.to_iso_date_string(s), True 

33 

34 return '', False 

35 

36 

37def escape_text(s: str) -> str: 

38 """Escape ``&``, ``<`` and ``>`` for XML text content. 

39 

40 Args: 

41 s: The text. 

42 

43 Returns: 

44 The escaped text. 

45 """ 

46 

47 s = s.replace('&', '&amp;') 

48 s = s.replace('>', '&gt;') 

49 s = s.replace('<', '&lt;') 

50 return s 

51 

52 

53def escape_attribute(s: str) -> str: 

54 """Escape a string for a double-quoted XML attribute value. 

55 

56 Escapes ``&``, ``"``, ``<``, ``>``, tabs and line breaks. 

57 

58 Args: 

59 s: The value. 

60 

61 Returns: 

62 The escaped value. 

63 """ 

64 

65 s = s.replace('&', '&amp;') 

66 s = s.replace('"', '&quot;') 

67 s = s.replace('>', '&gt;') 

68 s = s.replace('<', '&lt;') 

69 s = s.replace('\t', '&#x9;') 

70 s = s.replace('\r', '&#xd;') 

71 s = s.replace('\n', '&#xa;') 

72 return s