1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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
|
# encoding: utf-8
"""
Custom element classes related to text runs (CT_R).
"""
from ..ns import qn
from ..simpletypes import ST_BrClear, ST_BrType
from ..xmlchemy import (
BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
)
class CT_Br(BaseOxmlElement):
"""
``<w:br>`` element, indicating a line, page, or column break in a run.
"""
type = OptionalAttribute('w:type', ST_BrType)
clear = OptionalAttribute('w:clear', ST_BrClear)
class CT_R(BaseOxmlElement):
"""
``<w:r>`` element, containing the properties and text for a run.
"""
rPr = ZeroOrOne('w:rPr')
t = ZeroOrMore('w:t')
br = ZeroOrMore('w:br')
cr = ZeroOrMore('w:cr')
tab = ZeroOrMore('w:tab')
drawing = ZeroOrMore('w:drawing')
def _insert_rPr(self, rPr):
self.insert(0, rPr)
return rPr
def add_t(self, text):
"""
Return a newly added ``<w:t>`` element containing *text*.
"""
t = self._add_t(text=text)
if len(text.strip()) < len(text):
t.set(qn('xml:space'), 'preserve')
return t
def add_drawing(self, inline_or_anchor):
"""
Return a newly appended ``CT_Drawing`` (``<w:drawing>``) child
element having *inline_or_anchor* as its child.
"""
drawing = self._add_drawing()
drawing.append(inline_or_anchor)
return drawing
def clear_content(self):
"""
Remove all child elements except the ``<w:rPr>`` element if present.
"""
content_child_elms = self[1:] if self.rPr is not None else self[:]
for child in content_child_elms:
self.remove(child)
@property
def style(self):
"""
String contained in w:val attribute of <w:rStyle> grandchild, or
|None| if that element is not present.
"""
rPr = self.rPr
if rPr is None:
return None
return rPr.style
@style.setter
def style(self, style):
"""
Set the character style of this <w:r> element to *style*. If *style*
is None, remove the style element.
"""
rPr = self.get_or_add_rPr()
rPr.style = style
@property
def text(self):
"""
A string representing the textual content of this run, with content
child elements like ``<w:tab/>`` translated to their Python
equivalent.
"""
text = ''
for child in self:
if child.tag == qn('w:t'):
t_text = child.text
text += t_text if t_text is not None else ''
elif child.tag == qn('w:tab'):
text += '\t'
elif child.tag in (qn('w:br'), qn('w:cr')):
text += '\n'
return text
@text.setter
def text(self, text):
self.clear_content()
_RunContentAppender.append_to_run_from_text(self, text)
class CT_Text(BaseOxmlElement):
"""
``<w:t>`` element, containing a sequence of characters within a run.
"""
class _RunContentAppender(object):
"""
Service object that knows how to translate a Python string into run
content elements appended to a specified ``<w:r>`` element. Contiguous
sequences of regular characters are appended in a single ``<w:t>``
element. Each tab character ('\t') causes a ``<w:tab/>`` element to be
appended. Likewise a newline or carriage return character ('\n', '\r')
causes a ``<w:cr>`` element to be appended.
"""
def __init__(self, r):
self._r = r
self._bfr = []
@classmethod
def append_to_run_from_text(cls, r, text):
"""
Create a "one-shot" ``_RunContentAppender`` instance and use it to
append the run content elements corresponding to *text* to the
``<w:r>`` element *r*.
"""
appender = cls(r)
appender.add_text(text)
def add_text(self, text):
"""
Append the run content elements corresponding to *text* to the
``<w:r>`` element of this instance.
"""
for char in text:
self.add_char(char)
self.flush()
def add_char(self, char):
"""
Process the next character of input through the translation finite
state maching (FSM). There are two possible states, buffer pending
and not pending, but those are hidden behind the ``.flush()`` method
which must be called at the end of text to ensure any pending
``<w:t>`` element is written.
"""
if char == '\t':
self.flush()
self._r.add_tab()
elif char in '\r\n':
self.flush()
self._r.add_br()
else:
self._bfr.append(char)
def flush(self):
text = ''.join(self._bfr)
if text:
self._r.add_t(text)
del self._bfr[:]
|