(同じ利用者による、間の2版が非表示)
553行目: 553行目:


== LINQ to XMLの使用 ==
== LINQ to XMLの使用 ==
==== XMLファイルの作成 ====
以下の例では、LINQ to XMLを使用して、下記のXMLファイルを非同期で生成している。<br>
非同期処理およびストリーミング処理を使用しているため、大きなXMLファイルを扱う場合でもメモリ効率が良く、アプリケーションの応答性を維持している。<br>
<br>
* GenerateEarthquakeXmlAsyncメソッド
*: LINQ to XMLを使用してXMLドキュメントを構築する。
*: 指定されたXML構造に従って、全ての要素と属性を作成する。
*: jmx_eb名前空間を使用して、特定の要素に名前空間を適用している。
* SaveXmlToFileAsyncメソッド
*: ストリーミング処理を使用して、XMLドキュメントをファイルに非同期で保存する。
*: FileStreamクラスを使用して、非同期I/O操作を行う。
<br>
<syntaxhighlight lang="xml">
<!-- 作成するXMLファイルの構造 -->
<Earthquake>
  <OriginTime>2024-08-23T21:00:00+09:00</OriginTime>
  <ArrivalTime>2024-08-23T21:01:00+09:00</ArrivalTime>
  <Hypocenter>
    <Area>
      <Name>茨城県南部</Name>
      <Code type="震央地名">301</Code>
    </Area>
  </Hypocenter>
  <jmx_eb:Magnitude type="Mj" description="M3.8">3.8</jmx_eb:Magnitude>
</Earthquake>
<Observation>
  <Pref><Name>茨城県</Name><Code>08</Code><MaxInt>2</MaxInt>
    <Area><Name>茨城県北部</Name><Code>300</Code><MaxInt>2</MaxInt>
      <City><Name>小美玉市</Name><Code>0823600</Code><MaxInt>2</MaxInt>
        <IntensityStation><Name>小美玉市小川*</Name><Code>0823633</Code><Int>2</Int></IntensityStation>
        <IntensityStation><Name>小美玉市上玉里*</Name><Code>0823635</Code><Int>2</Int></IntensityStation>
      </City>
      <City><Name>水戸市</Name><Code>0820100</Code><MaxInt>1</MaxInt>
        <IntensityStation><Name>水戸市千波町*</Name><Code>0820121</Code><Int>1</Int></IntensityStation>
      </City>
    </Area>
  </Pref>
</Observation>
</syntaxhighlight>
<br>
<syntaxhighlight lang="c#">
using System;
using System.IO;
using System.Xml.Linq;
using System.Threading.Tasks;
class Program
{
    static async Task Main(string[] args)
    {
      try
      {
          // XMLドキュメントを生成
          XDocument doc = await GenerateEarthquakeXmlAsync();
          // ファイルに非同期で保存
          await SaveXmlToFileAsync(doc, "sample.xml");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"エラーが発生: {ex.Message}");
      }
    }
    static async Task<XDocument> GenerateEarthquakeXmlAsync()
    {
      // 非同期タスクをシミュレート
      await Task.Delay(100);
      // XMLの名前空間を定義
      XNamespace jmx_eb = "http://www.jma.go.jp/jmx-eb";
      // XMLドキュメントを作成
      XDocument doc = new XDocument(new XElement("Root",
                new XElement("Earthquake",
                    new XElement("OriginTime", "2024-08-23T21:00:00+09:00"),
                    new XElement("ArrivalTime", "2024-08-23T21:01:00+09:00"),
                    new XElement("Hypocenter",
                        new XElement("Area",
                            new XElement("Name", "茨城県南部"),
                            new XElement("Code", new XAttribute("type", "震央地名"), "301")
                        )
                    ),
                    new XElement(jmx_eb + "Magnitude",
                        new XAttribute("type", "Mj"),
                        new XAttribute("description", "M3.8"),
                        "3.8"
                    )
                ),
                new XElement("Observation",
                    new XElement("Pref",
                        new XElement("Name", "茨城県"),
                        new XElement("Code", "08"),
                        new XElement("MaxInt", "2"),
                        new XElement("Area",
                            new XElement("Name", "茨城県北部"),
                            new XElement("Code", "300"),
                            new XElement("MaxInt", "2"),
                            new XElement("City",
                                new XElement("Name", "小美玉市"),
                                new XElement("Code", "0823600"),
                                new XElement("MaxInt", "2"),
                                new XElement("IntensityStation",
                                    new XElement("Name", "小美玉市小川*"),
                                    new XElement("Code", "0823633"),
                                    new XElement("Int", "2")
                                ),
                                new XElement("IntensityStation",
                                    new XElement("Name", "小美玉市上玉里*"),
                                    new XElement("Code", "0823635"),
                                    new XElement("Int", "2")
                                )
                            ),
                            new XElement("City",
                                new XElement("Name", "水戸市"),
                                new XElement("Code", "0820100"),
                                new XElement("MaxInt", "1"),
                                new XElement("IntensityStation",
                                    new XElement("Name", "水戸市千波町*"),
                                    new XElement("Code", "0820121"),
                                    new XElement("Int", "1")
                                )
                            )
                        )
                    )
                )
            )
        );
      return doc;
    }
    static async Task SaveXmlToFileAsync(XDocument doc, string fileName)
    {
      // ストリーミング処理を使用してファイルに非同期で保存
      using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
      {
          await doc.SaveAsync(fs, SaveOptions.None, default);
      }
    }
}
</syntaxhighlight>
<br>
==== 要素の取得 ====
==== 要素の取得 ====
以下の例では、LINQ to XMLおよび非同期処理を使用してXMLファイルを読み込み、以下に示す要素を読み込んでいる。<br>
以下の例では、LINQ to XMLおよび非同期処理を使用してXMLファイルを読み込み、以下に示す要素を読み込んでいる。<br>
690行目: 835行目:
     }
     }
  }
  }
</syntaxhighlight>
<br>
==== 要素の変更 ====
以下の例では、LINQ to XMLを使用して、以下に示すXMLファイルの一部の値を変更している。<br>
<br>
* ModifyXmlFileAsync メソッド:
*: FileStreamクラスを使用して、XMLファイルを非同期で読み込む。
*: LINQ to XMLを使用して、指定された要素と属性を検索して、値を変更する。
*: 変更後のXMLドキュメントを非同期で保存する。
*: <br>
* 変更操作
*: <Hypocenter> -> <Area> -> <Name>の値を"hoge"に変更する。
*: <Hypocenter> -> <Area> -> <nowiki><Code></nowiki>のtype属性の値を"99"に変更する。
*: 全ての<Observation> -> <IntensityStation> -> <Name>の値を"piyo"に変更する。
*: <br>
* 名前空間の処理
*: XMLドキュメントのデフォルト名前空間を取得して、要素の検索に使用する。
* 非同期処理
*: ファイルの読み込みと保存に非同期メソッドを使用する。
* ストリーミング処理
*: FileStreamクラスを使用して、ファイルの読み込みと保存をストリーミング方式で行う。
<br>
<syntaxhighlight lang="xml">
<!-- 変更前のXMLファイルの構造 -->
<Earthquake>
  <OriginTime>2024-08-23T21:00:00+09:00</OriginTime>
  <ArrivalTime>2024-08-23T21:01:00+09:00</ArrivalTime>
  <Hypocenter>
    <Area>
      <Name>茨城県南部</Name>
      <Code type="震央地名">301</Code>
    </Area>
  </Hypocenter>
  <jmx_eb:Magnitude type="Mj" description="M3.8">3.8</jmx_eb:Magnitude>
</Earthquake>
<Observation>
  <Pref><Name>茨城県</Name><Code>08</Code><MaxInt>2</MaxInt>
    <Area><Name>茨城県北部</Name><Code>300</Code><MaxInt>2</MaxInt>
      <City><Name>小美玉市</Name><Code>0823600</Code><MaxInt>2</MaxInt>
        <IntensityStation><Name>小美玉市小川*</Name><Code>0823633</Code><Int>2</Int></IntensityStation>
        <IntensityStation><Name>小美玉市上玉里*</Name><Code>0823635</Code><Int>2</Int></IntensityStation>
      </City>
      <City><Name>水戸市</Name><Code>0820100</Code><MaxInt>1</MaxInt>
        <IntensityStation><Name>水戸市千波町*</Name><Code>0820121</Code><Int>1</Int></IntensityStation>
      </City>
    </Area>
  </Pref>
</Observation>
</syntaxhighlight>
<br>
<syntaxhighlight lang="c#">
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Threading.Tasks;
class Program
{
    static async Task Main(string[] args)
    {
      try
      {
          // XMLファイルのパス
          string filePath = "sample.xml";
          // XMLファイルを非同期で読み込み、修正し、保存する
          await ModifyXmlFileAsync(filePath);
      }
      catch (Exception ex)
      {
          Console.WriteLine($"エラーが発生: {ex.Message}");
      }
    }
    static async Task ModifyXmlFileAsync(string filePath)
    {
      // XMLファイルを非同期で読み込む
      XDocument doc;
      using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
      {
          doc = await XDocument.LoadAsync(fs, LoadOptions.None, default);
      }
      // XMLの名前空間を取得
      XNamespace ns = doc.Root.GetDefaultNamespace();
      // <Hypocenter> -> <Area> -> <Name>の値を変更
      var hypocenterAreaName = doc.Descendants(ns + "Hypocenter")
                                  .Elements(ns + "Area")
                                  .Elements(ns + "Name")
                                  .FirstOrDefault();
      if (hypocenterAreaName != null)
      {
          hypocenterAreaName.Value = "hoge";
      }
      // <Hypocenter> -> <Area> -> <Code>のtype属性の値を変更
      var hypocenterAreaCode = doc.Descendants(ns + "Hypocenter")
                                  .Elements(ns + "Area")
                                  .Elements(ns + "Code")
                                  .FirstOrDefault();
      if (hypocenterAreaCode != null)
      {
          hypocenterAreaCode.Attribute("type").Value = "99";
      }
      // 全ての<Observation> -> <IntensityStation> -> <Name>の値を変更
      var intensityStationNames = doc.Descendants(ns + "Observation")
                                      .Descendants(ns + "IntensityStation")
                                      .Elements(ns + "Name");
      foreach (var name in intensityStationNames)
      {
          name.Value = "piyo";
      }
      // 変更したXMLを非同期で保存
      using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
      {
          await doc.SaveAsync(fs, SaveOptions.None, default);
      }
    }
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="xml">
<!-- 変更後のXMLファイルの構造 -->
<Earthquake>
  <OriginTime>2024-08-23T21:00:00+09:00</OriginTime>
  <ArrivalTime>2024-08-23T21:01:00+09:00</ArrivalTime>
  <Hypocenter>
    <Area>
      <Name>hoge</Name>
      <Code type="99">301</Code>
    </Area>
  </Hypocenter>
  <jmx_eb:Magnitude type="Mj" description="M3.8">3.8</jmx_eb:Magnitude>
</Earthquake>
<Observation>
  <Pref><Name>茨城県</Name><Code>08</Code><MaxInt>2</MaxInt>
    <Area><Name>茨城県北部</Name><Code>300</Code><MaxInt>2</MaxInt>
      <City><Name>小美玉市</Name><Code>0823600</Code><MaxInt>2</MaxInt>
        <IntensityStation><Name>piyo</Name><Code>0823633</Code><Int>2</Int></IntensityStation>
        <IntensityStation><Name>piyo</Name><Code>0823635</Code><Int>2</Int></IntensityStation>
      </City>
      <City><Name>水戸市</Name><Code>0820100</Code><MaxInt>1</MaxInt>
        <IntensityStation><Name>piyo</Name><Code>0820121</Code><Int>1</Int></IntensityStation>
      </City>
    </Area>
  </Pref>
</Observation>
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>