2015-09-25 22 views
10

Chúng tôi có hệ thống dựa trên Java đọc dữ liệu từ cơ sở dữ liệu, hợp nhất các trường dữ liệu riêng lẻ với các thẻ XSL-FO đặt trước và chuyển kết quả thành PDF với Apache FOP.Báo cáo PDF với HTML nhúng

Trong định dạng XSL-FO nó trông như thế này:

<?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> 

Bây giờ tôi đang tìm kiếm một cách để cho phép một số lĩnh vực để chứa tĩnh định dạng HTML nội dung. Nội dung này sẽ được tạo bởi trình chỉnh sửa được bật HTML của chúng tôi (thứ gì đó dọc theo các dòng CLEditor, CKEditor, v.v.) hoặc được dán từ bên ngoài.

Kế hoạch của tôi là làm theo công thức from this JavaWorld article:

  • sử dụng JTidy để chuyển đổi chuỗi có định dạng HTML để XHTML đúng
  • tiếp tục sửa đổi xhtml2fo.xsl từ Antenna Nhà để loại bỏ tất cả các biến đổi tài liệu toàn và trên toàn bộ trang
  • áp dụng XSLT biến đổi này để chuỗi XHTML của tôi (javax.xml.transform)
  • trích xuất tất cả các nút dưới gốc với XPath (javax.xml.xpath)
  • nuôi kết quả trực tiếp vào XSL-FO tài liệu

hiện tại tôi có một phiên bản trần xương mã như vậy và đã nhận lỗi sau:

(Location of error unknown)org.apache.fop1.fo.ValidationException: "{ http://www.w3.org/1999/XSL/Format }table-body" is not a valid child of "fo:block"! (No context info available)

Câu hỏi của tôi:

  1. Điều gì sẽ là cách để khắc phục vấn đề này?
  2. Có thể <fo:block> đóng vai trò như một container chung với các đối tượng khác (bao gồm cả bảng) được lồng vào bên trong?
  3. Đây có phải là phương pháp tổng thể hợp lý để giải quyết tác vụ không?

Nếu ai đó đã "làm việc đó", vui lòng chia sẻ kinh nghiệm của bạn.

Trả lời

3

Cách tốt nhất để khắc phục sự cố là sử dụng trình xem/trình chỉnh sửa xác thực để kiểm tra XSL FO. Nhiều (chẳng hạn như oXygen) sẽ hiển thị cho bạn các lỗi trong cấu trúc XSL FO khi bạn mở chúng và chúng sẽ mô tả vấn đề (giống như lỗi được báo cáo).

Trong trường hợp của bạn, bạn rõ ràng có fo: table-body dưới dạng con của fo: block. No không thể. Một fo: table-body có một phụ huynh hợp lệ, fo: table. Bạn đang thiếu thẻ fo: table hoặc bạn đã chèn nhầm một khối fo vào vị trí này.

Theo tôi, tôi có thể làm những việc hơi khác. Tôi sẽ đặt nội dung XHTML vào trong XSL FO ngay tại nơi bạn muốn. Sau đó, tôi sẽ tạo một biến đổi nhận dạng sao chép tất cả nội dung dựa trên fo, nhưng chuyển đổi các phần XHTML bằng XSL. Bằng cách này, bạn thực sự có thể bước chuyển đổi đó trong trình soạn thảo XSL như oXygen và xem nơi xảy ra lỗi và chính xác lý do tại sao. Giống như bất kỳ degugger khác.

Lưu ý: Bạn cũng có thể xem các XSL khác, đặc biệt nếu HTML của bạn có thể có bất kỳ thuộc tính CSS style = "" nào.Nếu đây là trường hợp nó không phải là HTML đơn giản, thì bạn sẽ cần một phương thức tốt hơn để xử lý HTML với CSS thành FO.

http://www.cloudformatter.com/css2pdf dựa trên biến đổi hoàn chỉnh này. Biểu định kiểu chung đó có sẵn tại đây: http://xep.cloudformatter.com/doc/XSL/xeponline-fo-translate-2.xsl

Tôi là tác giả của biểu định kiểu đó. Nó có nhiều hơn bạn yêu cầu, nhưng có một đệ quy phân tích cú pháp khá phức tạp để chuyển đổi kiểu dáng CSS thành các thuộc tính FO của XSL.

+0

Chúng tôi sẽ cần hỗ trợ một cái gì đó như '' –

+0

Theo như tôi biết, bảng định kiểu mà bạn tham chiếu bỏ qua bất kỳ thuộc tính style = "" nào. Đó là lý do tại sao tôi đã chỉ cho bạn về phía cái kia sẽ xử lý toàn bộ chuỗi kiểu CSS đó và biến chúng thành các thuộc tính FO của XSL. Toàn bộ trang web này dựa trên biểu định kiểu này khi Javascript css-to-pdf giải quyết DOM của trình duyệt (tất cả là thuộc tính style = "") và chuyển đổi đầu vào HTML (X) thành XSL FO và định dạng nó. –

+0

Tôi hơi bối rối ở đây. Bạn có nói rằng XSL của bạn có thể được sử dụng riêng của nó và không phải là một phần của toàn bộ công cụ chuyển đổi đám mây của bạn? –

4
  1. Nếu bạn sử dụng trình gỡ lỗi XSLT như oXygen hoặc XML Spy, thì bạn có thể thực hiện bước chuyển đổi. Với oXygen - không chắc chắn về XML Spy hoặc các trình soạn thảo khác - nếu bạn nhấp vào đánh dấu trong đầu ra trình gỡ lỗi, oXygen sẽ đánh dấu đánh dấu từ cả nguồn và biểu định kiểu đã tạo nút đó.

    Khi bạn có FO, khung focheck (https://github.com/AntennaHouse/focheck) có xác thực hoàn chỉnh nhất của FO hiện có sẵn.

  2. fo:block có thể chứa bảng, v.v. Trong thông số XSL 1.1, định nghĩa của mỗi FO bao gồm phần phụ 'Nội dung' liệt kê nội dung được phép của nó. Xem, ví dụ: http://www.w3.org/TR/xsl11/#fo_block. Các định nghĩa của 'thực thể tham số' trong các mô hình nội dung là http://www.w3.org/TR/xsl11/#d0e6532, nhưng một số FO có các hạn chế bổ sung trong văn bản định nghĩa của chúng.
  3. Bài viết mà bạn trích dẫn dường như không có 'trích xuất tất cả các nút dưới gốc bằng bước XPath' và tôi không chắc chắn tại sao bạn cần nó. Ngoài ra, nó trông giống như một cách tiếp cận hợp lý để thực hiện công việc bằng cách sử dụng Java.

Thay vì chèn FO chuyển đổi từ JTidy-ed của bạn HTML vào FO tĩnh, bạn có thể thay thế <!-- Field A --> của bạn với những người không-FO đánh dấu cung cấp đủ thông tin để thực hiện một tham chiếu đến lĩnh vực này để chèn. Sau đó, bạn có thể tạo biểu định kiểu XSLT chuyển đổi tài liệu tham chiếu mẫu thành FO thẳng bằng cách thực hiện biến đổi nhận dạng trên các phần FO - như trong câu trả lời từ @ kevin-brown - và sử dụng thông tin trong đánh dấu tham chiếu để xây dựng URI để sử dụng với chức năng document() (http://www.w3.org/TR/xslt#document) để tìm đánh dấu để chèn.

Nếu FO cho nội dung trường đang ngồi trên đĩa, thì sử dụng document() rất đơn giản. Nếu không, thì bạn phải làm một cái gì đó như ghi đè URIResolver được sử dụng bởi bộ xử lý XSLT sao cho, thay vì nhìn vào đĩa, nó làm điều đúng để lấy nội dung. Thậm chí bạn có thể có khả năng JTidying xảy ra khi một phần của URIResolver truy xuất HTML. Bạn cũng có thể thực hiện phép chuyển đổi thành FO 'bên trong' URIResolver hoặc, cũng như @ kevin-brown được đề xuất, làm nó như một chế độ riêng biệt. Nếu phép biến đổi được thực hiện trước hoặc trong URIResolver truy xuất FO, thì việc chuyển đổi 'chính' của mẫu + tham chiếu sang FO chỉ cần trích xuất phần bên phải của tài liệu phụ FO, ví dụ: document('constructed-URI')/fo:root/fo:page-sequence/*. Tuy nhiên, nếu bạn đang sửa đổi biểu định kiểu từ Antenna House, thì bạn có thể sửa đổi nó để không tạo ra một bên ngoài fo:root, v.v.

Tôi đã làm điều gì đó tương tự như năm trước với việc ghi đè trình phân giải URI cho bộ xử lý XSLT libxslt cho máy chủ dựa trên XSLT: ngữ cảnh cho chạy liên tiếp của bộ xử lý XSLT bên trong được lưu dưới dạng tài liệu tại URI đặc biệt và không nhất thiết phải được viết vào hệ thống tập tin.

Thay vào đó, bạn có thể viết chức năng mở rộng thực hiện tra cứu các tham chiếu đến các trường.Ví dụ, nhóm cộng đồng Print and Page Layout @ W3C đã tạo ra các hàm mở rộng cho nhiều bộ xử lý XSLT chạy một bộ xử lý FO ở giữa phép chuyển đổi XSLT để lấy lại XML cho một cây khu vực cho kết quả được định dạng. Xem http://www.w3.org/community/ppl/wiki/XSLTExtensions

+0

Bài viết chuyển đổi tệp HTML thành tệp PDF hoàn toàn mới. Tôi cần phải nhúng kết quả vào tài liệu XSL-FO đã tồn tại (đã có phần tử ''. Tôi giả định rằng một 'root' khác trong' fo: block' sẽ không được chào đón. Tôi có sai ở đây không? –

+1

Không, bạn không sai: 'fo: block/fo: root' không phải là một phần của spec, bây giờ tôi thấy lý do cho thao tác XPath của bạn. –

Các vấn đề liên quan