飞碟不读样式表

时间:2010-07-07 09:59:06

标签: flying-saucer

我在一个asp.net应用程序(使用IKVM)中将flyingsaucer和iText一起用于将HTML转换为PDF。如果我直接在html中添加一个样式它可以正常工作(甚至样式放在样式标记之间)但是当我链接样式表时它没有注意到它并生成没有样式的pdf。

为什么会发生这种情况?

这是我正在使用的代码

        Dim renderer As New ITextRenderer
        Dim buf As New StringBuffer
        buf.append(HTML)
        Dim builder As DocumentBuilder = DocumentBuilderFactory.newInstance.newDocumentBuilder()
        Dim doc As Document = builder.parse(New StringBufferInputStream(buf.toString))

        renderer.setDocument(doc, Nothing)
        renderer.layout()

        renderer.createPDF(os)

这是样式表的链接

<link rel="stylesheet" href="stylemove.css" type="text/css"  />

4 个答案:

答案 0 :(得分:3)

from the FAQ:

我的PDF没有拿起我的CSS!

PDF被视为“打印”媒体;见CSS 2.1 specification section on media types。确保在链接或嵌入CSS时为CSS指定了媒体类型;使用“打印”或“全部”类型。

答案 1 :(得分:2)

如果您使用的是https,那么飞碟将无法读取.css文件,直到您使java的密钥库包含您的Web服务器的证书。

我也有同样的问题......请参阅此讨论

https://code.google.com/p/jmesa/issues/detail?id=182

如果你以其他方式解决了,请告诉我!!!

感谢。

答案 2 :(得分:1)

简易解决方案:

如果您想快速测试一下,看看您的文档是否适用于您的样式(无需编写大量代码即可将其集成到您的应用中)。只需将您需要的CSS复制并粘贴到您的页面中即可。

工作量更大的解决方案

我的解决方案是阅读CSS并使用预处理器将其放入html中。由于它是一个较旧的应用程序,可能不完全符合xhtml,我使用JSoup加载html。下面的代码进行预处理。我会说这些代码片段可以帮助您入门。最棒的是,一旦你有了它的工作,你可以将服务器上的任何页面转换为PDF而无需任何额外的代码。在我的情况下,我设置了一个过滤器来查找特定的参数。如果该参数存在,我使用请求包装器包装请求以访问html页面的最终呈现字节。然后我使用Jsoup来解析它,然后pre =处理它。

/**this method uses JSOUP  Document here is org.jsoup.nodes.Document
*/
 @Override
     public void modifyDOM(MyResourceResolver resources, Document normalizedDOM) {

         //move style into head section
         Elements styleTags = normalizedDOM.getElementsByTag("style");

         normalizedDOM.select("style").remove();

         for (org.jsoup.nodes.Element linkElement : styleTags) {

             String curHead = normalizedDOM.head().html();
             normalizedDOM.head().html(curHead + "\n" + linkElement.html() + "\n");


         }


         //now resolve css
         Elements links = normalizedDOM.getElementsByTag("link");


         for (org.jsoup.nodes.Element linkElement : links) {

             String linkHref = linkElement.attr("href");
             if (linkHref == null) {
                 linkHref = "";
             }


             String mediaSelector = linkElement.attr("media");
             if (mediaSelector == null) {
                 mediaSelector = "";
             }
             mediaSelector = mediaSelector.trim();
             if ("".equalsIgnoreCase(mediaSelector) || ("print".equalsIgnoreCase(mediaSelector))) {

                 byte[] contents = resources.getContentsOfHref(linkHref);

                 if (null != contents) {
                     //we've got the info let's add to the document as is
                     Tag styleTag = Tag.valueOf("style");
                     Attributes styleAttributes = new Attributes();
                     styleAttributes.put("type", "text/css");
                     String baseUri = "";
                     org.jsoup.nodes.Element styleElement = new Element(styleTag, baseUri, styleAttributes);
                     styleElement.text(new String(contents));
                     String curHead = normalizedDOM.head().html();
                     normalizedDOM.head().html(curHead + "\n<style type='text/css'>" + styleElement.html() + "</style>\n");

                 }
             }


         }


         normalizedDOM.select("link").remove();
         normalizedDOM.select("script").remove();
     }

由于我插入css和飞碟不支持javascript,我只是在预处理结束时从文档中删除那些引用。类 MyResourceResolver 只是我编写的一个类,它引用了servlet上下文。实际从服务器读取css字节的方法如下所示:

 public byte[] getContentsOfHref(String href) {
         byte[] retval = null;
         byte[] buf = new byte[8195];
         int nread;
         ByteArrayOutputStream bos = new ByteArrayOutputStream();

         InputStream is = null;
         try {

             if (href.startsWith("/myurlcontext")) {
                 href = href.substring("/myurlcontext".length());
             }
                 is = context.getResourceAsStream(href);
                 while ((nread = is.read(buf)) >= 0) {
                     bos.write(buf, 0, nread);
                 }
                 retval = bos.toByteArray();


         } catch (Exception ex) {
             //do nothing for now
         } finally {
             try {
                 is.close();
             } catch (Exception ex) {/*do nothing*/}
         }
         if (retval == null) {
             System.out.println("Did not find: " + href);
         } else {
             System.out.println("Found: " + href + " " + retval.length + " bytes");
         }
         return retval;
     }

接下来的问题,如何初始化JSOUP Dom。好吧,我在请求包装器中执行此操作,该包装器读取呈现的JSP页面的内容并将其传递给我的PDF生成代码:

 String renderedJSPString = new String(renderedJSP);
 //these escape sequences are nuisance in xhtml.
         renderedJSPString = renderedJSPString.replaceAll("&nbsp;|&copy;|&amp;|&lt;|&gt;", "");
         org.jsoup.nodes.Document parsedHtmlDOM = Jsoup.parse(renderedJSPString);
         org.jsoup.nodes.Document normalizedDOM = parsedHtmlDOM.normalise();
         normalizedDOM.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
         normalizedDOM.outputSettings().prettyPrint(true);
 ...
 preProcessor.modifyDOM(resolver, normalizedDOM);
 ...

答案 3 :(得分:0)

您没有在setDocument调用中设置文档的基本URL。正如我所发现的那样,飞碟需要解决CSS和图像链接问题。有关详细信息,请参阅this answer

相关问题