2011-11-28 20 views
3

我正在使用下面的函數將DOM Document對象轉換爲Java中的String。使用Java序列化Document對象,同時保留任意元素的格式

public static String convertDocumentToString(final Document doc) { 
    final DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation(); 
    final LSSerializer lsSerializer = domImplementation.createLSSerializer(); 
    lsSerializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); 
    final String xml = lsSerializer.writeToString(doc); 

    return xml; 
} 

這種運作良好,大部分的時間,但有是我不希望的格式(例如屏幕的DocBook元素)的某些具體內容。所以我有兩個問題:

  1. 有沒有辦法跳過某些元素,當在Java中像在上面的代碼中格式化XML?
  2. 如果沒有,是否有另一種方法來將文檔轉換爲字符串,同時保留任意元素的佈局?

請注意,我過去也使用過變壓器(請參閱Getting xml string from Document in Java),但這並不能保留CDATA部分。

更新:

只是讓我明白,我反序列化,並以創建一個可以編程方式通過DOM編輯的文檔對象序列化XML,與序列化過程最好「漂亮打印」的產生的XML(除了一些任意元素)。

更新2:

最後,我創建了一個自定義函數節點轉換爲帶有可選格式的字符串。看到https://sourceforge.net/p/commonclasses/code/110/tree/trunk/src/com/redhat/ecs/commonutils/XMLUtilities.java的convertNodeToString函數調用就像這樣:

final String exampleXml = FileUtilities.readFileContents(new File("test.xml")); 

final ArrayList<String> contentsInlineElements = new ArrayList<String>(); 
contentsInlineElements.add("title"); 
contentsInlineElements.add("term"); 

final ArrayList<String> inlineElements = new ArrayList<String>(); 
inlineElements.add("prompt"); 
inlineElements.add("command"); 
inlineElements.add("firstterm"); 
inlineElements.add("ulink"); 
inlineElements.add("guilabel"); 
inlineElements.add("filename"); 
inlineElements.add("replaceable"); 
inlineElements.add("parameter"); 
inlineElements.add("literal"); 
inlineElements.add("classname"); 
inlineElements.add("sgmltag"); 
inlineElements.add("guibutton"); 
inlineElements.add("guimenuitem"); 
inlineElements.add("guimenu"); 
inlineElements.add("menuchoice"); 
inlineElements.add("citetitle"); 

final ArrayList<String> verbatimElements = new ArrayList<String>(); 
verbatimElements.add("screen"); 
verbatimElements.add("programlisting"); 

final Document doc = XMLUtilities.convertStringToDocument(exampleXml); 
final String formattedXml = XMLUtilities.convertNodeToString(doc.getDocumentElement(), true, false, false, verbatimElements, inlineElements, contentsInlineElements, true, 1, 0); 

回答

0

系列化設計通過傳輸介質來獲取數據,但不一定(或者說經常)的方式,是真實的輸入數據的形式,如果該表單根據定義不帶任何額外信息(如XML文檔的情況)。如果您還需要繼續進行設計,則必須將此「元」信息(即格式)編碼到數據本身中,例如通過轉義空格等。也許最簡單的解決方案,將不會讓你簡單地「閱讀」傳輸流(就像用你的眼睛看到的那樣),而是將你的格式化數據編碼成像Base64這樣的東西。這將完美地在XML包裝器內部傳輸,同時保存您輸入到編碼器的原始輸入數據的保真度。

另一方面,當然,在進一步處理之前,您必須再次解碼數據。

+0

我使用的工作流程是:1.反序列化一個XML字符串以創建一個Document對象2.處理Document對象(添加和移除元素)3.將Document對象序列化回String,最好使用漂亮的打印。在這種情況下,「序列化」只是一種創建內存表示的方式,我可以通過DOM可靠地編輯XML,而不是通過傳輸介質移動數據。 – Phyxx

+0

嗯...我不知道任何XML庫(儘管我沒有看起來太難)可能會排除格式化的任意元素。我甚至不確定這是否可以實施並滿足所有需求。我想你可能要考慮XML中的Base64(或任何其他)編碼。至少是一個可靠的實現,而不必擔心未來可能會破壞XML依賴關係的更新。 –

-4

在CDATA部分以外的XML文檔中,空白不重要,並且沒有任何標準工具可以保留它。任何相反的要求都是不合格的。

+0

@downvoter請解釋。如果在這裏出現錯誤,社區應該知道它是什麼,就像我一樣。 – EJP

+1

我沒有downvote,但是在XML文檔中空格是非常重要的。唯一沒有意義的時候(「可忽略的空白」)是當你有一個DTD專門將結構定義爲「元素內容」的時候。請參閱http://www.xml.com/axml/target.html#sec-element-content和http://www.xml.com/axml/target.html#sec-white-space(特別是第一個註釋) – kdgregory

+0

好的,現在我低估了。答案是不正確和誤導性的,你有機會編輯/刪除。 – kdgregory

0

簡短的回答:你不能。當你告訴序列化程序打印出漂亮的時候,你正在聲明使用元素間空白(即它是可忽略的)。

較長的答案:你不能沒有修改DOM(或它的副本)。 IMO最簡單的方法如下:

  1. 確定要保留的節點。我假設你有一個ID或其他方式來選擇它使用XPath。
  2. 調用Document.adoptNode()將該節點移動到新的DOM中。我記得這個方法有一些問題,但那是很多年前的事情。如果不起作用,請使用Document.importNode(),並明確從源文檔中刪除該節點。我相信你可以採用一個節點作爲文件的根,但不能保證。
  3. 將文本節點插入包含唯一內容的原始文檔。生成獨特內容的簡單方法是UUID.randomUUID().toString()
  4. 將兩個文檔轉換爲字符串,打印出漂亮的文檔,而不打印另一個文檔。
  5. 使用String.replace()將不漂亮的打印文檔插入到漂亮打印的文檔中。

,與以往一樣,如果你打算寫這些字符串文件或其他面向字節的格式,你必須明確編碼爲UTF-8。

相關問題