2012-05-04 6 views
1

私はISO-8859-1文字エンコーディングでXMLファイルを解析するためにJava SAXパーサを使用しようとしています。これはうまくいくが、äやöのような特殊文字は私に頭痛を与えている。つまり、ContentHandler.characters(...)メソッドは私に奇妙な文字を与え、文字配列を使って指定されたエンコーディングを持つStringを構築することさえできません。ラテン-1形式で保存するので、hexdumpに対してはこれを与えているファイル元のLatin-1 char []をSAXパーサから適切なUTF-8文字列に変換するにはどうすればよいですか?

<?xml version='1.0' encoding='ISO-8859-1' standalone='no' ?> 
<x>Motörhead</x> 

latin1.xml:ここ

は、2つのファイルに例を働い完全な最小です

$ hexdump -C latin1.xml 
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 27 31 |<?xml version='1| 
00000010 2e 30 27 20 65 6e 63 6f 64 69 6e 67 3d 27 49 53 |.0' encoding='IS| 
00000020 4f 2d 38 38 35 39 2d 31 27 20 73 74 61 6e 64 61 |O-8859-1' standa| 
00000030 6c 6f 6e 65 3d 27 6e 6f 27 20 3f 3e 0a 3c 78 3e |lone='no' ?>.<x>| 
00000040 4d 6f 74 f6 72 68 65 61 64 3c 2f 78 3e   |Mot.rhead</x>| 

"ö"は、期待通りに1バイトのf6でエンコードされています。

次に、ここではUTF-8形式で保存されたJavaファイル、だ:

MySAXHandler.java:

import java.io.File; 
import java.io.FileReader; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 
import org.xml.sax.InputSource; 
import org.xml.sax.XMLReader; 
import org.xml.sax.helpers.DefaultHandler; 

public class MySAXHandler extends DefaultHandler { 
private static final String FILE = "latin1.xml"; // Edit this to point to the correct file 

@Override 
public void characters(char[] ch, int start, int length) { 
    char[] dstCharArray = new char[length]; 
    System.arraycopy(ch, start, dstCharArray, 0, length); 
    String strValue = new String(dstCharArray); 
    System.out.println("Read: '"+strValue+"'"); 
    assert("Motörhead".equals(strValue)); 
} 

private XMLReader getXMLReader() { 
    try { 
     SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); 
     XMLReader xmlReader = saxParser.getXMLReader(); 
     xmlReader.setContentHandler(new MySAXHandler()); 
     return xmlReader; 
    } catch (Exception ex) { 
     throw new RuntimeException("Epic fail.", ex); 
    } 
} 

public void go() { 
    try { 
     XMLReader reader = getXMLReader(); 
     reader.parse(new InputSource(new FileReader(new File(FILE)))); 
    } catch (Exception ex) { 
     throw new RuntimeException("The most epic fail.", ex); 
    } 
} 

public static void main(String[] args) { 
    MySAXHandler tester = new MySAXHandler(); 
    tester.go(); 
} 
} 

は、このプログラムの実行結果は、それがRead: 'Mot�rhead'(ö置き換えを出力していることです"?in a box")、アサーションエラーのためクラッシュします。 char配列を調べると、文字öをエンコードするcharが3バイトで構成されていることがわかります。彼らはUTF-8のように2バイトでエンコードする必要があるので、私には分かりません。

は私が

を試してみましたが、私は、文字セットエンコーディングパラメータを別の文字列のコンストラクタに渡すためにその文字列のバイト数を取得し、文字列に文字列を変換しようとしています。私もCharBuffersで遊んで、この問題を解決するためにLocaleクラスで動作する可能性のあるものを見つけようとしましたが、何も試してみることはできません。文字で

+2

新しい 'FileReader()'ではなく 'new FileInputStream()'を使うとどうなりますか?または、新しいInputStreamReader(新しいFileInputStream(FILE)、 "ISO-8859-1")) '? –

+0

を参照してください。http://stackoverflow.com/questions/3482494/howto-let-the-sax-parser-determine-the-encoding-from-the-xml-declaration –

+0

注:characters()メソッドは、マルチバイト文字のバイトは、同じcharacters()イベントに一緒に表示されます。 –

答えて

4

問題は、ファイルを読むためにFileReaderを使用して、代わりにしているということです以前に提案されたコメント作成者としてのFileInputStream。 goメソッドでは、FileReaderを取り出し、FileInputStreamに置き換えます。

public void go() { 
    try { 
     XMLReader reader = getXMLReader(); 
     reader.parse(new InputSource(new FileInputStream(new File(FILE)))); 
    } catch (Exception ex) { 
     throw new RuntimeException("The most epic fail.", ex); 
    } 
} 

あなたは今それを持っている方法は、FileReaderは、あなたが欲しいものではありませんSAXパーサに渡す前に文字をデコードするために、デフォルトプラットフォームのエンコーディングを使用しています。 FileInputStreamと置き換えた場合、XMLパーサは、は、文字セットエンコーディングで処理命令を正しく読み込み、キャラクタセットのデコードを処理する必要があります。

FileReaderはデコードを行っているため、無効な文字が表示されています。SAXパーサーがそれを処理させるようにすれば、それはうまくいくはずです。

+1

まあ、これは甘いです。私は金曜日の午後、私の 'キャラクター(...)'メソッドで何が間違っているかを調べようとしていましたが、実際の犯人は一見無害なFileReaderでした! RuntimeExceptionで言うように:最も壮大な失敗。もちろん、それはあなたに壮大な勝利をもたらします。どうもありがとうございました! :) – ZeroOne

+3

FileReaderはほとんど使用されるべきではありません。少なくとも、Sun/Oracleが最終的に引数として文字セットを取るコンストラクタを提供することを決定するまで。文字を読み込むには、FileInputStreamをラップするInputStreamReaderを使用し、文字セットを指定します。そうしないと、プラットフォームのデフォルトが使用されます。 –

+0

@JBNizet私は少なくともそれの精神的な注意を払うつもりです、ありがとうございます。 :)それはFileReaderのような多くの問題を引き起こす可能性がありますように聞こえる。 – ZeroOne

0

()メソッド:新しいStringオブジェクトを構築

、まず[]、その後、コンストラクタの新しい文字列(バイト[]、ストリングたcharsetName)を呼び出すバイトに[]あなたの文字を変換します」、代わりにデフォルトの 『新しいString(文字[]』)

さらにヘルプが必要な場合は、試してみてください。http://www.exampledepot.com/egs/java.nio.charset/ConvertChar.html

0

あなたは暗い海で釣っています。多くのことが誤解を招く。 @ JBNizetが示すように、Readerはエンコーディングでテキストを読み込み、すでにバイトを読み取るInputStreamで変換を行っています。エンコーディングを指定しない場合は、プラットフォームのエンコーディングが使用されます。

reader.parse(new InputSource(new FileInputStream(new File(FILE)))); 

これは、XMLの実際のエンコーディング属性には中立です。

Javaソースコードはエディタエンコーディングと一致する必要があります。そうしないと、文字列リテラルが正しく処理されません。

System.out.printlnも誤解を招く可能性があります。

「ISO-8859-1」は、Windows Latin-1のサブセット「Windows-1252」です。特別な文字で問題が発生した場合は、「Windows-1252」(Javaでは「Cp1252」を使用できます)を提案してください。

関連する問題