hl7parse
Classes | Macros | Typedefs | Enumerations | Functions
node.h File Reference

Main datastructures for HL7 nodes and messages This file contains the main parser data structures and methods to read and parse hl7 files. More...

#include <stdio.h>
#include <stdlib.h>
#include "meta.h"
#include "address.h"
#include "message_state.h"
#include "logging.h"
Include dependency graph for node.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  raw_field_t
 structure to track delmiter fields in a fieldset More...
 
struct  node_t
 primary storage type of a delimited element More...
 
struct  message_t
 

Macros

#define NODE_PREALLOC_CHILDREN   5
 number of children to pre-allocate when there is not room in children anymore
 
#define MESSAGE_PREALLOC_CHILDREN   10
 number of children to pre-allocate when there is not room in children anymore
 
#define MAX_FIELDS   1000
 maximum number of temporary elements to allocate in the parser buffer
 

Typedefs

typedef struct raw_field_t raw_field_t
 structure to track delmiter fields in a fieldset More...
 
typedef enum node_type_t node_type_t
 Node types.
 
typedef struct node_t node_t
 primary storage type of a delimited element More...
 
typedef struct message_state_t message_state_t
 hl7 message container More...
 
typedef struct message_t message_t
 

Enumerations

enum  node_type_t {
  MESSAGE = 1, SEGMENT = 2, FIELDLIST = 4, FIELD = 8,
  COMP = 16, SUBCOMP = 32, LEAF = 64
}
 Node types. More...
 

Functions

raw_field_tcreate_raw_field_t (void)
 create raw fied structure More...
 
void free_raw_field (raw_field_t *raw_e)
 free raw fiel structure
 
node_tcreate_node_t (node_type_t type, unsigned char *data, size_t length, int pos)
 create a new node More...
 
void free_node_t (node_t *node)
 cleanup all memory of a node More...
 
int node_append (node_t **parent, node_t *node)
 append a child node More...
 
int node_parent_child_pos (node_t *node)
 find the position in parent's children struct More...
 
node_tprocess_node (raw_field_t *raw_e, hl7_meta_t *meta, int start_pos)
 
void disply_raw_node (raw_field_t *raw_e)
 dump raw_e structure to stdout More...
 
node_tnode_in_segment (node_t *segment, hl7_addr_t *addr)
 check if a node with given addres exists More...
 
const char * node_type_to_string (node_type_t type)
 string representation of node_type_t More...
 
message_tcreate_message_t (hl7_meta_t *meta)
 initialize an empty messagte_t struct More...
 
void free_message_t (message_t *message)
 free message_t an all it's child objects More...
 
int message_append (message_t **parent, node_t *node)
 append a segment to the message More...
 
hl7_addr_taddr_from_node (node_t *node)
 generate an addr from any node in a message More...
 

Detailed Description

Main datastructures for HL7 nodes and messages This file contains the main parser data structures and methods to read and parse hl7 files.

All api functions defined here are used by the parser to create a node_t structure. For advanced node capabilities (for example editing) see node_util.h experiemntal functions.

Typedef Documentation

◆ message_state_t

hl7 message container

This struct holds data about the hl7 file (delimiter) in messgae_t.meta as well as a tree structure of nodes, stored in message_t.segments.

This is your main structure returned by the parser.

Example:

#include <stdio.h>
#include "decode.h" // or lib7.h which is the combined header for lib7.so
char *filename "some_file.hl7";
FILE *fd = fopen(filename, "rb");
int ret = hl7_decode(fd, &root);
fclose(fd); // no need for fd anymore, all data in memory
if (ret != 0) {
// whoopsie
}
// do something with the data in root
// cleanup

◆ node_t

typedef struct node_t node_t

primary storage type of a delimited element

Every hl7 element (regardless of place in the hirarchy) is represented by a node_t. The node_t.type defines where in the hirarchy the node is. Every node_t has a parent node.

The top level node of a parsed HL7 message is always of type message_t. The Hirarchy looks like this:

  • message_t this is the top level node
    • node_t.type == SEGMENT this is the segment node
      • node_t.type == FIELDLIST array of elements between |, always one, may have multiple children delimited by ~
        • node_t.type == FIELD array of fields delimited by ~, always at least one
          • node_t.type == COMP optional components delimited by ^
            • node_t.type == SUBCOMP optional sub components delimited by &

The delimiters shown above are the standard delimiters. The HL7 file may define different delimiters which are read and accounted for by the parser.

Every node has potential children indicated by node_t.num_children (0 means none) and has a parent (special case is message_t which is always the root of the structure and is the partent of node_type_t SEGMENT).

This also means, that some node types (node_t.type) need to be treated specially.

  • node_type_t.SUBCOMP never has children
  • node_type_t.SEGMENT always has a parent of type message_t, you need to cast it when accessing it
  • node_type_t.SEGMENT the data property always contains the segment's name

creating a node

To create a valid node_t you need to know it's data and length.

Example:

char *data = "abc";
int length = 4; // must include \0
node_t *n = create_node_t(FIELD, data, length, 0);
// you may also create an empty node like this
node_t *n = create_node_t(FIELD, NULL, 0, 0);

node_t takes owenship of the pointer pointing to data. be aware of the fact that when you free a node then all children and it's data will get freed.

Example:

char *data = "abc";
int length = 4; // must include \0
node_t *n = create_node_t(FIELD, data, length, 0);
// free it
// NOTE: data points to NULL now

using the api

You should use the api to manage relationships between children and parents. this will make sure you don't get any dangling nodes in your structure.

Example:

int ret = -1;
message_t *root = create_message_t(NULL); // will create a message and meta with default delimiters
node_t *n = create_node(SEGMENT, "PID", 4, 0);
ret = message_append(&root, n);
if (ret != 0) {
// whoopsie, something went wrong
return;
}
// create PID-1(1) segment
node_t *pid1 = create_node(FIELDLIST, NULL, 0 , 0);
node_t *pid11 = create_node(FIELD, "DATA", 5 , 0);
ret = node_append(&n, n1);
ret = node_append(&n1, n11);
// from node_util.h
char *str = messate_to_string(root);
printf("%s\n", str);
free(str);
free_message(root); // frees all children

checking for children

if (node->num_children > 0)
// we have some children

getting the parent

message_t has a very similar structure (lacking data but having file metadata). when accessing the parent of a SEGMENT, then the parent should be casted into message_t*.

if (node->type == SEGMENT)
message_t* parent = (message_t*) node->parent;
else
node_t* parent = node->parent;

◆ raw_field_t

typedef struct raw_field_t raw_field_t

structure to track delmiter fields in a fieldset

This is a private data structure for parse_segment(). It keeps track of all delimiters in a segment while looping over it byte by byte. process_node() the uses it to calculate bounds and structure of the message while extracting the data and structure.

This is a parser internal structure used to keep track of delimiters.

Note
do not use outside of parse_segment()
Bug:
move into parser, this is not being used by the node facilities at all.

Enumeration Type Documentation

◆ node_type_t

Node types.

Enumerator
MESSAGE 

root node, holding all segments

SEGMENT 

segment node, this is one lien in an hl7 file

FIELDLIST 

fieldlist is everything btween | and |, respecting repetition characters ~

FIELD 

this is the actual field content, if there is a repetition delimiter ~ multiple of these fields are present, otherwise always one

COMP 

the component delimited by ^

SUBCOMP 

the sub componentent, delimited by &

LEAF 

unused

Function Documentation

◆ addr_from_node()

hl7_addr_t* addr_from_node ( node_t node)

generate an addr from any node in a message

traverse up until message is reached. The structure must have a message type as top parent or it will return NULL.

while traversing up through parents, if type is MESSAGE and parent is NULL, we have successfully reached the top and can produce a result.

Parameters
nodethe starting point from where to traverse up
Returns
hl7_addr_t address structure.

◆ create_message_t()

message_t* create_message_t ( hl7_meta_t meta)

initialize an empty messagte_t struct

This function wil lsetup your message_t. If the first param is NULL then default values for message_t.meta and message_t.meta.bom are set according to init_hl7_meta_t().

See also
init_hl7_meta_t()
Parameters
metaor NULL
Returns
message_t with default values

◆ create_node_t()

node_t* create_node_t ( node_type_t  type,
unsigned char *  data,
size_t  length,
int  pos 
)

create a new node

you must make sure to properly free the node

See also
free_node_t(). You should add a pointer to the parent after creation like this: my_node->parent = another_node;

if you just plan to append as a child,

See also
node_append() and relationship with parent is taken care of.
Parameters
typethe node type
databyte array of data
lengthlength including \0 delimiting byte if there is any
posposition of element in line (segment). the position marks the beginnign delimiter
Returns
initialized node

◆ create_raw_field_t()

raw_field_t* create_raw_field_t ( void  )

create raw fied structure

Returns
raw_field_t

◆ disply_raw_node()

void disply_raw_node ( raw_field_t raw_e)

dump raw_e structure to stdout

Note
this is only useful for debugging insede the parser
Todo:
move to decode.c
Parameters
raw_ethe node's delimiter information

◆ free_message_t()

void free_message_t ( message_t message)

free message_t an all it's child objects

This method will free messgate_t.meta and messagte_t.segments (recoursively).

Note
all pointer pointg to nodes within this message will be invalid after this function has been executed, be careful.
Parameters
messagethe message to free

◆ free_node_t()

void free_node_t ( node_t node)

cleanup all memory of a node

Note
be careful, if you have passed in pointers to node data or elements, they will be cleaned (node_t.data will be freed).

All children and children's children are freed.

Parameters
nodethe node and it's children to be cleaned

◆ message_append()

int message_append ( message_t **  parent,
node_t node 
)

append a segment to the message

This method will dynamically allocate more memory for message_t.segments and store the number of allocated items in messgae_t._num_children_allocated.

Parameters
parenttypically the root node, a message_t object
nodethe segment to append to message
Returns
0 on success, 1 if no memory could be allocated

◆ node_append()

int node_append ( node_t **  parent,
node_t node 
)

append a child node

Memory is allocated if _num_children_allocated is too small to hold an additional pointer in the children array. You must make sure to properly allocate memory for the child itself, use create_node_t() for that.

Parameters
parentthe parent node to be associated, may be null (this is reserved for the root node)
nodethe node to append
Returns
0 on success, 1 if realloc() fails, 2 if parent is missing

◆ node_in_segment()

node_t* node_in_segment ( node_t segment,
hl7_addr_t addr 
)

check if a node with given addres exists

Parameters
segmentnode tree to search (must be of type segment)
addrthe address to look up
Returns
the node if found, NULL otherwise

◆ node_parent_child_pos()

int node_parent_child_pos ( node_t node)

find the position in parent's children struct

This is useful to find next/previous siblings.

Returns
pos in child array, -1 if there is no parent and -2 if the node is not found in parents children

◆ node_type_to_string()

const char* node_type_to_string ( node_type_t  type)

string representation of node_type_t

Parameters
typetype
Returns
string name of type

◆ process_node()

node_t* process_node ( raw_field_t raw_e,
hl7_meta_t meta,
int  start_pos 
)

Sub component parser

This is the sub component prser that takes care of braking down all elements in a field delimited by ^~&.

creates a node structure for components and subcomponents. don't forget to set the parent after creation. This is an internal function of the parsers and is not useful anywhere else.

Todo:
move to decode.c
Parameters
raw_eraw field elements
metahl7 meta data, containing delimiter
start_posthe position of the first delimiter beginning data of thes field in the segment
Returns
node structure