在 XSLT 中有 URL 时使用 fop 和 XSL 生成 PDF

Posted

技术标签:

【中文标题】在 XSLT 中有 URL 时使用 fop 和 XSL 生成 PDF【英文标题】:Generating PDF using fop and XSL when having URLS in XSLT 【发布时间】:2019-08-26 16:43:07 【问题描述】:

我正在使用 FOP 2.0 和 XSLT 生成 PDF。在这里,我从 web url 获取 XSL。我的一个 XSL URL 包含和导入其他 XSL 的 URL。如果它是单个 XSL,我可以生成 PDF。如果我在 Web 上的一个 XSLT 中有多个 URL。 FOP 无法自动连接到其他 URL[使用 XSLTS 的示例]


xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" \

xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">

<xsl:include href="abc.xsl"/> 

<xsl:include href="xyz.xsl"/>

<xsl:include href="wgh.xsl"/>

这是将 XSL 包含在一个 XSL 中的方式。在这种情况下,我的 FOP 没有重定向到那些 xsls 并且无法生成 PDF

错误:

SystemId 未知;第 3 行;第 34 列;样式表文件出现 IO 异常:header.xsl 系统 ID 未知;第 4 行;第 34 列;样式表文件出现 IO 异常:footer.xsl 系统 ID 未知;第 5 行;第 36 列;样式表文件出现 IO 异常:mainbody.xsl 系统 ID 未知;第 6 行;第 41 列;样式表文件出现 IO 异常:secondarybody.xsl 系统 ID 未知;第 10 行;第 38 列; org.xml.sax.SAXException:ElemTemplateElement 错误:布局 javax.xml.transform.TransformerException:ElemTemplateElement 错误:布局 13:58:27.326 [http-nio-auto-1-exec-2] 调试 org.apache.fop.fo.FOTreeBuilder - 构建格式化对象树 系统 ID 未知;第 10 行;第 38 列;找不到名为:布局的模板

PDF 生成器代码:

公共类 PdfGenerator

private static final Logger LOG=LoggerFactory.getLogger(PdfGenerator.class);

public List<OutputStream>  generatePdfs(List<Content> xmlList, int reqestListSize,String xslPath)

试试

    List<OutputStream> pdfOutputStreams= new ArrayList();   

    for(int p = 0; p <reqestListSize; p++) 

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        String jaxbType = "com.abc.model"; // model package
        JAXBContext context = JAXBContext.newInstance(jaxbType);  
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
        marshaller.marshal(xmlList.get(p),bos);
        ByteArrayInputStream inStream = new ByteArrayInputStream(bos.toByteArray());                
        StreamSource xmlSource = new StreamSource(inStream);                
        // create an instance of fop factory
        FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
        // a user agent is needed for transformation
        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        ByteArrayOutputStream tempOutputStream = new ByteArrayOutputStream();
        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, tempOutputStream);
        pdfOutputStreams.add(p, tempOutputStream);      
        // Setup XSLT
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        URL url = new URL(xslPath);
        InputStream xslFile = url.openStream();  (   **http://home.www.test.com/abc_web/xsl/test.xsl**  ( Using an url to get XSLT. faild loading due to XSL :include) )
        StreamSource xsltStreamSource = new StreamSource(xslFile);
        Transformer transformer = transformerFactory.newTransformer(xsltStreamSource);  
        Result res = new SAXResult(fop.getDefaultHandler());    
        // Start XSLT transformation and FOP processing
        // That's where the XML is first transformed to XSL-FO and then 
        // PDF is created      
        transformer.transform(xmlSource, res);
    
    return pdfOutputStreams;

    catch(Exception ex) 
        LOG.error("Error", ex);
        return new ArrayList();
    

【问题讨论】:

您是否编写 Java 代码来运行 Apache FOP?然后向我们展示相关代码。还告诉我们确切的错误消息。 请注意,FOP 确实在处理 XSLT 转换的 结果 中发挥作用;在此之前,工作的是 XSLT 处理器。 @MartinHonnen 我已经添加了逻辑和错误部分,请您查看一下 直接使用StreamSource xsltStreamSource = new StreamSource(xslPath);是不是也可以避免问题? 感谢@MartinHonnen 它的工作。你让我开心:) 【参考方案1】:

简单替换

URL url = new URL(xslPath);
InputStream xslFile = url.openStream();
StreamSource xsltStreamSource = new StreamSource(xslFile);

StreamSource xsltStreamSource = new StreamSource(xslPath);

XSLT 处理器应该能够解析任何相关的导入或包含。

或者您需要在您的xsltStreamSource 上显式设置SystemId。但是我建议的单行应该可以很好地完成这项工作。

【讨论】:

以上是关于在 XSLT 中有 URL 时使用 fop 和 XSL 生成 PDF的主要内容,如果未能解决你的问题,请参考以下文章

XSLT FOP PDF 表格行编号

使用fop在XSL-FO中设置字体

将命名空间从 java 传递给 xslt,并使用 java 中的参数作为 xslt 中的节点

pdfbox / XSL + FOP 转换 PDF文档

pdfbox / XSL + FOP 转换 PDF文档

FOP 无法从 url 加载图像