nested.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. # Copyright (c) 2010-2024 openpyxl
  2. """
  3. Generic serialisable classes
  4. """
  5. from .base import (
  6. Convertible,
  7. Bool,
  8. Descriptor,
  9. NoneSet,
  10. MinMax,
  11. Set,
  12. Float,
  13. Integer,
  14. String,
  15. )
  16. from openpyxl.compat import safe_string
  17. from openpyxl.xml.functions import Element, localname, whitespace
  18. class Nested(Descriptor):
  19. nested = True
  20. attribute = "val"
  21. def __set__(self, instance, value):
  22. if hasattr(value, "tag"):
  23. tag = localname(value)
  24. if tag != self.name:
  25. raise ValueError("Tag does not match attribute")
  26. value = self.from_tree(value)
  27. super().__set__(instance, value)
  28. def from_tree(self, node):
  29. return node.get(self.attribute)
  30. def to_tree(self, tagname=None, value=None, namespace=None):
  31. namespace = getattr(self, "namespace", namespace)
  32. if value is not None:
  33. if namespace is not None:
  34. tagname = "{%s}%s" % (namespace, tagname)
  35. value = safe_string(value)
  36. return Element(tagname, {self.attribute:value})
  37. class NestedValue(Nested, Convertible):
  38. """
  39. Nested tag storing the value on the 'val' attribute
  40. """
  41. pass
  42. class NestedText(NestedValue):
  43. """
  44. Represents any nested tag with the value as the contents of the tag
  45. """
  46. def from_tree(self, node):
  47. return node.text
  48. def to_tree(self, tagname=None, value=None, namespace=None):
  49. namespace = getattr(self, "namespace", namespace)
  50. if value is not None:
  51. if namespace is not None:
  52. tagname = "{%s}%s" % (namespace, tagname)
  53. el = Element(tagname)
  54. el.text = safe_string(value)
  55. whitespace(el)
  56. return el
  57. class NestedFloat(NestedValue, Float):
  58. pass
  59. class NestedInteger(NestedValue, Integer):
  60. pass
  61. class NestedString(NestedValue, String):
  62. pass
  63. class NestedBool(NestedValue, Bool):
  64. def from_tree(self, node):
  65. return node.get("val", True)
  66. class NestedNoneSet(Nested, NoneSet):
  67. pass
  68. class NestedSet(Nested, Set):
  69. pass
  70. class NestedMinMax(Nested, MinMax):
  71. pass
  72. class EmptyTag(Nested, Bool):
  73. """
  74. Boolean if a tag exists or not.
  75. """
  76. def from_tree(self, node):
  77. return True
  78. def to_tree(self, tagname=None, value=None, namespace=None):
  79. if value:
  80. namespace = getattr(self, "namespace", namespace)
  81. if namespace is not None:
  82. tagname = "{%s}%s" % (namespace, tagname)
  83. return Element(tagname)