J'essaie de faire fonctionner ceci dans python-docx
:
Une liste de puces que je peux obtenir en utilisant ceci:
from docx import Document
doc = Document()
p = doc.add_paragraph()
p.style = 'List Bullet'
r = p.add_run()
r.add_text("Item 1")
# Something's gotta come here to get the Sub-Item 1
r = p.add_run()
r.add_text("Item 2")
# Something's gotta come here to get the Sub-Item 2
Je pense que l'ajout d'un autre paragraphe au milieu n'aidera pas car cela signifierait essentiellement que je fais un autre List Bullet
avec la même mise en forme que son parent et non la mise en forme enfantine que je souhaite. De plus, l'ajout d'un autre run
au même paragraphe n'aide pas non plus (j'ai essayé, ça gâche tout ..). Une façon de le faire?
Il existe un moyen de le faire, mais cela implique un peu de travail supplémentaire de votre part. Il n'y a actuellement aucune interface "native" dans python-docx pour ce faire. Chaque élément à puce doit être un paragraphe individuel. Les exécutions s'appliquent uniquement aux caractères du texte.
L'idée est que la puce ou la numérotation des listes est contrôlée par un style de puce ou de nombre concret, qui fait référence à un style abstrait. Le style abstrait détermine le style du paragraphe affecté, tandis que la numérotation concrète détermine le nombre/puce dans la séquence abstraite. Cela signifie que vous pouvez avoir des paragraphes sans puces et numérotation entrecoupés entre les paragraphes à puces. Dans le même temps, vous pouvez redémarrer la séquence de numérotation/puce à tout moment en créant un nouveau style concret.
Toutes ces informations sont hachées (en détail mais sans succès) dans numéro 25 . Je n'ai pas le temps ni les ressources pour mettre cela au repos en ce moment, mais j'ai écrit une fonction que j'ai laissée dans un commentaire dans le fil de discussion. Cette fonction recherchera un style abstrait basé sur le niveau d'indentation et le style de paragraphe souhaités. Il créera ou récupérera ensuite un style concret basé sur ce style abstrait et l'affectera à votre objet paragraphe:
def list_number(doc, par, prev=None, level=None, num=True):
"""
Makes a paragraph into a list item with a specific level and
optional restart.
An attempt will be made to retreive an abstract numbering style that
corresponds to the style of the paragraph. If that is not possible,
the default numbering or bullet style will be used based on the
``num`` parameter.
Parameters
----------
doc : docx.document.Document
The document to add the list into.
par : docx.paragraph.Paragraph
The paragraph to turn into a list item.
prev : docx.paragraph.Paragraph or None
The previous paragraph in the list. If specified, the numbering
and styles will be taken as a continuation of this paragraph.
If omitted, a new numbering scheme will be started.
level : int or None
The level of the paragraph within the outline. If ``prev`` is
set, defaults to the same level as in ``prev``. Otherwise,
defaults to zero.
num : bool
If ``prev`` is :py:obj:`None` and the style of the paragraph
does not correspond to an existing numbering style, this will
determine wether or not the list will be numbered or bulleted.
The result is not guaranteed, but is fairly safe for most Word
templates.
"""
xpath_options = {
True: {'single': 'count(w:lvl)=1 and ', 'level': 0},
False: {'single': '', 'level': level},
}
def style_xpath(prefer_single=True):
"""
The style comes from the outer-scope variable ``par.style.name``.
"""
style = par.style.style_id
return (
'w:abstractNum['
'{single}w:lvl[@w:ilvl="{level}"]/w:pStyle[@w:val="{style}"]'
']/@w:abstractNumId'
).format(style=style, **xpath_options[prefer_single])
def type_xpath(prefer_single=True):
"""
The type is from the outer-scope variable ``num``.
"""
type = 'decimal' if num else 'bullet'
return (
'w:abstractNum['
'{single}w:lvl[@w:ilvl="{level}"]/w:numFmt[@w:val="{type}"]'
']/@w:abstractNumId'
).format(type=type, **xpath_options[prefer_single])
def get_abstract_id():
"""
Select as follows:
1. Match single-level by style (get min ID)
2. Match exact style and level (get min ID)
3. Match single-level decimal/bullet types (get min ID)
4. Match decimal/bullet in requested level (get min ID)
3. 0
"""
for fn in (style_xpath, type_xpath):
for prefer_single in (True, False):
xpath = fn(prefer_single)
ids = numbering.xpath(xpath)
if ids:
return min(int(x) for x in ids)
return 0
if (prev is None or
prev._p.pPr is None or
prev._p.pPr.numPr is None or
prev._p.pPr.numPr.numId is None):
if level is None:
level = 0
numbering = doc.part.numbering_part.numbering_definitions._numbering
# Compute the abstract ID first by style, then by num
anum = get_abstract_id()
# Set the concrete numbering based on the abstract numbering ID
num = numbering.add_num(anum)
# Make sure to override the abstract continuation property
num.add_lvlOverride(ilvl=level).add_startOverride(1)
# Extract the newly-allocated concrete numbering ID
num = num.numId
else:
if level is None:
level = prev._p.pPr.numPr.ilvl.val
# Get the previous concrete numbering ID
num = prev._p.pPr.numPr.numId.val
par._p.get_or_add_pPr().get_or_add_numPr().get_or_add_numId().val = num
par._p.get_or_add_pPr().get_or_add_numPr().get_or_add_ilvl().val = level
En utilisant les styles du talon de document intégré par défaut, vous pouvez faire quelque chose comme ceci:
d = docx.Document()
p0 = d.add_paragraph('Item 1', style='List Bullet')
list_number(d, p0, level=0, num=False)
p1 = d.add_paragraph('Item A', style='List Bullet 2')
list_number(d, p1, p0, level=1)
p2 = d.add_paragraph('Item 2', style='List Bullet')
list_number(d, p2, p1, level=0)
p3 = d.add_paragraph('Item B', style='List Bullet 2')
list_number(d, p3, p2, level=1)
Le style affectera non seulement les taquets de tabulation et les autres caractéristiques d'affichage du paragraphe, mais aidera également à rechercher le schéma de numérotation abstrait approprié. Lorsque vous définissez implicitement prev=None
dans l'appel à p0
, la fonction crée un nouveau schéma de numérotation concret. Tous les paragraphes restants hériteront du même schéma car ils obtiennent un paramètre prev
. Les appels à list_number
ne doit pas être entrelacé avec les appels à add_paragraph
comme ça, tant que la numérotation du paragraphe utilisé comme prev
est définie avant l'appel.