如何将XML输出保存为PDF

时间:2018-04-12 11:29:42

标签: java xml pdf jaxb itext

我正在使用JAXB来解组XML。然后我想拿一些信息并使用iText将其写成PDF格式。由于某种原因,PDF已创建,但我无法打开该文件。我也在使用ZFile,因为它也适用于大型机,但这不应该是一个问题。

写PDF文件时可能我做错了。这是我的代码:

package music;

import java.io.*;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import com.ibm.jzos.ZFile;

import java.io.FileOutputStream;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import music.Music.Artist;
import music.Music.Artist.Album;
import music.Music.Artist.Album.Description;
import music.Music.Artist.Album.Song;

public class MusicXml {

    public static void main(String[] args) throws JAXBException, IOException {

        ZFile inputZ = null, outputZ = null;

        File inputW = null;
        PdfWriter outputW = null;

        PdfContentByte cb = null;
        Document pdf = new Document(PageSize.A4);
        Paragraph paragraf = new Paragraph();

        // Font
        Font fnt12n;

        JAXBContext jaxb = null;
        Unmarshaller unmarsh = null;

        String line = null, sep = " ";
        Music music;

        Date date = new Date();
        Date startDate = new Timestamp(date.getTime());
        System.out.println("Start: " + startDate);

        jaxb = JAXBContext.newInstance(ObjectFactory.class);
        unmarsh = jaxb.createUnmarshaller();

        String os = System.getProperty("os.name");
        System.out.println("System: " + os);
        boolean isWin = os.toLowerCase().contains("wind");

        if (!isWin) {
            // z/OS:
            inputZ = new ZFile(args[0], "rt"); // "rt" - readtext
            InputStream inpStream = inputZ.getInputStream();
            InputStreamReader streamRdr = new InputStreamReader(inpStream, "CP870");
            try {
                outputW = PdfWriter.getInstance(pdf, (new ZFile(args[1], "wb")).getOutputStream());
            } catch (DocumentException e) {
                e.printStackTrace();
            }

            music = (Music) unmarsh.unmarshal(streamRdr);

        } else {
            // Windows:
            inputW = new File(args[0]);
            music = (Music) unmarsh.unmarshal(inputW);
            try {
                outputW = PdfWriter.getInstance(pdf, new FileOutputStream(args[1]));
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        }

        List<Artist> listaArtystow = music.getArtist();
        for (Artist artysta : listaArtystow) {
            List<Album> listaAlbumow = artysta.getAlbum();
            for (Album album : listaAlbumow) {
                Description opis = album.getDescription();
                List<Song> listaPiosenek = album.getSong();
                for (Song piosenka : listaPiosenek) {
                    String artistName = artysta.getName();
                    String albumName = album.getTitle();
                    int numberOfSongs = listaPiosenek.size();
                    String albumDescription = album.getDescription().getValue();
                    String songTitle = piosenka.getTitle();
                    String songDuration = piosenka.getLength();

                    line = songTitle + sep + songDuration;

                    FontFactory.register(args[2], "jakiesFonty");
                    Font font = FontFactory.getFont("jakiesFonty", BaseFont.CP1250, BaseFont.EMBEDDED);
                    BaseFont bf = font.getBaseFont();
                    fnt12n = new Font(bf, 12f, Font.NORMAL, BaseColor.BLACK);

                    // PDF
                    outputW.setPdfVersion(PdfWriter.VERSION_1_7);

                    pdf.addTitle("Musical collection");
                    pdf.addAuthor("Natalia Nazaruk");
                    pdf.addSubject("Cwiczenie tworzenia PDF z XML");
                    pdf.addKeywords("Metadata, Java, iText, PDF");
                    pdf.addCreator("Program: MusicXML");
                    pdf.setMargins(60, 60, 50, 40);

                    pdf.open();
                    pdf.newPage();
                    try {


                        paragraf.setAlignment(Element.ALIGN_JUSTIFIED);

                        paragraf.setSpacingAfter(16f);

                        paragraf.setLeading(14f);

                        paragraf.setFirstLineIndent(30f);

                        paragraf.setFont(fnt12n);

                        pdf.add(new Paragraph(line, fnt12n));


                    } catch (DocumentException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        date = new Date();
        Date stopDate = new Timestamp(date.getTime());
        System.out.println("Stop:  " + stopDate);
        long diffInMs = stopDate.getTime() - startDate.getTime();
        float diffInSec = diffInMs / 1000.00f;
        System.out.format("Czas przetwarzenia pliku XML: %.2f s.", diffInSec);
        System.exit(0);

        if (isWin) {
            outputW.close();
        } else
            outputZ.close();
    }
}

1 个答案:

答案 0 :(得分:2)

除了您选择使用旧版iText之外,您的代码还有其他一些问题。你读过哪些文件?我不认为您已经发现了官方的iText网站,否则您将使用iText 7而不是iText 5,如果您从未关闭Document对象,您就会知道没有创建有效文档

简短的回答是你忘记了:

pdf.close();

我看到你关闭了输出流:

if (isWin) {
        outputW.close();
    } else
        outputZ.close();
}

这没有多大意义,因为此时PDF还没有最终确定(例如:没有创建交叉引用表)。当您关闭文档时,隐式关闭基础输出流(除非您明确告知iText不这样做)。

您正在创建的循环也有些尴尬:

List<Artist> listaArtystow = music.getArtist();
for (Artist artysta : listaArtystow) {
    ...
    for (Album album : listaAlbumow) {
        ...
        for (Song piosenka : listaPiosenek) {
            ...
            FontFactory.register(args[2], "jakiesFonty");
            Font font = FontFactory.getFont("jakiesFonty", BaseFont.CP1250, BaseFont.EMBEDDED);
            BaseFont bf = font.getBaseFont();
            fnt12n = new Font(bf, 12f, Font.NORMAL, BaseColor.BLACK);
            // PDF
            outputW.setPdfVersion(PdfWriter.VERSION_1_7);
            pdf.addTitle("Musical collection");
            pdf.addAuthor("Natalia Nazaruk");
            pdf.addSubject("Cwiczenie tworzenia PDF z XML");
            pdf.addKeywords("Metadata, Java, iText, PDF");
            pdf.addCreator("Program: MusicXML");
            pdf.setMargins(60, 60, 50, 40);
            pdf.open();
            pdf.newPage();
            ...
        }
    }
}
output.close();

您反复创建相同的字体。一个PDF只能有1个版本(在您的情况下为PDF-1.7)和1组元数据,但您一遍又一遍地定义该版本和元数据。最后,您多次打开文档,而只需打开一次。

这更有意义:

FontFactory.register(args[2], "jakiesFonty");
Font font = FontFactory.getFont("jakiesFonty", BaseFont.CP1250, BaseFont.EMBEDDED);
BaseFont bf = font.getBaseFont();
fnt12n = new Font(bf, 12f, Font.NORMAL, BaseColor.BLACK);
// PDF
outputW.setPdfVersion(PdfWriter.VERSION_1_7);
pdf.addTitle("Musical collection");
pdf.addAuthor("Natalia Nazaruk");
pdf.addSubject("Cwiczenie tworzenia PDF z XML");
pdf.addKeywords("Metadata, Java, iText, PDF");
pdf.addCreator("Program: MusicXML");
pdf.setMargins(60, 60, 50, 40);
pdf.open();
List<Artist> listaArtystow = music.getArtist();
for (Artist artysta : listaArtystow) {
    ...
    for (Album album : listaAlbumow) {
        ...
        for (Song piosenka : listaPiosenek) {
            ...
            pdf.newPage();
            ...
        }
    }
}
pdf.close();

正如您所看到的那样,在循环之前open() Document实例pdf ,编写PDF标题,close()循环之后Document 写一些对象(例如字体),交叉引用表和PDF预告片。由于您的代码中没有pdf.close(),因此PDF中缺少所有必要的信息。

由于您是iText的新手,我强烈建议您使用早于iText 7的版本。您可能已经发现最新的iText 5版本是iText 5.5.13,但这是一个维护发布。在维护版本中,我们仅为付费客户提供错误修复;我们不添加新功能。例如:新的PDF规范ISO 32000-2(又名PDF 2.0)仅适用于iText 7.1。我们不支持旧版本的PDF 2.0。

如果您访问官方网站,您会注意到iText 7.1.1是最新版本(iText 7 download page)。你在哪里找到iText,你怎么选择旧版本? (这不是一个修辞问题:我们想知道如何改进我们的网站。我们也想知道为什么这么多人在Stack Overflow上发布这么糟糕的代码;就好像他们不能找到教程。这很难过,因为我们在这些教程中投入了大量的时间和金钱。(但如果没有人阅读它们,那有什么意义呢?)

您可以在Jump-Start tutorialBuilding Blocks tutorial找到有关iText 7的更多信息。

至于将XML转换为PDF,为什么不首先转换为HTML,然后使用pdfHTML add-on?有关如何在chapter 4 HTML to PDF tutorial以及ZUGFeRD tutorial中执行此操作的示例。