【C#】【book】「実戦で役立つ C# プログラミングのイディオム/定石&パターン」の学習記録(11)

下記の「実戦で役立つ Cプログラミングのイディオム/定石&パターン」を使った学習記録のページです。
本ページのプログラムは「実戦で役立つ Cプログラミングのイディオム/定石&パターン」をもとにして作成したものも多数あります。

 

本学習のトップページ

本学習のトップページへ
 

11.2 XML ファイルの入力

11.2.1 特定の要素を取り出す

 下記 NovelistInfo_11_2_1 関数を参照。
 

11.2.2 特定の要素をキャストして取り出す

 下記 NovelistInfo_11_2_2 関数を参照。
 

11.2.3 属性を取り出す

 下記 NovelistInfo_11_2_3 関数を参照。
 

11.2.4 条件指定で XML 要素を取り出す

 下記 NovelistInfo_11_2_4 関数を参照。
 

11.2.5 XML 要素を並び替える

 下記 NovelistInfo_11_2_5 関数を参照。
 

11.2.6 入れ子になった子要素を取り出す

 下記 NovelistInfo_11_2_6 関数を参照。
 

11.2.7 子孫要素を取り出す

 下記 NovelistInfo_11_2_7 関数を参照。
 

11.2.8 匿名クラスのオブジェクトとして要素を取り出す

 下記 NovelistInfo_11_2_8 関数を参照。
 

未作成 11.2.9  カスタムクラスのオブジェクトとして要素を取り出す

 

novelists.xml
<?xml version="1.0" encoding="utf-8" ?>
<novelists>
	<novelist>
		<name kana="なつめ そうせき">夏目 漱石</name>
		<birth>1867-02-09</birth>
		<death>1916-12-09</death>
		<masterpieces>
			<title>吾輩は猫である</title>
			<title>坊っちゃん</title>
			<title>こゝろ</title>
		</masterpieces>
	</novelist>
	<novelist>
		<name kana="かわばた やすなり">川端 康成</name>
		<birth>1899-06-14</birth>
		<death>1972-04-16</death>
		<masterpieces>
			<title>雪国</title>
			<title>伊豆の踊子</title>
		</masterpieces>
	</novelist>
	<novelist>
		<name kana="だざい おさむ">太宰 治</name>
		<birth>1909-06-19</birth>
		<death>1948-06-13</death>
		<masterpieces>
			<title>斜陽</title>
			<title>人間失格</title>
		</masterpieces>
	</novelist>
	<novelist>
		<name kana="みやざわ けんじ">宮沢 賢治</name>
		<birth>1896-08-27</birth>
		<death>1933-09-21</death>
		<masterpieces>
			<title>銀河鉄道の夜</title>
			<title>風の又三郎</title>
		</masterpieces>
	</novelist>
</novelists>

 

XMLOprクラス (Program.cs)
using System;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using System.Reflection;

namespace XMLOpr
{
  class Program
  {
    static void Main(string[] args)
    {
      string path = "";

      if (args.Length < 1)
      {
        path = @"C:\Users\neko\source\repos\JISSEN\11\11.2\XMLOpr\XMLOpr\InputData\novelists.xml";
      }

      Console.WriteLine(path);

      if (File.Exists(path))
      {
        var xdoc = XDocument.Load(path);
        NovelistInfo_11_2_1(xdoc);
        NovelistInfo_11_2_2(xdoc);
        NovelistInfo_11_2_3(xdoc);
        NovelistInfo_11_2_4(xdoc);
        NovelistInfo_11_2_5(xdoc);
        NovelistInfo_11_2_6(xdoc);
        NovelistInfo_11_2_7(xdoc);
        NovelistInfo_11_2_8(xdoc);
      }
      else
      {
        Console.Write("Error: could not found {0}\n", path);
      }
    }


    // 11.2.1 特定の要素を取り出す
    public static void NovelistInfo_11_2_1(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var xelements = xdoc.Root.Elements();
      foreach (var xnovelist in xelements)
      {
        XElement xname = xnovelist.Element("name");
        Console.WriteLine(xname.Value);
      }
    }

    // 11.2.2 特定の要素をキャストして取り出す
    public static void NovelistInfo_11_2_2(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var xelements = xdoc.Root.Elements();
      foreach (var xnovelist in xelements)
      {
        XElement xname = xnovelist.Element("name");
        // デフォルトでは string 型なので、DateTime型にキャストする
        var birth = (DateTime)xnovelist.Element("birth");
        Console.WriteLine("{0} {1}", xname.Value, birth.ToShortDateString());
      }
    }
    // 11.2.3 属性を取り出す
    public static void NovelistInfo_11_2_3(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var xelements = xdoc.Root.Elements();
      foreach (var xnovelist in xelements)
      {
        XElement xname = xnovelist.Element("name");
        // 属性 kana を取り出す
        // 属性が空の場合場合に備えて null 条件演算子 xkana?.Value を使う
        XAttribute xkana = xname.Attribute("kana");
        // string 型として取り出すことも可能
        string kana = (string)xname.Attribute("kana");
        Console.WriteLine("{0} [{1}] [{2}]", xname.Value, xkana?.Value, kana);

      }
    }

    // 11.2.4 条件指定で XML 要素を取り出す
    // → 1900年以降生まれの作家名を取り出す
    public static void NovelistInfo_11_2_4(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var xnovelists = xdoc.Root.Elements()
        .Where(x => ((DateTime)x.Element("birth")).Year >= 1900);

      foreach (var xnovelist in xnovelists)
      {
        var xname = xnovelist.Element("name");
        var birth = (DateTime)xnovelist.Element("birth");
        Console.WriteLine("{0} {1}", xname.Value, birth.ToShortDateString());
      }
    }

    // 11.2.5 XML 要素を並び替える
    public static void NovelistInfo_11_2_5(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      // LINQ OrderBy を使う
      var xnovelists = xdoc.Root.Elements()
        .OrderBy(x => (string)(x.Element("name").Attribute("kana")));
      foreach( var xnovelist in xnovelists)
      {
        var xname = xnovelist.Element("name");
        var birth = (DateTime)xnovelist.Element("birth");
        Console.WriteLine("{0} {1}", xname.Value, birth.ToShortDateString());
      }
    }

    // 11.2.6 入れ子になった子要素を取り出す
    // 代表作を表す masterpieces 要素の子要素に該当する title を取り出す
    public static void NovelistInfo_11_2_6(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      // LINQ OrderBy を使う
      foreach( var xnovelist in xdoc.Root.Elements())
      {
        var xname = xnovelist.Element("name");
        var works = xnovelist.Element("masterpieces") // ある masterpieces 要素にアクセスする
                             .Elements("title")       // その子要素である title を全て取り出す
                             .Select(x => x.Value);   // title の値 .Value を取り出す
        Console.WriteLine("{0} - {1}", xname.Value, string.Join(",", works));
      }
    }

    // 11.2.7 子孫要素を取り出す
    // 上記 11.2.6 のように親を明示的に経由せずに子・孫要素に直接アクセスする
    public static void NovelistInfo_11_2_7(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var xtitles = xdoc.Root.Descendants("title");
      // LINQ OrderBy を使う
      foreach( var xtitle in xtitles)
      {
        Console.WriteLine(xtitle.Value);
      }
    }

    // 11.2.8 子孫要素を取り出す
    // Select メソッドを利用して匿名クラスのオブジェクトとして要素を取り出す
    public static void NovelistInfo_11_2_8(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var novelists = xdoc.Root.Elements()
        .Select(x => new
        {
          Name = (string)x.Element("name"),
          Birth = (DateTime)x.Element("birth"),
          Death = (DateTime)x.Element("death")
        });
      foreach( var novelist in novelists)
      {
        Console.WriteLine("{0} ({1}-{2})", novelist.Name, novelist.Birth.Year, novelist.Death.Year);
      }
    }

    // 11.2.9 カスタムクラスのオブジェクトとして要素を取り出す
    public static void NovelistInfo_11_2_8(XDocument xdoc)
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      // 現時点では難しいため未着手
    }
  }
}

 
 

11.3 XML オブジェクトの生成

11.3.1 文字列からXDocument を生成する

 下記 NovelistInfo_11_3_1 関数を参照。
 

11.3.2 文字列からXElement を生成する

 下記 NovelistInfo_11_3_2 関数を参照。
 

未作成 11.3.3

11.3.4 コレクションからXDocument を生成する

 下記 NovelistInfo_11_3_4 関数を参照。
 
 

novelists.xml
<?xml version="1.0" encoding="utf-8"?>
<novelists>
    <novelist>
        <name kana="よみがな">作家名</name>
        <birth>1900-01-01</birth>
        <death>1900-01-01</death>
        <masterpieces>
            <title>Title(1)</title>
            <title>Title(2)</title>
        </masterpieces>
    </novelist>
</novelists>

 

XMLStringクラス (Program.cs)
using System;
using System.Linq;
using System.Xml.Linq;
using System.Reflection;
using System.Collections.Generic; // List<>を使うために必要

namespace XMLString
{
  class Program
  {
    static void Main(string[] args)
    {
      NovelistInfo_11_3_1();
      NovelistInfo_11_3_2();
      NovelistInfo_11_3_4();
    }

    // 11.3.1 文字列からXDocument を生成する
    public static void NovelistInfo_11_3_1()
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      // @ を使えば改行することができる。
      // @ を使った記述の中で " を入力したい場合は "" というように 2個並べる。
      string xmlstring =
          @"<?xml version=""1.0"" encoding=""utf-8"" ?>
                    <novelists>
                      <novelist>
                        <name kana=""だざい おさむ"">太宰 治</name>
                        <birth>1909-06-19</birth>
                        <death>1948-06-13</death>
                        <masterpieces>
                          <title>斜陽</title>
                          <title>人間失格</title>
                        </masterpieces>
                      </novelist>
                    </novelists>";
      var xdoc = XDocument.Parse(xmlstring);

      Display(xdoc);
    }

    // 11.3.2 文字列から XElement を生成する
    // XElement.Parse メソッドを使って XElement オブジェクトを生成する
    public static void NovelistInfo_11_3_2()
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      string elmstring =
                    @"<novelist>
                        <name kana=""だざい おさむ"">太宰 治</name>
                        <birth>1909-06-19</birth>
                        <death>1948-06-13</death>
                        <masterpieces>
                          <title>斜陽</title>
                          <title>人間失格</title>
                        </masterpieces>
                      </novelist>";
      XElement element = XElement.Parse(elmstring);

      var xdoc = XDocument.Load(@"C:\Users\neko\source\repos\JISSEN\11\11.3\XMLString\XMLString\novelists.xml");
      xdoc.Root.Add(element);

      Display(xdoc);
    }

    // 11.3.4 コレクションから XDocument を作成する
    // List<Novelist> から XDocument を生成する例
    public static void NovelistInfo_11_3_4()
    {
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine("\n********* {0} *********", methodName);

      var novelists = new List<Novelist> {
        new Novelist {
          Name = "夏目漱石",
          KanaName = "なつめそうせき",
          Birth = DateTime.Parse("1867-02-09"),
          Death = DateTime.Parse("1916-12-09"),
          Masterpieces = new string[] {"我輩は猫である","坊ちゃん"},
        },
        new Novelist {
          Name = "川端康成",
          KanaName = "かわばたやすなり",
          Birth = DateTime.Parse("1899-06-14"),
          Death = DateTime.Parse("1972-04-16"),
          Masterpieces = new string[] {"雪国","伊豆の踊り子"},
        },
      };
      // Linq to Objectsを使い、リストの内容をXElementnのシーケンスに変換
      var elements = novelists.Select(x =>
        new XElement("novelist",
          new XElement("name", x.Name, new XAttribute("kana", x.KanaName)),
          new XElement("birth", x.Birth),
          new XElement("death", x.Death),
          new XElement("masterpieces", x.Masterpieces.Select(t => new XElement("title", t)))
        )
      );

      // 最上位の novelists 要素を作成する
      var root = new XElement("novelists", elements);

      // root要素を指定し、XDocument オブジェクトを生成する
      var xdoc = new XDocument(root);

      Display(xdoc);
    }


    // 書籍サンプルコード Chapter11\Section03\Program.cs より転記した
    static private void Display(XDocument xdoc)
    {
      // これ以降は確認用のコード
      // <novelists> から <novelist> を取り出す
      foreach (var xnovelist in xdoc.Root.Elements())
      {
        // <novelist><name> にアクセスする
        var xname = xnovelist.Element("name");
        // <novelist><birth> にアクセスする
        var birth = (DateTime)xnovelist.Element("birth");
        // <novelist><death> にアクセスする
        var death = (DateTime)xnovelist.Element("death");
        var masterpieces = xnovelist.Element("masterpieces").Elements().Select(x => x.Value);

        Console.WriteLine("{0}({1}-{2}) - {3}", xname.Value,
                                                birth.ToShortDateString(),
                                                death.ToShortDateString(),
                                                string.Join(", ", masterpieces));
      }
      Console.WriteLine();
    }
  }
}