An Nhax file is a file format that is used to export/import data from Noah.
A Nhax file is mix of binary data and XML formatted data the so called sections. As the Nhax format is complex and hard to implement HIMSA has developed a standalone library that can be used by business system developers that must support the Nhax format.
Extension to Old Nhax Format
The data in Nhax sections is defined using XSD files. All data must validate with respect to the XSD when reading/writing Nhax files.
The Misc section is now used and is defined in and XSD file.
Link to binary Nhax format: Noah 4 Extended Native Format (Nhax and Enhax)
Link to XML Sections in Nhax Files: XML Sections in Nhax Files
Error Handling
NhaxLib functions returns a ValidateResult class:
public class ValidateResult
{
/// <summary>
/// Set to false if an error occurs
/// </summary>
public bool Validated { get; private set; }
// Error code
public ErrorCode ErrorCode { get; private set; }
/// <summary>
/// Textual description of the failing entity
/// </summary>
public string ErrorEntity { get; private set; }
/// <summary>
/// Textual description of the error
/// </summary>
public string ErrorDescription { get; private set; }
}
Furthermore functions may throw exceptions.
Nhax Writer
The Nhax writer writes Noah data to a Nhax file or a stream. When writing data to a file the NhaxWriter will either produce a number of files of a given max size or one file that contains all data or all data written to a stream.
/// <summary>
/// Write all data to one Nhax file.
/// </summary>
/// <param name="fullPath">Full path to Nhax file</param>
/// <param name="password">Password to access the file</param>
/// <param name="nhaxFileCreatedCallback">Function called when Nhax file is written. The function is called with the name of the file that is written. Can be set to null.</param>
/// <param name="overwriteExistingFiles">True existing files will be overwritten. If false an error will be reported if file exists.</param>
/// <param name="compressData">If true data are compressed</param>
public NhaxWriter(string fullPath, string password, NhaxFileCreatedCallback nhaxFileCreatedCallback = null, bool overwriteExistingFiles = false, bool compressData = true)
/// <summary>
/// NhaxWriter constructor that writes data to one or more Nhax files.
/// If more than one Nhax file are created the file will contain a Misc section containing al Misc data provided. The user section will only contain users that are referenced by patients or actions.
/// </summary>
/// <param name="path">Path where the files is stored</param>
/// <param name="filePrefix">The prefix of the Nhax file. The file name is "filePrefix-dddddd" where d is digit e.g. "file-000001", "file-000002"</param>
/// <param name="password">Password to access the file</param>
/// <param name="nhaxFileCreatedCallback">Function called when Nhax file is written. The function is called with the name of the file that is written. Can be set to null.</param>
/// <param name="overwriteExistingFiles">True existing files will be overwritten. If false an error will be reported if file exists.</param>
/// <param name="compressData">If true data are compressed</param>
/// <param name="maxFileSize">Max size of created file. When this size is reached a new Nhax file is created and data written to this file.</param>
/// <param name="maxPatients">Max patients written to file. When this size is reached new Nhax file is created and data written to this file.</param>
public NhaxWriter(string path, string filePrefix, string password, NhaxFileCreatedCallback nhaxFileCreatedCallback = null, bool overwriteExistingFiles = false, bool compressData = true, long maxFileSize = ConstMaxFileSize, int maxPatients=ConstMaxPatients)
When the NhaxWriter instance has been created WriteUsers and WriteMiscData must be called in order to add users and add Misc data to the Nhax file. These functions must be called before the WritePatient is called. Each call of WritePatient will add a patient to the Nhax file.
If using the constructor that takes maxFileSize argument a new Nhax file is created when the file size exceeds the maxFileSize after a patient is written. When start writing a new Nhax file the nhaxFileCreatedCallback is called with name of created Nhax file. The default size of maxFileSize is the advised size when generating Nhax file that is used when migrating to NoahES.
It is possible to call the WriteUsers multiple times. When writing patient data - WritePatient - the user referred from a patient data must be known.
IMPORTANT: Be aware that the Nhax Writer implements the idisposable interface. It is important that dispose is called in order to update the binary part of the Nhax file correctly.
Nhax Reader
The Nhax reader reads data from an Nhax file or a stream that contains an Nhax file. The Nhax reader can be initialized with file or a stream.
/// <summary>
/// Initializing Nhax file reader
/// </summary>
/// <param name="password">Password if Nhax file is encrypted</param>
public ValidateResult Initialize(string filePath, string password)
/// <summary>
/// Initializing Nhax stream reader
/// </summary>
/// <param name="inStream">Stream that contains Nhax formatted data</param>
/// <param name="password">Password if Nhax data is encrypted</param>
/// <returns></returns>
public ValidateResult Initialize(Stream inStream, string password)
Be aware that the Nhax reader implements the idisposable interface. It is important to called the dispose function.
When reading large Nhax files it is recommended to read a moderate number of patients.
Nhax Logger Interface
Logging in NhaxLib can be enabled either by implementing the Nhax logger interface INhaxLogger or create and use the simple logger that NhaxLib implements. The logger must be added using NhaxLogger.AddLogger.
Using the NhaxLib logger:
string logPath = @"c:\..."
INhaxLogger Logger = NhaxLogger.CreateLogger(logPath, true, 10 * 1024 * 1024);
NhaxLogger.AddLogger(Logger, NhaxLogLevel.Debug);
Sample
using Himsa.Noah.NhaxLib; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace NhaxFileSplit { internal class NhaxFileSplit { private static INhaxLogger Logger; private static string ExeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); private static Guid CreatedByGuid = Guid.Parse("08d794ca-012f-4785-9f0d-d0aa42564f1f"); static bool InitLogger() { // initialise a logger used by Nhax lib int logMaxSizeBytes = 10 * 1024 * 1024; if (ExeDir == null) { Console.WriteLine("Error: failed to get path to executing assembly"); return false; } string logPath = Path.Combine(ExeDir, "NhaxFileSplit.log"); Logger = NhaxLogger.CreateLogger(logPath, true, logMaxSizeBytes); NhaxLogger.AddLogger(Logger, NhaxLogLevel.Debug); return true; } static string ToBase64EncodedString(string s) { if (s == null) return null; return Convert.ToBase64String(Encoding.UTF8.GetBytes(s)); } static string FromBase64EncodedString(string s) { if (s == null) return null; byte[] ba = Convert.FromBase64String(s); return System.Text.Encoding.UTF8.GetString(ba); } static bool ValidateResultFailed( ValidateResult vr) { if (!vr.Validated) return true; Console.WriteLine("Error: ValiedateResult {0}", vr.ToString()); return false; } static void NhaxFileCallback(string pathToFileCreated) { Console.WriteLine("Nhax file created: {0}", pathToFileCreated); } static bool ReadWriteNhaxFile(string inputFile) { int skip = 0, take = 3; // Number of patients read in each iteration List<NhaxUser> users; List<NhaxPatient> patients; int maxFileSize = 1; // One patient per Nhax file (size og written a Nhax file will always be greater than 1) string privateDataBase64Encoded = ToBase64EncodedString("Test saving private data"); using (NhaxWriter writer = new NhaxWriter( ExeDir, "test", null, NhaxFileCallback, true, true, maxFileSize)) { using (NhaxReader reader = new NhaxReader()) { if (ValidateResultFailed(reader.Initialize(inputFile, null))) return false; NhaxMiscData miscData = reader.ReadMiscData(); if (ValidateResultFailed(reader.ReadUsers(out users))) return false; // Users and misc data must be written before patients is written to Nhax file if (ValidateResultFailed(writer.WriteMiscData("NhaxFileSplit", CreatedByGuid, privateDataBase64Encoded))) return false; if (ValidateResultFailed(writer.WriteUsers(users))) return false; int noOfPatients = reader.NoOfPatients(); while (skip < noOfPatients) { if (skip + take > noOfPatients) take = Math.Min(take, noOfPatients - skip); if (ValidateResultFailed(reader.ReadPatients(skip, take, out patients))) return false; foreach (var patient in patients) { if (ValidateResultFailed(writer.WritePatient(patient))) return false; } skip += take; } } } return true; } static void Main(string[] args) { // Program that split an Nhax file up in a number of Nhax files each containing one patient string inputFile = Path.Combine(ExeDir, "Input.nhax"); if (args.Length > 0) inputFile = args[0]; try { if (!InitLogger()) return; if (!ReadWriteNhaxFile(inputFile)) return; } catch (Exception e) { Console.WriteLine(e); } } } }