Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2016)
XMLデータのパース
投稿日時: 21/09/13 09:37:14
投稿者: シミスケ

お世話になります。シミスケと申します。
早速ですが、質問をさせていただきます。
 
以下のプログラムを作成ました。
xmlText に格納したXML情報からItemIDタグの情報を抽出したいのですが、うまくいきません。
「For Each xmlNode In xmlList」のループに入らず、スキップしてしまうのですが、何が問題か分からない状況です。
 
参照設定では、「Microsoft XML, v6.0」を有効にしています。
皆様のお知恵を拝借できればと思います。よろしくお願い致します。
---------------------
Option Explicit
 
Sub GetItemId()
    Dim xmlText as String
    xmlText = "<GetItemResponse xmlns=""urn:ebay:apis:eBLBaseComponents"">" & _
              "<Timestamp>2021-09-13T00:19:59.217Z</Timestamp>" & _
              "<Ack>Success</Ack>" & _
              "<Version>1193</Version>" & _
              "<Build>E1193_CORE_API_19146280_R1</Build>" & _
              "<Item>" & _
                 "<AutoPay>false</AutoPay>" & _
                 "<BuyerProtection>ItemIneligible</BuyerProtection>" & _
                 "<BuyItNowPrice currencyID=""USD"">0.0</BuyItNowPrice>" & _
                 "<Country>US</Country>" & _
                 "<Currency>USD</Currency>" & _
                 "<Description>This is the first book in the Harry Potter series. In excellent condition!</Description>" & _
                 "<GiftIcon>0</GiftIcon>" & _
                 "<HitCounter>NoHitCounter</HitCounter>" & _
                 "<ItemID>110537986603</ItemID>" & _
              "</Item>" & _
           "</GetItemResponse>"
     
    Dim xmlDoc As MSXML2.DOMDocument60
    Set xmlDoc = New MSXML2.DOMDocument60
    xmlDoc.async = False
    xmlDoc.Load xmlText
     
    Dim xmlList As IXMLDOMNodeList
    Set xmlList = xmlDoc.SelectNodes("//Item")
     
    Dim xmlNode As IXMLDOMNode
    For Each xmlNode In xmlList
        Debug.Print xmlNode.SelectSingleNode("ItemID").Text
    Next

 
    Set xmlDoc = Nothing
End Sub

回答
投稿日時: 21/09/13 11:34:51
投稿者: simple

対象文字列の文字コードが関係しているんですかね。
UTF-8で保存したファイルを相手にして、下記のコードを実行すると、

ItemID        110537986603
という結果が得られます。
Sub test()
    Dim objXML As Object
    Dim aNode As Object
    Set objXML = CreateObject("MSXML2.DOMDocument")
    objXML.async = False
    If objXML.Load("test.xml") Then
        For Each aNode In objXML.SelectNodes(".//ItemID")
             Debug.Print aNode.nodeName, aNode.Text
        Next
    End If
End Sub

回答
投稿日時: 21/09/13 11:47:25
投稿者: Suzu

出力されない と言うことで、
 
ローカルウィンドにて、 xmlNode の中身は確認されましたでしょうか?
中身が入っていない 事が判るはずです。
 
と言うことは、xmlNode の取得に失敗しています。
 
次に、For Each xmlNode In xmlList の部分を怪しみます。
 
  通常は、
   For Each xmlNode In xmlList.〇〇
  として
  
  xmlList の 〇〇 の コレクションプロパティー の中身を、
  xmlNode 変数に順に入れていきます。
  
  〇〇に、コレクションをとるプロパティーを指定するのですが。。
 
  そうはなっていませんね。
 
更に、ローカルウィンドにて、 xmlList の中身を確認します。
 
見ていくと、childNodes というプロパティーがあります。
「s」がついているので、コレクションプロパティーなのでは? と推測できます。
 
この中身を確認すると。。。
 中身がありません。
 
今回は、入らないプロパティーなにかも知れないと予測。
 
更に、ローカルウィンドにて、上位となる xlmDoc を確認します。
Null とか、Nothing が多いな〜 と気づきます。
 
「もしかすると この段階で、XMLの取得に失敗しているのかも」と推測できます。
 
じゃぁ、動くコードをWEBで探そう!
 
適当に探し、MSXML2.DOMDocument60 の中身を見てみると。。あれ?入っている??
コードの違いを見てみると、
DOMDocument60 オブジェクトの Load メソッドで渡しているのは、ファイルパスです。
今回は、XML構造の文字列データ。
 
もしかして。。。
とさらにWEB検索をすると、LoadXML メソッドにて、XML構造の文字データを渡すと読み込める事が判りました。
 
 
直接の対応策は、示しませんが、コードの検証方法を並べてみました。
 
問題のある部分を探すには、まず 構造体の中身の確認
あとは、その構造体の使い方を、WEBなり、リファレンス/HELPにて確認します。
 
参考になれば。

投稿日時: 21/09/13 14:17:06
投稿者: シミスケ

Suzu様、simple様
 
ご回答ありがとうございます。
おかげ様でとりあえず、目的を遂げることができました。
 
なお、ご指摘を元にして、以下のサイトを見つけたのですが、
ここに記載されいたとおり、名前空間を指定しないと「SelectNodes」や「SelectSingleNode」は、動作しませんでした。
他のWebサイトを見たときはこういった記載は見当たらなかったのですが、これは、正規の使用方法なのでしょうか。
https://masayoshi-9a7ee.hatenablog.com/entry/20150111/1420966300
 
唯一、以下のMicrosoftページに名前空間の記載がありますが、
SelectSingleNode(String, XmlNamespaceManager)
と記載されているので、若干使用方法が違うような気がします。
https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlnode.selectsinglenode?view=net-5.0
 
もし、ご存じでしたら、ご教授いただけますと幸いです。
 
---------------------
Option Explicit
  
Sub GetItemId()
    Dim xmlText as String
    xmlText = "<GetItemResponse xmlns=""urn:ebay:apis:eBLBaseComponents"">" & _
              "<Timestamp>2021-09-13T00:19:59.217Z</Timestamp>" & _
              "<Ack>Success</Ack>" & _
              "<Version>1193</Version>" & _
              "<Build>E1193_CORE_API_19146280_R1</Build>" & _
              "<Item>" & _
                 "<AutoPay>false</AutoPay>" & _
                 "<BuyerProtection>ItemIneligible</BuyerProtection>" & _
                 "<BuyItNowPrice currencyID=""USD"">0.0</BuyItNowPrice>" & _
                 "<Country>US</Country>" & _
                 "<Currency>USD</Currency>" & _
                 "<Description>This is the first book in the Harry Potter series. In excellent condition!</Description>" & _
                 "<GiftIcon>0</GiftIcon>" & _
                 "<HitCounter>NoHitCounter</HitCounter>" & _
                 "<ItemID>110537986603</ItemID>" & _
              "</Item>" & _
           "</GetItemResponse>"
      
    Dim xmlDoc As MSXML2.DOMDocument60
    Set xmlDoc = New MSXML2.DOMDocument60
 
    xmlDoc.async = False
    xmlDoc.validateOnParse = False
    xmlDoc.resolveExternals = False
    xmlDoc.SetProperty "SelectionNamespaces", "xmlns:default='urn:ebay:apis:eBLBaseComponents'"
     
    xmlDoc.LoadXML xmlHttpReq.responseText
    Debug.Print xmlDoc.SelectSingleNode("//default:ItemID").Text
 
    Set xmlHttpReq = Nothing
    Set xmlDoc = Nothing
 
End Sub

回答
投稿日時: 21/09/14 16:30:42
投稿者: Suzu

WEB検索でも、Load の例は結構ありますが、 LoadXML の例はあまりありませんね。
LoadXML の場合(Load でも一部) SetProperty を 行っている 記事がありました。
 
 
ただ、簡単な構造のXML の場合 下記のコードで、A,B が得られますから
SetProperty が無くとも読める場合もある。
 
Sub TEST()
  Dim doc As New MSXML2.DOMDocument60
  Dim lst As MSXML2.IXMLDOMNodeList
  Dim nod As MSXML2.IXMLDOMNode
 
  doc.LoadXML ("<message>Hello!</message>")
  doc.LoadXML "<DATA><Item><ID>1</ID><Value>A</Value></Item><Item><ID>2</ID><Value>B</Value></Item></DATA>"
 
  Debug.Print doc.getElementsByTagName("DATA")(0).Text
 
  Set lst = doc.getElementsByTagName("Item")
  For Each nod In lst
    Debug.Print nod.SelectSingleNode("Value").Text
  Next
End Sub
 
となると、XMLの構造なのでしょうかね。
詳しくは判りかねます。

投稿日時: 21/09/14 18:02:42
投稿者: シミスケ

Suzu様
 
お返事ありがとうございます。
わざわざ検証までしていただき、感謝致します。
 
XMLの内容によって、SetPropertyの要否が変わるのですね。
原因は分かりませんが、重要なポイントとして、覚えておきます。
 
どうもありがとうございました。