XML转PDF的XSL解析问题:仅显示page标签下首行元素
First off, the issue you're hitting comes down to how your XML is structured right now. Each <page> has <line_number> and <product_code> elements floating directly under it without a wrapping element for each individual line. This makes it impossible for your XSL to reliably loop through each line item—instead, it's only grabbing the first pair it finds.
Step 1: Correct Your XML Structure
Wrap each line's data in a <line> element (or whatever name you prefer, as long as it's consistent). Here's how your corrected XML should look:
<receipt> <order> <page> <!-- Empty page, nothing to display --> </page> <page> <line> <line_number>1</line_number> <product_code>S10</product_code> </line> <line> <line_number>2</line_number> <product_code>S20</product_code> </line> <line> <line_number>3</line_number> <product_code>S30</product_code> </line> </page> </order> </receipt>
Step 2: Update Your XSL to Iterate Over Lines
Now, use XSL-FO (the standard for XML-to-PDF conversion) to create a stylesheet that loops through each <page> and then each <line> inside it. Here's a working example:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:template match="/"> <fo:root> <fo:layout-master-set> <!-- Define a basic page layout --> <fo:simple-page-master master-name="page-layout" page-width="8.5in" page-height="11in"> <fo:region-body margin="1in"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="page-layout"> <fo:flow flow-name="xsl-region-body"> <!-- Process each page in the order --> <xsl:for-each select="receipt/order/page"> <!-- Add a heading for the page (optional) --> <fo:block font-size="14pt" font-weight="bold" margin-bottom="10pt"> Page <xsl:value-of select="position()"/> </fo:block> <!-- Loop through each line in the current page --> <fo:table border="1px solid black" table-layout="fixed" width="100%"> <fo:table-column column-width="20%"/> <fo:table-column column-width="80%"/> <fo:table-header> <fo:table-row> <fo:table-cell padding="5pt" background-color="#eee"> <fo:block font-weight="bold">Line Number</fo:block> </fo:table-cell> <fo:table-cell padding="5pt" background-color="#eee"> <fo:block font-weight="bold">Product Code</fo:block> </fo:table-cell> </fo:table-row> </fo:table-header> <fo:table-body> <xsl:for-each select="line"> <fo:table-row> <fo:table-cell padding="5pt"> <fo:block><xsl:value-of select="line_number"/></fo:block> </fo:table-cell> <fo:table-cell padding="5pt"> <fo:block><xsl:value-of select="product_code"/></fo:block> </fo:table-cell> </fo:table-row> </xsl:for-each> </fo:table-body> </fo:table> <!-- Add a page break after each page (except the last one) --> <xsl:if test="position() != last()"> <fo:block break-after="page"/> </xsl:if> </xsl:for-each> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> </xsl:stylesheet>
Step 3: Generate the PDF
To turn this into a PDF, you'll need an XSL-FO processor like Apache FOP. Run it with a command like:
fop -xml your-corrected.xml -xsl your-stylesheet.xsl -output final-receipt.pdf
This stylesheet will create a separate table for each page, displaying all line items with their line numbers and product codes. The empty page will still appear (as a blank page with the "Page 1" heading), but you can adjust that by adding a check to skip empty pages if needed.
内容的提问来源于stack exchange,提问作者Karthikeyan

