2009-04-29 9 views
1

私はいくつかのXMLを取り、テキストノードがCDATAでラップされるように書き直す必要がある奇妙な要件があります。通常のエスケープは許可されません)。xmlにテキストの周りにCDATAを持つ最良の方法(Javaで)

通常のXMLライブラリdom4j、jdom、java xmlのようには見えませんが、これをサポートしています。何か案は?これにXSLTを使用できますか?

私はあまり明確ではありませんでした。ここで私は始めましょうです:既成のXMLを取り、(XMLパーサーで)解析する

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

-Dave

+0

"通常のエスケープを許可しないクライアント"とは、どういう意味ですか?それは、CDATAノードを追加するとdom4jがCDATAを出力するためです。 XMLを処理できないプログラムにXMLを送信しているようです。それは本当に起こっているのでしょうか? –

答えて

2

a)出力する必要があるすべてのテキストが要素内にあり、b)テキストノードのみを気にする場合、c)含まれ​​るすべての要素の名前が分かっている場合は、XSLTを使用してこれを実行できますテキスト、そしてd)CDATAのようなすべての出力要素のテキストを出すことは大丈夫です。これらの例すべてに該当する場合は、それには、この要素を変換し、追加のアイデンティティを書くことができます:

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

このテーマにthe W3C XSLT recommendationを参照してください。

0

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

私がする必要がどのようなことにこれを変換していますエスケープされていない文字に対してパーサのチョークを作成するだけです。私が考えることができる唯一の解決策は、あなた自身のタグスープパーサを解析し、修正してxmlにダンプすることです。

+0

この場合、データをエスケープするさまざまな方法を使用するだけで、開始および終了XMLの両方が有効です。 – Dave

1

私はそれがXSLT変換で動作すると思いますが、変換のパフォーマンスに関してはわかりません。 CDATA Sections and XSLTを見て、それはあなたを助けるかもしれません。

+0

これはうまくいくかもしれませんが、ええ、パフォーマンスをチェックする必要があります。ありがとう! – Dave

3

すべてのご回答ありがとうございます。私はdom4jを使ってこれを行う方法を見つけました。要素に「子要素が混在している」(つまりテキスト要素)要素がある場合、実装は機能しませんが、私の場合は問題ありません。

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

私のためにうまく働いた!ありがとう! –

+0

このコードには注意してください。文字列の値を正規化するe.getTextTrim()を呼び出しています。私は潰され続けるテキストをフォーマットし、最終的にここまで追跡しました。私はより正確な結果を得るためにe.getText()に置き換えました。 –

関連する問題