Excel2016のVBAで、XMLを使った処理をしています。
例えば、以下のようなXMLファイル(UTF-8で保存)を用意して、
XML
1<?xml version="1.0" encoding="UTF-8"?> 2<組織> 3 <ユーザ class="cls" id="AAA" 名前="やまだ たろう"/> 4 <ユーザ class="cls" id="BBB" 名前="さとう じろう"/> 5</組織>
VBAで読み込みます。
※とりあえずモジュールで。あくまでサンプルなので細かい書き方は無視してください。
VB
1Dim dom As New MSXML2.DOMDocument 2’以下試しましたが全部同じでした 3'DOMDocument 4'DOMDocument26 5'DOMDocument30 6'DOMDocument60 7 8Sub Test() 9 dom.Load "C:\前述の\XMLファイル.xml" 10 dom.setProperty "SelectionLanguage", "XPath" 11End Sub 12
この後、読み込んだXMLの検索を実装するために以下のような関数を用意したところ、
1バイト文字は正常に動くのに2バイト文字だと検索に引っ掛かりません。
VB
1Sub Search(Text As String) 2 Dim nl As IXMLDOMNodeList 3 4 'XPathのcontains関数で、指定のキーワードを含む属性を持つノードを検索 5 Set nl = dom.SelectNodes("//*[contains(@*, '" & Text & "')]") 6 7 MsgBox nl.Length & "件見つかりました!!" 8End Sub 9 10 11Call Search("AA") ’⇒「1件見つかりました!!」 12Call Search("ろう") ’⇒「0件見つかりました!!」 ※期待値は2件見つかる 13
属性を「@*」でワイルドカード指定しているにもかかわらず、ノードの最初の属性しか見に行かないような動きになります。
どなたか解決方法ご存じの方いらっしゃいましたらご教授お願いいたします。
「それ無理なんだよねー!!」と言う情報でも構いません。その情報ソースをご教示いただけると助かります
もしかして id の方を探しに行ってないですか?
"AAA"→"やまだ たろう"
"BBB"→"さとう じろう"
に変えてみたらヒットしませんか?
タグ名も属性名もワイルドカードで指定しているので、想定では全属性見ていると思ってますが違うんですかね…
明日確認してみます。
※違うワイルドカードの指定方法もあるみたいなのでそっちも確認してみます
とりあえず、ローカルで
"AAA"→"やまだ たろう"
"BBB"→"さとう じろう"
に変えてみたところヒットするのは確認しました。
また、以下のように変えた場合は、"ろう" でヒットすることを確認しました。
変更前)"//*[contains(@*, '"
変更後)"//*[contains(@名前, '"
XPath についてあまり詳しくないですが、なんとなく「@*」だと先頭の属性しか見ていないような感じでした。
なるほど!ありがとうございます!!
属性を[contains(., 'hoge')]と指定する方法もあると聞いたので、明日調べてみます。
> 属性を[contains(., 'hoge')]
それも試してみたのですが、残念ながら、テキストノードを検索する書き方のようでした。。
残念…
ありがとうございます!
んー、XPath の仕様が良く分からなくなってきました。
こちらにあったサンプルだと、属性名のワイルドカードは「@*」でやってますね。
VBA+MSXML2 だと全角半角関係なく先頭の属性値しかヒットしないので理由が良く分からず・・(PythonとXPathの扱いが違う?)
https://ai-inter1.com/xpath/
> 4.2. 任意の属性を取得(ワイルドカード):*(アスタリスク)
> 検索対象)<a class="book" id="link1" href="xxx">Python3</a>
> XPath)//a[@*="link1"]
ホントですね、ありがとうございます。
一点、ソースに記載漏れがありました。
xmldoc.setProperty "SelectionLanguage", "XPath"
で明示的にXPath指定してます。
完全一致なら動きますね…contains関数の問題か…
dom.SelectNodes("//*[@*='" & Text & "']")
なるほど。。
contains関数だけではなく、
concatやstarts-withも@*でダメでした。
ちなみに、実際のプログラムで扱っているデータは最初の属性がidではないので、最初の属性ではなくidを見ちゃってる可能性がありますね。
やはり "id" ではなく最初の属性を見に行っているっぽいですね。
<ユーザ class="cls" id="AAA" 名前="やまだ たろう"/>
だと class の内容を見に行っているようでした。
あら、こちらの環境と動き違いますね。
謎だ…
ごめんなさい、分かりました。
確かに仰られる通り、最初の属性を見ていますね。
実際に使用しているデータでちょっと混乱してしまいました。
仕様だというご回答をいただきました。
一緒に調べていただいてありがとうございました!!
こちらこそ、色々と知見を得られて良かったです。今後の参考にしたいと思います。
回答1件
あなたの回答
tips
プレビュー