xb
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace XbrlParser
{
public class XbrlDocument
{
private readonly XDocument _document;
private readonly XNamespace _xbrli = "http://www.xbrl.org/2003/instance";
private readonly Dictionary<string, XNamespace> _namespaces;
public XbrlDocument(string filePath)
{
_document = XDocument.Load(filePath);
_namespaces = _document.Root.Attributes()
.Where(a => a.IsNamespaceDeclaration)
.GroupBy(
a => a.Name.Namespace == XNamespace.None ? "" : a.Name.LocalName,
a => XNamespace.Get(a.Value))
.ToDictionary(g => g.Key, g => g.First());
}
/// <summary>
/// 要素名と年度を指定して値を取得します。
/// </summary>
/// <param name="elementName">要素名(プレフィックス付き)</param>
/// <param name="year">年度(YYYY形式)</param>
/// <returns>該当する値。見つからない場合はnull。</returns>
public string GetValue(string elementName, int year)
{
var parts = elementName.Split(':');
if (parts.Length != 2)
throw new ArgumentException("要素名はプレフィックス付きで指定してください。例: gaap:Assets");
var prefix = parts[0];
var localName = parts[1];
if (!_namespaces.ContainsKey(prefix))
throw new ArgumentException($"名前空間プレフィックス '{prefix}' が見つかりません。");
var ns = _namespaces[prefix];
// 指定した年度のコンテキストを取得
var contextRefs = GetContextRefsByYear(year);
if (contextRefs == null || !contextRefs.Any())
return null;
// 要素を検索
var elements = _document.Descendants(ns + localName)
.Where(e => e.Attribute("contextRef") != null && contextRefs.Contains(e.Attribute("contextRef").Value));
var element = elements.FirstOrDefault();
return element?.Value;
}
/// <summary>
/// 指定した年度に対応するコンテキストIDのリストを取得します。
/// </summary>
/// <param name="year">年度(YYYY形式)</param>
/// <returns>コンテキストIDのリスト。見つからない場合は空のリスト。</returns>
private List<string> GetContextRefsByYear(int year)
{
var contextRefs = new List<string>();
// コンテキスト要素を取得
var contexts = _document.Descendants(_xbrli + "context");
foreach (var context in contexts)
{
var period = context.Element(_xbrli + "period");
if (period == null)
continue;
var instant = period.Element(_xbrli + "instant");
var startDate = period.Element(_xbrli + "startDate");
var endDate = period.Element(_xbrli + "endDate");
DateTime contextDate;
if (instant != null && DateTime.TryParse(instant.Value, out contextDate))
{
if (contextDate.Year == year)
contextRefs.Add(context.Attribute("id")?.Value);
}
else if (startDate != null && endDate != null &&
DateTime.TryParse(endDate.Value, out contextDate))
{
if (contextDate.Year == year)
contextRefs.Add(context.Attribute("id")?.Value);
}
}
return contextRefs;
}
/// <summary>
/// 名前空間URIを取得します。
/// </summary>
/// <param name="prefix">名前空間プレフィックス</param>
/// <returns>名前空間URI。見つからない場合はnull。</returns>
public string GetNamespaceUri(string prefix)
{
if (_namespaces.ContainsKey(prefix))
return _namespaces[prefix].NamespaceName;
return null;
}
}
}
使用例
using System;
using XbrlParser;
namespace XbrlExample
{
class Program
{
static void Main(string[] args)
{
// XBRLファイルのパスを指定
var xbrlFilePath = "sample.xbrl";
// XbrlDocumentオブジェクトを作成
var xbrlDoc = new XbrlDocument(xbrlFilePath);
// 要素名と年度を指定して値を取得
var elementName = "gaap:Assets";
int year = 2022;
var value = xbrlDoc.GetValue(elementName, year);
if (value != null)
{
Console.WriteLine($"{year}年の{elementName}の値は {value} です。");
}
else
{
Console.WriteLine($"{year}年の{elementName}の値が見つかりませんでした。");
}
// 名前空間URIを取得
var namespaceUri = xbrlDoc.GetNamespaceUri("gaap");
if (namespaceUri != null)
{
Console.WriteLine($"プレフィックス 'gaap' の名前空間URIは {namespaceUri} です。");
}
else
{
Console.WriteLine("名前空間プレフィックス 'gaap' が見つかりませんでした。");
}
}
}
}