2013-02-12 341 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內容的不錯工具。如果你喜歡它,你可以幫助改善它。