Change styles for complete document

@Prakruth Could you please attach your input document, your current and expected output documents? We will check the issue and provide you more information.
Is you goal simply change font name and size in the document?

schedule.docx (76.7 KB)

Please find the attached document, we are able to change style(font name from “Times New Roman” to “Aptos”) but the font name is not reflecting when the document is saved and re-opened.
Same is the case with numbering

Thank you for additional information. Please try using the following code to change font in the document:

def change_font(font) :
    font.name = "Aptos"
    font.size = 10
doc = aw.Document("C:\\Temp\\in.docx")

for n in doc.get_child_nodes(aw.NodeType.ANY, True):
    match n.node_type:
        case aw.NodeType.RUN:
            change_font(n.as_run().font)
        case aw.NodeType.PARAGRAPH:
            change_font(n.as_paragraph().paragraph_break_font)
        case aw.NodeType.FIELD_START:
            change_font(n.as_field_start().font)
        case aw.NodeType.FIELD_END:
            change_font(n.as_field_end().font)
        case aw.NodeType.FIELD_SEPARATOR:
            change_font(n.as_field_separator().font)
        case aw.NodeType.FOOTNOTE:
            change_font(n.as_footnote().font)
        case aw.NodeType.FORM_FIELD:
            change_font(n.as_form_field().font)
        case aw.NodeType.SPECIAL_CHAR:
            change_font(n.as_special_char().font)
    
doc.save("C:\\Temp\\out.docx")

thanks for quick response, but this code worked for me

   doc = aw.Document(input_path)
  #1) Retarget base styles so newly-typed text also uses the new font
    for style in doc.styles:
        if style.type in (aw.StyleType.PARAGRAPH, aw.StyleType.CHARACTER, aw.StyleType.TABLE):
            f = style.font
            f.name = font_name
            f.name_bi = font_name
            f.name_far_east = font_name


    # changes to styles
    for name in ("Normal", "Default Paragraph Font", "Heading 1", "Heading 2", "Heading 3"):
        st = doc.styles.get_by_name(name)
        if st is not None:
            f = st.font
            f.name = font_name
            f.name_bi = font_name
            f.name_far_east = font_name


    # 2) Ensure list numbers/bullets (labels) use the new font & size
    for i in range(doc.lists.count):
        lst = doc.lists[i]
        lvls = lst.list_levels
        for j in range(lvls.count):
            lf = lvls[j].font
            lf.name = font_name
            lf.name_bi = font_name
            lf.name_far_east = font_name


    # 3) Force-update every existing run (deep scan: body, headers/footers, shapes, notes, comments, etc.)
    runs = doc.get_child_nodes(aw.NodeType.RUN, True)  # True = deep
    for k in range(runs.count):
        r = runs[k].as_run()
        f = r.font
        f.name = font_name
        f.name_bi = font_name
        f.name_far_east = font_name


    # 4) Refresh dynamic content (e.g., TOC) so its display reflects style changes
    doc.update_fields()

@Prakruth Your code des almost the same as I have proposed. The only difference my code changes explicit formatting applied to the nodes in the document. You can replace the 3rd stage of your code with code I have proposed to make sure font is applied to whole document’s content.

follow up question on change of styles
when we are changing the font in text box in attached document say to “Aptose” like early, certain data in text box is getting hidden due to text box property, can we fix the dimensions according to text in text box without overlay?

@Prakruth You can try setting TextBox.fit_shape_to_text property to resolve this problem. but this might affect the layout.
Unfortunately, there is no easy way to fix this whiteout affecting the original shapes layout.

follow-up on this
Hi can you please help me with the following

  1. change the comment text font size to 8pt
  2. change the comment subject to size 10pt
  3. comment reference to 12pt
  4. highlight the footer table(top border) with blue color

@Prakruth Could you please attach your input and expected output documents here for our reference? This will help us to better understand your requirements. We will check your documents and provide you more information.

can you please help us if we can access comment subject, comment text fonts and comment references
attaching document for footer table border
file heading has sample content and desired output in heading_output

@Prakruth MS Word does not allow you to change the fonts for comment text and comment subject separately. The font size for balloons is stored in the “Balloon Text” style. Here is the code you need to use to make changes:

doc = aw.Document("headings.docx")

balloon_style = doc.styles.get_by_style_identifier(aw.StyleIdentifier.BALLOON_TEXT)
balloon_style.font.size = 8

comment = doc.get_child(aw.NodeType.COMMENT_RANGE_START, 0, True).as_comment_range_start()
comment_reference = comment.next_sibling.as_run()
comment_reference.font.size = 12

footer = doc.first_section.headers_footers.get_by_header_footer_type(aw.HeaderFooterType.FOOTER_PRIMARY)
table = footer.get_child(aw.NodeType.TABLE, 0, True).as_table()

table.set_border(aw.BorderType.TOP, aw.LineStyle.SINGLE, 1, aspose.pydrawing.Color.blue, True)

doc.save("output.docx")

thanks for the code, comments when opened in document are not seen with newer font.size as 12
though when printed as run.font.size is 12pt

@Prakruth I can also see changes in the document:

the comment text cannot be viewed with updated font size correct?

@Prakruth Could you please provide more information about the problem you have? If you are referring to comments in balloons, this is how comments are displayed in MS Word, and we cannot change it.

thanks for the update that we cannot change font styles for comments.
this is a follow-up for the footer table where are trying to add table border
while operating only on footer table is giving us good results but when we (referring to Headings.docx) footer details say footer center(page number to font size 11, and everything under footer section, including footer notes, end notes, and respective continuations to font size say “9”) border styles for tables are vanishing
is there a way to make changes to both table border and font size in single go?

@Prakruth Unfortunately, it is not quite clear what the problem is. The code provided by Vyacheslav does exactly what it required - changes font and specifies table border in the document footer.

headings.docx (83.3 KB)
headings_output.docx (80.4 KB)

Headings is the input file, while headings_output is what is desired,
while performing the font change operations independently, table border and font style changes are happening perfectly fine.

when we try to integrate both font style changes and border changes with text removal in sequence, the changes are not happening as desired

@Prakruth Could you please provide your code that will allow us to reproduce the problem?

    def set_name_to_target(self, font, target_font: str = None) -> None:
        target_font = target_font or self.target_font_name
        if self.is_protected_font(font):
            return
        for attr in ("name", "name_bi", "name_far_east"):
            if hasattr(font, attr):
                setattr(font, attr, target_font)

    def is_protected_font(self, font) -> bool:
        try:
            nm = (getattr(font, "name", "") or "").strip()
        except Exception:
            return False
        return nm in self.PROTECTED_FONTS

    def set_style_font_size(self, doc: aw.Document, style_name: str, size_pt: float) -> bool:
        try:
            st = doc.styles.get_by_name(style_name)
            if st is None:
                return False
            f = getattr(st, "font", None)
            if f is None:
                return False
            changed = False
            for attr in ("size", "size_bi"):
                if hasattr(f, attr):
                    try:
                        setattr(f, attr, float(size_pt))
                        changed = True
                    except Exception:
                        logging.debug("[change style] style '%s' set %s failed", style_name, attr, exc_info=True)
            return changed
        except Exception:
            logging.debug("[change style] set_style_font_size('%s') failed", style_name, exc_info=True)
            return False

    def force_runs_size_in_paragraphs_with_style(self, doc: aw.Document, style_name: str, size_pt: float) -> None:
        try:
            paras = doc.get_child_nodes(aw.NodeType.PARAGRAPH, True)
            hits_p = hits_r = 0
            target = style_name.casefold()
            for i in range(paras.count):
                p = paras[i].as_paragraph()
                if p is None:
                    continue
                sname = (getattr(p.paragraph_format, "style_name", "") or "").strip().casefold()
                if sname != target:
                    continue
                runs = p.get_child_nodes(aw.NodeType.RUN, True)
                for j in range(runs.count):
                    rr = runs[j].as_run()
                    if rr is None:
                        continue
                    rf = rr.font
                    for attr in ("size", "size_bi"):
                        if hasattr(rf, attr):
                            try:
                                setattr(rf, attr, float(size_pt))
                                hits_r += 1
                            except Exception:
                                logging.debug("[change style] run size set failed (%s)", attr, exc_info=True)
                hits_p += 1
            logging.info("[change style] Forced sizes for style '%s' (paras=%d, runs≈%d)", style_name, hits_p, hits_r)
        except Exception:
            logging.debug("[change style] force_runs_size_in_paragraphs_with_style('%s') failed", style_name, exc_info=True)

 # =============== 1a) Footer / Page Number precise tweaks ===============
            try:
                # Footer & Footer Right -> 10pt (style + existing content)
                for style_name, to_sz in (("Footer", 10.0), ("Footer Right", 10.0)):
                    self.set_style_font_size(doc, style_name, to_sz)
                    self.force_runs_size_in_paragraphs_with_style(work, style_name, to_sz)

                # Page Number style -> 12pt + target family
                pn_style = work.styles.get_by_name("Page Number")
                if pn_style is not None:
                    self.set_name_to_target(pn_style.font, target_font)
                    for attr in ("size", "size_bi"):
                        if hasattr(pn_style.font, attr):
                            try:
                                setattr(pn_style.font, attr, 12)
                            except Exception:
                                logging.debug("[change style] 'Page Number' style set %s failed", attr, exc_info=True)

                # HARD ENFORCEMENT: field result runs inside footers
                pn_runs = 0
                for i in range(work.sections.count):
                    sect = work.sections[i]
                    hfs = getattr(sect, "headers_footers", None)
                    if hfs is None:
                        continue

                    for hft in (
                        aw.HeaderFooterType.FOOTER_PRIMARY,
                        aw.HeaderFooterType.FOOTER_FIRST,
                        aw.HeaderFooterType.FOOTER_EVEN,
                    ):
                        hf = hfs.get_by_header_footer_type(hft)
                        if hf is None:
                            continue

                        rng = getattr(hf, "range", None)
                        fields = getattr(rng, "fields", None) if rng is not None else None
                        if not fields:
                            continue

                        for fi in range(fields.count):
                            try:
                                fld = fields[fi]
                                if getattr(fld, "type", None) not in (
                                    aw.fields.FieldType.FIELD_PAGE,
                                    aw.fields.FieldType.FIELD_NUM_PAGES,
                                    aw.fields.FieldType.FIELD_SECTION_PAGES,
                                ):
                                    continue

                                sep = getattr(fld, "separator", None)
                                end = getattr(fld, "end", None)
                                start = getattr(fld, "start", None)
                                anchor = sep if sep is not None else start
                                if anchor is None or end is None:
                                    continue

                                cur = anchor.next_sibling
                                while cur is not None and cur is not end:
                                    if cur.node_type == aw.NodeType.RUN:
                                        rn = cur.as_run()
                                        rf = rn.font
                                        if not self.is_protected_font(rf):
                                            self.set_name_to_target(rf, target_font)
                                        if hasattr(rf, "size"):
                                            rf.size = 12
                                        if hasattr(rf, "size_bi"):
                                            rf.size_bi = 12
                                        pn_runs += 1

                                    # catch shallow nested runs (like in shapes/containers)
                                    if hasattr(cur, "get_child_nodes"):
                                        inner = cur.get_child_nodes(aw.NodeType.RUN, False)
                                        for j in range(inner.count):
                                            rr = inner[j].as_run()
                                            if rr is None:
                                                continue
                                            rf = rr.font
                                            if not self.is_protected_font(rf):
                                                self.set_name_to_target(rf, target_font)
                                            if hasattr(rf, "size"):
                                                rf.size = 12
                                            if hasattr(rf, "size_bi"):
                                                rf.size_bi = 12
                                            pn_runs += 1

                                    cur = cur.next_sibling
                            except Exception:
                                logging.debug("[change style] page-number field formatting failed", exc_info=True)

                logging.info("[change style] Footer 10pt + Page Number 12pt enforced (runs touched=%d)", pn_runs)
            except Exception as e:
                logging.debug("[change style] Footer/Page Number tweaks failure: %s", e, exc_info=True)

            # =============== 1a-EXT) Style-size table (sizes only) =================
            try:
                # 1) Apply at STYLE level (unconditional set)
                for style_name, to_sz in self.STYLE_SIZE_MAP.items():
                    self.set_style_font_size(work, style_name, float(to_sz))

                # 2) Apply to EXISTING content (paragraphs/runs) using those styles
                paras = work.get_child_nodes(aw.NodeType.PARAGRAPH, True)
                _affected_paras = 0
                _affected_runs = 0
                style_names_cf = {n.casefold(): v for n, v in self.STYLE_SIZE_MAP.items()}

                for i in range(paras.count):
                    try:
                        p = paras[i].as_paragraph()
                        if p is None:
                            continue
                        pf = p.paragraph_format
                        sname = (getattr(pf, "style_name", "") or "").strip().casefold()
                        if sname not in style_names_cf:
                            continue

                        to_sz = float(style_names_cf[sname])
                        pruns = p.get_child_nodes(aw.NodeType.RUN, True)
                        for r_i in range(pruns.count):
                            rr = pruns[r_i].as_run()
                            if rr is None:
                                continue
                            rf = rr.font

                            # Family always to target (unless protected)
                            if not self.is_protected_font(rf):
                                self.set_name_to_target(rf, target_font)


                            # Enforce size
                            for attr in ("size", "size_bi"):
                                if hasattr(rf, attr):
                                    try:
                                        setattr(rf, attr, to_sz)
                                        _affected_runs += 1
                                    except Exception:
                                        logging.debug("[change style] Style-size map: run set failed", exc_info=True)
                        _affected_paras += 1
                    except Exception:
                        logging.debug("[change style] Style-size map: per-paragraph handling failed", exc_info=True)

                logging.info("[change style] Style-size table enforced (paras=%d, runs≈%d)",
                            _affected_paras, _affected_runs)
            except Exception as e:
                logging.debug("[change style] Style-size table enforcement failure: %s", e, exc_info=True)
            
            # =============== 1c) Comments ballons ==============================
            try:
                
                balloon_style = work.styles.get_by_style_identifier(aw.StyleIdentifier.BALLOON_TEXT)
                balloon_style.font.size = 8

                comment = work.get_child(aw.NodeType.COMMENT_RANGE_START, 0, True).as_comment_range_start()
                comment_reference = comment.next_sibling.as_run()
                comment_reference.font.size = 8.5

            except Exception as e:
                logging.debug("[change style] comments enforcement failure: %s", e, exc_info=True)