nested.py 2.6 KB

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