簡體   English   中英

帶有嵌入式HTML的PDF報告

[英]PDF report with embedded HTML

我們有一個基於Java的系統,該系統從數據庫讀取數據,將單個數據字段與預設的XSL-FO標簽合並,然后使用Apache FOP將結果轉換為PDF

XSL-FO格式中,它看起來像這樣:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE Html [
<!ENTITY nbsp  "&#160;"> 
    <!-- all other entities -->
]>
<xsl:stylesheet version="1.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" />
    <xsl:template match="/">

        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" font-family="..." font-size="...">
            <fo:layout-master-set>          
                <fo:simple-page-master master-name="Letter Page" page-width="8.500in" page-height="11.000in">

                    <!-- appropriate settings -->

                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="Letter Page">

                <!-- some static content -->

            <fo:flow flow-name="xsl-region-body">
                    <fo:block>
                        <fo:table ...>
                            <fo:table-column ... />
                            <fo:table-body>
                                <fo:table-row>
                                    <fo:table-cell ...>
                                        <fo:block text-align="...">
                                            <fo:inline font-size="..." font-weight="...">
                                                <!-- Header / Title -->
                                            </fo:inline>
                                        </fo:block>
                                    </fo:table-cell>
                                </fo:table-row>
                            </fo:table-body>
                        </fo:table>
                    </fo:block>

                    <fo:block>

                        <fo:table ...>
                            <fo:table-column ... />
                            <fo:table-body> 
                                <fo:table-row>
                                    <fo:table-cell>
                                        <fo:block ...>
                                            <!-- Field A -->                                
                                        </fo:block>
                                    </fo:table-cell>
                                </fo:table-row>
                            </fo:table-body>
                        </fo:table>

                        <!-- Other fields in a very similar fashion as the above "Field A" -->

                    </fo:block>

                </fo:flow>      

            </fo:page-sequence>

        </fo:root>              

    </xsl:template>

</xsl:stylesheet>

現在,我正在尋找一種允許某些字段包含靜態HTML格式內容的方法。 此內容將由我們啟用HTML的編輯器(類似於CLEditorCKEditor等)生成,或者從外部粘貼。

我的計划是遵循此JavaWorld文章的配方:

  • 使用JTidy將HTML格式的字符串轉換為正確的XHTML
  • 從Antenna House進一步修改xhtml2fo.xsl以刪除所有文檔范圍和頁面范圍的轉換
  • 將此修改后的XSLT應用於我的XHTML字符串(javax.xml.transform)
  • 使用XPath(javax.xml.xpath)提取根目錄下的所有節點
  • 將結果直接輸入到現有的XSL-FO文檔中

我有這樣的代碼的准系統版本,並收到以下錯誤:

(錯誤位置未知)org.apache.fop1.fo.ValidationException:“ { http://www.w3.org/1999/XSL/Format } table-body”不是“ fo:block”的有效子代! (沒有可用的上下文信息)

我的問題:

  1. 解決此問題的方法是什么?
  2. <fo:block>可以用作嵌套了其他對象(包括表)的通用容器嗎?
  3. 這是解決任務的整體合理方法嗎?

如果有人已經“ 在那里做過 ”,請分享您的經驗。

  1. 如果在oXygen或XML Spy中使用XSLT調試器,則可以逐步完成轉換。 使用oXygen(不確定XML Spy或其他編輯器)時,如果單擊調試器輸出中的標記,則oXygen將從源和生成該節點的樣式表中突出顯示標記。

    擁有FO后, focheck框架( https://github.com/AntennaHouse/focheck )具有當前可用的最完整的FO驗證。

  2. fo:block可以包含表等。在XSL 1.1規范中,每個FO的定義都包括一個“ Contents”小節,列出了其允許的內容。 參見例如http://www.w3.org/TR/xsl11/#fo_block 內容模型中“參數實體”的定義位於http://www.w3.org/TR/xsl11/#d0e6532 ,但是某些FO在其定義文本中有其他限制。
  3. 您引用的文章似乎沒有“用XPath提取根目錄下的所有節點”的步驟,而且我不確定為什么需要它。 除此之外,它看起來是使用Java進行這項工作的合理方法。

可以將<!-- Field A -->替換為非FO標記,以提供足夠的信息來引用要插入的字段,而不是將從JTidy-ed HTML轉換的FO插入到靜態FO中。 然后,您可以制作XSLT樣式表,方法是對FO部分進行身份轉換(如@ kevin-brown的回答),並使用引用標記中的信息來構造模板,從而將模板+引用文檔轉換為純FO。與document()函數( http://www.w3.org/TR/xslt#document )一起使用的URI,以查找要插入的標記。

如果字段內容的FO位於磁盤上,則使用document()很簡單。 如果不是,那么您就必須執行諸如覆蓋XSLT處理器所使用的URIResolver之類的操作,以便與其在磁盤上查看,不如在磁盤上進行檢索內容。 您甚至可以在檢索HTML的URIResolver中使JTidying發生。 您也可以在URIResolver內部進行到FO的轉換,也可以按照@ kevin-brown的建議,將其轉換為單獨的模式。 如果轉換是在URIResolver檢索FO之前或期間完成的,則對FO的模板+引用的“主”轉換只需要提取FO子文檔的正確部分,例如document('constructed-URI')/fo:root/fo:page-sequence/* 但是,如果您要從Antenna House修改樣式表,則應該能夠對其進行修改,以使其始終不產生外部fo:root等。

幾年前,我做了一些類似的事情,為基於XSLT的服務器重寫libxslt XSLT處理器的URI解析器:內部XSLT處理器連續運行的上下文被另存為特殊URI的文檔,而不必寫入文件系統完全沒有

相反,您可以編寫擴展功能來查找對字段的引用。 例如,W3C的Print and Page Layout Community Group @已為多個XSLT處理器生成了擴展功能,這些擴展功能在XSLT轉換的中間運行FO處理器,以獲取格式化結果的區域樹的XML。 參見http://www.w3.org/community/ppl/wiki/XSLTExtensions

解決問題的最佳方法是使用驗證查看器/編輯器檢查XSL FO。 當您打開它們時,許多(例如oXygen)將向您顯示XSL FO結構中的錯誤,並且它們將描述問題(就像報告的錯誤一樣)。

在您的情況下,您顯然有一個fo:table-body作為fo:block的子級。 它不可能是。 一個fo:table-body只有一個有效的父對象fo:table。 您或者缺少fo:table標記,或者在該位置錯誤地插入了fo:block。

在我看來,我做的事情可能略有不同。 我會將XHTML內容內聯到XSL FO中,就在您需要的位置。 然后,我將創建一個標識轉換,復制所有基於fo的內容,但使用XSL轉換XHTML部分。 這樣,您實際上可以在像oXygen這樣的XSL編輯器中逐步進行轉換,並查看錯誤發生的位置以及原因。 像其他任何騙子一樣。

注意:您可能還希望查看其他XSL,尤其是在HTML可能具有任何style =“” CSS屬性的情況下。 如果是這種情況,那么它不是簡單的HTML,那么您將需要一個更好的方法來將CSS與FO一起處理HTML。

http://www.cloudformatter.com/css2pdf基於此完整的轉換。 該常規樣式表可在此處獲得: http : //xep.cloudformatter.com/doc/XSL/xeponline-fo-translate-2.xsl

我是該樣式表的作者。 它的功能遠遠超出您的要求,但是具有相當復雜的解析遞歸,可以將CSS樣式轉換為XSL FO屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM