XML은 건강 관리 데이터 교환, HL7 메시지, 기업 통합 엔진 및 유산 병원 정보 시스템을 강화하는 기둥으로 남아 있습니다. DICOM 메타 데이터를 XML으로 변환하면 의료 이미지 시스템과 더 광범위한 의료 IT 인프라 사이의 무조건 통화를 가능하게합니다.이 가이드는 Aspose.Medical을 사용하여 DIKOM을 XML로 변형하는 방법을 보여줍니다. .NET.

왜 건강 관리 통합을위한 XML?

JSON은 현대 웹 APIs를 지배하지만 XML은 여러 가지 이유로 건강 관리에 필수적입니다.

  • HL7 표준: HL7 v2 및 v3 메시지는 XML 기반 형식을 광범위하게 사용합니다.
  • 기업 통합 : 많은 의료 통신 엔진 (Mirth Connect, Rhapsody)은 주로 XML과 함께 작동합니다.
  • Legacy 시스템: 설립된 병원 정보 시스템은 종종 XML 데이터 피드를 필요로합니다.
  • 문서 표준: CDA (Clinical Document Architecture) 및 기타 임상 문서 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();
    }
}

Healthcare Middleware와의 통합

기업 통합 엔진을위한 서비스 만들기 :

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 코어 API XML 변환

On-demand 변환을 위한 웹 엔드 포인트 만들기:

[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 성능: 대형 아카이브의 경우 스트리밍 시리화 및 병렬 처리 사용
  • Document Mappings: DICOM이 XML 구조에 지도를 표시하는 방법에 대한 명확한 문서를 유지하십시오.

결론

DICOM 파일을 XML으로 변환하면 기업 건강 관리 시스템, HL7 메시지 및 유산 응용 프로그램과의 통합이 가능합니다. Aspose.Medical for .NET은 둥근 트리프 전환을 지원하는 강력한 시리화 능력을 제공하며, 형식 변형을 통해 데이터의 무결성을 보장하고 있습니다. 당신이 통신 다리를 구축하고, 데이터를 이주하거나, 병원 정보 시스템에 연결하는지 여부, 이러한 XML 전송 기술은 의료 상호 작용을위한 견고한 기초를 제공한다.

DICOM XML 시리즈에 대한 자세한 내용은 다음을 참조하십시오. ASPOSE. 의료 문서.

More in this category