■ utf-8形式のXMLファイルをDOMにLoadするには?

[Visual Basic Q & A 掲示板] [過去ログの一覧]


sumomo 2008/01/30(水) 07:54:20 <初心者>
お世話になります。
VB6.0(SP6)で、MSXML2.DOMDocument50を利用して、encoding="utf-8"形式のXMLファイルをloadしようとしています。

その際に、タグのvalueが"&#160;"のものが?で表示されてしまいます。
どのようにすれば、正常に半角空白として認識されるでしょうか。
※&#160;は半角空白

---XMLファイル(C:\text.xml)-----
<?xml version="1.0" encoding="utf-8"?>
<sample>&#160;</sample>

----VB-------
dim domdoc50 as MSXML2.DOMDocument50

set domdoc50 = new MSXML2.DOMDocument50

if domdoc50.load("C\text.xml") then
    debug.print domdoc50.xml
end if 

---実行結果----
<sample>?</sample>

いな 2008/01/30(水) 10:34:41
そのxmlファイルは本当にUTF-8の文字コードで記載されていますか?

YuO [E-Mail] 2008/01/30(水) 11:17:31
単に,debug.printでチェックしているからではないでしょうか。

6.0までの32bit版VBは,内部はUnicodeですが入出力系はShift_JIS (日本語版の場合) です。
U+00A0 NO-BREAK SPACEはShift_JISの範囲内に無い文字なので,?になっているのだと思います。

sumomo 2008/02/01(金) 06:58:10 <初心者>
回答がおそくなり申し訳ありません。
ありがとうございます。

>6.0までの32bit版VBは,内部はUnicodeですが入出力系はShift_JIS (日本語版の場合) です。
>U+00A0 NO-BREAK SPACEはShift_JISの範囲内に無い文字なので,?になっているのだと思います。
なるほど。
確かに、domdoc50.load("C\text.xml")で読み込んだXMLを
domdoc50.save("C:\test2.xml")という風にファイルに出力すると
?は表示されません。
以下のようになります。
---XMLファイル(C:\text.xml)-----
<?xml version="1.0" encoding="utf-8"?>
<sample>&#160;</sample>

---XMLファイル(C:\text2.xml)-----
<?xml version="1.0" encoding="utf-8"?>
<sample> </sample>


それでは、domdoc50.load("C\text.xml")で読み込んだXMLを、Shift_JISの文字コードで編集したあと、encording = utf-8形式で出力したいのですができないのでしょうか?

魔界の仮面弁士 2008/02/01(金) 11:11:56 <常連>
> Shift_JISの文字コードで編集したあと
それは具体的には、どういう意味でしょうか?

VB6 の String 型は、内部的には UTF-16 相当のバイナリとして格納されています。
Left / Mid / Right / Replace をはじめとする関数群も、それを前提に処理しますので、
Shift_JIS でエンコードされたデータを処理する事はできません。

StrConv を使うなどして、UTF-16 以外の(Shift_JISなどの)バイナリを、String 変数に
押し込めることは可能ですが、その場合、VB 標準の関数は使えません。

Print # ステートメントや Print メソッドは、String を「Shift_JIS」として出力し、
Line Input # ステートメントや InputBox 関数は、「Shift_JIS」でデータを得ますが、
それは、String の内部が UTF-16 である事を前提に、Unicode → ANSI 変換を行っているだけです。


> encording = utf-8形式で出力したいのですができないのでしょうか?
Save メソッドの引数に、「ファイル名を示す String」ではなく、
「UTF-8 エンコードの Stream」を渡せば OK です。

Set stm = New ADODB.Stream
stm.Type = adTypeText
stm.Charset = "UTF-8"
stm.Open
doc.save stm
stm.SaveToFile "C:\sample.xml", adSaveCreateOverWrite
stm.Close

ただしこの方法の場合、<?xml verion="1.0" encoding="***"?> の部分の
書き換えは行われませんので、この部分は出力前に編集しておく必要があります。

sumomo 2008/02/02(土) 00:28:34 <初心者>
>魔界の仮面弁士様
ご回答ありがとうございます。

>> Shift_JISの文字コードで編集したあと
>それは具体的には、どういう意味でしょうか?
⇒すいません。具体的に処理したいことは以下のことです。Shift_JISでは
 なくUnicode(utf-16)でした。。。
 @encording='utf-8'のXMLファイルをVB6.0上でMSXMLパーサ(DOM)で読み込む。
 A読み込んだXMLをVB6.0上でMSXMLパーサ(DOM)で編集して、nodeの追加、削除などを行う)する。
 B編集したXMLを、UTF-8形式のXMLファイルとして出力する。
です。

>Save メソッドの引数に、「ファイル名を示す String」ではなく、
>「UTF-8 エンコードの Stream」を渡せば OK です。

>Set stm = New ADODB.Stream
>stm.Type = adTypeText
>stm.Charset = "UTF-8"
>stm.Open
>doc.save stm
>stm.SaveToFile "C:\sample.xml", adSaveCreateOverWrite
>stm.Close
>ただしこの方法の場合、<?xml verion="1.0" encoding="***"?> の部分の
>書き換えは行われませんので、この部分は出力前に編集しておく必要があり>ます。
⇒ありがとうございます。今から試してみます。試した結果をまた記載します。

sumomo 2008/02/02(土) 09:03:00
おせわになります。

>> Shift_JISの文字コードで編集したあと
>それは具体的には、どういう意味でしょうか?
>⇒すいません。具体的に処理したいことは以下のことです。Shift_JISでは
> なくUnicode(utf-16)でした。。。
> @encording='utf-8'のXMLファイルをVB6.0上でMSXMLパーサ(DOM)で読み込む。
> A読み込んだXMLをVB6.0上でMSXMLパーサ(DOM)で編集して、nodeの追加、削除などを行う)する。
> B編集したXMLを、UTF-8形式のXMLファイルとして出力する。
です。
すいません。訂正です。

 @encording='utf-8'のXMLファイルをVB6.0上でMSXMLパーサ(DOM)で読み込む。
 A読み込んだXMLをVB6.0上でMSXMLパーサ(DOM)で編集して、nodeの追加、削除などを行う)する。
 BDomDocument.xmlでString変数に代入。
 CString変数に格納された文字列をDOMでload。
 DDOMでloadしたstring文字列を、UTF-8形式のXMLファイルとして出力する。
でした。

魔界の仮面弁士 2008/02/02(土) 12:50:23 <常連>
>(1)encording='utf-8'のXMLファイルをVB6.0上でMSXMLパーサ(DOM)で読み込む。
>(2)読み込んだXMLをVB6.0上でMSXMLパーサ(DOM)で編集して、nodeの追加、削除などを行う)する。
ここまでは良いとして。

>(3)DomDocument.xmlでString変数に代入。
>(4)String変数に格納された文字列をDOMでload。
この部分は、何のために必要なのでしょう?

>(5)DOMでloadしたstring文字列を、UTF-8形式のXMLファイルとして出力する。
文字列を UTF-8 のテキストファイルとして出力したいのであれば、
ADODB.Stream にWriteText して、それを SaveToFile すれば OK。

sumomo 2008/02/03(日) 05:53:00 <初心者>
ご回答ありがとうございます。

>(3)DomDocument.xmlでString変数に代入。
>(4)String変数に格納された文字列をDOMでload。
>この部分は、何のために必要なのでしょう?
⇒別の関数に引数として渡す際にStringにしました。
(関数で要求されているのがStringのため)

気になる点としては、UTF-8形式のXMLファイルをDOMに読み込ませたときに、
DOMが、UTF-8形式のXMLファイルをVB6.0で使用されているUnicode(UTF-16)に
自動的に変換しているのかという点です。
自動的に変換していないのであれば、DOMの各ノードに対して、nodeValueなどにstringの文字列を直接代入するのはNGで、変換が必要かと思います。

>@encording='utf-8'のXMLファイルをVB6.0上でMSXMLパーサ(DOM)で読み込む。

>(5)DOMでloadしたstring文字列を、UTF-8形式のXMLファイルとして出力する。
>文字列を UTF-8 のテキストファイルとして出力したいのであれば、
>ADODB.Stream にWriteText して、それを SaveToFile すれば OK。
⇒教えていただいた方法で試したところ上手くいきました。
 ありがとうございます。
 

魔界の仮面弁士 2008/02/03(日) 21:13:21 <常連>
> DOMが、UTF-8形式のXMLファイルをVB6.0で使用されているUnicode(UTF-16)に
> 自動的に変換しているのかという点です。

String 型に、生の UTF-8 のデータが渡される事はありません。

COM の世界においては、String 型は基本的に Unicode データとして
管理されますが、内部的には、これは UCS-2 (UTF-16) 相当のバイナリです。

つまり通常は、元ファイルの文字コードが何であるかを意識する必要は無く、
MSXML にロードされた XML データが、nodeValue プロパティ等を通じて
「String 型」で受け渡しされる際には、その内部データは、常に
UTF-16 の Unicode データとなっている、という事です。


ただしこれは、MSXML の内部データが、常に UTF-16 固定であるという意味ではありません。

MSXML の load メソッドは、ファイル名やURLを表す「文字列(String または Byte配列)」だけではなく、
他にも XML データを持った「ストリーム(IStream, ISequentialStream, IPersistStream)」を渡す事が
できるようになっています。(ASP の Request オブジェクトや、ADODB の Stream オブジェクトなど)

MSXML がストリームから読み込みを行った場合には(または、ストリームが MSXML に保存した場合には)、
ストリーム自体が UTF-8 であった場合には、Call .Save("C:\sample.xml") の結果は、元ストリームと同じく
UTF-8 形式の文字列で出力されます。(元が euc-jp なら、euc-jp のまま)

そして、出力結果の文字コードを変えたい場合は、先に示した例のように、Save メソッドの引数を
「文字列」ではなく、「ストリーム」にしてやれば OK です。


> nodeValueなどにstringの文字列を直接代入するのはNGで、変換が必要かと思います。
上記のような理由から、そうした変換は不要です。

ただし、(文字コードではなく)文字集合の点から言えば、例えば Shift_JIS ファイルの場合、
http://support.microsoft.com/kb/170559/ja
http://support.microsoft.com/kb/286776/ja
のように、Unicode との間での変換上の問題が発生する可能性があります。
(UTF-8 の場合は、UTF-16 文字集合が同じであるため、そうした問題は発生しません。

ちなみに loadXML メソッドは、UTF-16 バイナリを持った String を受け取れますが
データ中の <?xml version="1.0" encoding="〜"?> の encoding 指定を無視します。

sumomo 2008/02/10(日) 14:26:27 <初心者>
ご回答ありがとうございます。投稿が遅くなりまして申し訳ありません。

これまで、内部的な文字コードをあまり意識することが無かったため、
今回の変換の問題は非常に自分のためになっています。
魔界の仮面弁士さんの解説が非常に丁寧で理解の手助けになってます。
ありがとうございます。

このトピックの最初で起こっていた"&#160;"⇒"?"になってしまう件がどうして発生するのかという原因は今、やっと整理できた状態です。
(いまさらですが・・・)

まず、"&#160;"は、UTF-8,16には存在するが、Shift_JISには存在しない。
そのため、UTF-8から、Shift_JIS形式のファイルに出力しようとすると、
変換できず"?"として出力されてしまう。

UTF-8⇒UTF-16(VB6.0の内部文字コード)⇒Shift_JIS(ファイル出力)⇒UTF-16(VB6.0の内部文字コード)⇒UTF-8という文字コードの変換を行った際には、
Shitf_JISに変換するタイミングで?として出力されてしまうので、その後UTF-8に変換しなおしても?のままになってしまう。

上記の課題を解決するには、"&#160;"をShift_JISに変換する際に、何か違う文字(たとえば"nbsp")に置き換える必要があり、Shift_JIS⇒UNICODEに変換する際も、置き換えた文字を"&#160;"に変換しなおす必要がある。

というところまでは、整理できました。
今、その解決策を模索中です。

一応途中経過のみお伝えします。。。

毎週金曜日はポイント最大3倍!さらに4倍のチャンスも!

Programming Library