2009-04-29 64 views
1

我有一個奇怪的要求,我需要採取一些xml並重新編寫它,以便文本節點被包裝在CDATA中(這是一個客戶端不會允許正常轉義)。最好的方法來轉換xml以圍繞文本的CDATA

它似乎不像任何正常的XML庫dom4j,jdom,java xml,都有內置的支持。有任何想法嗎?我可以使用XSLT嗎?

我不是很清楚。這裏是我開始:

<foo>This has an &amp; escaped value</foo> 

我需要做的是轉換爲:

<foo><![CDATA[This has an & escaped value]]></foo> 

-Dave

+0

你是什麼意思「一個不允許正常轉義的客戶端」?這聽起來像您將XML發送給無法處理XML的程序。這是真的嗎? – 2009-04-29 17:54:50

回答

2

只要a)需要輸出的所有文本都在元素中,b)您只關心文本節點,c)您知道包含所有元素的名稱文本和d)可以將所有這些輸出元素中的任何文本發送爲CDATA。如果所有的這些情況都是真實的,那麼你可以寫一個身份轉換並將此元素添加到它:

<xsl:output method="xml" cdata-section-elements="elm1 elm2 elm3..."/> 

the W3C XSLT recommendation在這個問題上。

0

以預製XML和解析(與XML解析器)它只會讓解析器淹沒非轉義字符。我能想到的唯一解決方案就是讓你自己的標籤湯分析器解析它,修改並將其轉儲回xml。

+0

在這種情況下,開始和結束xml都是有效的,只是使用不同的方式來轉義數據。 – Dave 2013-05-17 14:11:00

1

我認爲它可以用於XSLT轉換,但我不確定轉換的性能。看看CDATA Sections and XSLT,它可能會幫助你。

+0

這可能有效,但是,我需要檢查性能。謝謝! – Dave 2009-04-29 14:13:35

3

感謝您的所有答案。我找到了一種使用dom4j來做到這一點的方法。如果元素具有「混合」子元素(即文本元素),我的實現不起作用,但在我的情況下,這不是問題。它的工作原理是,如果添加CDATA節點,dom4j將輸出CDATA:

public void replaceTextWithCdataNoMixedText(Document doc) { 
     if(doc == null) 
      return; 
     replaceTextWithCdata(doc.content()); 
    } 

    private void replaceTextWithCdata(List content) { 
     if (content == null) 
      return; 
     for (Object o : content) { 
      if (o instanceof Element) { 
       Element e = (Element) o; 
       String t = e.getTextTrim(); 
       if (textNeedsEscaping(t)) { 
        e.clearContent(); 
        e.addCDATA(t); 
       } else { 
        List childContent = e.content(); 
        replaceTextWithCdata(childContent); 
       } 
      } 
     } 
    } 


    private boolean textNeedsEscaping(String t) { 
     if (t == null) 
      return false; 
     for (int i = 0; i < t.length(); i++) { 
      char c = t.charAt(i); 
      if (c == '<' || c == '>' || c == '&') { 
       return true; 
      } 
     } 
     return false; 
    } 
+0

工作很好,我來!謝謝! – 2013-05-17 08:06:25

+0

請注意此代碼。它調用e.getTextTrim()來標準化你的字符串值。我已經格式化了文本,不斷被壓縮,並最終跟蹤到這裏。我用e.getText()替換了一個更準確的結果。 – 2014-09-26 16:21:36