def resolve_paragraph(self, p): ans = self.para_cache.get(p, None) if ans is None: ans = self.para_cache[p] = ParagraphStyle() ans.style_name = None direct_formatting = None for pPr in XPath('./w:pPr')(p): ps = ParagraphStyle(pPr) if direct_formatting is None: direct_formatting = ps else: direct_formatting.update(ps) if direct_formatting is None: direct_formatting = ParagraphStyle() parent_styles = [] if self.default_paragraph_style is not None: parent_styles.append(self.default_paragraph_style) ts = self.tables.para_style(p) if ts is not None: parent_styles.append(ts) default_para = self.default_styles.get('paragraph', None) if direct_formatting.linked_style is not None: ls = self.get(direct_formatting.linked_style) if ls is not None: ans.style_name = ls.name ps = ls.paragraph_style if ps is not None: parent_styles.append(ps) if ls.character_style is not None: self.para_char_cache[p] = ls.character_style elif default_para is not None: if default_para.paragraph_style is not None: parent_styles.append(default_para.paragraph_style) if default_para.character_style is not None: self.para_char_cache[p] = default_para.character_style is_numbering = direct_formatting.numbering is not inherit if is_numbering: num_id, lvl = direct_formatting.numbering if num_id is not None: p.set('calibre_num_id', '%s:%s' % (lvl, num_id)) if num_id is not None and lvl is not None: ps = self.numbering.get_para_style(num_id, lvl) if ps is not None: parent_styles.append(ps) for attr in ans.all_properties: if not (is_numbering and attr == 'text_indent'): # skip text-indent for lists setattr( ans, attr, self.para_val(parent_styles, direct_formatting, attr)) ans.linked_style = direct_formatting.linked_style return ans
def resolve_based_on(self, parent): if parent.table_style is not None: if self.table_style is None: self.table_style = TableStyle(self.namespace) self.table_style.resolve_based_on(parent.table_style) if parent.paragraph_style is not None: if self.paragraph_style is None: self.paragraph_style = ParagraphStyle(self.namespace) self.paragraph_style.resolve_based_on(parent.paragraph_style) if parent.character_style is not None: if self.character_style is None: self.character_style = RunStyle(self.namespace) self.character_style.resolve_based_on(parent.character_style)
def __init__(self, namespace, tblPr=None): self.namespace = namespace if tblPr is None: for p in self.all_properties: setattr(self, p, inherit) else: self.overrides = inherit self.bidi = binary_property(tblPr, 'bidiVisual', namespace.XPath, namespace.get) for x in ('width', 'float', 'padding', 'shd', 'justification', 'spacing', 'indent', 'borders', 'band_size', 'look'): f = globals()['read_%s' % x] f(tblPr, self, self.namespace.XPath, self.namespace.get) parent = tblPr.getparent() if self.namespace.is_tag(parent, 'w:style'): self.overrides = {} for tblStylePr in self.namespace.XPath( './w:tblStylePr[@w:type]')(parent): otype = self.namespace.get(tblStylePr, 'w:type') orides = self.overrides[otype] = {} for tblPr in self.namespace.XPath('./w:tblPr')(tblStylePr): orides['table'] = TableStyle(self.namespace, tblPr) for trPr in self.namespace.XPath('./w:trPr')(tblStylePr): orides['row'] = RowStyle(self.namespace, trPr) for tcPr in self.namespace.XPath('./w:tcPr')(tblStylePr): orides['cell'] = CellStyle(self.namespace, tcPr) for pPr in self.namespace.XPath('./w:pPr')(tblStylePr): orides['para'] = ParagraphStyle(self.namespace, pPr) for rPr in self.namespace.XPath('./w:rPr')(tblStylePr): orides['run'] = RunStyle(self.namespace, rPr) self._css = None
def __init__(self, tblPr=None): if tblPr is None: for p in self.all_properties: setattr(self, p, inherit) else: self.overrides = inherit for x in ('width', 'padding', 'shd', 'justification', 'spacing', 'indent', 'borders', 'band_size', 'look'): f = globals()['read_%s' % x] f(tblPr, self) parent = tblPr.getparent() if is_tag(parent, 'w:style'): self.overrides = {} for tblStylePr in XPath('./w:tblStylePr[@w:type]')(parent): otype = get(tblStylePr, 'w:type') orides = self.overrides[otype] = {} for tblPr in XPath('./w:tblPr')(tblStylePr): orides['table'] = TableStyle(tblPr) for trPr in XPath('./w:trPr')(tblStylePr): orides['row'] = RowStyle(trPr) for tcPr in XPath('./w:tcPr')(tblStylePr): orides['cell'] = tcPr for pPr in XPath('./w:pPr')(tblStylePr): orides['para'] = ParagraphStyle(pPr) for rPr in XPath('./w:rPr')(tblStylePr): orides['run'] = RunStyle(rPr)
def read_from_xml(self, lvl, override=False): XPath, get = self.namespace.XPath, self.namespace.get for lr in XPath('./w:lvlRestart[@w:val]')(lvl): try: self.restart = int(get(lr, 'w:val')) except (TypeError, ValueError): pass for lr in XPath('./w:start[@w:val]')(lvl): try: self.start = int(get(lr, 'w:val')) except (TypeError, ValueError): pass for rPr in XPath('./w:rPr')(lvl): ps = RunStyle(self.namespace, rPr) if self.character_style is None: self.character_style = ps else: self.character_style.update(ps) lt = None for lr in XPath('./w:lvlText[@w:val]')(lvl): lt = get(lr, 'w:val') for lr in XPath('./w:numFmt[@w:val]')(lvl): val = get(lr, 'w:val') if val == 'bullet': self.is_numbered = False cs = self.character_style if lt in { '\uf0a7', 'o' } or (cs is not None and cs.font_family is not inherit and cs.font_family.lower() in {'wingdings', 'symbol'}): self.fmt = { '\uf0a7': 'square', 'o': 'circle' }.get(lt, 'disc') else: self.bullet_template = lt for lpid in XPath('./w:lvlPicBulletId[@w:val]')(lvl): self.pic_id = get(lpid, 'w:val') else: self.is_numbered = True self.fmt = STYLE_MAP.get(val, 'decimal') if lt and re.match(r'%\d+\.$', lt) is None: self.num_template = lt for lr in XPath('./w:pStyle[@w:val]')(lvl): self.para_link = get(lr, 'w:val') for pPr in XPath('./w:pPr')(lvl): ps = ParagraphStyle(self.namespace, pPr) if self.paragraph_style is None: self.paragraph_style = ps else: self.paragraph_style.update(ps)
def __init__(self, namespace, elem): self.namespace = namespace self.name_path = namespace.XPath('./w:name[@w:val]') self.based_on_path = namespace.XPath('./w:basedOn[@w:val]') self.resolved = False self.style_id = namespace.get(elem, 'w:styleId') self.style_type = namespace.get(elem, 'w:type') names = self.name_path(elem) self.name = namespace.get(names[-1], 'w:val') if names else None based_on = self.based_on_path(elem) self.based_on = namespace.get(based_on[0], 'w:val') if based_on else None if self.style_type == 'numbering': self.based_on = None self.is_default = namespace.get(elem, 'w:default') in {'1', 'on', 'true'} self.paragraph_style = self.character_style = self.table_style = None if self.style_type in {'paragraph', 'character', 'table'}: if self.style_type == 'table': for tblPr in namespace.XPath('./w:tblPr')(elem): ts = TableStyle(namespace, tblPr) if self.table_style is None: self.table_style = ts else: self.table_style.update(ts) if self.style_type in {'paragraph', 'table'}: for pPr in namespace.XPath('./w:pPr')(elem): ps = ParagraphStyle(namespace, pPr) if self.paragraph_style is None: self.paragraph_style = ps else: self.paragraph_style.update(ps) for rPr in namespace.XPath('./w:rPr')(elem): rs = RunStyle(namespace, rPr) if self.character_style is None: self.character_style = rs else: self.character_style.update(rs) if self.style_type in {'numbering', 'paragraph'}: self.numbering_style_link = None for x in namespace.XPath('./w:pPr/w:numPr/w:numId[@w:val]')(elem): self.numbering_style_link = namespace.get(x, 'w:val')
def read_from_xml(self, lvl, override=False): for lr in XPath('./w:lvlRestart[@w:val]')(lvl): try: self.restart = int(get(lr, 'w:val')) except (TypeError, ValueError): pass for lr in XPath('./w:start[@w:val]')(lvl): try: self.start = int(get(lr, 'w:val')) except (TypeError, ValueError): pass lt = None for lr in XPath('./w:lvlText[@w:val]')(lvl): lt = get(lr, 'w:val') for lr in XPath('./w:numFmt[@w:val]')(lvl): val = get(lr, 'w:val') if val == 'bullet': self.is_numbered = False self.fmt = {'\uf0a7': 'square', 'o': 'circle'}.get(lt, 'disc') for lpid in XPath('./w:lvlPicBulletId[@w:val]')(lvl): self.pic_id = get(lpid, 'w:val') else: self.is_numbered = True self.fmt = STYLE_MAP.get(val, 'decimal') if lt and re.match(r'%\d+\.$', lt) is None: self.num_template = lt for lr in XPath('./w:pStyle[@w:val]')(lvl): self.para_link = get(lr, 'w:val') for pPr in XPath('./w:pPr')(lvl): ps = ParagraphStyle(pPr) if self.paragraph_style is None: self.paragraph_style = ps else: self.paragraph_style.update(ps) for rPr in XPath('./w:rPr')(lvl): ps = RunStyle(rPr) if self.character_style is None: self.character_style = ps else: self.character_style.update(ps)
def __call__(self, root, fonts, theme): self.fonts, self.theme = fonts, theme self.default_paragraph_style = self.default_character_style = None if root is not None: for s in self.namespace.XPath('//w:style')(root): s = Style(self.namespace, s) if s.style_id: self.id_map[s.style_id] = s if s.is_default: self.default_styles[s.style_type] = s if getattr(s, 'numbering_style_link', None) is not None: self.numbering_style_links[ s.style_id] = s.numbering_style_link for dd in self.namespace.XPath('./w:docDefaults')(root): for pd in self.namespace.XPath('./w:pPrDefault')(dd): for pPr in self.namespace.XPath('./w:pPr')(pd): ps = ParagraphStyle(self.namespace, pPr) if self.default_paragraph_style is None: self.default_paragraph_style = ps else: self.default_paragraph_style.update(ps) for pd in self.namespace.XPath('./w:rPrDefault')(dd): for pPr in self.namespace.XPath('./w:rPr')(pd): ps = RunStyle(self.namespace, pPr) if self.default_character_style is None: self.default_character_style = ps else: self.default_character_style.update(ps) def resolve(s, p): if p is not None: if not p.resolved: resolve(p, self.get(p.based_on)) s.resolve_based_on(p) s.resolved = True for s in self: if not s.resolved: resolve(s, self.get(s.based_on))
class Style(object): ''' Class representing a <w:style> element. Can contain block, character, etc. styles. ''' def __init__(self, namespace, elem): self.namespace = namespace self.name_path = namespace.XPath('./w:name[@w:val]') self.based_on_path = namespace.XPath('./w:basedOn[@w:val]') self.resolved = False self.style_id = namespace.get(elem, 'w:styleId') self.style_type = namespace.get(elem, 'w:type') names = self.name_path(elem) self.name = namespace.get(names[-1], 'w:val') if names else None based_on = self.based_on_path(elem) self.based_on = namespace.get(based_on[0], 'w:val') if based_on else None if self.style_type == 'numbering': self.based_on = None self.is_default = namespace.get(elem, 'w:default') in {'1', 'on', 'true'} self.paragraph_style = self.character_style = self.table_style = None if self.style_type in {'paragraph', 'character', 'table'}: if self.style_type == 'table': for tblPr in namespace.XPath('./w:tblPr')(elem): ts = TableStyle(namespace, tblPr) if self.table_style is None: self.table_style = ts else: self.table_style.update(ts) if self.style_type in {'paragraph', 'table'}: for pPr in namespace.XPath('./w:pPr')(elem): ps = ParagraphStyle(namespace, pPr) if self.paragraph_style is None: self.paragraph_style = ps else: self.paragraph_style.update(ps) for rPr in namespace.XPath('./w:rPr')(elem): rs = RunStyle(namespace, rPr) if self.character_style is None: self.character_style = rs else: self.character_style.update(rs) if self.style_type in {'numbering', 'paragraph'}: self.numbering_style_link = None for x in namespace.XPath('./w:pPr/w:numPr/w:numId[@w:val]')(elem): self.numbering_style_link = namespace.get(x, 'w:val') def resolve_based_on(self, parent): if parent.table_style is not None: if self.table_style is None: self.table_style = TableStyle(self.namespace) self.table_style.resolve_based_on(parent.table_style) if parent.paragraph_style is not None: if self.paragraph_style is None: self.paragraph_style = ParagraphStyle(self.namespace) self.paragraph_style.resolve_based_on(parent.paragraph_style) if parent.character_style is not None: if self.character_style is None: self.character_style = RunStyle(self.namespace) self.character_style.resolve_based_on(parent.character_style)
def resolve_paragraph(self, p): ans = self.para_cache.get(p, None) if ans is None: linked_style = None ans = self.para_cache[p] = ParagraphStyle(self.namespace) ans.style_name = None direct_formatting = None is_section_break = False for pPr in self.namespace.XPath('./w:pPr')(p): ps = ParagraphStyle(self.namespace, pPr) if direct_formatting is None: direct_formatting = ps else: direct_formatting.update(ps) if self.namespace.XPath('./w:sectPr')(pPr): is_section_break = True if direct_formatting is None: direct_formatting = ParagraphStyle(self.namespace) parent_styles = [] if self.default_paragraph_style is not None: parent_styles.append(self.default_paragraph_style) ts = self.tables.para_style(p) if ts is not None: parent_styles.append(ts) default_para = self.default_styles.get('paragraph', None) if direct_formatting.linked_style is not None: ls = linked_style = self.get(direct_formatting.linked_style) if ls is not None: ans.style_name = ls.name ps = ls.paragraph_style if ps is not None: parent_styles.append(ps) if ls.character_style is not None: self.para_char_cache[p] = ls.character_style elif default_para is not None: if default_para.paragraph_style is not None: parent_styles.append(default_para.paragraph_style) if default_para.character_style is not None: self.para_char_cache[p] = default_para.character_style def has_numbering(block_style): num_id, lvl = getattr(block_style, 'numbering_id', inherit), getattr( block_style, 'numbering_level', inherit) return num_id is not None and num_id is not inherit and lvl is not None and lvl is not inherit is_numbering = has_numbering(direct_formatting) is_section_break = is_section_break and not self.namespace.XPath( './w:r')(p) if is_numbering and not is_section_break: num_id, lvl = direct_formatting.numbering_id, direct_formatting.numbering_level p.set('calibre_num_id', '%s:%s' % (lvl, num_id)) ps = self.numbering.get_para_style(num_id, lvl) if ps is not None: parent_styles.append(ps) if (not is_numbering and not is_section_break and linked_style is not None and has_numbering(linked_style.paragraph_style)): num_id, lvl = linked_style.paragraph_style.numbering_id, linked_style.paragraph_style.numbering_level p.set('calibre_num_id', '%s:%s' % (lvl, num_id)) is_numbering = True ps = self.numbering.get_para_style(num_id, lvl) if ps is not None: parent_styles.append(ps) for attr in ans.all_properties: if not (is_numbering and attr == 'text_indent'): # skip text-indent for lists setattr( ans, attr, self.para_val(parent_styles, direct_formatting, attr)) ans.linked_style = direct_formatting.linked_style return ans
class Style(object): """ Class representing a <w:style> element. Can contain block, character, etc. styles. """ name_path = XPath("./w:name[@w:val]") based_on_path = XPath("./w:basedOn[@w:val]") def __init__(self, elem): self.resolved = False self.style_id = get(elem, "w:styleId") self.style_type = get(elem, "w:type") names = self.name_path(elem) self.name = get(names[-1], "w:val") if names else None based_on = self.based_on_path(elem) self.based_on = get(based_on[0], "w:val") if based_on else None if self.style_type == "numbering": self.based_on = None self.is_default = get(elem, "w:default") in {"1", "on", "true"} self.paragraph_style = self.character_style = self.table_style = None if self.style_type in {"paragraph", "character", "table"}: if self.style_type == "table": for tblPr in XPath("./w:tblPr")(elem): ts = TableStyle(tblPr) if self.table_style is None: self.table_style = ts else: self.table_style.update(ts) if self.style_type in {"paragraph", "table"}: for pPr in XPath("./w:pPr")(elem): ps = ParagraphStyle(pPr) if self.paragraph_style is None: self.paragraph_style = ps else: self.paragraph_style.update(ps) for rPr in XPath("./w:rPr")(elem): rs = RunStyle(rPr) if self.character_style is None: self.character_style = rs else: self.character_style.update(rs) if self.style_type == "numbering": self.numbering_style_link = None for x in XPath("./w:pPr/w:numPr/w:numId[@w:val]")(elem): self.numbering_style_link = get(x, "w:val") def resolve_based_on(self, parent): if parent.table_style is not None: if self.table_style is None: self.table_style = TableStyle() self.table_style.resolve_based_on(parent.table_style) if parent.paragraph_style is not None: if self.paragraph_style is None: self.paragraph_style = ParagraphStyle() self.paragraph_style.resolve_based_on(parent.paragraph_style) if parent.character_style is not None: if self.character_style is None: self.character_style = RunStyle() self.character_style.resolve_based_on(parent.character_style)