XML ostaje kornjač razmjene zdravstvenih podataka, omogućuje HL7 poruke, poduzetničke integracijske motore i naslijeđene bolničke informacijske sustave. pretvaranje metapodataka DICOM-a u XML omogućava bezuvjetnu integraciju između medicinskih slikarskih sustava i šire IT infrastrukture zdravstvene skrbi. Ovaj vodič pokazuje kako pretvoriti DIKOM na XML pomoću Aspose.Medical za .NET.

Zašto XML za zdravstveno osiguranje?

Dok JSON dominira modernim web API-ima, XML i dalje je neophodan u zdravstvenoj skrbi iz nekoliko razloga:

  • HL7 standardi: HL7 v2 i v3 poruke koriste XML formate široko
  • Integracija poduzeća: Mnogi motori za integraciju zdravstvene skrbi (Mirth Connect, Rhapsody) uglavnom rade s XML-om
  • Legacy sustavi: Ugrađeni bolnički informacijski sistemi često zahtijevaju XML datoteke
  • Dokumentni standardi: CDA (Clinical Document Architecture) i drugi klinički dokumenti koriste XML
  • Validacija: XML Schema (XSD) pruža snažne sposobnosti za validaciju podataka

DICOM za XML konverziju

Najjednostavnija konverzija od DICOM-a na 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);
        }
    }
}

Formatiran XML izlazak

Za ljudsko čitavu proizvodnju i debugiranje:

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;
}

Konverzija: XML na DICOM

Konvertirati XML nazad na DICOM za bilateralne radne tokove:

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}");
    }
}

Izgradnja HL7 integracijskog mosta

Stvorite uslugu koja pretvara DICOM metapodatke u HL7-kompatibilni 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();
    }
}

Integracija s zdravstvenim sredstvima

Stvorite uslugu za motore za integraciju poduzeća:

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();
    }
}

Batch Prerađivanje za poduzetničku migraciju

Upravljanje velikim razmjerom konverzije DICOM-a na XML za migracije sustava:

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 za XML konverziju

Stvaranje web krajnjih točaka za konverziju na zahtjev:

[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 validacija s rasporedom

Validacija konvertiranog XML-a protiv prilagođene sheme:

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;
    }
}

Najbolje prakse

Pri pretvaranju DICOM-a u XML za integraciju zdravstvene skrbi:

  • Održavanje kodiranja: osigurajte da se kodiranje karaktera tretira ispravno, osobito za međunarodne imena pacijenata
  • Trgovanje binarnim podacima: Veličanstveni pixel podaci trebaju se upućivati vanjski umjesto da se ugrađuju u XML
  • Validacija rezultata: Koristite validaciju XML sheme za kritične integracijske točke
  • Consider performanse: Za velike arhive, koristite serijalizaciju i paralelnu obradu
  • Mapiranje dokumenata: Održavajte jasnu dokumentaciju o tome kako DICOM označava mapu na XML strukturu

zaključak

Konvertirajući DICOM datoteke u XML omogućuje integraciju s poslovnim zdravstvenim sustavima, HL7 poruke i nasljednih aplikacija. Aspose.Medical za .NET pruža snažne serializirane sposobnosti s podrškom za konverziju okruglo-trip, osiguravajući integritet podataka kroz transformacije formata. Bilo da gradite integracijske mostove, migrirate podatke ili se povezujete s bolničkim informacijskim sustavom, ove tehnike konverzije XML pružaju čvrstu osnovu za interoperabilnost zdravstvene skrbi.

Za više informacija o DICOM XML serializiranju, posjetite Aspose.Medicinske dokumentacije.

More in this category