Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

revisions/track changes #340

Open
igptrs opened this issue Dec 12, 2016 · 5 comments
Open

revisions/track changes #340

igptrs opened this issue Dec 12, 2016 · 5 comments

Comments

@igptrs
Copy link

igptrs commented Dec 12, 2016

Request for implementation of revision/track changes. This should allow to generate documents from other tools, such as databases highlighting the differences into the resulting MSWord document.

@kaidoloor
Copy link

Ability to read original and amended text would be great, to start with. Maybe I am able to contribute.

@jfthuong
Copy link

jfthuong commented Oct 23, 2019

@kaidoloor

To get text with accepted changes, we could add something like that in class Paragraph of paragraph.py:

from xml.etree.ElementTree import XML

...
class Paragraph(Parented):
...
    @property
    def accepted_text(self):
        """
        String formed by accepting all changes and concatenating
        the text of each run in the paragraph.
        Tabs and line breaks in the XML are mapped to ``\\t`` and ``\\n``
        characters respectively.
        """
        W_NAMESPACE = "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}"
        TEXT = W_NAMESPACE + "t"
        xml = self._p.xml
        if "w:del" in xml or "w:ins" in xml:
            tree = XML(xml)
            runs = (node.text for node in tree.iter(TEXT) if node.text)
            return "".join(runs)
        else:
            return self.text

We would use as follows:

for p in Document(path).paragraphs:
    print(p.accepted_text)

Note: Tested and working on Python 3.7 and Python 2.7.

I actually added a better and simpler version in a PR #734

@sterbon
Copy link

sterbon commented Nov 10, 2021

@igptrs did you find any solution for this?

@alanlivio
Copy link

I needed to do some similar task and created the following python code using python-openxml and xml.etree:
   https://github.com/alanlivio/docx_reviews_to_txt
Hope it can be used as inspiration.

@caramdache
Copy link

I had to handle additional cases that were not catered for by @jfthuong or @semanticz0, so I came up with the following solution. It handles inserted, moved and deleted text, as well as figure text annotations (AlternateContent). It also reuses the already parsed XML structure rather than reparsing from string.

from docx.oxml.ns import qn, nsmap

def accepted_text(p):
    def _accepted_text(p):
        text = ''
        for run in p.xpath('w:r[not(w:pPr/w:rPr/w:moveFrom)] | w:ins/w:r'):
            for child in run:
                if child.tag == qn('w:t'):
                    text += child.text or ''
                elif child.tag == qn('w:tab'):
                    text += '\t'
                elif child.tag in (qn('w:br'), qn('w:cr')):
                    text += '\n'
                elif child.tag == qn('mc:AlternateContent'):
                    for nested_p in child.xpath('mc:Choice[1]//w:p', namespaces=nsmap):
                        text += _accepted_text(nested_p)
                        text += '\n'
        return text

    nsmap['mc'] = 'http://schemas.openxmlformats.org/markup-compatibility/2006'
    return _accepted_text(p._p)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants