简体   繁体   中英

python-docx: Insert a paragraph after

In python-docx, the paragraph object has a method insert_paragraph_before that allows inserting text before itself:

p.insert_paragraph_before("This is a text")

There is no insert_paragraph_after method, but I suppose that a paragraph object knows sufficiently about itself to determine which paragraph is next in the list. Unfortunately, the inner workings of the python-docx AST are a little intricate (and not really documented).

I wonder how to program a function with the following spec?

def insert_paragraph_after(para, text):

Trying to make sense of the inner workings of docx made me dizzy, but fortunately, it's easy enough to accomplish what you want, since the internal object already has the necessairy method addnext , which is all we need:

from docx import Document

from docx.text.paragraph import Paragraph
from docx.oxml.xmlchemy import OxmlElement

def insert_paragraph_after(paragraph, text=None, style=None):
    """Insert a new paragraph after the given paragraph."""
    new_p = OxmlElement("w:p")
    paragraph._p.addnext(new_p)
    new_para = Paragraph(new_p, paragraph._parent)
    if text:
        new_para.add_run(text)
    if style is not None:
        new_para.style = style
    return new_para

def main():
    # Create a minimal document
    document = Document()
    p1 = document.add_paragraph("First Paragraph.")
    p2 = document.add_paragraph("Second Paragraph.")

    # Insert a paragraph wedged between p1 and p2
    insert_paragraph_after(p1, "Paragraph One And A Half.")

    # Test if the function succeeded
    document.save(r"D:\somepath\docx_para_after.docx")

if __name__ == "__main__":
    main()

In the mean time I found another method, more high level (though perhaps not as elegant). It essentially finds the parent, lists the children, works out its own position in line and then gets the next one.

def par_index(paragraph):
    "Get the index of the paragraph in the document"
    doc = paragraph._parent
    # the paragraphs elements are being generated on the fly,
    # they change all the time
    # so in order to index, we must use the elements
    l_elements = [p._element for p in doc.paragraphs]
    return l_elements.index(paragraph._element)


def insert_paragraph_after(paragraph, text, style=None):
    """
    Add a paragraph to a docx document, after this one.
    """
    doc = paragraph._parent
    i = par_index(paragraph) + 1 # next
    if i <= len(doc.paragraphs):
        # we find the next paragraph and we insert before:
        next_par = doc.paragraphs[i]
        new_par = next_par.insert_paragraph_before(text, style)
    else:
        # we reached the end, so we need to create a new one:
        new_par = parent.add_paragraph(text, style)
    return new_par

One advantage is that it mostly avoids getting into the inner workings.

Please refer below details:

para1 = document.add_paragraph("Hello World")
para2 = document.add_paragraph("Testing!!")

p1 = para1._p
p1.addnext(para2._p)

Reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM