C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: xmlファイルへコメント出力する方法


(過去ログ 176 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■101345 / inTopicNo.1)  xmlファイルへコメント出力する方法
  
□投稿者/ kiku (322回)-(2023/02/07(Tue) 15:27:44)

分類:[C#] 

C#
.NETFramework4.8
WinForm

https://dobon.net/vb/dotnet/file/xmlserializer.html

上記環境で、上記URLのようにクラスのインスタンスを
XMLファイルにシリアライズしたり、
逆にXMLファイルからデシリアライズしたりは
簡単にできます。

このXMLファイルをアプリの設定ファイルと利用したときに、
XMLファイル内の各項目にコメントとして
説明を追加したいと思っています。

例えば下記のような感じです。

public class SampleClass
{
    public int Number;
    [●ここの属性に説明文を追加することでコメントに反映●]
    public string Message;
}

<?xml version="1.0" encoding="utf-8"?>
<SampleClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Number>123</Number>
  <!--●ここに項目の説明文●-->
  <Message>テストです。</Message>
</SampleClass>

XmlSerializerクラスを調べてみたところ
そのものズバリの機能はなさそうです。
https://learn.microsoft.com/ja-jp/dotnet/api/system.xml.serialization.xmlserializer?view=netframework-4.8

上記のような機能を実現する方法はないでしょうか?
カスタムの属性なんかは実装できるのでしょうか?
何かアドバイス頂けますと助かります。

引用返信 編集キー/
■101346 / inTopicNo.2)  Re[1]: xmlファイルへコメント出力する方法
□投稿者/ kiku (323回)-(2023/02/07(Tue) 15:37:12)
ちなみに現在は、XmlSerializerクラスは使わずに、
コメント付きのxmlファイルを読み込む機能と、
xmlファイル内のコメントを書き換えずに、値のみを書き換える機能を
実装しています。
しかし、項目が多いとコーディングミスが
発生する場合があり、できればXmlSerializerクラスを使って
もっと簡便に使えないかと検討している状態です。
引用返信 編集キー/
■101348 / inTopicNo.3)  Re[2]: xmlファイルへコメント出力する方法
□投稿者/ ぼーちゃん (40回)-(2023/02/08(Wed) 09:20:24)
以下のような方法はあります。デシリアライズも問題ないです。
https://stackoverflow.com/questions/7385921/how-to-write-a-comment-to-an-xml-file-when-using-the-xmlserializer

対象クラスに余計なパブリックメンバを定義することになるので、あまりシンプルではないですが・・・


using System;
using System.Windows.Forms;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.CompilerServices;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var fileName = @"test.xml";
            var obj = new SampleClass() { Number = 123, Message = "メッセージ1"};
            XmlSerializer serializer = new XmlSerializer(typeof(SampleClass));
            
            using(var sw = new System.IO.StreamWriter(fileName, false, new System.Text.UTF8Encoding(false)))
            {
                serializer.Serialize(sw, obj);
            }
        }
    }

    public class SampleClass
    {

        public int Number { get; set; }


        [XmlAnyElement("MessageXmlComment")]
        public XmlComment MessageXmlComment { get { return GetType().GetXmlComment(); } set { } }

        [XmlComment("Messageのコメント")]
        public string Message { get; set; }

    }

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class XmlCommentAttribute : Attribute
    {
        public XmlCommentAttribute(string value)
        {
            this.Value = value;
        }

        public string Value { get; set; }
    }

    public static class XmlCommentExtensions
    {
        const string XmlCommentPropertyPostfix = "XmlComment";

        static XmlCommentAttribute GetXmlCommentAttribute(this Type type, string memberName)
        {
            var member = type.GetProperty(memberName);
            if (member == null)
                return null;
            var attr = member.GetCustomAttribute<XmlCommentAttribute>();
            return attr;
        }

        public static XmlComment GetXmlComment(this Type type, [CallerMemberName] string memberName = "")
        {
            var attr = GetXmlCommentAttribute(type, memberName);
            if (attr == null)
            {
                if (memberName.EndsWith(XmlCommentPropertyPostfix))
                    attr = GetXmlCommentAttribute(
                        type, memberName.Substring(0, memberName.Length - XmlCommentPropertyPostfix.Length)
                        );
            }
            if (attr == null || string.IsNullOrEmpty(attr.Value))
                return null;
            return new XmlDocument().CreateComment(attr.Value);
        }
    }
}

引用返信 編集キー/
■101349 / inTopicNo.4)  Re[3]: xmlファイルへコメント出力する方法
□投稿者/ kiku (324回)-(2023/02/08(Wed) 10:28:20)
No101348 (ぼーちゃん さん) に返信
> 以下のような方法はあります。デシリアライズも問題ないです。
> https://stackoverflow.com/questions/7385921/how-to-write-a-comment-to-an-xml-file-when-using-the-xmlserializer
>
> 対象クラスに余計なパブリックメンバを定義することになるので、あまりシンプルではないですが・・・

返答頂きありがとうございます。
出来るんですね。
すぐに検証できないのですが
できるだけ早く検証してみます。
ありがとうございました。
引用返信 編集キー/
■101350 / inTopicNo.5)  Re[3]: xmlファイルへコメント出力する方法
□投稿者/ kiku (325回)-(2023/02/08(Wed) 13:06:41)
No101348 (ぼーちゃん さん) に返信
> 以下のような方法はあります。デシリアライズも問題ないです。
> https://stackoverflow.com/questions/7385921/how-to-write-a-comment-to-an-xml-file-when-using-the-xmlserializer

動作することを確認しました。
ありがとうございます。
ソースコードは短いですが、まだ理解できていない><

> 対象クラスに余計なパブリックメンバを定義することになるので、あまりシンプルではないですが・・・

確かに使い方がシンプルではないと感じてしまいました。
もうちょっとなんとかならないかなー。

提示頂いたstackoverflow内にシンプルな実装というものがあり、
こちらも試してみたいと思います。
引用返信 編集キー/
■101354 / inTopicNo.6)  Re[4]: xmlファイルへコメント出力する方法
□投稿者/ kiku (326回)-(2023/02/09(Thu) 09:44:49)
No101350 (kiku さん) に返信
> 提示頂いたstackoverflow内にシンプルな実装というものがあり、
> こちらも試してみたいと思います。

stackoverflow内の下記のシンプルな実装の方も試してみました。
使い方がシンプルでとても良いのですが、
ReadXmlメソッドを独自にすべて実装する必要が発生し、
XmlSerializerクラスを利用する最大のメリットが
失われてしまうと思いました。

なんか中間的な良いアイデアはないでしょうか?
ちょっとしばらく考えてみます。
皆さん、何かアイデアがあればヒントでも良いので
教えて欲しいです。

public class Foo : IXmlSerializable
{
[XmlComment(Value = "The application version, NOT the file version!")]
public string Version { get; set; }
public string Name { get; set; }


public void WriteXml(XmlWriter writer)
{
var properties = GetType().GetProperties();

foreach (var propertyInfo in properties)
{
if (propertyInfo.IsDefined(typeof(XmlCommentAttribute), false))
{
writer.WriteComment(
propertyInfo.GetCustomAttributes(typeof(XmlCommentAttribute), false)
.Cast<XmlCommentAttribute>().Single().Value);
}

writer.WriteElementString(propertyInfo.Name, propertyInfo.GetValue(this, null).ToString());
}
}
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}

public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
}
引用返信 編集キー/
■101355 / inTopicNo.7)  Re[5]: xmlファイルへコメント出力する方法
□投稿者/ 魔界の仮面弁士 (3561回)-(2023/02/09(Thu) 10:04:51)
No101354 (kiku さん) に返信
> なんか中間的な良いアイデアはないでしょうか?

XmlSerializer で、コメント無しでシリアライズした後で、
XSLT なり XLinq なりでコメントを追加挿入するとか?
引用返信 編集キー/
■101356 / inTopicNo.8)  Re[6]: xmlファイルへコメント出力する方法
□投稿者/ kiku (327回)-(2023/02/09(Thu) 10:23:11)
No101355 (魔界の仮面弁士 さん) に返信
> ■No101354 (kiku さん) に返信
>>なんか中間的な良いアイデアはないでしょうか?
>
> XmlSerializer で、コメント無しでシリアライズした後で、
> XSLT なり XLinq なりでコメントを追加挿入するとか?

回答ありがとうございます。
ちょうど同じことを思っていました。
この方向性が良さそうです。

XSLTやXLinqの方法がわかっていないので
ちょっと勉強してみます。
たぶん下記ができる必要があると思っています。
・カスタム属性の取得
・挿入する位置の特定
・コメント挿入

引用返信 編集キー/
■101359 / inTopicNo.9)  Re[7]: xmlファイルへコメント出力する方法
□投稿者/ ぼーちゃん (41回)-(2023/02/09(Thu) 13:44:59)
No101356 (kiku さん) に返信
> ■No101355 (魔界の仮面弁士 さん) に返信
>>■No101354 (kiku さん) に返信
> >>なんか中間的な良いアイデアはないでしょうか?
>>
>>XmlSerializer で、コメント無しでシリアライズした後で、
>>XSLT なり XLinq なりでコメントを追加挿入するとか?
> 
> 回答ありがとうございます。
> ちょうど同じことを思っていました。
> この方向性が良さそうです。

私は最初の方法で妥協して、スニペットを登録して入力補助する方向で運用してしまってました。
でも、後からコメント挿入の方向性が良さそうですね。
検証お願い致しますm(_ _)m


一応VisualStudio用スニペット定義:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>PropertyWithXmlComment</Title>
      <Shortcut>xmlc</Shortcut>
    </Header>
    <Snippet>
      <Code Language="CSharp">
        <![CDATA[
        [XmlAnyElement("$Name$XmlComment")]
        public XmlComment $Name$XmlComment { get { return GetType().GetXmlComment(); } set { } }
        [XmlComment("$Comment$")]
        public $Type$ $Name$ { get; set; }]]>
      </Code>
      <Declarations>
        <Literal>
          <ID>Name</ID>
          <ToolTip>Input property name.</ToolTip>
          <Default>Name</Default>
        </Literal>
        <Literal>
          <ID>Type</ID>
          <ToolTip>Input data type.</ToolTip>
          <Default>object</Default>
        </Literal>
        <Literal>
          <ID>Comment</ID>
          <ToolTip>Input property comment.</ToolTip>
          <Default>Comment</Default>
        </Literal>
      </Declarations>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

引用返信 編集キー/
■101373 / inTopicNo.10)  Re[8]: xmlファイルへコメント出力する方法
□投稿者/ kiku (328回)-(2023/02/10(Fri) 08:40:21)
No101359 (ぼーちゃん さん) に返信
> ■No101356 (kiku さん) に返信
>>■No101355 (魔界の仮面弁士 さん) に返信
> >>■No101354 (kiku さん) に返信
>>>>なんか中間的な良いアイデアはないでしょうか?
> >>
> >>XmlSerializer で、コメント無しでシリアライズした後で、
> >>XSLT なり XLinq なりでコメントを追加挿入するとか?
>>
>>回答ありがとうございます。
>>ちょうど同じことを思っていました。
>>この方向性が良さそうです。
>
> 私は最初の方法で妥協して、スニペットを登録して入力補助する方向で運用してしまってました。
> でも、後からコメント挿入の方向性が良さそうですね。
> 検証お願い致しますm(_ _)m

おおお、なるほど、皆さんに聞くといろいろとアイデアが聞けて良いですね。
本当に参考になります。
すぐに検証できないのですが、どんな感じで動作するのか試してみたいと思います。

上記の件、下記の件も、時間作って検証・検討していきたいので
しばらく締めずに続けていきたいと思います。

>>XmlSerializer で、コメント無しでシリアライズした後で、
>>XSLT なり XLinq なりでコメントを追加挿入するとか?
引用返信 編集キー/
■101381 / inTopicNo.11)  Re[9]: xmlファイルへコメント出力する方法
□投稿者/ kiku (329回)-(2023/02/13(Mon) 13:57:15)
No101373 (kiku さん) に返信
> ■No101359 (ぼーちゃん さん) に返信
>>■No101356 (kiku さん) に返信
> >>■No101355 (魔界の仮面弁士 さん) に返信
>>>>■No101354 (kiku さん) に返信
> >>XmlSerializer で、コメント無しでシリアライズした後で、
> >>XSLT なり XLinq なりでコメントを追加挿入するとか?

上記、下記のコードで実現できました。
もうちょっと整理して使っていきたいと思います。
何かコメントあれば頂きたいです。
しばらくしてコメントなければ締めます。

    public class Ramen
    {
        public Ramen()
        {
            Gu = new Gu();
        }

        [XmlComment("コメントMen")]
        public string Men { get; set; }

        [XmlComment("コメントSoup")]
        public string Soup { get; set; }

        [XmlComment("コメントGu")]
        public Gu Gu { get; set; }
    };

    public class Gu
    {
        [XmlComment("コメントVegetable")]
        public string Vegetable { get; set; }

        [XmlComment("コメントMeat")]
        public string Meat { get; set; }

        [XmlComment("コメントEgg")]
        public string Egg { get; set; }
    };

    public class XmlCommentAttribute : Attribute
    {
        public XmlCommentAttribute(string value)
        {
            this.Value = value;
        }
        public string Value { get; set; }
    }

        private void button1_Click(object sender, EventArgs e)
        {
            var file1 = "c:\test1.xml";

            //インスタンス作成
            var ramen = new Ramen();
            ramen.Men = "太麺";
            ramen.Soup = "しょうゆ味";
            ramen.Gu.Vegetable = "ねぎ";
            ramen.Gu.Meat = "チャーシュー";
            ramen.Gu.Egg = "半熟味玉";

            //シリアライズ
            var xs = new XmlSerializer(typeof(Ramen));
            using (var sw = new StreamWriter(file1, false, Encoding.UTF8))
            {
                xs.Serialize(sw, ramen);
            }

            //型からプロパティ名を解析
            var list = GetPropertyList(typeof(Ramen));

            // XMLファイルを読み込む
            var doc = XDocument.Load(file1);

            foreach(var pro in list)
            {
                var namelist = pro.name.Split('.');
                XElement element = null;
                var first = true;
                foreach (var name in namelist)
                {
                    if (first)
                    {
                        first = false;
                        element = doc.Root.Elements().FirstOrDefault(x => x.Name == name);
                    }
                    else
                    {
                        element = element.Elements().FirstOrDefault(x => x.Name == name);
                    }
                }
                var comment = new XComment(pro.comment);
                element.AddBeforeSelf(comment);
            }

            doc.Save(file1);
        }

        private List<(string name, string comment)> GetPropertyList(Type rootprotype_type)
        {
            var list = new List<(string name, string comment)>();
            var subprolist = rootprotype_type.GetProperties();

            foreach(var subpro in subprolist)
            {
                var subproname = subpro.Name;
                var subprotype_string = subpro.PropertyType.FullName;
                //Console.WriteLine($"プロパティの名前={subproname}");
                //Console.WriteLine($"プロパティの型={subprotype_string}");

                var test = subpro.GetCustomAttribute<XmlCommentAttribute>();
                if(test != null)
                {
                    //XmlComment属性が存在した
                    list.Add((subproname, test.Value));
                }

                if (subprotype_string.StartsWith("System."))
                {
                    //階層終了
                    continue;
                }

                //階層あり
                var subprotype_type = Type.GetType(subprotype_string);
                var list2 = GetPropertyList(subprotype_type);
                foreach(var pro2 in list2)
                {
                    list.Add((subproname + "." + pro2.name, pro2.comment));
                }
            }
            return list;
        }

引用返信 編集キー/
■101384 / inTopicNo.12)  Re[10]: xmlファイルへコメント出力する方法
□投稿者/ kiku (330回)-(2023/02/15(Wed) 08:09:26)
No101381 (kiku さん) に返信
> ■No101373 (kiku さん) に返信
>>■No101359 (ぼーちゃん さん) に返信
> >>■No101356 (kiku さん) に返信
>>>>■No101355 (魔界の仮面弁士 さん) に返信
> >>>>■No101354 (kiku さん) に返信
>>>>XmlSerializer で、コメント無しでシリアライズした後で、
>>>>XSLT なり XLinq なりでコメントを追加挿入するとか?
>
> 上記、下記のコードで実現できました。
> もうちょっと整理して使っていきたいと思います。
> 何かコメントあれば頂きたいです。
> しばらくしてコメントなければ締めます。

特にコメントもないようなので
締めます。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -