Extracting paragraph styles from a DOCX in Python3

Viewed 794

I have been trying to solve this problem for a while in Python3.

I normally use to extract some information from DOCX documents, by using python-docx library.

from docx.document import Document
from docx import Document

document = Document("test.docx")

for paragraph in document.paragraphs:
    for run in paragraph.runs:
        print(run.font.name)
        #returns None

So, as you can see from the above code, this is a very simple python-docx code to extract some information. I can access some properties such as; font name, size, outline levels, etc.

However, all of these properties are returning None. Because they haven't been explicitly defined.

I have checked StackOverflow for a similar problem and found these.

Extracting word document with styles associated to the content

How to get actual style of text in word document using python docx

In the documentation, it also says, if it returns None, then it's the Default style, that is inherited.

Also tried some XML parsing, but could not reach the desired parameters:

words = document._element.xpath('//w:r')
WORD_NAMESPACE = '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
PARA = WORD_NAMESPACE + 'p'

for elem in document.element.getiterator():
    if elem.tag == WORD_NAMESPACE + 'p':
       for i, child in enumerate(elem.getchildren()):
           if child.tag == WORD_NAMESPACE + 'pPr':
                ...
           # No idea how to access, all the styles with which 
           # tags etc.

How do we extract these default styles too? I would want to extract, the indentation levels, bold, italic, font name, size, etc properties from a DOCX. What could be the alternative ways. I want to solve it in Python3.

1 Answers

I believe what you're trying to discover is the effective style, which is to say, after the style hierarchy for this run has been traversed, which character formatting attribute has which of its possible values for this particular run.

This is a non-trivial problem. The style hierarchy work similarly to Cascading Style Sheets (CSS) in that formatting attributes can be set at various levels and the "closest" setting wins. At the same time, a run can have no assigned character formatting or style in which case the "farthest away" or "default of last resort" determines its character formatting.

In order to compute the effective formatting you need to traverse the style hierarchy level by level until you find the setting you're looking for (like say font.name). To do that, you need to know what the style hierarchy is for a particular run and then have access to each level of it.

So that's a pretty big ask. Roughly, just to give an idea, the style hierarchy would typically be:

  • character formatting applied directly to the run, like bold, italic, font name and size.
  • character formatting applied using a character style
  • character formatting applied using a character style attached to a paragraph style.
  • character formatting associated with the default paragraph style.
  • an assigned document-level default
  • A client-internal final fallback, client being something like Word, OpenOffice, etc.

There are exceptions when the text appears in a table and a table-style may fit in that hierarchy somewhere. I expect there are others as well.

There's no API support for this in python-docx at the moment and I haven't seen any successful implementations of it. I don't believe it is impossible to get a pretty useful implementation, it's just hard enough that most folks find some way to avoid it.

Related