環境はVB.NET WindowsXP Proです。
XMLファイルの中身が下のようになってるものを読もうとしています
<Items>
<SampleClass>
<Number>123</Number>
<Message>テストです。</Message>
</SampleClass>
</Items>
1段だけのときはどぼんプログラミング道場さんのサンプルで
わかりました。
http://dobon.net/vb/dotnet/file/xmlserializer.html
2段階に子ノードができてるときの読み方がわかりません。
よろしくお願いします。
XMLを読み込むためのクラスはこう宣言してだめでした。
Public Class Items
Public Class SampleClass
Public Number As Integer
Public Message As String
End Class
End Class
よろしくお願いします。
Dim doc As New XmlDocument
Dim xmlPath = Me.MapPath("Test.xml")
doc.Load(xmlPath)
Dim NodeLists As XmlNodeList
Dim Node As XmlNode
NodeLists = doc.SelectNodes("//SampleClass[text()='SAmple'])
For Each Node In NodeLists
TextBox1.Text = TextBox1.Text & Node.InnerText
Next
<Items>
<SampleClass>Sample</SampleClass>
<TESTNODE>
<Number>123</Number>
<Message>テストです。</Message>
<TESTNODE>
</SampleClass>
</Items>
ソースとXMLファイルを上記にすることでSampleClassの値Sampleが取れるのですが、中の123やテストですがとれません。
子の値をとる方法でヒントでもいいのでよろしくお願いします。
> 中の123やテストですがとれません。
XPath 式はご存じのようなので、SelectNodes 等で取得するとか。
あるいは、特定の XMLNode を取得することまではできているようなので、
そこから ChildNodes, NextSibling 等々で親子兄弟ノードを辿るとか。
SelectNodesで取得する方法を試しています。
XPathをこのように書き換えてみました。
//SampleClass[text()=Sample]../TESTNODE
または()でくくって
(//SampleClass[text()=Sample])../TESTNODE
とやってみたんですが、トークンが無効です。とエラーがでてしまいます。
XPathの指定方法が悪いのでしょうか。
よろしくお願いします
XPathの指定で//child::SampleClass[text()='Sample']/parent::*
といったようにparentで親ノードにあがっったり
//child::SampleClass[text()='Sample']/parent::*/Childとすることで
子も見れるようになりました。
ありがとうございました。
解決のチェックを忘れてました。
> ソースとXMLファイルを上記にすることで
VB コードも XML ファイルも文法違反なので、それでは動かないと思いますよ。
実験用のコードを書いたのであれば、その実際のコードをそのまま貼り付けてください。
> //SampleClass[text()=Sample]../TESTNODE
> (//SampleClass[text()=Sample])../TESTNODE
述部が、"Sampleという文字列"ではなく、"Sample要素ノード" の指定になっているのは
単なる誤記かと思われますが、それにしても、軸部やノードテストの記述が不正です。
(括弧指定は論外として…)
まず、それらのパスは、どのようなノードを取得する目的で書かれた物なのでしょうか?
コードの意図がわかれば、代替コードも示せるのですが、何しろ、元になる XML データすら
正しくありませんでしたので、具体例を示しにくいですのが、一応、
//SampleClass[text()='Sample']/../TESTNODE
//TESTNODE[../SampleClass/text()='SampleClass']
//TESTNODE[../SampleClass='SampleClass']
といった構文ならば文法違反にはなりません。そちらの意図にあっているかは不明ですが。
で。基本的には「軸::ノードテスト[述語]」をスラッシュで区切っていけば OK です。
(角括弧で囲まれる述語の部分は、すでに御存知ですよね)
このとき、「軸::」は省略形が使われる事が多く、
child:: → 「」記述しない。
descendant:: → 「//」スラッシュ2つ。
self:: → 「.」ドット。
parent:: → 「..」ドット2つ。
などと書かれるのが一般的です。ただし、軸によっては省略形が用意されていないものも
ありますので、できれば正しい記述方法を学んでおかれた方がよろしいかと。
とりあえず、(2 回目の XML は不正なので)は、最初の XML データを例として使わせてもらうと、
単に「テストです。」という文字列を得るためにも、いろいろな構文を使う事ができます。
たとえば、[文書ノード]-[Items要素ノード]-[SampleClass要素ノード]-[Message要素ノード]の
テキストノードのうち、最初に見つかった物を得ると考えれば、
S = doc.SelectSingleNode("Items/SampleClass/Message/text()").Value
S = doc.SelectSingleNode("Items/SampleClass/Message").InnerText
S = doc.SelectNodes("Items/SampleClass/Message/text()")(0).Value
S = doc.SelectNodes("Items/SampleClass/Message")(0).InnerText
といった構文を使うことができます。
あるいは子孫ノードのうち、最初のMessage要素ノードを取り出すと考えれば、
S = doc.SelectSingleNode("descendant::Message[1]/text()").Value
S = doc.SelectSingleNode("descendant::Message/text()").Value
S = doc.SelectSingleNode("descendant::Message").InnerText
S = doc.SelectSingleNode("//Message/text()").Value
S = doc.SelectSingleNode("//Message").InnerText
などとも書けます。
あるいは、Number 要素を ID のように扱い、「数値 123 に対応するメッセージを取得する」と考えるなら、
S = doc.SelectSingleNode("descendant::Number[number(self::node())=123]/parent::SampleClass/child::Message/child::text()").Value
S = doc.SelectSingleNode("descendant::Number[number(self::node())=123]/parent::SampleClass/Message/text()").Value
S = doc.SelectSingleNode("//Number[number(.)=123]/../Message/text()").Value
S = doc.SelectSingleNode("//Number[number()=123]/../Message/text()").Value
S = doc.SelectSingleNode("//Number[text()='123']/../Message/text()").Value
S = doc.SelectSingleNode("//Number[.='123']/ancestor::node()//Message/text()").Value
S = doc.SelectSingleNode("//Number[.='123']/ancestor::node()//Message").InnerText
S = doc.SelectSingleNode("//Number[number(.)=123]/../Message/text()").Value
S = doc.SelectSingleNode("descendant::Message[parent::node()/child::Number/child::text()='123']/text()").Value
S = doc.SelectSingleNode("descendant::Message[parent::node()/child::Number/text()='123']/text()").Value
S = doc.SelectSingleNode("descendant::Message[parent::node()/descendant::text()='123']/text()").Value
S = doc.SelectSingleNode("//Message[../descendant::*='123']/text()").Value
S = doc.SelectSingleNode("//Message[../Number/text()='123']/text()").Value
S = doc.SelectSingleNode("//Message[../Number/text()=123]/text()").Value
S = doc.SelectSingleNode("//Message[../Number='123']").InnerText
などとも書けます。
'XMLファイルです
<?xml version="1.0" encoding="utf-8" ?>
<RootEle>
<Ele>
<Node1>TestNode1</Node1>
<Node2>
<Child1>TestNode1_Child1</Child1>
<Child2>TestNode1_Child2</Child2>
</Node2>
</Ele>
<Ele>
<Node1>TestNode1</Node1>
<Node2>
<Child1>TestNode1_Child1</Child1>
<Child2>TestNode1_Child2</Child2>
</Node2>
</Ele>
</RootEle>
'ソースファイル
Dim StrChild1 As String
Dim StrChild2 As String
'XPath式の代入
Dim SelectNodesXPath As String
Dim doc As XmlDocument = New XmlDocument
'XmlPathにはファイルの絶対パスが入ってる
doc.Load(xmlPath)
'ノードの中に"が出てきたときの対策
SelectNodesXPath = "//child::Ele/child::Node1[text()='TestNode1']/parent::*/child::Node2/child::*"
'Node2以下をノードリストに格納
Dim NodeList As XmlNodeList = doc.SelectNodes(SelectNodesXPath)
'子ノードいるのか検索
If NodeList.Item(0).HasChildNodes Then
'この部分は要素が増える予定です。
For Each Node As XmlNode In NodeList
Select Case Node.LocalName
Case "Child1"
'要素内のテキストが入る
StrChild1 = Node.InnerText
Case "Child2"
'要素内のテキストが入る
StrChild2 = Node.InnerText
End Select
Next
Else
'子ノードが存在しない
End If
StrChild1 ,StrChild2に Node1内要素の値をいれるサンプルです。
よろしくお願いします。
一番最初のNode2の子要素Child1、Child2を入れるサンプルでした。
魔界の仮面弁士さんありがとうございます。
XPathの正式な方法を知らなかったのでとても勉強になりました。
動かない状態での載せてしまい、返信をいただくのに大変お手数おかけしました。
今度は動く状態のものをそのまま貼り付けてみました。
よろしくお願いします。
魔界の仮面弁士さんありがとうございます。
XPathの正式な方法を知らなかったのでとても勉強になりました。
動かない状態での載せてしまい、返信をいただくのに大変お手数おかけしました。
今度は動く状態のものをそのまま貼り付けてみました。
よろしくお願いします。
今度は、肝心な質問内容が抜けているような…。
サンプルを実行すると、「Dim NodeList As XmlNodeList」に、
<Child1>TestNode1_Child1</Child1>
<Child2>TestNode1_Child2</Child2>
<Child1>TestNode1_Child1</Child1>
<Child2>TestNode1_Child2</Child2>
の 4 つの要素ノードが格納されるであろうという事は分かりますが、
それについて、何を回答すれば良いでしょうか。
> よろしくお願いします。
いや、よろしくって……何を? (^^;
> 'ノードの中に"が出てきたときの対策
このコメントの意味が分からなかったのですが、どういう意味でしょうか?
> SelectNodesXPath = "//child::Ele/child::Node1[text()='TestNode1']/parent::*/child::Node2/child::*"
他の表現としては、
SelectNodesXPath = "//Ele/Node2[preceding-sibling::Node1='TestNode1']/node()"
SelectNodesXPath = "//Node2[../Node1='TestNode1']/node()"
なども使えますね。
返信がおそくなってすいません。
魔界の仮面弁士さんがいろいろ教えてくださって完成しました。
文法は変なのにたまたま動いてる可能性もあったので、ソースを見ていただけるとありがたいです。お願いします。
のつもりでした。
前後の文脈が抜けてるせいで読みにくい文章になってすいません。
また何かありましたら、質問いたしますので
これからもよろしくお願いします。
ツイート | ![]() |