python-openxml / python-docx

Create and modify Word documents with Python
MIT License
4.38k stars 1.08k forks source link

Workaround to set <w:bidi/> property on a paragraph's properties <w:pPr>? #1411

Closed jamesbcd closed 3 weeks ago

jamesbcd commented 3 weeks ago

Hi,

Can anyone help with a work-around to set the property on a paragraph's properties ? This is necessary to set the whole paragraph to have a right-to-left text direction.

Any help appreciated!

scanny commented 3 weeks ago

In general, for this sort of thing:

  1. Get as close as possible to the desired location in the XML using python-docx (proxy) objects.
  2. Use lxml.etree._Element methods to manipulate the XML from there.

<w:bidi> is an element, not an attribute. That distinction matters here.

<w:pPr> is the "parent" element. You can get the w:pPr element you want from the paragraph like so:

paragraph = ...  # -- however you arrive to the right one --
pPr = paragraph._p.pPr

From there you want to create your new element,

from docx.oxml.parser import OxmlElement

bidi = OxmlElement("w:bidi")

Then insert it in the right sequence within the child-elements of pPr:

pPr.insert_element_before(
    bidi,
    (
        "w:adjustRightInd",
        "w:snapToGrid",
        "w:spacing",
        "w:ind",
        "w:contextualSpacing",
        "w:mirrorIndents",
        "w:suppressOverlap",
        "w:jc",
        "w:textDirection",
        "w:textAlignment",
        "w:textboxTightWrap",
        "w:outlineLvl",
        "w:divId",
        "w:cnfStyle",
        "w:rPr",
        "w:sectPr",
        "w:pPrChange",
    )
jamesbcd commented 3 weeks ago

Thanks so much @scanny, that's really helpful.

(The only tweaks I had to make were calling get_or_add_pPr() in case there was no existing <w:pPr> element yet, and unpacking the list of child elements.)

from docx.oxml.parser import OxmlElement

pPr = para._p.get_or_add_pPr()
bidi = OxmlElement("w:bidi")
pPr.insert_element_before(bidi,
    *(
        "w:adjustRightInd",
        "w:snapToGrid",
        "w:spacing",
        "w:ind",
        "w:contextualSpacing",
        "w:mirrorIndents",
        "w:suppressOverlap",
        "w:jc",
        "w:textDirection",
        "w:textAlignment",
        "w:textboxTightWrap",
        "w:outlineLvl",
        "w:divId",
        "w:cnfStyle",
        "w:rPr",
        "w:sectPr",
        "w:pPrChange",
    )
)