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

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

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

XMLファイルから一致するデータを取得する方法

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

■91261 / inTopicNo.1)  XMLファイルから一致するデータを取得する方法
  
□投稿者/ 河童 (54回)-(2019/06/09(Sun) 10:49:47)

分類:[.NET 全般] 

いつも大変お世話になっております。

西暦から和暦に変換したいと思っています。

和暦はXMLファイルからテーブルを読み込んで
変換する和暦の略称を取得します。
変換の形式は「R1.6月」です。

わからないことは、
変換する日付と和暦のデータをどのように一致させるかです。
令和の終了日はまだわからないので、
開始日と終了日の間というのはできなかったです。

現状は、XMLファイルの最後のデータを取得していますが、
平成や昭和に変換したいときができたときは、
やはり開始日と終了日の間にないといけないと思います。

任意の日付で和暦の略称を取得するには、
どのように処理をすればよいでしょうか?

よろしくお願いします。


和暦のXMLファイルです。
<?xml version="1.0" encoding="UTF-8"?>
<wareki>
  <data>
    <era_name>Heisei</era_name>
    <era_ryaku>H</era_ryaku>
    <era_start>19890108</era_start>
    <era_end>20190430</era_end>
  </data>
  <data>
    <era_name>Reiwa</era_name>
    <era_ryaku>R</era_ryaku>
    <era_start>20190501</era_start>
    <era_end></era_end>
  </data>
</wareki>


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;

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

        private void button1_Click(object sender, EventArgs e)
        {

            DateTime dt = DateTime.Now;
            string era = getChangeEra(dt);

        }

        #region 西暦から和暦に変換する
        //************************************************
        // 和暦の形式(R1.5月)
        // 変換できない場合は空白とする
        //************************************************
        private static string getChangeEra(DateTime pDate)
        {

            string EraName;

            try
            {
                string wdate = pDate.ToString();

                // XML ロード
                var table = XDocument.Load(@"C:\era.xml").Element("wareki");

                string era_name = "";
                string era_ryaku = "";
                string era_start = "";
                string era_end = "";

                foreach (var row in table.Elements("data"))
                {
                    era_name = row.Element("era_name").Value;
                    era_ryaku = row.Element("era_ryaku").Value;
                    era_start = row.Element("era_start").Value;
                    era_end = row.Element("era_end").Value;
                }

                // 西暦から和暦の年を取得
                int era_year = pDate.Year - int.Parse(era_start.Substring(0, 4)) + 1;

                string era_month = pDate.Month.ToString();

                // 和暦へ変換
                EraName = era_ryaku + era_year.ToString() + "." + era_month + "月";

            }
            catch (FormatException)
            {
                EraName = "";
            }

            return EraName;

        }
        #endregion
         
    }
}

引用返信 編集キー/
■91262 / inTopicNo.2)  Re[1]: XMLファイルから一致するデータを取得する方法
□投稿者/ Hongliang (823回)-(2019/06/09(Sun) 11:13:33)
data要素は昇順に並んでいるという前提で、data要素でそれぞれ、
・data要素内のデータを読み取る
・startとendをそれぞれDateTime型にする
 ・DateTime.ParseExactが便利
 ・endは空である可能性に注意する
・pDateは時刻まで含んでいるので、日付だけで比較できるようDateプロパティが返すDateTimeを使う
・日付がstartDate未満なら、空文字列を返す
・endDateを持っていない、または日付がendDate以下なら、日付とstartDateとのYearプロパティの計算で年を取得して書式化して返す
引用返信 編集キー/
■91267 / inTopicNo.3)  Re[2]: XMLファイルから一致するデータを取得する方法
□投稿者/ 河童 (55回)-(2019/06/09(Sun) 23:05:40)
Hongliang さん、お返事ありがとうございます。

処理が混雑していますが、何とかできたと思います。

和暦に変換する日付が、どの和暦の期間に入るかの
判定と期間の終了日がないときの判定も併せると混乱してしまします。

和暦略称が代入されたときを判定基準にしています。
・和暦期間の開始日と比較 
・和暦期間の終了日と比較

比較時に和暦略称を代入したり、リセットしたりしています。

もう少しわかりやすい処理や考え方あれば、勉強したいです。
先生方はどのように処理されるのでしょうか。


<?xml version="1.0" encoding="UTF-8"?>
<wareki>
  <data>
    <era_name>Meiji</era_name>
    <era_ryaku>M</era_ryaku>
    <era_start>18680125</era_start>
    <era_end>19120729</era_end>
  </data>
  <data>
    <era_name>Taisho</era_name>
    <era_ryaku>T</era_ryaku>
    <era_start>19120730</era_start>
    <era_end>19261224</era_end>
  </data>
  <data>
    <era_name>Showa</era_name>
    <era_ryaku>S</era_ryaku>
    <era_start>19261225</era_start>
    <era_end>19890107</era_end>
  </data>
  <data>
    <era_name>Heisei</era_name>
    <era_ryaku>H</era_ryaku>
    <era_start>19890108</era_start>
    <era_end>20190430</era_end>
  </data>
  <data>
    <era_name>Reiwa</era_name>
    <era_ryaku>R</era_ryaku>
    <era_start>20190501</era_start>
    <era_end></era_end>
  </data>
</wareki>


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;

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

        private void button1_Click(object sender, EventArgs e)
        {

            //DateTime dt = DateTime.Now;

            string strTime = "1989/01/07 1:10:50";
            DateTime dt = DateTime.Parse(strTime);

            string era = getChangeEra(dt);
            
            
            MessageBox.Show(era, "和暦変換");

        }

        #region 西暦から和暦に変換する
        //************************************************
        // 和暦の形式(R1.5月)
        // 変換できない場合は空白とする
        // 明治元年(1868年1月25日)	明治45年(1912年7月29日)
        // 大正	元年(1912年7月30日)	15年(1926年12月24日)
        // 昭和	元年(1926年12月25日)	64年(1989年1月7日)
        // 平成	元年(1989年1月8日)	31年(2019年4月30日)
        // 令和 元年(2019年5月1日)	未定
        //************************************************
        private static string getChangeEra(DateTime pDate)
        {

            string EraName = "";

            try
            {

                // 日時から日付のみ取得
                DateTime wdate = pDate.Date;

                // XML ロード
                var table = XDocument.Load(@"C:\era.xml").Element("wareki");

                string era_name = "";
                string era_ryaku = "";
                string era_start = "";
                string era_end = "";

                foreach (var row in table.Elements("data"))
                {
                    // XMLのデータをセット
                    era_name = row.Element("era_name").Value;
                    era_ryaku = row.Element("era_ryaku").Value;
                    era_start = row.Element("era_start").Value;
                    era_end = row.Element("era_end").Value;

                    // 開始日が空白なら読み飛ばし
                    if (era_start != "")
                    {
                        DateTime? e_start = null; // Null許容型
                        // 和暦の開始日を日付型に変換
                        e_start = DateTime.ParseExact(era_start, "yyyyMMdd", null);

                        // 日付がera_start以上なら、和暦略称を代入
                        if (e_start <= wdate)
                        {
                            EraName = era_ryaku;
                        }
                        else
                        {
                            EraName = "";
                        }
                        
                        // 和暦の終了日の有無
                        DateTime? e_end = null; // Null許容型
                        if (era_end != "")
                        {
                            // 和暦の終了日を日付型に変換
                            e_end = DateTime.ParseExact(era_end, "yyyyMMdd", null);

                            // 日付がera_end以下なら、和暦略称を代入
                            if (e_end >= wdate)
                            {
                                EraName = era_ryaku;
                            }
                            else // 日付がera_end以上なら、和暦略称をリセット
                            {
                                EraName = "";
                            }
                        }

                    }

                    // 和暦略称が入力された場合は、繰り返し中断
                    if (EraName != "")
                    {
                        // 西暦から和暦の年を取得
                        int era_year = pDate.Year - int.Parse(era_start.Substring(0, 4)) + 1;
                        // 月を取得
                        string era_month = pDate.Month.ToString();
                        // 和暦へ変換
                        EraName = era_ryaku + era_year.ToString() + "." + era_month + "月";

                        break;
                    }
 
                }

            }
            catch (FormatException)
            {
                EraName = "";
            }

            return EraName;

        }
        #endregion

引用返信 編集キー/
■91269 / inTopicNo.4)  Re[3]: XMLファイルから一致するデータを取得する方法
□投稿者/ shu (1181回)-(2019/06/10(Mon) 07:43:12)
No91267 (河童 さん) に返信

漢字であれば以下で
Dim dt = Date.Parse(TextBox1.Text)
Dim jcul As New System.Globalization.CultureInfo("ja-JP", True)
jcul.DateTimeFormat.Calendar = New System.Globalization.JapaneseCalendar()
TextBox2.Text = $"{dt.ToString("gyy/MM/dd", jcul)}"

英字にしたい場合は、レジストリから元号の漢字に対応するアルファベットを取得して
置き換えるとか。レジストリを直接使用しない方法が用意されているかは分かりません。

令和対応のUpdateが適用されていることが前提です。

引用返信 編集キー/
■91270 / inTopicNo.5)  Re[4]: XMLファイルから一致するデータを取得する方法
□投稿者/ 河童 (56回)-(2019/06/10(Mon) 10:00:57)
shu さん、お返事ありがとうございます。

申し訳ありません。.Netとなっていてますが、C#で作成しています。

今、違う問題が発生してアドバイスいただければ嬉しいです。

XMLファイルの中に日本語が入力されていると、エラーが発生します。
例えば、略称の部分を令和なら「R」→「令」にすると
「指定されたエンコードに無効な文字があります。」

XMLファイルの最初の行を
<?xml version="1.0" encoding="UTF-8"?>


<?xml version="1.0"?>
<wareki xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
に変更しても同じエラーが発生します。

日本語が含まれるXMLを読み込むにはどのようにするのでしょうか?
お教えください。よろしくお願いします。



引用返信 編集キー/
■91271 / inTopicNo.6)  Re[5]: XMLファイルから一致するデータを取得する方法
□投稿者/ とっちゃん (601回)-(2019/06/10(Mon) 10:29:10)
No91270 (河童 さん) に返信
> XMLファイルの中に日本語が入力されていると、エラーが発生します。
> 例えば、略称の部分を令和なら「R」→「令」にすると
> 「指定されたエンコードに無効な文字があります。」
>
> XMLファイルの最初の行を
> <?xml version="1.0" encoding="UTF-8"?>
>
>
> <?xml version="1.0"?>
> <wareki xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
> に変更しても同じエラーが発生します。
>
> 日本語が含まれるXMLを読み込むにはどのようにするのでしょうか?
> お教えください。よろしくお願いします。
>
<?xml ....?>
の項目で encoding を指定しない場合(デフォルト)は、UTF-8 になります。

で、漢字が化けるということからすると、ファイルとして保存されている文字コード形式が
UTF-8 になっていないのだと思います。

昨今なら、メモ帳でも UTF-8 で保存できるので、どの文字コード形式で保存されているかを確認してみてください。

引用返信 編集キー/
■91273 / inTopicNo.7)  Re[4]: XMLファイルから一致するデータを取得する方法
□投稿者/ 魔界の仮面弁士 (2200回)-(2019/06/10(Mon) 11:12:20)
No91269 (shu さん) に返信
> 漢字であれば以下で
> Dim dt = Date.Parse(TextBox1.Text)

質問投稿が C# コードだったのに、何で例示コードが
Visual Basic なんだろう……と思ったら、
質問時の分類が [C#] ではなく [.NET 全般] になっていたんですね。


> TextBox2.Text = $"{dt.ToString("gyy/MM/dd", jcul)}"

$ で始まる文字列表記は、VS2015 以降(C# 6.0 以上/VB14 以上)で使用可能な構文ですね。
河童 さんの環境は VS2010 だったかも。


> 令和対応のUpdateが適用されていることが前提です。

ということで、自分も書いてみました。
ただし下記の場合、
 1912/07/30 → 明治45年でもあり大正元年でもある
 1926/12/25 → 大正15年でもあり昭和元年でもある
のように「元号が被る期間」については、新元号が優先されます。



// using System.Globalization;

/// <returns>R1.6月</returns>
private static string getChangeEra(DateTime pDate)
{
  var jp = new JapaneseCalendar();
  if (pDate < jp.MinSupportedDateTime) { return ""; }
  var jpCal = new CultureInfo("ja-JP", true) { DateTimeFormat = { Calendar = jp } };
  if (eraTable == null)
  {
    eraTable = (from value in new int[] { '?' }
            .Concat(Enumerable.Range('A', 26))
            .Select(c => ((char)c).ToString())
          let key = jpCal.DateTimeFormat.GetEra(value)
          where key > 0
          select new { key, value })
          .ToDictionary(_ => _.key, _ => _.value);
  }
  return eraTable[jp.GetEra(pDate)] + pDate.ToString("y'.'M月", jpCal);
}
private static Dictionary<int, string> eraTable = null;

#region おまけ
/// <returns>令和元年6月10日</returns>
private static string Sample1(DateTime pDate)
{
  var jpCal = new CultureInfo("ja-JP", true) { DateTimeFormat = { Calendar = new JapaneseCalendar() } };
  return pDate.ToString("gy年M月d日", jpCal);
}

/// <returns>令和1年6月10日</returns>
private static string Sample2(DateTime pDate)
{
  var jpCal = new CultureInfo("ja-JP", true) { DateTimeFormat = { Calendar = new JapaneseCalendar() } };
  return string.Format(jpCal, "{0:gy}年{0:M月d日}", pDate);
}
#endregion



== 元号表 ==
「★」は複数の元号が競合する日付
「☆」は旧暦(太陰太陽暦)が使われていた日付

 2019/05/01 → 「令和元年5月1日」
 2019/04/30 → 「平成31年4月30日」
   :
 1989/01/08 → 「平成元年1月8日」
 1989/01/07 → 「昭和64年1月7日」
   :
 1926/12/26 → 「昭和元年12月26日」
★1926/12/25 → 「大正15年12月25日」かつ「昭和元年12月25日」
 1926/12/24 → 「大正15年12月24日」
   :
 1912/07/31 → 「大正元年7月31日」
★1912/07/30 → 「明治45年7月30日」かつ「大正元年7月30日」
 1912/07/29 → 「明治45年7月29日」
   :
 1873/01/01 → 「明治6年1月1日」  …これより後はグレゴリオ暦
☆1872/12/31 → 「明治5年12月2日」 …これより前は天保暦
☆  :
☆1868/10/24 → 「明治元年9月9日」
★1868/10/23 → 「慶應4年9月8日」かつ「明治元年9月8日」 …JapaneseCalendarで扱える最小日付
★  :
★1868/01/25 → 「慶應4年1月1日」かつ「明治元年1月1日」
☆1868/01/24 → 「慶應3年12月30日」
☆  :
☆1865/05/02 → 「慶應元年4月8日」
★1865/05/01 → 「元治2年4月7日」かつ「慶應元年4月7日」
☆1865/04/30 → 「元治2年4月6日」
☆  :
引用返信 編集キー/
■91283 / inTopicNo.8)  Re[5]: XMLファイルから一致するデータを取得する方法
□投稿者/ 河童 (57回)-(2019/06/11(Tue) 17:14:58)
こんばんは。

とっちゃん さん、お返事ありがとうございます。
メモ帳で文字コードを「UTF-8」で保存したら、エラーがなくなりました。
ありがとうございました。

魔界の仮面弁士 さん、お返事ありがとうございます。
教えてくださいましたコードで和暦の略称を所得することができました。
コードが高度すぎて全然理解できていませんが、興味深いです。
スマートなコードは難しいですね。


解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


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

このトピックに書きこむ