質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

VSTO

Visual Studio Tools for Office

Q&A

解決済

1回答

2918閲覧

VSTO,C#を用いてxmlファイルのタグの属性を動的に変更したい

退会済みユーザー

退会済みユーザー

総合スコア0

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

VSTO

Visual Studio Tools for Office

0グッド

0クリップ

投稿2021/08/04 13:19

前提・実現したいこと

C#側の処理を用いてxmlファイルのタグの属性を動的に変更したいです。

発生している問題・エラーメッセージ

xmlファイルの読み込みまではうまくいくが、書き込みの際に例外エラーが発生し、
xmlファイルへの書き込みが反映されない状態となっています。

現在はlabel属性の動的な追加(書き換え)を目標にしているがOnActionというイベントも動的に追加したいと考えています。

書き込みの部分をどう記述すればいいかわからないので有識者の方がいましたら教えていただきたいです。
下記のソースコードと全く違う書き方になってしまうのであればソースも教えていただきたいです。

System.InvalidOperationException: 'シーケンスに要素が含まれていません'

該当のソースコード

C#

1 public void Ribbon_Load(Office.IRibbonUI ribbonUI) 2 { 3 this.ribbon = ribbonUI; 4 //xml読み込み 5 XElement xml = XElement.Load(@"C:\Users\信一郎\source\repos\ExcelAddIn2\ExcelAddIn2\Ribbon1.xml"); 6 7 //xmlファイルが正常に読み取れているかstring型にしてメッセージ表示 8 string hoge = xml.ToString(); 9 System.Windows.Forms.MessageBox.Show(hoge); 10 11 //例外エラーの発生元 12 XElement info = (from item in xml.Elements("button") 13 where item.Attributes("label").ToString() == "test" 14 select item).Single(); 15      //ここまで 16 17 //label属性の書き換え 18 info.Attribute("label").Value = "aaaaa"; 19 //保存 20 xml.Save(@"C:\Users\信一郎\source\repos\ExcelAddIn2\ExcelAddIn2\Ribbon1.xml"); 21 22 23 24 } 25 public void click_Event(Office.IRibbonControl control) 26 { 27 System.Windows.Forms.MessageBox.Show("ボタンが押されました"); 28 }

xml

1<?xml version="1.0" encoding="UTF-8"?> 2<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load"> 3 <ribbon> 4 <tabs> 5 <tab idMso="TabAddIns"> 6 <group id="MyGroup" 7 label="My Group"> 8 <button id="btniId" label="test" onAction="click_Event"></button> 9 </group> 10 </tab> 11 </tabs> 12 </ribbon> 13</customUI> 14

試したこと

XElement info = (from item in xml.Elements("button") where item.Attributes("label").ToString() == "test" select item).Single();の.SingleをSingleOrDefault()に変更した。

すると
System.NullReferenceException: 'オブジェクト参照がオブジェクト インスタンスに設定されていません。'info が null でした。
という例外エラーに変化した。
発生元のソースコードも info.Attribute("label").Value = "aaaaa";に変化した。

補足情報(FW/ツールのバージョンなど)

VisualStudio 2019
Excel 2016
.NetFramework 4.7.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

xmlファイルの読み込みまではうまくいくが、書き込みの際に例外エラーが発生し、
xmlファイルへの書き込みが反映されない状態となっています。

書き込み以前に、要素(XElement)の取得ができていません。

LINQは便利ですがエラーが出たときにどこで失敗しているかがわかりにくいです。
適当に勘であれこれするのではなく、分解して一つずつ確認してください。

cs

1using System; 2using System.Linq; 3using System.Xml.Linq; 4 5namespace Questions352772 6{ 7 internal class Program 8 { 9 private static void Main() 10 { 11 var xml = XElement.Load(@"Ribbon1.xml"); 12 13 // まずは分解して一個ずつ確かめていくぞー 14 var a = xml.Elements("button"); 15 Console.WriteLine(a.Count()); // 0 16 17 // あれー取れないなぁ? 18 // そもそもElementsってなんだっけ? 19 var aa = xml.Elements(); 20 Console.WriteLine(aa.Count()); // 1 21 22 // 1!? どういうこと? 23 // リファレンス見てみよ 24 // [XElement クラス (System.Xml.Linq) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.linq.xelement?view=netframework-4.7.2) 25 // [XContainer.Elements メソッド(System.Xml.Linq) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.linq.xcontainer.elements?view=netframework-4.7.2#System_Xml_Linq_XContainer_Elements_System_Xml_Linq_XName_) 26 //ああそうか直接の子だけなのか... 27 28 // 子孫を取得する方法を調べよー 29 // これっぽいね 30 // [XContainer.Descendants メソッド(System.Xml.Linq) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.linq.xcontainer.descendants?view=netframework-4.7.2#System_Xml_Linq_XContainer_Descendants_System_Xml_Linq_XName_) 31 32 var b = xml.Descendants(); 33 Console.WriteLine(b.Count()); // 5 34 35 // うんうん予想通り! 36 // じゃあbutton 37 38 var bb = xml.Descendants("button"); 39 Console.WriteLine(bb.Count()); // 0 40 41 // なんでやねん! 42 // ggる 「xelement descendants not working」 43 // [c# - XDocument.Descendants not returning descendants - Stack Overflow](https://stackoverflow.com/questions/11933782/xdocument-descendants-not-returning-descendants) 44 // なるほど名前空間をつけないといけないのね(めんどくさ) 45 46 XNamespace ns = "http://schemas.microsoft.com/office/2009/07/customui"; 47 var bbb = xml.Descendants(ns + "button"); 48 Console.WriteLine(bbb.Count()); // 1 49 50 // よしよしここまではOK! 51 // じゃあlabelも 52 53 var c = from item in xml.Descendants(ns + "button") 54 where item.Attributes("label").ToString() == "test" 55 select item; 56 Console.WriteLine(c.Count()); // 0 57 58 // だめかぁorz 59 // そういえばAttributesもよくわかってないなー 60 61 var button = xml.Descendants(ns + "button").First(); 62 foreach (var att in button.Attributes()) 63 { 64 Console.WriteLine(att.ToString()); 65 //id = "btniId" 66 //label = "test" 67 //onAction = "click_Event" 68 } 69 70 // あっ そうだよねToStringじゃおかしいよね 71 // もっといいのがあるはず 72 // [XAttribute クラス (System.Xml.Linq) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.linq.xattribute?view=netframework-4.7.2) 73 // [XAttribute.Value プロパティ (System.Xml.Linq) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.linq.xattribute.value?view=netframework-4.7.2#System_Xml_Linq_XAttribute_Value) 74 // 普通にValueあったやん 75 76 // ええと。。こうか? 77 //var cc = from item in xml.Descendants(ns + "button") 78 // where item.Attributes("label").Value == "test" 79 // select item; 80 81 // コンパイルエラー 82 // そうだよな複数形(Attributes)だもんな 83 // えっと。。こうかな?? 84 var cc = from item in xml.Descendants(ns + "button") 85 from att in item.Attributes("label") 86 where att.Value == "test" 87 select item; 88 Console.WriteLine(c.Count()); // 1 89 90 // ふぅやっとできたっぽいぞー 91 // ほんとにダイジョブかテストをしとこう 92 93 94 // xmlのbuttonの行を増やす・labelの文字を変える等 あってるかのテスト 95 96 97 // よーしだいじょぶそう 98 // で、なにやってたんだっけ?w 99 // あぁそうそう 100 var info = (from item in xml.Descendants(ns + "button") 101 from att in item.Attributes("label") 102 where att.Value == "test" 103 select item).Single(); // Singleは必ず1つだけ該当するという前提ならOK 104 105 info.Attribute("label").Value = "aaaaa"; 106 xml.Save(@"Ribbon1.xml"); 107 } 108 } 109}

LINQに不慣れならforeachで書いたほうがいいかもしれません。

cs

1using System.Xml.Linq; 2 3namespace Questions352772 4{ 5 internal class Program 6 { 7 private static void Main() 8 { 9 var xml = XElement.Load(@"Ribbon1.xml"); 10 XNamespace ns = "http://schemas.microsoft.com/office/2009/07/customui"; 11 12 foreach (var button in xml.Descendants(ns + "button")) 13 { 14 foreach (var att in button.Attributes("label")) 15 { 16 if (att.Value == "test") 17 { 18 button.Attribute("label").Value = "aaaaa"; 19 xml.Save(@"Ribbon1.xml"); 20 return; 21 } 22 } 23 } 24 } 25 } 26}

OnActionというイベントも動的に追加したいと考えています。

VSTOについてはなにもわかりません^^;

投稿2021/08/04 16:37

編集2023/08/15 15:31
TN8001

総合スコア9807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/08/04 21:55

TN8001様回答ありがとうございます。 Linqは不慣れどころか使ったことが数えるほどですね、、笑 foreachを使うことも頭に入れておきます! OnActionについてですが info.Attribute("label").Value = "aaaaa"; のように info.Attribute("OnAction").Value = "イベント名"; といった感じでイベントの名前をxmlファイルに動的に追加できればいいなと思っているのですが上記の回答の流用でイベント名を追加することは可能でしょうか?
TN8001

2021/08/05 02:48

> info.Attribute("OnAction").Value = "イベント名"; > といった感じでイベントの名前をxmlファイルに動的に追加できればいいなと思っているのですが上記の回答の流用でイベント名を追加することは可能でしょうか? まあやってみればすぐわかりますが、 もしxmlが <button id="btniId" label="test"></button> という状態ならば info.Attribute("OnAction").Value = "イベント名"; はエラーです。 すでに何か入っているものを変えることはできますが、無い属性の値は変えられないからです。 属性ごと追加したい場合は info.Add(new XAttribute("onAction", "click_Event")); です。
退会済みユーザー

退会済みユーザー

2021/08/05 04:08

解説ありがとうございます。 参考にさせていただきます。 ちなみに最初の回答もとにソースコードを変更して試したところ、変更されるようになったのですが、1度目の読み込み時には書き換え前のデータのままで1度閉じて再度開かないと適用されないのですが、.saveの後で.loadを用いて読み込みをすればいいのでしょうか?
TN8001

2021/08/05 04:32

> 1度目の読み込み時には書き換え前のデータのままで1度閉じて再度開かないと適用されないのですが、.saveの後で.loadを用いて読み込みをすればいいのでしょうか? えーとOfficeの話でしょうか? VSTOは使ったことも試せる環境もないので私にはわかりません。 このままほかの回答をお待ちいただくか、 あるいはxmlの読み書きは分かったとしてこの質問は閉じ、新たに質問を立ててください。
退会済みユーザー

退会済みユーザー

2021/08/05 10:46

そうですね。 xmlの追加、書き込みの仕方はわかったのでVSTOはVSTOで改めて質問することにします。 今回はありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問