3

Spring-WS で OXM を実行するために JAXB2 を使用しています。私が指定した XSD では、soap メッセージに大きな XML ファイルを添付する必要があるため、MTOM を使用してファイルを転送し、JAXB2Marshaller で MTOM を有効にしました。

JAXB2 は、期待される MIME タイプが text/xml である MTOM 添付ファイルをマーシャリングするときに、その要素を javax.xml.transform.Source オブジェクトとして配信します。いくつか検索した後、その Source オブジェクトをファイルに送信する方法を見つけることができました。

final Source source = request.getSource();
StreamSource streamSource = (StreamSource) source;
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
File file = new File ("/tempxmlfile.xml");
try{
    transformer.transform(streamSource, new StreamResult(file));
    LOG.info("File saved in "+file.getAbsolutePath());
    }
catch(Exception ex){
        ex.getMessage();
    }

私が抱えている問題は、添付ファイルとして UTF-8 でエンコードされたファイルを送信すると、次のエラーが発生することです。

[Fatal Error] :1:1: Content is not allowed in prolog.
ERROR:  'Content is not allowed in prolog.'

これは、ファイル内のエンコードされたテキストの前にあるバイト オーダー マークが原因です。この BOM は、Unicode 標準で許可されている UTF-8 でエンコードされたファイルでは必要ありませんが、Java は UTF-8 でエンコードされた BOM をサポートしていません。ストリーム。

BOM なしでファイルを送信することでこの問題を解決できますが、BOM を挿入するほとんどの Microsoft 製品で問題が発生するため、これは現実的ではありません。

Sun/Oracle が Streams でこの問題を修正することを拒否したための回避策はたくさんありますが、それらはすべて Stream にアクセスする必要があります。JAXB2 によって提供される Source Object には InputStream がなく、Reader オブジェクトのみがあります。UTF-8エンコーディングでBOMを無視する方法を知っているリーダーでSources Readerオブジェクトをラップするか、JAXB2が添付ファイルをソースに読み込む方法を変更して無視できるようにすることで、この問題を解決する方法はありますか? UTF-8 エンコーディングの BOM。

前もって感謝します、クレイグ

4

1 に答える 1

3

秘訣は、リーダーを「マーク」することです。リーダーがマーキングをサポートしていない場合は、次のことを行う BufferedReader でラップできます。

オプション #1 - BOM を確認して削除する

元のコードが BOM を間違って書いていたと思います。以下のソースコードはより理にかなっています:

import java.io.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static char[] UTF32BE = {0x00, 0x00, 0xFE, 0xFF}; 
    private static char[] UTF32LE = {0xFF, 0xFE, 0x00, 0x00};
    private static char[] UTF16BE = {0xFE, 0xFF}; 
    private static char[] UTF16LE = {0xFF, 0xFE};
    private static char[] UTF8 = {0xEF, 0xBB, 0xBF};

    public static void main(String[] args) throws Exception {
        // Create an XML document with a BOM
        FileOutputStream fos = new FileOutputStream("bom.xml");
        writeBOM(fos, UTF16LE);

        OutputStreamWriter oswUTF8 = new OutputStreamWriter(fos, "UTF-8");
        oswUTF8.write("<root/>");
        oswUTF8.close();

        // Create a Source based on a Reader to simulate source.getRequest()
        StreamSource attachment = new StreamSource(new FileReader(new File("bom.xml")));

        // Wrap reader in BufferedReader so it will support marking
        Reader reader = new BufferedReader(attachment.getReader());

        // Remove the BOM
        removeBOM(reader);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        t.transform(new StreamSource(reader), new StreamResult(System.out));
    }

    private static void writeBOM(OutputStream os, char[] bom) throws Exception {
        for(int x=0; x<bom.length; x++) {
            os.write((byte) bom[x]);
        }
    }

    private static void removeBOM(Reader reader) throws Exception {
        if(removeBOM(reader, UTF32BE)) {
            return;
        }
        if(removeBOM(reader, UTF32LE)) {
            return;
        }
        if(removeBOM(reader, UTF16BE)) {
            return;
        }
        if(removeBOM(reader, UTF16LE)) {
            return;
        }
        if(removeBOM(reader, UTF8)) {
            return;
        }
    }

    private static boolean removeBOM(Reader reader, char[] bom) throws Exception {
        int bomLength = bom.length;
        reader.mark(bomLength);
        char[] possibleBOM = new char[bomLength];
        reader.read(possibleBOM);
        for(int x=0; x<bomLength; x++) {
            if(bom[x] != possibleBOM[x]) {
                reader.reset();
                return false;
            }
        }
        return true;
    }

}

オプション #2 - '<' を見つけてリーダーをそのポイントに進める

「<」レバレッジマーク/リセットに到達するまで読んでください。

import java.io.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class Demo2 {

    private static char[] UTF32BE = {0x00, 0x00, 0xFE, 0xFF}; 
    private static char[] UTF32LE = {0xFF, 0xFE, 0x00, 0x00};
    private static char[] UTF16BE = {0xFE, 0xFF}; 
    private static char[] UTF16LE = {0xFF, 0xFE};
    private static char[] UTF8 = {0xEF, 0xBB, 0xBF};

    public static void main(String[] args) throws Exception {
        // Create an XML document with a BOM
        FileOutputStream fos = new FileOutputStream("bom.xml");
        writeBOM(fos, UTF16BE);

        OutputStreamWriter oswUTF8 = new OutputStreamWriter(fos, "UTF-8");
        oswUTF8.write("<root/>");
        oswUTF8.close();

        // Create a Source based on a Reader to simulate source.getRequest()
        StreamSource attachment = new StreamSource(new FileReader(new File("bom.xml")));

        // Wrap reader in BufferedReader so it will support marking
        Reader reader = new BufferedReader(attachment.getReader());

        // Remove the BOM
        removeBOM(reader);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        t.transform(new StreamSource(reader), new StreamResult(System.out));
    }

    private static void writeBOM(OutputStream os, char[] bom) throws Exception {
        for(int x=0; x<bom.length; x++) {
            os.write((byte) bom[x]);
        }
    }

    private static Reader removeBOM(Reader reader) throws Exception {
        reader.mark(1);
        char[] potentialStart = new char[1];
        reader.read(potentialStart);
        if('<' == potentialStart[0]) {
            reader.reset();
            return reader;
        } else {
            return removeBOM(reader);
        }
    }

}
于 2011-01-18T15:49:53.250 に答える