Search code examples
pythonxmldocxpython-docx

How to add line numbers to a docx document section using python-docx


I am using python-docx to generate some documents.

I can see that there exists a line numbering property which may be applied to document sections (for the OOXML standard at least).

I can also see that this property is not present in the python-docx API.

I am assuming it is possible to access the underlying sectPr field to add the lnNumType tag, but I have not been able to (easily) find any examples.

Am I getting my standards confused? Or is my question just a bit obscure?


Solution

  • Once you have the Section object, you can get the sectPr element with:

    sectPr = section._sectPr
    

    If you Google on 'python-docx workaround function OxmlElement' you'll find examples. All elements inherit from lxml _Element so lxml manipulation works. There are also some handy other methods added by BaseOxmlElement. A basic gist would be:

    sectPr = section._sectPr
    lnNumType = OxmlElement('w:lnNumType')
    lnNumType.set('fooAttrib', '42')
    sectPr.append(lnNumType)
    

    In many cases you'll need to attend to getting any new child elements in the right order, as the sequence is almost always prescribed.

    You can find some handy analysis of the w:sectPr element here: http://python-docx.readthedocs.io/en/latest/dev/analysis/features/sections.html

    It looks from a quick glance that you'll be able to just append a w:lnNumType on the end as the elements that follow it are less common. But if you wanted to be more rigorous you could use this instead of sectPr.append():

    sectPr.insert_element_before(lnNumType, (
        'w:pgNumType', 'w:pgNumType', 'w:cols', 'w:formProt', 'w:vAlign',
        'w:noEndnote', 'w:titlePg', 'w:textDirection', 'w:bidi',
        'w:rtlGutter', 'w:docGrid', 'w:printerSettings', 'w:sectPrChange',
    ))
    

    You can see the implementation for .insert_element_before() here: https://github.com/python-openxml/python-docx/blob/master/docx/oxml/xmlchemy.py#L718