XMLは、医療データの交換、HL7メッセージ、企業統合エンジン、および遺産病院情報システムを強化する角の石であり続けています。DICOMメタデータをXMLに変換すると、医学イメージシステムとより広範な医療ITインフラストラクチャの間の無限の組み合わせが可能になります。このガイドでは、Aspose.Medical for .NET を使用してDIKOM を XML に転換する方法を示しています。
なぜXMLは健康保健統合のためのものですか?
JSON が現代の Web APIs を支配している間、XML は、いくつかの理由で医療に不可欠です。
- HL7標準:HL7 v2 および v3 メッセージは、XML ベースのフォーマットを広く使用します。
- エンタープライズ統合:多くの保健整合エンジン(Mirth Connect、Rhapsody)は主にXMLで動作します。
- Legacy システム:設立された病院情報システムには、XML データフィードが必要です。
- ドキュメント基準:CDA(臨床文書アーキテクチャ)およびその他のクリニック文献はXMLを使用します。
- 認証: XML スケジュール(XSD)は、強力なデータ認定機能を提供します。
DICOM から XML への変換
DICOM から XML に変換する最も簡単な方法:
using Aspose.Medical.Dicom;
using Aspose.Medical.Dicom.Serialization;
public class DicomXmlConverter
{
public string ConvertToXml(string dicomFilePath)
{
// Load DICOM file
DicomFile dicomFile = DicomFile.Open(dicomFilePath);
// Serialize to XML string
string xml = DicomXmlSerializer.Serialize(dicomFile.Dataset);
return xml;
}
public void ConvertToXmlFile(string dicomFilePath, string outputXmlPath)
{
DicomFile dicomFile = DicomFile.Open(dicomFilePath);
using (var stream = new FileStream(outputXmlPath, FileMode.Create))
{
DicomXmlSerializer.Serialize(stream, dicomFile.Dataset);
}
}
}
フォーマット XML 出力
人間で読めやすい生産とデブギング:
public string ConvertToFormattedXml(string dicomFilePath)
{
DicomFile dicomFile = DicomFile.Open(dicomFilePath);
var options = new DicomXmlSerializerOptions
{
WriteIndented = true // Pretty-print XML
};
string xml = DicomXmlSerializer.Serialize(dicomFile.Dataset, options);
return xml;
}
ラウンドトリップ変換: XML から DICOM
XML を DICOM に変換して、二方向のワークフロー:
public class DicomXmlRoundTrip
{
public void XmlToDicom(string xmlFilePath, string outputDicomPath)
{
// Read XML content
string xml = File.ReadAllText(xmlFilePath);
// Deserialize to DICOM dataset
DicomDataset dataset = DicomXmlSerializer.Deserialize(xml);
// Create DICOM file and save
DicomFile dicomFile = new DicomFile(dataset);
dicomFile.Save(outputDicomPath);
}
public DicomDataset XmlStringToDataset(string xml)
{
return DicomXmlSerializer.Deserialize(xml);
}
public void ValidateRoundTrip(string originalDicomPath)
{
// Load original
DicomFile original = DicomFile.Open(originalDicomPath);
// Convert to XML
string xml = DicomXmlSerializer.Serialize(original.Dataset);
// Convert back to DICOM
DicomDataset restored = DicomXmlSerializer.Deserialize(xml);
// Compare key fields
string originalPatientName = original.Dataset.GetString(DicomTag.PatientName);
string restoredPatientName = restored.GetString(DicomTag.PatientName);
Console.WriteLine($"Original Patient Name: {originalPatientName}");
Console.WriteLine($"Restored Patient Name: {restoredPatientName}");
Console.WriteLine($"Match: {originalPatientName == restoredPatientName}");
}
}
HL7統合橋の建設
DICOM メタデータを HL7 互換性のある XML に変換するサービスを作成します。
using System.Xml.Linq;
public class DicomHl7Bridge
{
public string ConvertToHl7CompatibleXml(string dicomFilePath)
{
DicomFile dicomFile = DicomFile.Open(dicomFilePath);
var dataset = dicomFile.Dataset;
// Create HL7-style XML structure
var hl7Message = new XElement("ORU_R01",
new XAttribute("xmlns", "urn:hl7-org:v2xml"),
// Message Header
new XElement("MSH",
new XElement("MSH.1", "|"),
new XElement("MSH.2", "^~\\&"),
new XElement("MSH.3", "PACS"),
new XElement("MSH.4", dataset.GetString(DicomTag.InstitutionName) ?? ""),
new XElement("MSH.7", DateTime.Now.ToString("yyyyMMddHHmmss")),
new XElement("MSH.9",
new XElement("MSG.1", "ORU"),
new XElement("MSG.2", "R01")),
new XElement("MSH.10", Guid.NewGuid().ToString()),
new XElement("MSH.11", "P"),
new XElement("MSH.12", "2.5.1")
),
// Patient Identification
new XElement("PID",
new XElement("PID.3",
new XElement("CX.1", dataset.GetString(DicomTag.PatientID) ?? "")),
new XElement("PID.5",
new XElement("XPN.1", dataset.GetString(DicomTag.PatientName) ?? "")),
new XElement("PID.7", dataset.GetString(DicomTag.PatientBirthDate) ?? ""),
new XElement("PID.8", dataset.GetString(DicomTag.PatientSex) ?? "")
),
// Order Information
new XElement("OBR",
new XElement("OBR.2", dataset.GetString(DicomTag.AccessionNumber) ?? ""),
new XElement("OBR.4",
new XElement("CE.1", dataset.GetString(DicomTag.Modality) ?? ""),
new XElement("CE.2", dataset.GetString(DicomTag.StudyDescription) ?? "")),
new XElement("OBR.7", dataset.GetString(DicomTag.StudyDate) ?? ""),
new XElement("OBR.24", "RAD")
),
// Observation with DICOM reference
new XElement("OBX",
new XElement("OBX.2", "RP"),
new XElement("OBX.3",
new XElement("CE.1", "DICOM"),
new XElement("CE.2", "DICOM Study")),
new XElement("OBX.5", dataset.GetString(DicomTag.StudyInstanceUID) ?? ""),
new XElement("OBX.11", "F")
)
);
return hl7Message.ToString();
}
}
ヘルスケア・ミッドウェアとの統合
企業統合エンジンのためのサービスを作成する:
public class HealthcareIntegrationService
{
private readonly string _outputDirectory;
private readonly ILogger _logger;
public HealthcareIntegrationService(string outputDirectory, ILogger logger)
{
_outputDirectory = outputDirectory;
_logger = logger;
}
public async Task ProcessDicomForIntegration(string dicomFilePath)
{
try
{
DicomFile dicomFile = DicomFile.Open(dicomFilePath);
var dataset = dicomFile.Dataset;
string accessionNumber = dataset.GetString(DicomTag.AccessionNumber) ??
Guid.NewGuid().ToString();
// Generate standard DICOM XML
string dicomXml = DicomXmlSerializer.Serialize(dataset,
new DicomXmlSerializerOptions { WriteIndented = true });
// Save DICOM XML
string dicomXmlPath = Path.Combine(_outputDirectory, $"{accessionNumber}_dicom.xml");
await File.WriteAllTextAsync(dicomXmlPath, dicomXml);
// Generate HL7 bridge XML
var bridge = new DicomHl7Bridge();
string hl7Xml = bridge.ConvertToHl7CompatibleXml(dicomFilePath);
string hl7XmlPath = Path.Combine(_outputDirectory, $"{accessionNumber}_hl7.xml");
await File.WriteAllTextAsync(hl7XmlPath, hl7Xml);
// Generate metadata summary for quick lookup
var summary = GenerateMetadataSummary(dataset, accessionNumber);
string summaryPath = Path.Combine(_outputDirectory, $"{accessionNumber}_summary.xml");
await File.WriteAllTextAsync(summaryPath, summary);
_logger.LogInformation($"Processed DICOM file: {accessionNumber}");
}
catch (Exception ex)
{
_logger.LogError($"Failed to process {dicomFilePath}: {ex.Message}");
throw;
}
}
private string GenerateMetadataSummary(DicomDataset dataset, string accessionNumber)
{
var summary = new XElement("DicomMetadataSummary",
new XAttribute("timestamp", DateTime.UtcNow.ToString("O")),
new XElement("Identifiers",
new XElement("AccessionNumber", accessionNumber),
new XElement("StudyInstanceUID", dataset.GetString(DicomTag.StudyInstanceUID)),
new XElement("SeriesInstanceUID", dataset.GetString(DicomTag.SeriesInstanceUID)),
new XElement("SOPInstanceUID", dataset.GetString(DicomTag.SOPInstanceUID))
),
new XElement("Patient",
new XElement("ID", dataset.GetString(DicomTag.PatientID)),
new XElement("Name", dataset.GetString(DicomTag.PatientName)),
new XElement("BirthDate", dataset.GetString(DicomTag.PatientBirthDate)),
new XElement("Sex", dataset.GetString(DicomTag.PatientSex))
),
new XElement("Study",
new XElement("Date", dataset.GetString(DicomTag.StudyDate)),
new XElement("Time", dataset.GetString(DicomTag.StudyTime)),
new XElement("Description", dataset.GetString(DicomTag.StudyDescription)),
new XElement("ReferringPhysician", dataset.GetString(DicomTag.ReferringPhysicianName))
),
new XElement("Series",
new XElement("Modality", dataset.GetString(DicomTag.Modality)),
new XElement("Description", dataset.GetString(DicomTag.SeriesDescription)),
new XElement("BodyPart", dataset.GetString(DicomTag.BodyPartExamined))
),
new XElement("Equipment",
new XElement("Manufacturer", dataset.GetString(DicomTag.Manufacturer)),
new XElement("Model", dataset.GetString(DicomTag.ManufacturerModelName)),
new XElement("StationName", dataset.GetString(DicomTag.StationName)),
new XElement("Institution", dataset.GetString(DicomTag.InstitutionName))
)
);
return summary.ToString();
}
}
企業移民のためのバッチ処理
システム移行のための大規模なDICOMからXMLへの変換を処理する:
public class EnterpriseMigrationService
{
public async Task MigrateDicomArchiveToXml(
string sourceDirectory,
string targetDirectory,
int maxParallelism = 4)
{
Directory.CreateDirectory(targetDirectory);
var dicomFiles = Directory.GetFiles(sourceDirectory, "*.dcm", SearchOption.AllDirectories);
var semaphore = new SemaphoreSlim(maxParallelism);
var tasks = new List<Task>();
var progress = 0;
var total = dicomFiles.Length;
foreach (var filePath in dicomFiles)
{
await semaphore.WaitAsync();
tasks.Add(Task.Run(async () =>
{
try
{
await ConvertSingleFile(filePath, sourceDirectory, targetDirectory);
var current = Interlocked.Increment(ref progress);
if (current % 100 == 0)
{
Console.WriteLine($"Progress: {current}/{total} files processed");
}
}
finally
{
semaphore.Release();
}
}));
}
await Task.WhenAll(tasks);
Console.WriteLine($"Migration complete: {total} files processed");
}
private async Task ConvertSingleFile(
string sourcePath,
string sourceRoot,
string targetRoot)
{
try
{
DicomFile dicomFile = DicomFile.Open(sourcePath);
// Preserve directory structure
string relativePath = Path.GetRelativePath(sourceRoot, sourcePath);
string targetPath = Path.Combine(targetRoot,
Path.ChangeExtension(relativePath, ".xml"));
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
var options = new DicomXmlSerializerOptions { WriteIndented = true };
using (var stream = new FileStream(targetPath, FileMode.Create))
{
DicomXmlSerializer.Serialize(stream, dicomFile.Dataset, options);
}
}
catch (Exception ex)
{
// Log error but continue processing
await File.AppendAllTextAsync(
Path.Combine(targetRoot, "errors.log"),
$"{DateTime.Now}: {sourcePath} - {ex.Message}\n");
}
}
}
ASP.NET Core API for XML コンバージョン
On-demand 変換のための Web エンドポイントを作成する:
[ApiController]
[Route("api/[controller]")]
public class DicomXmlController : ControllerBase
{
[HttpPost("convert")]
[Produces("application/xml")]
public async Task<IActionResult> ConvertToXml(IFormFile file)
{
if (file == null || file.Length == 0)
{
return BadRequest("No DICOM file provided");
}
var tempPath = Path.GetTempFileName();
try
{
using (var stream = new FileStream(tempPath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
DicomFile dicomFile = DicomFile.Open(tempPath);
var options = new DicomXmlSerializerOptions { WriteIndented = true };
string xml = DicomXmlSerializer.Serialize(dicomFile.Dataset, options);
return Content(xml, "application/xml");
}
finally
{
System.IO.File.Delete(tempPath);
}
}
[HttpPost("to-hl7")]
[Produces("application/xml")]
public async Task<IActionResult> ConvertToHl7(IFormFile file)
{
if (file == null || file.Length == 0)
{
return BadRequest("No DICOM file provided");
}
var tempPath = Path.GetTempFileName();
try
{
using (var stream = new FileStream(tempPath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
var bridge = new DicomHl7Bridge();
string hl7Xml = bridge.ConvertToHl7CompatibleXml(tempPath);
return Content(hl7Xml, "application/xml");
}
finally
{
System.IO.File.Delete(tempPath);
}
}
[HttpPost("from-xml")]
public async Task<IActionResult> ConvertFromXml()
{
using var reader = new StreamReader(Request.Body);
string xml = await reader.ReadToEndAsync();
try
{
DicomDataset dataset = DicomXmlSerializer.Deserialize(xml);
DicomFile dicomFile = new DicomFile(dataset);
var memoryStream = new MemoryStream();
dicomFile.Save(memoryStream);
memoryStream.Position = 0;
return File(memoryStream, "application/dicom", "converted.dcm");
}
catch (Exception ex)
{
return BadRequest($"Invalid XML: {ex.Message}");
}
}
}
XML スケジュールによる認証
カスタマイズされたスケジュールに対して変換されたXMLを有効にする:
using System.Xml;
using System.Xml.Schema;
public class DicomXmlValidator
{
private readonly XmlSchemaSet _schemaSet;
private readonly List<string> _validationErrors;
public DicomXmlValidator(string schemaPath)
{
_schemaSet = new XmlSchemaSet();
_schemaSet.Add(null, schemaPath);
_validationErrors = new List<string>();
}
public bool ValidateXml(string xml, out List<string> errors)
{
_validationErrors.Clear();
var settings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
Schemas = _schemaSet
};
settings.ValidationEventHandler += (sender, e) =>
{
_validationErrors.Add($"{e.Severity}: {e.Message}");
};
try
{
using (var stringReader = new StringReader(xml))
using (var xmlReader = XmlReader.Create(stringReader, settings))
{
while (xmlReader.Read()) { }
}
}
catch (XmlException ex)
{
_validationErrors.Add($"XML Error: {ex.Message}");
}
errors = new List<string>(_validationErrors);
return errors.Count == 0;
}
}
ベストプラクティス
医療統合のためのDICOMをXMLに変換するとき:
- コードを保存する: 特に国際的な患者名の場合、キャラクターコーディングが正しく処理されていることを保証します。
- ハンドルバイナリーデータ:大きなピクセルデータはXMLに組み込まれるのではなく、外部に参照する必要があります。
- 出力確認:重要な統合ポイントのためのXMLスケジュール認証を使用する
- Consider パフォーマンス: 大型アーカイブの場合は、ストリーミングシリアリズムおよびパラレル処理を使用します。
- ドキュメントマッピング:DICOMがあなたのXML構造に地図をタグする方法の明確な文書化を維持する
結論
DICOM ファイルを XML に変換すると、企業の医療システム、HL7 メッセージング、および遺産アプリケーションとの統合が可能になります. Aspose.Medical for .NET は、サークルトリップ転換のサポートを備えた強力なセリアリズム機能を提供し、フォーマット変革を通じてデータの完全性を確保します。
DICOM XML シリアリズムに関する詳細については、 メディカル・ドキュメンタリー.