Python 使用目录创建多个文档时,Reportlab不会重置序列
我正在使用一个模板函数,该函数使用reportlab在一个程序执行中创建多个PDF文档 这些文件的结构相同,标题也相同。它们仅在标题下的内容不同。所有这些文档都包含一个目录元素 我正在使用序列标签(Python 使用目录创建多个文档时,Reportlab不会重置序列,python,python-3.x,reportlab,Python,Python 3.x,Reportlab,我正在使用一个模板函数,该函数使用reportlab在一个程序执行中创建多个PDF文档 这些文件的结构相同,标题也相同。它们仅在标题下的内容不同。所有这些文档都包含一个目录元素 我正在使用序列标签(等)创建编号标题e。g 1. Top1 1.1 Sub1 2. Top2 2.1 Sub1 2.2 Sub2 这对一个文档很有效,但只要我在第一个文档之后创建第二个文档,序列就不会重置,第二个文档的TOC如下所示 2. Top1 2.1 Sub1 3. Top2 3.1 Sub1
等)创建编号标题e。g
1. Top1
1.1 Sub1
2. Top2
2.1 Sub1
2.2 Sub2
这对一个文档很有效,但只要我在第一个文档之后创建第二个文档,序列就不会重置,第二个文档的TOC如下所示
2. Top1
2.1 Sub1
3. Top2
3.1 Sub1
3.2 Sub2
创建第三个文档Top1
将从3
开始
但是,由于我正在启动一个新文档,创建一个新的BaseDocTemplate
类,所以我希望序列被重置。我怎样才能做到这一点
我尝试使用reportlab的一个教程创建一个尽可能小的示例
from reportlab.lib.styles import ParagraphStyle as PS
from reportlab.platypus import PageBreak
from reportlab.platypus.paragraph import Paragraph
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.platypus.frames import Frame
from reportlab.lib.units import cm
class MyDocTemplate(BaseDocTemplate):
def __init__(self, filename, **kw):
self.allowSplitting = 0
super().__init__(filename, **kw)
template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])
self.addPageTemplates(template)
# Entries to the table of contents can be done either manually by
# calling the addEntry method on the TableOfContents object or automatically
# by sending a 'TOCEntry' notification in the afterFlowable method of
# the DocTemplate you are using. The data to be passed to notify is a list
# of three or four items countaining a level number, the entry text, the page
# number and an optional destination key which the entry should point to.
# This list will usually be created in a document template's method like
# afterFlowable(), making notification calls using the notify() method
# with appropriate data.
def afterFlowable(self, flowable):
"Registers TOC entries."
if flowable.__class__.__name__ == 'Paragraph':
text = flowable.getPlainText()
style = flowable.style.name
if style == 'Heading1':
self.notify('TOCEntry', (0, text, self.page))
if style == 'Heading2':
self.notify('TOCEntry', (1, text, self.page))
centered = PS(name = 'centered',
fontSize = 30,
leading = 16,
alignment = 1,
spaceAfter = 20)
h1 = PS(
name = 'Heading1',
fontSize = 14,
leading = 16)
h2 = PS(name = 'Heading2',
fontSize = 12,
leading = 14)
# Heading definition with sequence numbers
heading = {
1 : "<seq id='h1'/>.<seqreset id='h2'/><seqreset id='h3'/> {}",
2 : "<seq id='h1' inc='no'/>.<seq id='h2'/><seqreset id='h3'/> {}",
3 : "<seq id='h1' inc='no'/>.<seq id='h2' inc='no'/>.<seq id='h3'/> {}",
}
def build_document(filename):
# Build story.
story = []
# Create an instance of TableOfContents. Override the level styles (optional)
# and add the object to the story
toc = TableOfContents()
toc.levelStyles = [
PS(fontName='Times-Bold', fontSize=20, name='TOCHeading1', leftIndent=20, firstLineIndent=-20, spaceBefore=10, leading=16),
PS(fontSize=18, name='TOCHeading2', leftIndent=40, firstLineIndent=-20, spaceBefore=5, leading=12),
]
story.append(toc)
story.append(Paragraph('<b>Table of contents</b>', centered))
story.append(PageBreak())
story.append(Paragraph(heading[1].format('First heading'), h1))
story.append(Paragraph('Text in first heading', PS('body')))
story.append(Paragraph(heading[2].format('First sub heading'), h2))
story.append(Paragraph('Text in first sub heading', PS('body')))
story.append(PageBreak())
story.append(Paragraph(heading[2].format('Second sub heading'), h2))
story.append(Paragraph('Text in second sub heading', PS('body')))
story.append(PageBreak())
story.append(Paragraph(heading[2].format('Last heading'), h1))
doc = MyDocTemplate(filename)
doc.multiBuild(story)
if __name__ == "__main__":
build_document("1.pdf")
build_document("2.pdf")
从reportlab.lib.styles将段落样式导入为PS
从reportlab.platypus导入PageBreak
来自reportlab.platypus.paragration导入段落
从reportlab.platypus.DoctTemplate导入页面模板,BaseDoctTemplate
从reportlab.platypus.tableofcontents导入目录
从reportlab.platypus.frames导入框架
从reportlab.lib.units导入cm
类MyDoctTemplate(BaseDoctTemplate):
def u uu init uuuu(self,文件名,**kw):
self.allowSplitting=0
super()。\uuuuu init\uuuuu(文件名,**kw)
template=PageTemplate('normal',[Frame(2.5*cm,2.5*cm,15*cm,25*cm,id='F1'))
self.addPageTemplates(模板)
#目录的条目可以通过以下方式手动完成:
#在TableOfContents对象或自动调用addEntry方法
#通过在的afterFlowable方法中发送“TOCEntry”通知
#您正在使用的DocTemplate。要传递给notify的数据是一个列表
#三个或四个项目中的一个级别编号,条目文本,页面
#数字和条目应指向的可选目标键。
#此列表通常使用文档模板的方法创建,如
#afterFlowable(),使用notify()方法进行通知调用
#有适当的数据。
def可后流式(自动、可流动):
“注册TOC条目。”
如果是可流动的。类别名称=段落:
text=flowable.getPlainText()
style=flowable.style.name
如果样式=='Heading1':
self.notify('toccentry',(0,文本,self.page))
如果样式=='Heading2':
self.notify('toccentry',(1,文本,self.page))
居中=PS(名称=‘居中’,
fontSize=30,
领先=16,
对齐=1,
spaceAfter=20)
h1=PS(
名称='Heading1',
fontSize=14,
领先=16)
h2=PS(名称='Heading2',
fontSize=12,
领先=14)
#带序列号的标题定义
标题={
1 : ". {}",
2 : ". {}",
3 : ".. {}",
}
def build_文档(文件名):
#构建故事。
故事=[]
#创建TableOfContents的实例。替代标高样式(可选)
#并将对象添加到故事中
toc=目录()
toc.levelStyles=[
PS(fontName='Times-Bold',fontSize=20,name='toheading1',leftIndent=20,firstLineIndent=-20,spaceBefore=10,leading=16),
PS(fontSize=18,name='TOCHeading2',leftIndent=40,firstLineIndent=-20,spaceBefore=5,leading=12),
]
故事附加(toc)
附加(段落(“目录”,居中))
story.append(PageBreak())
附加(段落(标题[1]。格式(“第一标题”),h1))
附加(段落('第一标题中的文本',PS('正文'))
附加(段落(标题[2]。格式(“第一副标题”),h2))
故事。附加(段落(“第一小标题中的文本”,PS(“正文”))
story.append(PageBreak())
附加(段落(标题[2]。格式(“第二副标题”),h2))
附加(段落(‘第二小标题中的文本’、PS(‘正文’))
story.append(PageBreak())
附加(段落(标题[2]。格式(“最后一个标题”),h1))
doc=MyDocTemplate(文件名)
多版本文档(故事)
如果名称=“\uuuuu main\uuuuuuuu”:
构建文档(“1.pdf”)
构建文档(“2.pdf”)
我找到了一个快速解决方案,解决了我的问题,但我不喜欢将其作为最终解决方案
问题是我使用的是同名的全局序列h1
、h2
和h3
出现在每个文档中。当新文档启动时,reportlab似乎不会重置它们。因此,我在填充故事列表之前手动重置了
def build_document(filename):
# Build story. story = []
# Reset the sequences
story.append(Paragraph("<seqreset id='h1'/>", PS('body')))
story.append(Paragraph("<seqreset id='h2'/>", PS('body')))
story.append(Paragraph("<seqreset id='h3'/>", PS('body')))
# ... rest of the code from the question
def build_文档(文件名):
#构建故事。故事=[]
#重置序列
故事。附加(段落(“,PS(‘正文’))
故事。附加(段落(“,PS(‘正文’))
故事。附加(段落(“,PS(‘正文’))
# ... 问题的其余代码
看起来所使用的reportlab.lib.sequencer.sequencer
对象是全局对象
您可以通过提供新的序列器重置所有计数器
from reportlab.lib.sequencer import setSequencer, Sequencer
setSequencer(Sequencer())
您可以通过执行以下操作重置单个计数器:
from reportlab.lib.sequencer import getSequencer
s = getSequencer()
s.reset('h1')
您还可以尝试直接使用Sequencer,而不是注入XML
类序列器:使段落编号变得容易的东西,
部分、图像和其他任何内容。这些功能包括注册
序列的新字符串格式,以及一些计数器的“链”
当他们的父母重新设定时。它记录了许多信息
“计数器”,根据请求创建
仅仅第一个
就足够了吗?当第一次使用h1
时,其他已重置?@B8vrede no。这似乎不够。我已经对它进行了测试,但序列仍然是递增的。我知道可以链接序列,然后重置h1
就足够了,但在我的示例中,它们似乎没有链接。
Usage::
>>> seq = Sequencer()
>>> seq.next('Bullets')
1
>>> seq.next('Bullets')
2
>>> seq.next('Bullets')
3
>>> seq.reset('Bullets')
>>> seq.next('Bullets')
1
>>> seq.next('Figures')
1
>>>