'#################### XMLファイルインプット用 ####################
Public Sub LoadXMLDocument()
Dim xDoc As MSXML.DOMDocument
Set xDoc = New MSXML.DOMDocument
xDoc.validateOnParse = False
If xDoc.Load("C:\Document\testXML.xml") Then '
DisplayXMLNode xDoc.childNodes, 0
Else
' エラー情報
Dim strErrText As String
Dim xPE As MSXML.IXMLDOMParseError
' ParseError オブジェクトを取得
Set xPE = xDoc.parseError
With xPE
strErrText = "次の XML ドキュメントの読み込みに失敗しました :" & _
"次のエラーが原因です :" & vbCrLf & _
"エラー # : " & .errorCode & ": " & xPE.reason & _
"行 #: " & .Line & vbCrLf & _
"行位置 : " & .linepos & vbCrLf & _
"ファイル内の位置 : " & .filepos & vbCrLf & _
"ソース テキスト : " & .srcText & vbCrLf & _
"ドキュメント URL : " & .URL
End With
MsgBox strErrText, vbExclamation
End If
Set xPE = Nothing
End Sub
Public Sub DisplayXMLNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _
Indent As Integer)
Dim xNode As MSXML.IXMLDOMNode
Indent = Indent + 2
For Each xNode In Nodes
If xNode.nodeType = NODE_TEXT Then
Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _
":" & xNode.nodeValue
ElseIf xNode.nodeType = NODE_ELEMENT Then
→→→→→→
End If
If xNode.hasChildNodes Then
DisplayXMLNode xNode.childNodes, Indent
End If
Next xNode
End Sub
矢印(→)部をどう処理していいのかよくわかりません。
(下記XML文書の場合の"currency=dollar"のdollarを取り込みたい)
<cars>
<car>
<name>乗用車</name>
<price currency=dollar>150</price>
</car>
<car>
<name>トラック</name>
<price currency=dollar>500</price>
</car>
<car>
<name>オープンカー</name>
<price currency=dollar>200</price>
</car>
</cars>
初心者のため、説明等不足が多いと思いますが
ご指導願います。
参考になるホームページや本でもよいので
教えてください。
よろしくお願いします。
開発環境を書くのを忘れていました。
「VB6」です。
よろしくお願いします。
# できれば MSXML1 ではなく、MSXML4 以降を使った方が良いかと。
> (下記XML文書の場合の"currency=dollar"のdollarを取り込みたい)
……その前に、提示されたデータは、XMLの文法になっていませんよね。
読み込み時に、構文エラーになりませんでしたか? (^_^;)
まぁ、XMLが正しいという前提であれば、値を読み書きするために
標準の『nodeValueプロパティ』を利用する事ができます。あるいは、
Microsoft独自プロパティの「textプロパティ」を使う事もできるでしょう。
Dim N As IXMLDOMNode
For Each N In xDoc.selectNodes("//*|//@*")
Debug.Print N.nodeTypeString; ","; N.nodeName; ","; N.nodeValue
Next
ただ、NODE_ELEMENT は「要素」になってしまいます。
「属性」なら、NODE_ATTRIBUTE となりますね。
もし、要素が持っている属性を取得したいのであれば、
・xNode.attributes
・xNode.getNamedItem
・xNode.selectNodes
・xNode.selectSingleNode
などを利用できます。SDKで確認してみてください。
おっと、テキストノードも取得するんでしたね。
誤) For Each N In xDoc.selectNodes("//*|//@*")
正) For Each N In xDoc.selectNodes("//*|//@*|//text()")
# コメントノードや処理命令ノードは無視して良いのかな?
元の DisplayXMLNode() にて処理するなら、たとえば、
Dim Attr As IXMLDOMAttribute
のような変数を宣言しておき、先の「→→→→→→」部に、
For Each Attr In xNode.Attributes
Debug.Print Space$(Indent) & "@" & Attr.nodeName & ":" & Attr.nodeValue
Next
などと書いても処理できるかと。
魔界の仮面弁士 様
ありがとうございます。
なんだか、感動してしまいました。
(と共に自分がいかにVBも何もわかっていないか痛感しました)
まずXMLですが、急いで書いてしまったので、
すみません。
○→<price currency='dollar'>150</price>
です。
魔界の仮面弁士さんのアドバイスに従って
下記のように直してみました。
Public Sub DisplayXMLNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _
ByVal Indent As Integer)
Dim xNode As MSXML.IXMLDOMNode
Dim Attr As IXMLDOMAttribute
Dim Role$
Indent = Indent + 2
For Each xNode In Nodes
If xNode.nodeType = NODE_ELEMENT Then
For Each Attr In xNode.Attributes
Role = Attr.nodeValue
Next
ElseIf xNode.nodeType = NODE_TEXT Then
Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _
"(" & Role & ")" & ":" & xNode.nodeValue
End If
If xNode.hasChildNodes Then
DisplayXMLNode xNode.childNodes, Indent
End If
Next xNode
End Sub
実は、<price currency='dollar'/> となっているときの事を
考えての事なのですが・・・。
どうも今ひとつ上手くいっていません。
現在はそのような状態です。
※上記のように訂正する前に
最初の質問のプログラムの「→→→→→→」部に
For Each Attr In xNode.Attributes 〜 を
挿入し、属性がprintされるのは確認しました。
追記:
> # できれば MSXML1 ではなく、MSXML4 以降を使った方が良いかと。
MSXML4を参照設定しました。
ありがとうございます。
あとはプログラム上の
Dim xDoc As MSXML.DOMDocument や
Set xDoc = New MSXML.DOMDocument の
【MSXML】部を【MSXML4】に直せばいいんですよね?
> どうも今ひとつ上手くいっていません。
えぇと。そもそも「どのように Debug.Print したいのか」という、
求めている最終結果がわからないので、コードの修正案を書けません……。
先のXML形式だとしたら、どのような結果が出力されれば良いのでしょうか?
>【MSXML】部を【MSXML4】に直せばいいんですよね?
えーと。そうではなく、 MSXML2.DOMDocument40 となります。
# MSXML4以降のバージョンをお持ちであれば、そちらを使ってもOK。
# http://www.interq.or.jp/japan/koi_san/trash/2004/msxml.htm
古いバージョンを使うべきでは無いというのは、その当時は、まだ
XSLT等の規格が定まっていない頃だったので、勧告版の実装ではなく、
ワーキングドラフト版の実装が行われている部分があるためです。
また、古いバージョンにはセキュリティ上の問題もありますし、
後継バージョンなら、XPathの解析速度が向上しているという利点もあります。
魔界の仮面弁士 様
たびたびすみません・・・。
> 先のXML形式だとしたら、どのような結果が出力されれば良いのでしょうか?
下記のXMLで下記のような出力を望んでいます。
<cars>
<car>
<name>乗用車</name>
<price currency='dollar'>150</price>
</car>
<car>
<name>トラック</name>
<price currency='dollar'/> #←←←最初の質問と変更してます
</car>
<car>
<name>オープンカー</name>
<price currency='dollar'>200</price>
</car>
</cars>
※※※※※ 希望出力結果 ※※※※※
(データのあるものだけが出力される)
-----------------------------------
name:
乗用車
price (dollar):
150
name:
トラック
name:
オープンカー
price (dollar):
200
-----------------------------------------
これにより、実際はこの後 Select Case を使って
VBプログラム中の変数にこのデータを挿入していきたいと
考えています。
また参考までにお聞きしたいのですが、
.nodeValueはStringではないのでしょうか?
::::::::::::::::::::::::::::::::::::::::::::
> えーと。そうではなく、 MSXML2.DOMDocument40 となります。
> # MSXML4以降のバージョンをお持ちであれば、そちらを使ってもOK。
> # http://www.interq.or.jp/japan/koi_san/trash/2004/msxml.htm
今、マシンにはMSXML4が入っているので、VBに参照設定をしました。
MSXML4の使い方などが載っているページがみつけられないのですが、
(MSXML.DOMDocument → MSXML2.DOMDocument4.0 となるなどの)
どこか参考になるページ等ご存知でしょうか?
本当に何もわかっていなくて大変申し訳ないです。
お手数ばかりおかけしますが、
よろしくお願い致します。
魔界の仮面弁士 様
魔界の仮面弁士さん!ありがとうございます。
やっと頭が動き始めたというか、うまくできました。
本当にありがとうございます。
下記のようにプログラムしてみました。
Public Sub DisplayXMLNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _
ByVal Indent As Integer, ByVal Role As String)
Dim xNode As MSXML.IXMLDOMNode
Dim Attr As IXMLDOMAttribute
Indent = Indent + 2
For Each xNode In Nodes
If xNode.nodeType = NODE_ELEMENT Then
For Each Attr In xNode.Attributes
Role = Attr.nodeValue
Next
ElseIf xNode.nodeType = NODE_TEXT Then
Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _
"(" & Role & ")" & ":" & xNode.nodeValue
End If
If xNode.hasChildNodes Then
DisplayXMLNode xNode.childNodes, Indent, Role
End If
Role = ""
Next xNode
End Sub
魔界の仮面弁士さんの指導をいただいたおかげです。
MSXML4の使い方についても引き続いて
ご指導いただけると幸いです。
[魔界の仮面弁士 2004/09/16(木) 01:20:08]
> 誤) For Each N In xDoc.selectNodes("//*|//@*")
> 正) For Each N In xDoc.selectNodes("//*|//@*|//text()")
> # コメントノードや処理命令ノードは無視して良いのかな?
もし、コメントノードや処理命令ノードも加えるなら、
For Each N In xDoc.selectNodes("//*|//@*|//text()|//comment()|//processing-instruction()")
という感じで。
[初心者さん 2004/09/17(金) 09:34:57]
>(データのあるものだけが出力される)
微妙な表現ですね。(^^;)
この場合の『データ』が、何を表しているのかが曖昧です。
# 「<a><b /></a>」というXMLなら、要素ノード"a"は、要素ノード"b"というデータを
# 持っているという見方もできますし…。
とりあえず、この場合の『データ』は、「テキストノード」と「属性値」の事だと
思いますが、その場合、white-space の扱いはどうされますか?
1.「<AA />」
2.「<AA></AA>」
3.「<AA> </AA>」
の場合、XML的には 1 と 2 は等価ですが、3 は別ですよね。
3の場合、空白一つのテキストノードが存在しますから。
今回の場合、空白だけでなく、改行まで含まれていますので、
ほとんどの要素ノードに「データが含まれている」と思いますよ。
[初心者 2004/09/17(金) 09:34:57]
> 下記のような出力を望んでいます。
一応、こちらでもサンプルを書いてみました。
とりあえず、white-spaceのみのテキストノードは無視させていますが、
<car>
あ
<name />
い
<price />
う
</car>
のような時には、どのような出力結果を望んでいるのかが分からなかったため、
「要素ノードとテキストノードが並んでいる場合」については考慮していません。
このようなケースにも対応させたい場合は、適宜、コードを書き変えてください。
'======================================================
'エラー処理は省略してあります。
Option Explicit
Private Sub Main()
Dim oDoc As DOMDocument
Set oDoc = CreateObject("MSXML2.DOMDocument.4.0")
oDoc.async = False
oDoc.preserveWhiteSpace = True
oDoc.Load "C:\Sample.xml"
oDoc.setProperty "SelectionLanguage", "XPath"
Dim S As String
Dim N As IXMLDOMNode
Dim W As IXMLDOMNode
For Each N In oDoc.selectNodes("//*[@*]|//*[not(*) and normalize-space(text())!=' ']|//comment()")
If N.nodeType = NODE_COMMENT Then
Debug.Print "(コメント):"
Debug.Print Tab(4); N.nodeValue
Else
S = N.nodeName
For Each W In N.Attributes
Debug.Print S; "("; W.nodeName; "):"
'属性値が空の時は、属性名だけ出力する
If W.nodeValue <> "" Then
Debug.Print Tab(4); W.nodeValue
End If
Next
If N.Text <> "" Then
'テキストノードが空の時は、要素名も出力しない
Debug.Print S; ":"
Debug.Print Tab(4); N.Text
End If
End If
Next
Set oDoc = Nothing
End Sub
========== C:\Sample.xml (UTF-8、サイズ=573バイト) ============
<cars>
<car>
<name>乗用車</name>
<price currency="dollar">150</price>
</car>
<car>
<name>トラック</name>
<price currency="dollar"/><!--テキストノードが無い場合-->
</car>
<car>
<name><![CDATA[オープンカー]]></name><!--CDATAセクションが使用されている場合-->
<price currency="dollar" currency2="US-dollar">200</price><!--属性が2つある場合-->
</car>
<car>
<name></name><!--空要素だが終了タグを持つ場合-->
<price currency="" /><!--属性値が空の場合-->
</car>
</cars>
==================================================================
> MSXML4の使い方などが載っているページがみつけられないのですが、
Microsoft の ダウンロードセンターから、MSXML4 の SDK をダウンロードしてみてください。
書き忘れ。
[初心者さん 2004/09/17(金) 09:34:57]
> また参考までにお聞きしたいのですが、
> .nodeValueはStringではないのでしょうか?
常にString型で受け取りたいなら、text や xml などを
使うこともできます。(若干、意味は変わりますけど)
nodeValue については、String の時もあれば、Null の時もあります。
このプロパティは、SDK を見ていただくと分かりますが、
ノードの種類によって出力結果が異なります。
NODE_TEXT:
テキストノードの内容をStringで返します。
NODE_ATTRIBUTE:
属性の値をStringで返します。
NODE_CDATA_SECTION:
セクションの内容をStringで返します。
NODE_COMMENT:
コメントの内容をStringで返します。
NODE_PROCESSING_INSTRUCTION:
処理命令の内容をStringで返します。
それ以外のノードタイプ:
常に Null が返されます。
魔界の仮面弁士 様
ありがとうございます。
大変参考になりました。
本当に色々とありがとうございます。
何から何まで・・。(弟子入りしたいくらいです)
魔界の仮面弁士さんのSampleプログラムを
じっくり噛みしめて、自分なりに消化して
プログラムを完成させたいと思います。
SDKも今読んでます。英語なのでゆっくりですが。(^^;)
本当にありがとうございました。
追記:
[魔界の仮面弁士 2004/09/17(金) 11:45:02]
> とりあえず、この場合の『データ』は、「テキストノード」と「属性値」の事だと
> 思いますが、その場合、white-space の扱いはどうされますか?
おっしゃるとおりです。
<name>乗用車</name>
<price currency="dollar">150</price>
私の言いたかった「データ」とは
上記XMLでの「乗用車」と「dollar」です。
-----------------------------------------------------------
XMLの解説も丁寧にしていただいて、
本当にありがとうございました。
ツイート | ![]() |