需求:基于XML与XSLT生成带页眉页脚、表格分页的PDF文件
Great question! Generating a PDF from XML with fixed-row tables, persistent headers/footers, and clean pagination is totally achievable with XSL-FO (Extensible Stylesheet Language Formatting Objects)—it’s the go-to toolchain for XML-to-PDF tasks that require precise layout control. Let’s walk through a complete solution that matches your exact requirements:
Step 1: Prepare Your XML Data
First, let’s assume your source XML looks something like this (adjust the structure to match your actual data):
<data> <table-row> <col1>Row 1 Col 1</col1> <col2>Row 1 Col 2</col2> </table-row> <table-row> <col1>Row 2 Col 1</col1> <col2>Row 2 Col 2</col2> </table-row> <table-row> <col1>Row 3 Col 1</col1> <col2>Row 3 Col 2</col2> </table-row> <table-row> <col1>Row 4 Col 1</col1> <col2>Row 4 Col 2</col2> </table-row> <table-row> <col1>Row 5 Col 1</col1> <col2>Row 5 Col 2</col2> </table-row> </data>
Step 2: Write the XSL-FO Stylesheet
This is the core of the solution. The XSL-FO stylesheet will define your page layout (headers/footers), group your XML rows into fixed batches (2 per page), and render each batch into a table on its own page.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <!-- Main template that triggers the PDF generation --> <xsl:template match="/"> <fo:root> <!-- Define the page structure: size, margins, header/footer regions --> <fo:layout-master-set> <fo:simple-page-master master-name="pdf-page" page-width="8.5in" page-height="11in" margin="1in"> <fo:region-before extent="0.75in" margin-bottom="0.25in"/> <!-- Header area --> <fo:region-body margin-top="1in" margin-bottom="1in"/> <!-- Main content area --> <fo:region-after extent="0.75in" margin-top="0.25in"/> <!-- Footer area --> </fo:simple-page-master> </fo:layout-master-set> <!-- Group XML rows into batches of 2 (adjust the number for different row counts per page) --> <xsl:for-each-group select="/data/table-row" group-by="(position() - 1) idiv 2"> <fo:page-sequence master-reference="pdf-page"> <!-- Persistent header content --> <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="12pt" font-weight="bold" text-align="center"> *Your Custom Header Text* </fo:block> </fo:static-content> <!-- Persistent footer content with page numbers --> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="10pt" text-align="center"> Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/> </fo:block> </fo:static-content> <!-- Main page content: table with the current batch of rows --> <fo:flow flow-name="xsl-region-body"> <fo:table table-layout="fixed" width="100%" border="1pt solid black"> <!-- Optional table header (remove if you don't need it) --> <fo:table-header> <fo:table-row> <fo:table-cell padding="5pt" font-weight="bold"> <fo:block>Column 1</fo:block> </fo:table-cell> <fo:table-cell padding="5pt" font-weight="bold"> <fo:block>Column 2</fo:block> </fo:table-cell> </fo:table-row> </fo:table-header> <!-- Table body with the 2 rows for this page --> <fo:table-body> <xsl:for-each select="current-group()"> <fo:table-row> <fo:table-cell padding="5pt"> <fo:block><xsl:value-of select="col1"/></fo:block> </fo:table-cell> <fo:table-cell padding="5pt"> <fo:block><xsl:value-of select="col2"/></fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> </fo:flow> </fo:page-sequence> </xsl:for-each-group> <!-- Hidden page to calculate total page count --> <fo:page-sequence master-reference="pdf-page" id="last-page"> <fo:flow flow-name="xsl-region-body"> <fo:block/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> </xsl:stylesheet>
Step 3: Generate the PDF
Use an XSL-FO processor to convert your XML and stylesheet into a PDF. Apache FOP is a free, open-source option that works perfectly. Here’s how to use it via the command line:
fop -xml your-input.xml -xsl your-style.xsl -pdf your-output.pdf
Key Customization Tips
- Adjust rows per page: Change the
2in(position() - 1) idiv 2to any number (e.g.,5for 5 rows per page). - Customize headers/footers: Modify the
fo:blockinsidefo:static-contentto change text, font styles, alignment, or add logos. - Match your XML structure: Update the node selectors (like
col1/col2) to match the actual element names in your XML. - Styling the table: Tweak the
border,padding, or font properties in thefo:tableandfo:table-cellelements to match your desired look.
内容的提问来源于stack exchange,提问作者Karthikeyan

