2013-02-12 293 views
0

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

该原型软件使用iText API。要阅读PDF文件,我们使用了PDFReader类。数据首先转换为字节数组,然后使用Stringbuffer,它将再次转换为字符串。然后我们使用StreamResult作为XML中转换结果的持有者。

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

方法startElement()endElement()TransformerHandler类已经在xml文件中创建了标签。解析器在每个元素的开始处调用startElement()方法,并在XML文档中的每个元素的末尾调用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(); 
     } 
} 
+0

“结果有点奇怪,所有的字符都变成符号”看起来像编码问题。在将字节数组转换为字符串时传递编码。取决于用例,可以使用StringBuilder而不是StingBuffer。 – sudmong 2013-02-12 12:58:09

+0

您也忽略了XObjects中存在的所有内容;你将如何捕获这些XML?另外:你只是阅读String对象,而没有考虑文本的实际顺序。为什么使用iText的过时版本? iText的当前版本具有更好的解析器。它甚至可以使用TaggedPdfReaderTool将标记PDF转换为XML文件:http://itextpdf.com/examples/iia.php?id=281(如果您的PDF已标记,显然只会生成XML)。 – 2013-02-12 13:47:36

回答

1

由于@sudmong说,有一个编码问题:PRTokeniser不应该被用来读取页面内容流串,它工作正常只能在外面他们,因为它假设一个特殊的字符编码,而页面内容流中字符串的编码完全取决于内容描述步骤中当前字体的编码。参看ISO 32000-1部分7.3.4.2 文字串用于内容流之外的字符串和9.6.6 字符编码用于内容流中的字符串。

正如@BrunoLowagie指出的那样,你还完全忽略了页面内容不仅仅是在直接页面内容流中,而且还在从那里引用的XObject中。 ISO 32000-1第8.10节表格XObjects。他还指出,内容流中的字符串不需要在阅读顺序中,参见参考资料。 ibidem第9.4节文本对象

您还忽略页字典的目录项的值可以是一个流或流的数组:

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

section 7.7.3。3页面对象ISO 32000-1

如果你真的想自己编写一个解析器,可要学ISO 32000-1第一。

另外看看iText的...text.pdf.parser包,它已经是解析PDF内容的不错工具。如果你喜欢它,你可以帮助改善它。