web-dev-qa-db-ja.com

JAXBマーシャラーを使用したXMLエスケープ文字(引用符など)の処理

JAXB Marshaller(JAXBバージョン2.2)を使用してXML JavaオブジェクトをXMLファイルにシリアル化する必要があります。xmlオブジェクトには、を含むタグがあります。次のような文字列値

"<"tagA>
**"<"YYYYY>done"<"/YYYYY>**
"<"/tagA>

ご覧のとおり、この文字列値には再びタグが含まれています。これをxmlファイルにも同じように記述したいと思います。

ただし、JAXBMarshallerは次のような値を変換します。

"&"lt;YYYYY"&"gt;"&"#xD;done ...&など

JAXB 2.2を使用してこれらのエスケープ文字を個別に処理することはできません。とにかく可能ですか?

この点でどんな助けも素晴らしいでしょう。

よろしくお願いします、Abhinav Mishra

8
javdev

JAXBマーシャラーに次のプロパティを設定して実行します。

marshaller.setProperty("jaxb.encoding", "Unicode");
9
javdev

より簡単な方法が1つあります。最初にカスタムエスケープシーケンスを使用します。

m.setProperty(CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() {
    @Override
    public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
        out.write( ch, start, length ); 
    }
}); 

次に、以下のような文字列にマーシャリングします

StringWriter writer = new StringWriter();
m.marshal(marshalObject, writer);

次に、下記のライターからドキュメントオブジェクトを作成します

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource( new StringReader( writer.toString() ) );
Document doc = builder.parse( is );

エスケープ文字の問題は解決されます

8
preetham

JAXBマーシャラーでは、エスケープする文字を完全に制御する必要がある場合(「\ '」など)、プロパティを追加する必要があります。

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CustomCharacterEscapeHandler());

新しいCustomCharacterEscapeHandlerクラスを作成します

import com.Sun.xml.bind.marshaller.CharacterEscapeHandler;

import Java.io.IOException;
import Java.io.Writer;

public class CustomCharacterEscapeHandler implements CharacterEscapeHandler {

    public CustomCharacterEscapeHandler() {
        super();
    }

    public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
        // avoid calling the Writerwrite method too much by assuming
        // that the escaping occurs rarely.
        // profiling revealed that this is faster than the naive code.
        int limit = start+length;
        for (int i = start; i < limit; i++) {
            char c = ch[i];
            if(c == '&' || c == '<' || c == '>' || c == '\'' || (c == '\"' && isAttVal) ) {
                if(i!=start)
                    out.write(ch,start,i-start);
                start = i+1;
                switch (ch[i]) {
                    case '&':
                        out.write("&amp;");
                        break;
                    case '<':
                        out.write("&lt;");
                        break;
                    case '>':
                        out.write("&gt;");
                        break;
                    case '\"':
                        out.write("&quot;");
                        break;
                    case '\'':
                        out.write("&apos;");
                        break;
                }
            }
        }

        if( start!=limit )
            out.write(ch,start,limit-start);
    }
}

お役に立てば幸いです。

3
Patrik Bego

CDATA構造を活用できます。標準のJAXBはこの構造をカバーしていません。 EclipseLink JAXB(MOXy) に拡張機能があります(私は技術リーダーです)。関連する質問への私の答えをチェックしてください:

MOXyの@XmlCDATAアノテーションについて説明します。

import javax.xml.bind.annotation.XmlRootElement;
import org.Eclipse.persistence.oxm.annotations.XmlCDATA;

@XmlRootElement(name="c")
public class Customer {

   private String bio;

   @XmlCDATA
   public void setBio(String bio) {
      this.bio = bio;
   }

   public String getBio() {
      return bio;
   }

}

詳細については、以下を参照してください。

2
bdoughan

正確に探しているものに応じて、次のいずれかを実行できます。

  • 文字のエスケープを無効にする
  • または、わずかな構成でJAXBにサポートを追加できるCDATA文字列を使用します
1
fred