VB6.0でDOMを使用してのXML編集でエラーになってしまう

解決


ポン酢好き  2007-01-10 20:57:04  No: 97605

VB6.0でDOMを使用してXML編集をしていますが、XMLに「<!DOCTYPE cXML SYSTEM "http://xml.・・・」の宣言がない場合は、正常に処理されるのですが、宣言がある場合、「Set xmlnodNode = xmlnodNodeList(0).Attributes.・・・」でエラーとなってしまいます。
ただデバッグ実行した際は、エラーが発生しませんでした。なぜなのでしょう?
エラーを回避する方法を教えてください。

<エラー内容>
オートメーション エラーです。
この操作を完了するのに必要なデータは、まだ利用できません。 

【SAMPLE.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.007/cXML.dtd">
<cXML timestamp="">
  <登場人物>
    <名前>孫悟空</名前>
  </登場人物>
  <登場人物>
    <名前>牛魔王</名前>
  </登場人物>
</cXML>

【VisualBasic】
'XML読込
If Not xmlDocument.Load("SAMPLE.xml") Then
    MsgBox "XMLファイルの読込に失敗しました。", vbCritical
    Exit Function
End If

Set xmlelmRootElement = xmlDocument.documentElement

Set xmlnodNodeList = xmlDocument.getElementsByTagName("cXML")
Set xmlnodNode = xmlnodNodeList(0).Attributes.getNamedItem("timestamp")      '←ここでエラーになる
xmlnodNode.Text = now


魔界の仮面弁士  2007-01-10 22:57:26  No: 97606

■1■ parseError プロパティの内容をチェックしていますか?

→ parseError の errorCode プロパティや reason プロパティには、
  解決のために役立つ情報が含まれていることがありますので、
  load メソッド失敗時には、これらをチェックしておくと良いでしょう。
← 特に、非同期モードで運用している場合は、load 直後は正常でも、
  後から、このプロパティの内容がエラー状態に変化することもあります。

■2■ parsed プロパティが、False の状態になっていませんか?

→外部 DTD のロードには、ダウンロードするだけの遅延が発生します。
  初期状態では、非同期モード(async = False)ですので、そのままだと
  load 自体は成功しても、後から parseError となる可能性があります。
←XML 自体はローカルにあったとしても、async プロパティは True にして
  同期モードを利用すべきでしょう。

# もし非同期モードを利用するのなら、onreadystate プロパティで
# イベント通知を受け取る必要がありますが、VB6 からの利用は困難です。
# (非同期モードは、VBScript や JScript 向けに用意されている機能なので)

■3■ そもそも、XML 自体が不正です。

→ XMLの文法自体は正しいので、XML 文書としては正常な物となっていますが、
  DTD 側の定義とは適合しない内容となっているようです。
  すなわち、「整形式(well-formed)」の XML 文書とはなっているが、
  「妥当(valid)」な XML 文書ではない状態です。
←スキーマを用いず、形式適合検査だけで済ませるのであれば、load 前に
  resolveExternals プロパティと validateOnParse を False にしましょう。
  逆に、構造厳密検査を必要とするのであれば、それらを True にしておき、
  XML ファイルの内容自体も、DTD で定義された XML データに修正しましょう。

■4■ 使用している MSXML のバージョンは幾つですか?

→ MSXML のバージョンによっては、外部 DTD の読み込みに関して、
  若干の相違があります。内容次第では、MSXML4 では OK だったのに、
  MSXML6 で同じ処理を行うと失敗すること(あるいはその逆)もありますので、
  質問時には、MSXML のバージョンや、New (あるいは CreateObject) 部の
  コード等も省略せずに提示した方が良いかと思いますよ。

■5■ データ型を一致させましょう。

→ テストコードだからとは思いますが、「xmlnodNode.Text = now」は、
  代入先が String 型、右辺が Date 型と不一致です。型を合わせましょう。
← 今回の timestamp 属性は datetime.tz なデータを要求するでしょうから、
    xmlnodNode.text = "2007-01-10T13:51:11.012+09:00"
  のような文字列代入が必要です。もしくは、nodeTypedValue プロパティから
    xmlnodNode.dataType = "datetime.tz"
    xmlnodNode.nodeTypedValue = Now()
  などとするのも良いかと思います。


魔界の仮面弁士  2007-01-10 23:37:59  No: 97607

訂正。m(_ _)m

> # もし非同期モードを利用するのなら、onreadystate プロパティで
> # イベント通知を受け取る必要がありますが、VB6 からの利用は困難です。

onreadystate プロパティの利用は困難ですが、
onreadystate イベントであれば、下記にて利用できました。

Option Explicit

Private WithEvents xmldoc As MSXML2.DOMDocument

Private Sub xmldoc_onreadystatechange()
    If xmldoc.readyState = 4 Then
        Rem 解析完了
    End If
End Sub
---------------

http://www.microsoft.com/japan/msdn/columns/askgui/askgui05012001.aspx
# を見て、VB6 では非同期モードを利用できないと思い込んでいました…。


ポン酢好き  2007-01-11 01:15:48  No: 97608

回答ありがとうございました。
「外部DTDのロードには、ダウンロードするだけの遅延が発生する」ということを教えていただいたので以下の対応でエラーを回避するようにしました。

Do
  Set xmlelmRootElement = xmlDocument.documentElement
  DoEvents
Loop Until Not xmlelmRootElement Is Nothing


魔界の仮面弁士  2007-01-11 11:49:17  No: 97609

>> 初期状態では、非同期モード(async = False)ですので、そのままだと

逆ですね。すみません。
『初期状態では、非同期モード(async = True)』と読み替えてください。

> 以下の対応でエラーを回避するようにしました。

う〜ん、確かにそれでも回避はできるかも知れませんが……。

非同期モードで読み込み、解析完了までループで待機させるぐらいなら、
最初から、同期モードで読み込ませた方がスマートなのでは。
  xmlDocument.async = False
  If Not xmlDocument.Load("SAMPLE.xml") Then

で、もしも非同期モードによる処理を望むのだとしても、やはり本来は
DoEvents ループではなく、そこは VB らしく「イベント」で処理すべきでしょう。
(そのための方法は、先述したとおりです)

どうしても非同期からの DoEvents ループを行う必要があるのだとしても、
ループ中で documentElement が取得できるかどうかを確認する形よりは、
まずは parsed プロパティ & readyState プロパティの状態をチェックし、
それから documentElement を得る形の方が良い気がします。

以上、蛇足までに。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加