Skip to content

Element Typed

ElementTyped subclass of Element.

Classes:

Name Description
ElementTyped

Subclass of Element for classes managing typed values.

ElementTyped

Bases: Element

Subclass of Element for classes managing typed values.

Methods:

Name Description
clear_attrinutes

Clear attrinutes defining type and value of the Cell.

get_value

Get the Python-typed value of the element.

set_value_and_type

Set the value and type of the element.

Source code in odfdo/element_typed.py
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
class ElementTyped(Element):
    """Subclass of Element for classes managing typed values."""

    def _erase_text_content(self) -> None:
        """Clear the textual content of the element.

        This method removes all paragraph elements (`text:p`), effectively
        erasing any visible text within the element.
        """
        paragraphs = self.get_elements("text:p")
        if not paragraphs:
            # E.g., text:p in draw:text-box in draw:frame
            paragraphs = self.get_elements("*/text:p")
        if paragraphs:
            # paragraphs.pop(0)
            for obsolete in paragraphs:
                obsolete.delete()

    def clear_attrinutes(self) -> None:
        """Clear attrinutes defining type and value of the Cell."""
        self.del_attribute_list(
            (
                "office:value-type",
                "office:boolean-value",
                "office:value",
                "office:date-value",
                "office:string-value",
                "office:time-value",
                "table:formula",
                "office:currency",
                "calcext:value-type",
                "loext:value-type",
            )
        )

    def set_value_and_type(
        self,
        value: Any,
        value_type: str | None = None,
        text: str | None = None,
        currency: str | None = None,
    ) -> str | None:
        """Set the value and type of the element.

        This method handles setting the appropriate ODF attributes
        (e.g., `office:value`, `office:value-type`, `office:string-value`)
        based on the Python type of the provided `value`.

        Args:
            value: The value to set.
            value_type: The ODF value type (e.g., "float",
                "date", "string"). If not provided, it is inferred from the
                type of `value`.
            text: The textual representation of the value.
                If not provided, it is generated automatically.
            currency: The currency symbol, used when
                `value_type` is "currency".

        Returns:
            str | None: The textual representation of the value that was set,
                or `None` if the value was `None`.

        Raises:
            TypeError: If the type of `value` is not supported.
        """
        # Remove possible previous value and type
        self.clear_attrinutes()
        if isinstance(value, bytes):
            value = bytes_to_str(value)
        if isinstance(value_type, bytes):
            value_type = bytes_to_str(value_type)
        if isinstance(text, bytes):
            text = bytes_to_str(text)
        if isinstance(currency, bytes):
            currency = bytes_to_str(currency)
        if value is None:
            self._erase_text_content()
            return text
        if isinstance(value, bool):
            if value_type is None:
                value_type = "boolean"
            if text is None:
                text = "true" if value else "false"
            value = Boolean.encode(value)
        elif isinstance(value, (int, float, Decimal)):
            if value_type == "percentage":
                text = f"{int(value * 100)} %"
            if value_type is None:
                value_type = "float"
            if text is None:
                text = str(value)
            value = str(value)
        elif isinstance(value, datetime):
            if value_type is None:
                value_type = "date"
            if text is None:
                text = str(DateTime.encode(value))
            value = DateTime.encode(value)
        elif isinstance(value, date):
            if value_type is None:
                value_type = "date"
            if text is None:
                text = str(Date.encode(value))
            value = Date.encode(value)
        elif isinstance(value, str):
            if value_type is None:
                value_type = "string"
            if text is None:
                text = value
        elif isinstance(value, timedelta):
            if value_type is None:
                value_type = "time"
            if text is None:
                text = str(Duration.encode(value))
            value = Duration.encode(value)
        else:
            raise TypeError(f"Type unknown: '{value!r}'")

        if isinstance(value_type, str):
            self.set_attribute("office:value-type", value_type)
            self.set_attribute("calcext:value-type", value_type)
        if value_type == "boolean":
            self.set_attribute("office:boolean-value", value)
        elif value_type == "currency":
            self.set_attribute("office:value", value)
            self.set_attribute("office:currency", currency)
        elif value_type == "date":
            self.set_attribute("office:date-value", value)
        elif value_type in ("float", "percentage"):
            self.set_attribute("office:value", value)
            self.set_attribute("calcext:value", value)
        elif value_type == "string":
            self.set_attribute("office:string-value", value)
        elif value_type == "time":
            self.set_attribute("office:time-value", value)

        return text

    def _get_typed_value_boolean(self) -> Any:
        """Get the boolean value from the 'office:boolean-value' attribute."""
        return self.get_attribute("office:boolean-value")

    def _get_typed_value_number_type(self) -> Decimal | int | float:
        """Get the numeric value from the 'office:value' attribute.

        Returns the value as an `int` if possible, otherwise as a `Decimal`.
        """
        read_number = self.get_attribute_string("office:value")
        if read_number is None:
            raise ValueError('"office:value" has None value')
        value = Decimal(read_number)
        # Return 3 instead of 3.0 if possible
        with contextlib.suppress(ValueError):
            if int(value) == value:
                return int(value)
        return value

    def _get_typed_value_float(self) -> Decimal | int | float:
        """Get the float value, delegating to _get_typed_value_number_type."""
        return self._get_typed_value_number_type()

    def _get_typed_value_percentage(self) -> Decimal | int | float:
        """Get the percentage value, delegating to _get_typed_value_number_type."""
        return self._get_typed_value_number_type()

    def _get_typed_value_currency(self) -> Decimal | int | float:
        """Get the currency value, delegating to _get_typed_value_number_type."""
        return self._get_typed_value_number_type()

    def _get_typed_value_date(self) -> date | datetime:
        """Get the date or datetime value from the 'office:date-value' attribute."""
        read_attribute = self.get_attribute_string("office:date-value")
        if read_attribute is None:
            raise ValueError('"office:date-value" has None value')
        if "T" in read_attribute:
            return DateTime.decode(read_attribute)
        return Date.decode(read_attribute)

    def _get_typed_value_string(self, try_get_text: bool) -> str | None:
        """Get the string value.

        Tries to get the value from the 'office:string-value' attribute first.
        If that fails, and `try_get_text` is True, it attempts to get the
        text content from child paragraph elements.
        """
        value = self.get_attribute_string("office:string-value")
        if value is not None:
            return str(value)
        if try_get_text:
            list_value = [para.inner_text for para in self.get_elements("text:p")]
            if list_value:
                return "\n".join(list_value)
        return None

    def _get_typed_value_time(self) -> timedelta:
        """Get the time value from the 'office:time-value' attribute."""
        read_value = self.get_attribute_string("office:time-value")
        if read_value is None:
            raise ValueError('"office:time-value" has None value')
        return Duration.decode(read_value)

    def _get_typed_value(
        self,
        value_type: str = "",
        try_get_text: bool = True,
    ) -> Any:
        """Get the Python-typed value based on the ODF value type.

        This is a dispatcher method that calls the appropriate `_get_typed_value_*`
        method based on the `value_type`.

        Args:
            value_type (str): The ODF value type (e.g., "string", "float").
            try_get_text (bool): For string types, whether to fall back to
                reading text from child paragraphs.

        Returns:
            Any: The value converted to its corresponding Python type.

        Raises:
            TypeError: If the `value_type` is not supported.
        """
        if value_type == "string":
            return self._get_typed_value_string(try_get_text)
        method = getattr(self, f"_get_typed_value_{value_type}", None)
        if method is None:
            raise TypeError(f"Unexpected value type: {value_type}")
        return method()

    def _get_value_and_type(
        self, value_type: str | None = None, try_get_text: bool = True
    ) -> tuple[Any, str | None]:
        """Get the value and its ODF type.

        If `value_type` is not provided, it is read from the element's
        'office:value-type' attribute.

        Args:
            value_type (str, optional): The expected ODF value type.
            try_get_text (bool): For string types, whether to fall back to
                reading text from child paragraphs.

        Returns:
            tuple[Any, str | None]: A tuple containing the Python-typed value
                and the ODF value type string, or (None, None) if the type
                cannot be determined.
        """
        if value_type is None:
            read_value_type = self.get_attribute_string("office:value-type")
            if read_value_type is None:
                return None, None
            value_type = read_value_type
        return (
            self._get_typed_value(
                value_type=value_type,
                try_get_text=try_get_text,
            ),
            value_type,
        )

    def get_value(
        self,
        value_type: str | None = None,
        try_get_text: bool = True,
        get_type: bool = False,
    ) -> Any | tuple[Any, str]:
        """Get the Python-typed value of the element.

        This method is for elements that have an `office:value-type` attribute.
        It does not apply to meta fields.

        Args:
            value_type: The expected ODF value type. If not
                provided, it's inferred from the 'office:value-type' attribute.
            try_get_text: For string types, whether to fall back to
                reading text from child paragraphs.
            get_type: If True, returns a tuple of (value, type_string)
                instead of just the value.

        Returns:
            Any | tuple[Any, str]: The Python-typed value, or a tuple of
                (value, type_string) if `get_type` is True.
        """
        value, actual_type = self._get_value_and_type(
            value_type=value_type, try_get_text=try_get_text
        )
        if get_type:
            return (value, actual_type)
        return value

_erase_text_content

_erase_text_content() -> None

Clear the textual content of the element.

This method removes all paragraph elements (text:p), effectively erasing any visible text within the element.

Source code in odfdo/element_typed.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def _erase_text_content(self) -> None:
    """Clear the textual content of the element.

    This method removes all paragraph elements (`text:p`), effectively
    erasing any visible text within the element.
    """
    paragraphs = self.get_elements("text:p")
    if not paragraphs:
        # E.g., text:p in draw:text-box in draw:frame
        paragraphs = self.get_elements("*/text:p")
    if paragraphs:
        # paragraphs.pop(0)
        for obsolete in paragraphs:
            obsolete.delete()

_get_typed_value

_get_typed_value(
    value_type: str = "", try_get_text: bool = True
) -> Any

Get the Python-typed value based on the ODF value type.

This is a dispatcher method that calls the appropriate _get_typed_value_* method based on the value_type.

Parameters:

Name Type Description Default
value_type str

The ODF value type (e.g., “string”, “float”).

''
try_get_text bool

For string types, whether to fall back to reading text from child paragraphs.

True

Returns:

Name Type Description
Any Any

The value converted to its corresponding Python type.

Raises:

Type Description
TypeError

If the value_type is not supported.

Source code in odfdo/element_typed.py
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
def _get_typed_value(
    self,
    value_type: str = "",
    try_get_text: bool = True,
) -> Any:
    """Get the Python-typed value based on the ODF value type.

    This is a dispatcher method that calls the appropriate `_get_typed_value_*`
    method based on the `value_type`.

    Args:
        value_type (str): The ODF value type (e.g., "string", "float").
        try_get_text (bool): For string types, whether to fall back to
            reading text from child paragraphs.

    Returns:
        Any: The value converted to its corresponding Python type.

    Raises:
        TypeError: If the `value_type` is not supported.
    """
    if value_type == "string":
        return self._get_typed_value_string(try_get_text)
    method = getattr(self, f"_get_typed_value_{value_type}", None)
    if method is None:
        raise TypeError(f"Unexpected value type: {value_type}")
    return method()

_get_typed_value_boolean

_get_typed_value_boolean() -> Any

Get the boolean value from the ‘office:boolean-value’ attribute.

Source code in odfdo/element_typed.py
172
173
174
def _get_typed_value_boolean(self) -> Any:
    """Get the boolean value from the 'office:boolean-value' attribute."""
    return self.get_attribute("office:boolean-value")

_get_typed_value_currency

_get_typed_value_currency() -> Decimal | int | float

Get the currency value, delegating to _get_typed_value_number_type.

Source code in odfdo/element_typed.py
199
200
201
def _get_typed_value_currency(self) -> Decimal | int | float:
    """Get the currency value, delegating to _get_typed_value_number_type."""
    return self._get_typed_value_number_type()

_get_typed_value_date

_get_typed_value_date() -> date | datetime

Get the date or datetime value from the ‘office:date-value’ attribute.

Source code in odfdo/element_typed.py
203
204
205
206
207
208
209
210
def _get_typed_value_date(self) -> date | datetime:
    """Get the date or datetime value from the 'office:date-value' attribute."""
    read_attribute = self.get_attribute_string("office:date-value")
    if read_attribute is None:
        raise ValueError('"office:date-value" has None value')
    if "T" in read_attribute:
        return DateTime.decode(read_attribute)
    return Date.decode(read_attribute)

_get_typed_value_float

_get_typed_value_float() -> Decimal | int | float

Get the float value, delegating to _get_typed_value_number_type.

Source code in odfdo/element_typed.py
191
192
193
def _get_typed_value_float(self) -> Decimal | int | float:
    """Get the float value, delegating to _get_typed_value_number_type."""
    return self._get_typed_value_number_type()

_get_typed_value_number_type

_get_typed_value_number_type() -> Decimal | int | float

Get the numeric value from the ‘office:value’ attribute.

Returns the value as an int if possible, otherwise as a Decimal.

Source code in odfdo/element_typed.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def _get_typed_value_number_type(self) -> Decimal | int | float:
    """Get the numeric value from the 'office:value' attribute.

    Returns the value as an `int` if possible, otherwise as a `Decimal`.
    """
    read_number = self.get_attribute_string("office:value")
    if read_number is None:
        raise ValueError('"office:value" has None value')
    value = Decimal(read_number)
    # Return 3 instead of 3.0 if possible
    with contextlib.suppress(ValueError):
        if int(value) == value:
            return int(value)
    return value

_get_typed_value_percentage

_get_typed_value_percentage() -> Decimal | int | float

Get the percentage value, delegating to _get_typed_value_number_type.

Source code in odfdo/element_typed.py
195
196
197
def _get_typed_value_percentage(self) -> Decimal | int | float:
    """Get the percentage value, delegating to _get_typed_value_number_type."""
    return self._get_typed_value_number_type()

_get_typed_value_string

_get_typed_value_string(try_get_text: bool) -> str | None

Get the string value.

Tries to get the value from the ‘office:string-value’ attribute first. If that fails, and try_get_text is True, it attempts to get the text content from child paragraph elements.

Source code in odfdo/element_typed.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def _get_typed_value_string(self, try_get_text: bool) -> str | None:
    """Get the string value.

    Tries to get the value from the 'office:string-value' attribute first.
    If that fails, and `try_get_text` is True, it attempts to get the
    text content from child paragraph elements.
    """
    value = self.get_attribute_string("office:string-value")
    if value is not None:
        return str(value)
    if try_get_text:
        list_value = [para.inner_text for para in self.get_elements("text:p")]
        if list_value:
            return "\n".join(list_value)
    return None

_get_typed_value_time

_get_typed_value_time() -> timedelta

Get the time value from the ‘office:time-value’ attribute.

Source code in odfdo/element_typed.py
228
229
230
231
232
233
def _get_typed_value_time(self) -> timedelta:
    """Get the time value from the 'office:time-value' attribute."""
    read_value = self.get_attribute_string("office:time-value")
    if read_value is None:
        raise ValueError('"office:time-value" has None value')
    return Duration.decode(read_value)

_get_value_and_type

_get_value_and_type(
    value_type: str | None = None, try_get_text: bool = True
) -> tuple[Any, str | None]

Get the value and its ODF type.

If value_type is not provided, it is read from the element’s ‘office:value-type’ attribute.

Parameters:

Name Type Description Default
value_type str

The expected ODF value type.

None
try_get_text bool

For string types, whether to fall back to reading text from child paragraphs.

True

Returns:

Type Description
tuple[Any, str | None]

tuple[Any, str | None]: A tuple containing the Python-typed value and the ODF value type string, or (None, None) if the type cannot be determined.

Source code in odfdo/element_typed.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def _get_value_and_type(
    self, value_type: str | None = None, try_get_text: bool = True
) -> tuple[Any, str | None]:
    """Get the value and its ODF type.

    If `value_type` is not provided, it is read from the element's
    'office:value-type' attribute.

    Args:
        value_type (str, optional): The expected ODF value type.
        try_get_text (bool): For string types, whether to fall back to
            reading text from child paragraphs.

    Returns:
        tuple[Any, str | None]: A tuple containing the Python-typed value
            and the ODF value type string, or (None, None) if the type
            cannot be determined.
    """
    if value_type is None:
        read_value_type = self.get_attribute_string("office:value-type")
        if read_value_type is None:
            return None, None
        value_type = read_value_type
    return (
        self._get_typed_value(
            value_type=value_type,
            try_get_text=try_get_text,
        ),
        value_type,
    )

clear_attrinutes

clear_attrinutes() -> None

Clear attrinutes defining type and value of the Cell.

Source code in odfdo/element_typed.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def clear_attrinutes(self) -> None:
    """Clear attrinutes defining type and value of the Cell."""
    self.del_attribute_list(
        (
            "office:value-type",
            "office:boolean-value",
            "office:value",
            "office:date-value",
            "office:string-value",
            "office:time-value",
            "table:formula",
            "office:currency",
            "calcext:value-type",
            "loext:value-type",
        )
    )

get_value

get_value(
    value_type: str | None = None,
    try_get_text: bool = True,
    get_type: bool = False,
) -> Any | tuple[Any, str]

Get the Python-typed value of the element.

This method is for elements that have an office:value-type attribute. It does not apply to meta fields.

Parameters:

Name Type Description Default
value_type str | None

The expected ODF value type. If not provided, it’s inferred from the ‘office:value-type’ attribute.

None
try_get_text bool

For string types, whether to fall back to reading text from child paragraphs.

True
get_type bool

If True, returns a tuple of (value, type_string) instead of just the value.

False

Returns:

Type Description
Any | tuple[Any, str]

Any | tuple[Any, str]: The Python-typed value, or a tuple of (value, type_string) if get_type is True.

Source code in odfdo/element_typed.py
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
def get_value(
    self,
    value_type: str | None = None,
    try_get_text: bool = True,
    get_type: bool = False,
) -> Any | tuple[Any, str]:
    """Get the Python-typed value of the element.

    This method is for elements that have an `office:value-type` attribute.
    It does not apply to meta fields.

    Args:
        value_type: The expected ODF value type. If not
            provided, it's inferred from the 'office:value-type' attribute.
        try_get_text: For string types, whether to fall back to
            reading text from child paragraphs.
        get_type: If True, returns a tuple of (value, type_string)
            instead of just the value.

    Returns:
        Any | tuple[Any, str]: The Python-typed value, or a tuple of
            (value, type_string) if `get_type` is True.
    """
    value, actual_type = self._get_value_and_type(
        value_type=value_type, try_get_text=try_get_text
    )
    if get_type:
        return (value, actual_type)
    return value

set_value_and_type

set_value_and_type(
    value: Any,
    value_type: str | None = None,
    text: str | None = None,
    currency: str | None = None,
) -> str | None

Set the value and type of the element.

This method handles setting the appropriate ODF attributes (e.g., office:value, office:value-type, office:string-value) based on the Python type of the provided value.

Parameters:

Name Type Description Default
value Any

The value to set.

required
value_type str | None

The ODF value type (e.g., “float”, “date”, “string”). If not provided, it is inferred from the type of value.

None
text str | None

The textual representation of the value. If not provided, it is generated automatically.

None
currency str | None

The currency symbol, used when value_type is “currency”.

None

Returns:

Type Description
str | None

str | None: The textual representation of the value that was set, or None if the value was None.

Raises:

Type Description
TypeError

If the type of value is not supported.

Source code in odfdo/element_typed.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def set_value_and_type(
    self,
    value: Any,
    value_type: str | None = None,
    text: str | None = None,
    currency: str | None = None,
) -> str | None:
    """Set the value and type of the element.

    This method handles setting the appropriate ODF attributes
    (e.g., `office:value`, `office:value-type`, `office:string-value`)
    based on the Python type of the provided `value`.

    Args:
        value: The value to set.
        value_type: The ODF value type (e.g., "float",
            "date", "string"). If not provided, it is inferred from the
            type of `value`.
        text: The textual representation of the value.
            If not provided, it is generated automatically.
        currency: The currency symbol, used when
            `value_type` is "currency".

    Returns:
        str | None: The textual representation of the value that was set,
            or `None` if the value was `None`.

    Raises:
        TypeError: If the type of `value` is not supported.
    """
    # Remove possible previous value and type
    self.clear_attrinutes()
    if isinstance(value, bytes):
        value = bytes_to_str(value)
    if isinstance(value_type, bytes):
        value_type = bytes_to_str(value_type)
    if isinstance(text, bytes):
        text = bytes_to_str(text)
    if isinstance(currency, bytes):
        currency = bytes_to_str(currency)
    if value is None:
        self._erase_text_content()
        return text
    if isinstance(value, bool):
        if value_type is None:
            value_type = "boolean"
        if text is None:
            text = "true" if value else "false"
        value = Boolean.encode(value)
    elif isinstance(value, (int, float, Decimal)):
        if value_type == "percentage":
            text = f"{int(value * 100)} %"
        if value_type is None:
            value_type = "float"
        if text is None:
            text = str(value)
        value = str(value)
    elif isinstance(value, datetime):
        if value_type is None:
            value_type = "date"
        if text is None:
            text = str(DateTime.encode(value))
        value = DateTime.encode(value)
    elif isinstance(value, date):
        if value_type is None:
            value_type = "date"
        if text is None:
            text = str(Date.encode(value))
        value = Date.encode(value)
    elif isinstance(value, str):
        if value_type is None:
            value_type = "string"
        if text is None:
            text = value
    elif isinstance(value, timedelta):
        if value_type is None:
            value_type = "time"
        if text is None:
            text = str(Duration.encode(value))
        value = Duration.encode(value)
    else:
        raise TypeError(f"Type unknown: '{value!r}'")

    if isinstance(value_type, str):
        self.set_attribute("office:value-type", value_type)
        self.set_attribute("calcext:value-type", value_type)
    if value_type == "boolean":
        self.set_attribute("office:boolean-value", value)
    elif value_type == "currency":
        self.set_attribute("office:value", value)
        self.set_attribute("office:currency", currency)
    elif value_type == "date":
        self.set_attribute("office:date-value", value)
    elif value_type in ("float", "percentage"):
        self.set_attribute("office:value", value)
        self.set_attribute("calcext:value", value)
    elif value_type == "string":
        self.set_attribute("office:string-value", value)
    elif value_type == "time":
        self.set_attribute("office:time-value", value)

    return text