2

XSLT と CSS を使用して XML レポートを PDF に変換しようとしています。この PDF には、フッターに特定のページ番号を含め、たとえば特定の表の後に改ページを含める必要があります。

私が見つけたものから、これは「ページ化されたメディア」のCSS3「at-attributes」を使用して実現できます(例:@page)。ただし、正しく理解していれば、これらの属性を解釈して PDF を作成するツールを見つけるのに問題があるかもしれません (最初に XML から変換する必要があることは言うまでもありません)。

paged.jsスクリプトを使用してブラウザーで動作させることができることがわかりましたがlive-server、すべての Web ブラウザーでローカル ファイルの制限があるため、ローカル サーバー (例: ) を実行している場合にのみ機能します。コマンドラインスイッチを使用してこれを(一種の)克服できますが、レンダリングが完了する前にドキュメントを印刷します(ブラウザがスクリプト--allow-file-access-from-filesの終了を待たないように見えます)。paged.jsさまざまなスイッチを試しました: chrome.exe --headless --disable-gpu --allow-file-access-from-files --run-all-compositor-stages-before-draw --virtual-time-budget=100000 --print-to-pdf="<destination>" "<source>". おそらく、ノード エンジンのいくつかのスイッチが役立つでしょうか?

私の質問は、XSLT を使用して XML から対象のデータを抽出し、CSS を使用して適切なページ付きドキュメントとして PDF をフォーマットし、無料の商用ライセンスを持つソフトウェアを使用して、プログラムで XML ファイルを PDF に変換する方法を教えてください。私はpaged.jsそれを達成する必要がありますか?

私のファイルについて: 私の XML ファイルでは、XML から特定のデータを抽出するローカル XSL ファイルを参照しています。重複を削除し、日付順に並べ替えます。この XSL ファイルはローカル CSS ファイルを参照して、優れた書式設定と「ページング」属性を提供します。スクリプト ドキュメントのように、 XSL リファレンスもpaged.jsスクリプトおよび関連する CSS に記載されています。

weasyprint、 、 、htmldochtml5-to-pdfとの間で試してみましたが、wkhtmltopdf成功しませんでした。

私はどんな提案にもオープンです。


編集: XSL-FO (コメントで提案されているように) を試していましたが、かなりうまく機能することを認めなければなりません。ページ コントロールは、CSS よりも読みやすいように思えます。私が今見ている唯一の問題は、追加のインストール (Apache FOP と Java ランタイム環境) が必要なことです。私のシナリオでは、.NET で FOP を使用する方がよいでしょう。

とにかく、Chrome をレンダラーとして使用した CSS ベースのソリューションについて詳しく説明することにしました。私はすでにそれでしばらく過ごしていますが、ほとんど機能しているようです。おそらく誰かがどこに問題があるかを発見し、CSS を使用したページ付きメディアの非常に優れたソリューションになるでしょう。

完全なtransform.xslファイルは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
    <html>
        <head>
            <title>Summary</title>
            <link href="css/style.css" rel="stylesheet" type="text/css"/>
            <link href="css/interface.css" rel="stylesheet" type="text/css"/>
            <script src="js/paged.polyfill.js"/>
        </head>
        <body>
            <h1>Summary</h1>
            <table class="summary">
                <tr><td>Total Quantity:</td><td><xsl:value-of select="count(Results/Result)"/></td></tr>
                <tr><td>Passed:</td><td><xsl:value-of select="count(Results/Result[Status='Pass'])"/></td></tr>
                <tr><td>Failed:</td><td><xsl:value-of select="count(Results/Result[Status='Fail'])"/></td></tr>
            </table>
            <br />
            <xsl:apply-templates/>
        </body>
    </html>
</xsl:template>

    <xsl:template match="Results">
        <table class="results">
            <tr>
                <th>Serial Number</th>
                <th>Test Result</th>
                <th>Date</th>
                <th>Time</th>
            </tr>
            <xsl:for-each select="Result">
                <tr>
                    <xsl:attribute name="class"><xsl:value-of select="./Status"/></xsl:attribute>
                    <td><xsl:value-of select="./SerialNumber"/></td>
                    <td><xsl:value-of select="./Status"/></td>
                    <td><xsl:value-of select="./Date"/></td>
                    <td><xsl:value-of select="./Time"/></td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

</xsl:stylesheet>

私のstyle.css中では@page以下のようなルールがあります。元のファイルにはもっとありますが、ここでは重要ではありません。

@page {
    size: A4;
    margin: 2cm 1cm;

    @top-left {
        content: "Summary Continued...";
        font-size: 15px;
    }

    @bottom-center{
        content: "Page " counter(page) "/" counter(pages);
        font-size: 15px;
    }
}

@page :first {
    @top-left {
        content: "";
    }
}

また、データはReports.xml(下記参照) に保存されます。Resultこの xml ファイルには、必要な数のフィールドを入れることができます。私のファイルには 200 件の結果がありますが、わかりやすくするためにここでは切り捨てました。

<?xml version="1.0" encoding="iso-8859-1" ?><?xml-stylesheet type="text/xsl" href="xsl/transform.xsl"?>

<Results>
    <Result ID="0">
        <SerialNumber>8652280431</SerialNumber>
        <Status>Fail</Status>
        <Date>05-Mar-21</Date>
        <Time>08:56:23</Time>
    </Result>
    <Result ID="1">
        <SerialNumber>11124002643</SerialNumber>
        <Status>Fail</Status>
        <Date>05-Mar-21</Date>
        <Time>08:56:23</Time>
    </Result>
.
.
.
    <Result ID="200">
        <SerialNumber>6616001379</SerialNumber>
        <Status>Fail</Status>
        <Date>05-Mar-21</Date>
        <Time>08:56:23</Time>
    </Result>
</Results>

また、ドキュメントに記載されているように、自分のファイルにもありinterface.cssます(「参考文献」を参照)。paged.polyfill.jstransform.xsl

Results.xmlコマンドを使用してChromeで開くと、chrome.exe --allow-file-access-from-files <file path>例外として機能します(下の画像を参照)。

画像

Results.xmlコマンドを使用して Chrome で印刷しようとすると、chrome.exe --headless --disable-gpu --allow-file-access-from-files --run-all-compositor-stages-before-draw --virtual-time-budget=100000 --print-to-pdf=<destination> <source>予期しない結果が生成されます。数ページのみが生成され、合計ページ数 ( counter(pages)) はフッターで 0 を返します (下の画像を参照)。

画像

だから多分誰かがそれを機能させる方法を理解するでしょう。

おそらく--js-flagsトリックを行うでしょうか?それとも、何かを追加/変更する必要がありpaged.polyfill.jsますか?

4

0 に答える 0