tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルXMLのデータ追加について
記事No7512
投稿日: 2008/05/13(Tue) 23:20
投稿者笹本
こんにちは。

XMLのデータ追加について質問です。

<root>
<data id=1>
  <sub>aaa</sub>
</data>
<data id=2>
  <sub>bbb</sub>
</data>
</root>

のXMLデータがあるとします。
ここに
id=2の後にデータを追加する、という方法がわからず困っています。
<data id=8>
  <sub>ccc</sub>
</data>
このデータを追加する方法はありますでしょうか?



  

[ツリー表示へ]
タイトルRe: XMLのデータ追加について
記事No7513
投稿日: 2008/05/13(Tue) 23:38
投稿者魔界の仮面弁士
> のXMLデータがあるとします。
似ていますけれども、それは XML データではありませんよね。
明らかに文法違反ですし。

> id=2の後にデータを追加する、という方法がわからず困っています。
もしも Valid XML であれば、パーサで //data[@id="2"] の“次”のノードを取得し、
/root ノードの InsertBefore メソッドで追加、とか。

[ツリー表示へ]
タイトルRe: XMLのデータ追加について
記事No7514
投稿日: 2008/05/13(Tue) 23:44
投稿者笹本
魔界の仮面弁士さん

早速ご返信ありがとうございます。

文法(一番上のノード)を省略して書いてしまいました。
すみません。

パーサとはいったい何のことでしょうか?
XMLの表示がやっと出来るようになった、まったくの初心者で申し訳ありません。

[ツリー表示へ]
タイトルRe^2: XMLのデータ追加について
記事No7515
投稿日: 2008/05/13(Tue) 23:54
投稿者魔界の仮面弁士
> 文法(一番上のノード)を省略して書いてしまいました。
一番上というのは、ルートノードとなる /root の事でしょうか?
それとも、XML 宣言などの事でしょうか?

私が言っていたのは、属性の表記法についての事です。

> パーサとはいったい何のことでしょうか?
「XML パーサ」の事です。文字通り、XML データを解析・編集などするために使われます。
VBA からの XML 操作なら、"Microsoft XML Parser" を使うのが一般的です。
.NET だと、XmlDocument とかかな。

[ツリー表示へ]
タイトルRe^3: XMLのデータ追加について
記事No7516
投稿日: 2008/05/14(Wed) 00:06
投稿者笹本
お返事ありがとうございます。

例えば、属性を指定しなければ、
下記のように追加できると思うのですが、
属性を指定した場合に、魔界の仮面弁士さんおっしゃっている
方法がつかめません・・・。

属性を指定して・・という方法は下記の方法を拡張すればできますでしょうか??


   XmlDocument xmlDoc = new XmlDocument();

    XmlDoc.Load("Test.xml");


        XmlElement xmlRoot = xmlDoc.DocumentElement;

        XmlElement xmldata = xmlDoc.CreateElement("data3");

        xmldata.InnerText = "ccc";

        xmlRoot.InsertAfter(xmldata, xmlRoot.LastChild);

        xmlDoc.Save("Test.xml");






//変更前
<?xml version="1.0" encoding="shift_jis"?>
<root>
    <data>aaa</data>
    <data2>bbb</data2>
</root>

//変更後
<?xml version="1.0" encoding="shift_jis"?>
<root>
    <data>aaa</data>
    <data2>bbb</data2>
    <data3>ccc</data3>
</root>

[ツリー表示へ]
タイトルRe^4: XMLのデータ追加について
記事No7517
投稿日: 2008/05/14(Wed) 04:50
投稿者魔界の仮面弁士
XML の場合、属性の指定は、
 <data id="1">
のような構文になります。
 <data id=1>
と書くのは、XML として文法違反です。


> 魔界の仮面弁士さんおっしゃっている方法がつかめません・・・。
System.Xml.XmlDocument であるので、LastChild で末尾ノードを得る代わりに、
SelectSingleNode メソッドを用いた「XPath 式」によるノード探索が可能です。
そして、その必要な XPath 式は、既に No.7513 に書いてあります。

# Microsoft のパーサは、この SelectSingleNode が結構便利だったりする。


> 下記のように追加できると思うのですが、
えぇと? C# なら板違いですが…。(^_^;)
VB2008 等を前提とした回答で良いのかな?


> xmlRoot.InsertAfter(xmldata, xmlRoot.LastChild);
はい。私は InsertBefore を紹介しましたが、InsertAfter でも良いと思いますよ。

XML DOM Level 3 の標準 API だと、InsertBefore はあっても、InsertAfter は
無いので、より一般的な回答として、InsertBefore を紹介しただけなので。

どちらでも同じ事を実現できますが、今回の用途で言えば、InsertAfter が使えるなら、
そちらの方がより直感的でしょうね。

[ツリー表示へ]
タイトルRe^5: XMLのデータ追加について
記事No7527
投稿日: 2008/05/14(Wed) 15:47
投稿者笹本

魔界の仮面弁士さん
お返事ありがとうございます。

>VB2008 等を前提とした回答で良いのかな?
そのとおりです。

SelectSingleNodeを使って、挿入位置を特定するとできました(^^)
ありがとうございました。

[ツリー表示へ]
タイトルRe^6: XMLのデータ追加について
記事No7528
投稿日: 2008/05/14(Wed) 18:56
投稿者魔界の仮面弁士
>> VB2008 等を前提とした回答で良いのかな?
> そのとおりです。

であれば、このようにも書けるかな。


Dim doc = _
  <root>
    <data id="1">
      <sub>aaa</sub>
    </data>
    <data id="2">
      <sub>bbb</sub>
    </data>
  </root>

Dim target = From node In doc...<data> Where node.@id = "2"

If target.Count = 0 Then
  MsgBox( "id=2 のノードはありません。" )
Else
  target(0).AddAfterSelf( <data id="8"><sub>ccc</sub></data> )
  MsgBox( doc.ToString() )
End If

[ツリー表示へ]
タイトルRe^7: XMLのデータ追加について
記事No7529
投稿日: 2008/05/14(Wed) 23:06
投稿者笹本
魔界の仮面弁士さん

毎度、お世話になっております。

そのような書き方があるんですね!
びっくりしました。
Dim docの部分は、As 〜
と型の指定は不要なんでしょうか?
.NETでは、XMLの操作クラスが充実していると聞いていますが
使いこなせず、困っています。(HELPでもなかなか理解できません・・・)

もうひとつ、こんなの出来るかな・・・というのがあるのですが、
例えば
test1.xml
<root>
<data>
  <get>
    <sub id="aaa">
      <mid>aaa</mid>
    </sub>
    <sub id="bbb">
      <mid>bbb</mid>
    </sub>
    <sub id="ccc">
      <mid>bbb</mid>
    </sub>
    <sub id="ddd">
      <mid>bbb</mid>
    </sub>
   </get>
</data>
<root>
というXmlあって
id="ccc"の
   <sub id="ccc">
      <mid>bbb</mid>
    </sub>
のデータをまるごとコピーして
指定のidの前や後ろに入れ替えることはできるのでしょうか?
また、指定範囲のXMLを別のXMLのファイルにそのままコピーして書き込む、
などもやってみたいと思うのですが・・・

[ツリー表示へ]
タイトルRe^8: XMLのデータ追加について
記事No7530
投稿日: 2008/05/15(Thu) 10:17
投稿者魔界の仮面弁士
> そのような書き方があるんですね!
> びっくりしました。
XML の埋め込みは、VB2005 以下では利用できない構文ですね。
(ただし VB2005 以下でも、System.Xml 名前空間のクラスを使って処理する事はできます)

VB2008 からは、言語レベルで XML を扱えるようになり、
 Dim c As XElement = <test>データ</test>
などと書けるようになっています。これは、"XML 要素リテラル"と呼ばれます。

また、From,Where,Order By といった構文でデータの抽出/列挙を行う、
 Dim target = From node In doc...<data> Where node.@id = "2"
などの「LINQ(リンク)」と呼ばれる物も、VB2008 の新機能です。

# 上記は、XLinq(LINQ to XML)とも呼ばれる事もあります。LINQ には他にも、
# DLinq(LINQ to SQL)、LINQ to DataSet, LINQ to Entities などがあります。

それから、「XML 軸プロパティ」という機能を使って、
 MsgBox( doc.<data>.Count )        'data 要素の数を取得する
 doc.<data>(1).@id = "TEST"        '2個目の<data id=""> の属性値を TEST に書き換える
 MsgBox( doc.<data>.<sub>.Value )  '最初の sub 要素の内容を取得する
のような書き方を行うこともできるようになっています。これも 2008 からですね。


> Dim docの部分は、As 〜
> と型の指定は不要なんでしょうか?
こちらも、VB2008 からの機能です。("ローカル型の推論"と呼ばれる機構です)

 Dim a = 123
 Dim b = "abc"
 Dim c = <test id="12">データ</test>
のように、宣言と同時に『初期値』を設定してある場合には、
その初期値の型が、変数の型としてコンパイルされ、結果的に
 Dim a As Integer = 123
 Dim b As String = "abc"
 Dim c As XElement = New XElement("test", New XAttribute("id", "12"), "データ")
などに展開される仕様になっています。


> もうひとつ、こんなの出来るかな・・・というのがあるのですが、
root 要素が閉じられていませんので、この XML は文法違反です。(^^;
最後の
>  </data>
> <root>
の部分は、正しくは
  </data>
</root>
の事ですよね?


> のデータをまるごとコピーして
> 指定のidの前や後ろに入れ替えることはできるのでしょうか?
もちろんできますよ。
挿入/追加用のメソッドだけではなく、削除や置換用のメソッドもありますので
ヘルプ等で探してみてください。

また、そうした XML DOM による操作を行う以外にも、
『XSLT』を使って整形する方法などもあります。やり方は色々と。


> また、指定範囲のXMLを別のXMLのファイルにそのままコピーして書き込む、
> などもやってみたいと思うのですが・・・
もちろん、XML ファイルの読み込み/書き込みもまた、機能として用意されています。

コンストラクタでファイル名を指定するものもあれば、Save/Load メソッドが
付いているものもあるなど、使用するクラス(XmlDocument とか、XDocument/XElement とか)
によって、必要な構文はそれぞれ異なりますけれどね。

また、巨大な XML ファイルなどのように、すべてをメモリ上に一括ロードすることが
困難な場合には、先頭から順次処理していくための XmlReader / XmlWriter クラスを
使うこともできます。

[ツリー表示へ]
タイトルRe^9: XMLのデータ追加について
記事No7531
投稿日: 2008/05/15(Thu) 11:58
投稿者笹本
魔界の仮面弁士さん

 詳しい説明をありがとうございます。

VB2008はまだ、情報が少なく、じっくり調べようと思います。
また、VB2005でも、挿入などできる、というお話ですが、
<root>
<data id="1">
<test id="1">
  <test2>aaa</test2>
</test>
<test id="2">
  <test2>bbb</test2>
</test>
</data>
<data id="2">
<test id="1">
  <test2>ccc</test2>
</test>
<test id="2">
  <test2>ddd</test2>
</test>
</data>
</root>

上記の場合に、<data id="2">〜</data>をコピーし、これを、<data id="1">〜</data>
の上に挿入し、、<data id="2">〜</data>を削除する(入れ替えをする)
場合は、VB2005ならゴリゴリ1Elementずつ挿入していくしかないでしょうか?

[ツリー表示へ]
タイトルRe^10: XMLのデータ追加について
記事No7532
投稿日: 2008/05/15(Thu) 12:35
投稿者笹本
試していてうまくいかない方法を挙げます。

<root>
<data>
  <grp id="1">
   <trt>aa<trt>
  </grp>
  <grp id="2">
   <trt>bb<trt>
  </grp>
  <crp id="1">
   <trt>aa<trt>
  </crp >
  <crp id="2">
   <trt>bb<trt>
  </crp >
</data>
</root>

このようなデータがあり

  <grp id="1">
   <trt>aa<trt>
  </grp>
このノードを

  <grp id="2">
   <trt>bb<trt>
  </grp>
の下に移動させたいのですが。
下記の方法でやるとうまくいきません。
Private xmlDoc As New System.Xml.XmlDocument
xmlDoc.Load(pu_path)

            Dim node As XmlNode = xmlDoc.SelectSingleNode("root/data/grp[@id=1]")
            Dim node2 As XmlNode = xmlDoc.SelectSingleNode("root/data/grp[@id=2]")

            node.InsertAfter(node2, node)
方法が間違っているのでしょうか?

[ツリー表示へ]
タイトルRe^11: XMLのデータ追加について
記事No7533
投稿日: 2008/05/15(Thu) 15:18
投稿者魔界の仮面弁士
> 試していてうまくいかない方法を挙げます。
またも XML の内容が文法違反です…。(^^;

毎回間違えている所を見ると、実際に使っている XML とは
別の内容を投稿されているようですね。

>    <trt>aa<trt>
</trt> の間違いですよね。


> の下に移動させたいのですが。
下というのは、「子」の意味では無く、「弟」の意味で良いでしょうか?
すなわち、処理結果が
  <grp id="2">
   <trt>bb<trt>
   <grp id="1">
     <trt>aa<trt>
    </grp>
  </grp>
となるのではなく、
  <grp id="2">
   <trt>bb<trt>
  </grp>
  <grp id="1">
   <trt>aa<trt>
  </grp>
となるようにしたい、と。


> node.InsertAfter(node2, node)
親子関係を正しく指定してください。この場合は、たとえばこうかな。

Dim xmlDoc As New XmlDocument()
xmlDoc.PreserveWhitespace = True
xmlDoc.Load("C:\sample.xml")

Dim nData As XmlNode = xmlDoc.SelectSingleNode("/root/data")
Dim nGrp1 As XmlNode = nData.SelectSingleNode("grp[@id=1]")
Dim nGrp2 As XmlNode = nData.SelectSingleNode("grp[@id=2]")
nData.InsertAfter(nGrp1, nGrp2)

MsgBox(xmlDoc.OuterXml)

[ツリー表示へ]
タイトルRe^12: XMLのデータ追加について
記事No7536
投稿日: 2008/05/16(Fri) 01:11
投稿者笹本
魔界の仮面弁士さん

 お返事ありがとうございました!!

実際試しているXMLがデータが結構いっぱいあるので
凝縮して投稿していたので・・・
文法ミスだらけですみません・・・><。

早速明日試してみます!!

[ツリー表示へ]
タイトルRe^13: XMLのデータ追加について
記事No7537
投稿日: 2008/05/16(Fri) 11:29
投稿者笹本
> 魔界の仮面弁士さん

試してみたら出来ました!!
ちょっとした考え方で全然かわってくるのですね!!
ありがとうございます。

そしてまた新たな問題が・・
すみません・・・
<root>
<data>
  <con id="1">aaa</con>
  <con id="2">bbb</con>
</data>
<data2>
  <con id="3>aaa</con>
  <con id="4>bbb</con>
</data2>
</root>

こんなデータがあり、
  <con id="1">aaa</con>
  <con id="2">bbb</con>
この部分だけ抜き出して、
<root>
<data>
</data>
<data2>
  <con id="3>aaa</con>
  <con id="4>bbb</con>
  <con id="1">aaa</con>
  <con id="2">bbb</con>
</data2>
</root>

このような結果を返したいのですが、

            Dim PrNode As XmlNode = xmlDoc.SelectSingleNode("root/data2")                  
Dim ChdNode As XmlNode = xmlDoc.SelectSingleNode("root/data/*")    



            PrNode.InsertAfter(ChdNode, PrNode.LastChild)

としても、dataノードの最初の子供しか取れてきません・・・
何がたりないのでしょう?
root/data//conとしても無理でした・・・。

[ツリー表示へ]
タイトルRe^14: XMLのデータ追加について
記事No7538
投稿日: 2008/05/16(Fri) 11:49
投稿者YuO
そりゃ,
>             Dim PrNode As XmlNode = xmlDoc.SelectSingleNode("root/data2")                  
> Dim ChdNode As XmlNode = xmlDoc.SelectSingleNode("root/data/*")    
と,Select「Single」Nodeを使っていますからね。
SelectNodes使えば,複数のノードを取得することができます。

[ツリー表示へ]
タイトルRe^15: XMLのデータ追加について
記事No7540
投稿日: 2008/05/16(Fri) 12:04
投稿者笹本
YuOさん

 ありがとうございます。

SelectNodesでもやろうとしたのですが、
これだとXmlList型なので、インサートができないのです。。。
インサートできる型がXMLNode型なので・・・

[ツリー表示へ]
タイトルRe^16: XMLのデータ追加について
記事No7541
投稿日: 2008/05/16(Fri) 12:59
投稿者魔界の仮面弁士
# 今回もまた、XML の文法が間違っているようで。(^_^;)

> そしてまた新たな問題が・・
いろいろと条件があるようですね。

変換処理の仕様次第によっては、XSLT で変換した方が良いかも知れません。
変換処理手順を *.XSL などとして、プログラムとは別に
外部ファイルとして定義できるので。

> これだとXmlList型なので、インサートができないのです。。。
> インサートできる型がXMLNode型なので・・・
その XmlList を列挙すれば、XMLNode が得られますよ。

[ツリー表示へ]
タイトルRe^16: XMLのデータ追加について
記事No7542
投稿日: 2008/05/16(Fri) 13:02
投稿者YuO
> SelectNodesでもやろうとしたのですが、
> これだとXmlList型なので、インサートができないのです。。。
> インサートできる型がXMLNode型なので・・・

XmlNodeList型は,XmlNodeのコレクションですから,問題ないと思うのですが……。
For Each node As XmlNode In xmlDoc.SelectNodes("root/data2/con")
    PrNode.AppendChild(node)
Next

[ツリー表示へ]
タイトルRe^17: XMLのデータ追加について
記事No7543
投稿日: 2008/05/16(Fri) 13:43
投稿者魔界の仮面弁士
> XmlNodeList型は,XmlNodeのコレクションですから,問題ないと思うのですが……。
そこまでは同意。でも

> For Each node As XmlNode In xmlDoc.SelectNodes("root/data2/con")
>     PrNode.AppendChild(node)
> Next
それだと、infinite loop になってしまいますよ。
(For Each では無く、For であったなら 2 回のループで済みますけれど)


root/data2/con を root/data2 に移動するのではなく、
root/data/con  を root/data2 に移動させるのが、今回の目的だったハズ。

[ツリー表示へ]
タイトルRe^17: XMLのデータ追加について
記事No7544
投稿日: 2008/05/16(Fri) 14:04
投稿者笹本
YuOさん、魔界の仮面弁士さん

 お返事ありがとうございました!
YuOさんの方法でやってみましたが・・う〜・うまくいかないです。
何か設定が足りない・・・とかなのでしょうか。
結局、カウントをとって毎回、FirstChildを見て更新する方法にしてみました。

            Dim PrNode As XmlNode = xmlDoc.SelectSingleNode("root/data2")      
            Dim ChdNode As XmlNode = xmlDoc.SelectSingleNode("root/data")    
            Dim intCnt As Integer = ChdNode.ChildNodes.Count

            For i = 1 To intCnt
                PrNode.InsertAfter(ChdNode.FirstChild, PrNode.LastChild)
            Next

同じような問題でまた悩んでいるのですが、
新規に挿入する場合、
<root>
<data id="1">aaa</data>
<data id="2">bbb</data>
<data2 id="3">ccc</data2>
<data2 id="4">ddd</data2>
<root>
この場合に,
<root>
<data id="1">aaa</data>
<data id="2">bbb</data>
<data id="100">rrr</data>
<data2 id="3">ccc</data2>
<data2 id="4">ddd</data2>
<root>

このように挿入したく、
<data id="100">rrr</data>
のElementを作成して
<data2 id="3">ccc</data2>
の直前にinsertする、というようなロジックを組みましたが、これも
うまくいきません。
<root>タグの<data>ノードの中で一番最後のもの、
<root>タグの<data2>ノードの中で一番最初のもの
などと位置が取れればいいのですが・・・

[ツリー表示へ]
タイトルRe^18: XMLのデータ追加について
記事No7545
投稿日: 2008/05/16(Fri) 15:39
投稿者魔界の仮面弁士
# そして今回も、XML 文法違反のようで……。(^^;)

> YuOさんの方法でやってみましたが・・う〜・うまくいかないです。
一文字削れば動くと思いますよ。

>> For Each node As XmlNode In xmlDoc.SelectNodes("root/data2/con")
ではなく、
   For Each node As XmlNode In xmlDoc.SelectNodes("root/data/con")
に。

> 結局、カウントをとって毎回、FirstChildを見て更新する方法にしてみました。
カウントを取るなら、
  Dim children As XmlNodeList = xmlDoc.SelectNodes("root/data/con")
  For N As Integer = 0 To children.Count - 1
      PrNode.AppendChild(children(N))
  Next
かな。


> Dim ChdNode As XmlNode = xmlDoc.SelectSingleNode("root/data")    
> Dim intCnt As Integer = ChdNode.ChildNodes.Count
この方法の場合、テキストノードも含まれる事に注意してください。
 Dim xmlDoc As New XmlDocument()
 xmlDoc.PreserveWhitespace = True  '空白の保持
 xmlDoc.Load("C:\sample.xml")
のように、PreserveWhitespace = True / False の影響を受けます。


ChdNode の内容が
<data>
  <con id="1">aaa</con>
  <con id="2">bbb</con>
</data>
の場合、data の子ノードは 5 つです。(改行、con、改行、con、改行)

ChdNode の内容が
<data><con id="1">aaa</con><con id="2">bbb</con></data>
の場合で、data の子ノードは 2 つです。(con、con)


> <data id="100">rrr</data>
> のElementを作成して
作成する所まではできましたでしょうか? CreateNode を使えば生成する事ができます。
あるいは、CreateElement や CreateAttribute などでも OK です。

>  <data2 id="3">ccc</data2>
> の直前にinsertする、というようなロジックを組みましたが、これも
> うまくいきません。
まず、その data2 ノードを取得する方法さえわかれば、
  Dim target As XmlNode = ???
 target.ParentNode.InsertBefore(newNode, target)
のように書くことができますね。

> <root>タグの<data>ノードの中で一番最後のもの、
Dim a As XmlNode = xmlDoc.SelectSingleNode("/root/data[position()=last()]")
または
Dim a As XmlNode = xmlDoc.SelectSingleNode("/root/data[last()]")

> <root>タグの<data2>ノードの中で一番最初のもの
Dim b As XmlNode = xmlDoc.SelectSingleNode("/root/data2")
または
Dim b As XmlNode = xmlDoc.SelectSingleNode("/root/data2[position()=1]")
または
Dim b As XmlNode = xmlDoc.SelectSingleNode("/root/data2[1]")

[ツリー表示へ]
タイトルRe^19: XMLのデータ追加について
記事No7550
投稿日: 2008/05/17(Sat) 06:42
投稿者YuO
> >> For Each node As XmlNode In xmlDoc.SelectNodes("root/data2/con")
> ではなく、
>    For Each node As XmlNode In xmlDoc.SelectNodes("root/data/con")
> に。

ご指摘の通り,私の書き間違いです。
お手数をおかけしてしまい,申し訳ないです。

[ツリー表示へ]