0

我正在尝试创建一个原型以将 PDF 文件转换为 XML 文件。结果有点奇怪,所有的字符都变成了符号。我认为错误是StringBuffer从字节数组中获取数据的地方。有Java知识的人可以帮忙吗?

该原型软件正在使用iTextAPI。为了阅读 PDF 文件,我们使用了PDFReader该类。数据先转换成字节数组,然后再用 ,Stringbuffer再转换成字符串。然后我们使用StreamResultwich 作为 XML 中转换结果的持有者。

之后,Transformer该类处理来自各种源的 XML,并将转换输出写入各种接收器。然后TransformerHandler侦听 SAX ContentHandler,解析事件并将它们转换为结果。

方法startElement()endElement()TransformerHandler在 xml 文件中创建了标签。Parser在 XML 文档中每个元素startElement()的开头和每个元素的结尾调用方法。endElement()

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class Cp2x {

        static StreamResult streamResult;
        static TransformerHandler handler;
        static AttributesImpl atts;

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

                try {
                        Document document = new Document();
                        document.open();
                        PdfReader reader = new PdfReader("C:\\helloworld.pdf");
                        PdfDictionary page = reader.getPageN(1);
                        PRIndirectReference objectReference = (PRIndirectReference) page
                                        .get(PdfName.CONTENTS);
                        PRStream stream = (PRStream) PdfReader
                                        .getPdfObject(objectReference);
                        byte[] streamBytes = PdfReader.getStreamBytes(stream);
                        PRTokeniser tokeniser = new PRTokeniser(streamBytes);

                        StringBuffer string_buffer = new StringBuffer();
                        while (tokeniser.nextToken()) {
                                if (tokeniser.getTokenType() == PRTokeniser.TK_STRING) {
                                        string_buffer.append(tokeniser.getStringValue());
                                }
                        }
                        String test = string_buffer.toString();
                        streamResult = new StreamResult("test.xml");
                        initXML();
                        process(test);
                        closeXML();
                        document.add(new Paragraph(".."));
                        document.close();
                } catch (Exception e) {
                }
        }

        public static void initXML() throws ParserConfigurationException,
                        TransformerConfigurationException, SAXException {
                SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory
                                .newInstance();

                handler = tf.newTransformerHandler();
                Transformer serializer = handler.getTransformer();
                serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                serializer.setOutputProperty(
                                "{http://xml.apache.org/xslt}indent-amount", "4");
                serializer.setOutputProperty(OutputKeys.INDENT, "yes");
                handler.setResult(streamResult);
                handler.startDocument();
                atts = new AttributesImpl();
                handler.startElement("", "", "Document", atts);
        }

        public static void process(String s) throws SAXException {
                String[] elements = s.split("\\|");
                atts.clear();
                handler.startElement("", "", "Note", atts);
                handler.characters(elements[0].toCharArray(), 0, elements[0].length());
                handler.endElement("", "", "Note");
        }

        public static void closeXML() throws SAXException {
                handler.endElement("", "", "Document");
                handler.endDocument();
        }
}
4

1 回答 1

1

正如@sudmong 所说,存在编码问题:PRTokeniser不应该用于从页面内容流内部读取字符串,它只能在外部内容流中正常工作,因为它假定特殊字符编码,而页面内容流中字符串的编码完全取决于在内容描述的该步骤中当前字体的编码。参照。ISO 32000-1第 7.3.4.2 节内容流外部字符串的文字字符串和内容流内部字符串的 9.6.6字符编码

正如@BrunoLowagie 指出的那样,您还完全忽略了页面内容不仅在直接页面内容流中,而且在从那里引用的 XObjects 中,参见。ISO 32000-1第 8.10 节表单 XObjects。他还指出,内容流中的字符串不必按阅读顺序排列,参见。同上第 9.4 节文本对象

您还忽略了页面字典的 Contents 条目的值可以是流或流数组:

该值应为单个流或流数组。如果该值是一个数组,则效果应该就像数组中的所有流都按顺序连接起来形成一个流一样。符合标准的编写者可以在图像对象和其他资源出现时创建它们,即使它们会中断内容流。流之间的划分可能只发生在词汇标记之间的边界(参见 7.2,“词汇约定”),但与页面的逻辑内容或组织无关。使用或生成 PDF 文件的应用程序不需要保留 Contents 数组的现有结构。符合标准的编写者不应创建不包含任何元素的 Contents 数组。

ISO 32000-1中的第 7.7.3.3 节页面对象

如果您真的想自己编写解析器,最好先学习ISO 32000-1

否则请查看...text.pdf.parseriText 的包,它已经是解析 PDF 内容的好工具。如果你喜欢它,你可以帮助改进它。

于 2013-02-12T15:31:09.587 回答