cniElementAsBitstream

Use this function to get the bitstream representation of the specified element.

The parser that is associated with the element serializes the element and all its child elements. The result is copied to memory allocated by the caller. In the special case where all the options that are specified match those of the original bit stream, for example a bit stream that is read from an IBM® MQ queue by the MQInput node, and the message has not been modified since receiving the original bit stream, this original bit stream is copied into the allocated memory. In this case, the parser is not required to parse and reserialize the message.

The algorithm that is used to generate the bit stream depends on the parser that is used, and the options that are specified. All parsers support the following modes:
  • RootBitStream, in which the algorithm that generates the bit stream is the same as that used by an output node. In this mode, a meaningful result is obtained only if the element pointed to is at the head of a subtree with an appropriate structure.
  • EmbeddedBitStream, in which not only is the algorithm that generates the bit stream the same as that used by an output node, but also the following elements are determined, if not explicitly specified, in the same way as the output node. Therefore they are determined by searching the previous siblings of element on the assumption that these elements represent headers:
    • Encoding
    • CCSID
    • Message set
    • Message type
    • Message format

    In this way, the algorithm for determining these properties is essentially the same as that used for the ESQL BITSTREAM function.

Some parsers also support another mode, FolderBitStream, which generates a meaningful bit stream for any subtree, provided that the field pointed to represents a folder.

Syntax

CciSize cniElementAsBitstream(
  int*                       returnCode,
  CciElement*                element,
  const struct CciByteArray* value,
  CciChar*                   messageType,
  CciChar*                   messageSet,
  CciChar*                   messageFormat,
  int                        encoding,
  int                        ccsid,
  int                        options);

Parameters

returnCode
The return code from the function (output). If you specify a NULL pointer on input, the value indicates that the node does not handle errors. If input is not NULL, the output signifies the success status of the call. Any exceptions that are produced during the execution of this call are sent to the next upstream node in the flow. Call cciGetLastExceptionData for details of the exception.
Possible return codes are:
  • CCI_SUCCESS
  • CCI_EXCEPTION
  • CCI_INV_ELEMENT_OBJECT
  • CCI_INV_DATA_POINTER
  • CCI_INV_DATA_BUFLEN
  • CCI_INV_BUFFER_TOO_SMALL
element
The syntax element to be serialized (input.)
value
A pointer to a CciByteArray struct that contains a pointer to a region of memory allocated by the caller, and the size in CciBytes of this memory (output).
messageType
The message type definition that is used to create the bit stream from the element tree (input). If you specify a NULL pointer, the parameter is ignored. The parameter is also ignored if the value is not relevant to the parser associated with the element; for example, a generic XML parser.
messageSet
The message set definition that is used to create the bit stream from the element tree (input). If you specify a NULL pointer, the parameter is ignored. The parameter is also ignored if the value is not relevant to the parser associated with the element; for example, a generic XML parser.
messageFormat
The format that is used to create the bit stream from the element tree (input). If you specify a NULL pointer, the parameter is ignored. The parameter is also ignored if the value is not relevant to the parser associated with the element; for example, a generic XML parser.
encoding
The encoding to use when writing the bit stream (input). This parameter is mandatory. You can specify a value of 0 to indicate that the encoding for the queue manager must be used.
ccsid
The coded character set identifier to use when writing the bit stream (input). This parameter is mandatory. If you specify a value of 0, the CCSID of the queue manager is used. A CCSID of -1 indicates that the bit stream is generated by using CCSID information contained in the subtree consisting of the field pointed to by the element and its child elements. No supplied parsers support this option.
options
The integer value that specifies which bitstream generation mode must be used. Set one of the following values:
  • CCI_BITSTREAM_OPTIONS_ROOT
  • CCI_BITSTREAM_OPTIONS_EMBEDDED
  • CCI_BITSTREAM_OPTIONS_FOLDER

Return values

  • If successful, the correct size of memory that is required to hold the bit stream is returned.
  • If the memory allocated by the caller was insufficient, returnCode is CCI_BUFFER_TOO_SMALL.
  • If an exception occurs during execution, returnCode is CCI_EXCEPTION.

Example

The following example demonstrates how you can use the options parameter to generate the bit stream for different parts of the message tree.

This code can be copied into the _evaluate function of the sample Transform node. For an input message such as:
MQMD
MQRFH2
<test><data><aaa>text</aaa></data></test>
the node propagates three messages:
  • One that contains a copy of the input message in the BLOB domain
  • One that contains a copy of the input MQRFH2 as the message body in the BLOB domain
  • One that contains the <data></data> folder as the message body in the BLOB domain
CciMessage*          outMsg[3];
  CciTerminal*         terminalObject;
  CciElement*          bodyChild;
  CciElement*          inRootElement;
  CciElement*          inSourceElement[3];
  CciElement*          outRootElement;
  CciElement*          outBlobElement;
  CciElement*          outBody;
  struct CciByteArray  bitstream[3];
  int                  bitstreamOptions[3];
  int                  retvalue;
  int                  rc = 0;
  int                  loopCount;
  CCI_EXCEPTION_ST     exception_st = {CCI_EXCEPTION_ST_DEFAULT};
  const CciChar*       constBLOBParserName  =
                 cciString("NONE",BIP_DEF_COMP_CCSID);
  const CciChar*       constBLOBElementName = 
                 cciString("BLOB",BIP_DEF_COMP_CCSID);
  const CciChar*       constEmptyString     =                     
                 cciString("",BIP_DEF_COMP_CCSID);

  /*build up and propagate 3 output messages*/
  /*first message has bit stream for input message body*/
  /*second message has bit stream for input MQRFH2*/
  /*third message has bit stream for sub element from input message*/

  /* Get the root element of the input message */
  inRootElement = cniRootElement(&rc, message);
  /*CCI_CHECK_RC();*/
  checkRC(rc);

  /*set up the array of source elements and bitstream options*/

  /*message body*/
  inSourceElement[0] =  cniLastChild(&rc,inRootElement);
  checkRC(rc);

  /*This is the root of the message body so we use RootBitStream mode*/
  bitstreamOptions[0] = CCI_BITSTREAM_OPTIONS_ROOT;

  
  /*last header*/
  inSourceElement[1] = cniPreviousSibling(&rc,inSourceElement[0]);
  checkRC(rc);

  /*This is the root of the MQRFH2 so we use RootBitStream mode*/
  bitstreamOptions[1] = CCI_BITSTREAM_OPTIONS_ROOT;

  
  /*body.FIRST(first child of message body) */
  inSourceElement[2] = cniFirstChild(&rc,inSourceElement[0]);
  checkRC(rc);
  
  /*body.FIRST.FIRST */
  inSourceElement[2] = cniFirstChild(&rc,inSourceElement[2]);
  checkRC(rc);

  /*This is a sub tree within the message body so we use FolderBitStream mode*/
  bitstreamOptions[2] = CCI_BITSTREAM_OPTIONS_FOLDER;

  
  for (loopCount=0;loopCount<3;loopCount++) {
    int bufLength;

    /* Create new message for output */
    outMsg[loopCount] = cniCreateMessage(&rc, cniGetMessageContext(&rc, message));
    checkRC(rc);

    /* Get the root element of the output message */
    outRootElement = cniRootElement(&rc, outMsg[loopCount]);
    checkRC(rc);

    /* Copy the contents of the input message to the output message */
    cniCopyElementTree(&rc, inRootElement, outRootElement);
    checkRC(rc);

    /* Get the last child of root (ie the body)  */
    bodyChild = cniLastChild(&rc, outRootElement);
    checkRC(rc);

    /*throw away the message body which was copied from the input message*/
    cniDetach(&rc,
              bodyChild);
    checkRC(rc);

    /*create the new output message body in the BLOB domain*/
    outBody = cniCreateElementAsLastChildUsingParser(&rc,
                                           outRootElement,
                                           constBLOBParserName);
    checkRC(rc);

    /*create the BLOB element*/
    outBlobElement = cniCreateElementAsLastChild(&rc,
                                outBody);
    checkRC(rc);

    cniSetElementName(&rc,
                      outBlobElement,
                      constBLOBElementName);
    checkRC(rc);
    
    /*Set the value of the blob element by obtaining the bit stream for the
    element */
    bitstream[loopCount].size=512;
    bitstream[loopCount].pointer=(CciByte*)malloc(sizeof(CciByte) * 512);
    
    bufLength = cniElementAsBitstream(&rc,
                          inSourceElement[loopCount],
                          &bitstream[loopCount],
                          constEmptyString,/*assume XML message so no interest in*/
                          constEmptyString,/* type, set or format*/
                          constEmptyString,
                          0,/*Use Queue Manager CCSID & Encoding*/
                          0,
                          bitstreamOptions[loopCount]);
    

    if (rc==CCI_BUFFER_TOO_SMALL)
    {
        free(bitstream[loopCount].pointer);
        bitstream[loopCount].size=bufLength;
        bitstream[loopCount].pointer=(CciByte*)malloc(sizeof(CciByte) * bitstream[loopCount].size);

        bufLength = cniElementAsBitstream(&rc,
                          inSourceElement[loopCount],
                          &bitstream[loopCount],
                          constEmptyString,/*assume XML message so no interest in*/
                          constEmptyString,/* type, set or format*/
                          constEmptyString,
                          0,/*Use Queue Manager CCSID & Encoding*/
                          0,
                          bitstreamOptions[loopCount]);      
    }
    checkRC(rc);
    bitstream[loopCount].size=bufLength;
    
    cniSetElementByteArrayValue(&rc,
                                outBlobElement,
                                &bitstream[loopCount]);
    checkRC(rc);
  }

  /* Get handle of output terminal */
  terminalObject = getOutputTerminalHandle( (NODE_CONTEXT_ST *)context,
                                            (CciChar*)constOut);

  /* If the terminal exists and is attached, propagate to it */
  if (terminalObject) {
    if (cniIsTerminalAttached(&rc, terminalObject)) {
      /* As this is a new, and changed message, it should be finalized... */
      cniFinalize(&rc, outMsg[0], CCI_FINALIZE_NONE);
      cniFinalize(&rc, outMsg[1], CCI_FINALIZE_NONE);
      cniFinalize(&rc, outMsg[2], CCI_FINALIZE_NONE);
      retvalue = cniPropagate(&rc, terminalObject, localEnvironment, exceptionList, outMsg[0]);
      retvalue = cniPropagate(&rc, terminalObject, localEnvironment, exceptionList, outMsg[1]);
      retvalue = cniPropagate(&rc, terminalObject, localEnvironment, exceptionList, outMsg[2]);
      if (retvalue == CCI_FAILURE) {
        if (rc == CCI_EXCEPTION) {
          /* Get details of the exception */
          memset(&exception_st, 0, sizeof(exception_st));
          cciGetLastExceptionData(&rc, &exception_st);

          /* Any local error handling can go here */

          /* Ensure message is deleted prior to return/throw */
          cniDeleteMessage(0, outMsg[0]);
          cniDeleteMessage(0, outMsg[1]);
          cniDeleteMessage(0, outMsg[2]);

          /* We must "rethrow" the exception; note this does not return */
          cciRethrowLastException(&rc);
        }
        else {

          /* Some other error...the plugin might choose to log it using the CciLog() */
          /* utility function                                                        */

        }
      }
      else {
      }
    }
  }
  else {
    /* Terminal did not exist...severe internal error. The plugin might want to */
    /* log an error here by using the cciLog() utility function.                 */
  }

  /* Delete the messages we created now we have finished with them */
  cniDeleteMessage(0, outMsg[0]);
  cniDeleteMessage(0, outMsg[1]);
  cniDeleteMessage(0, outMsg[2]);

  free((void*) constBLOBParserName);
  free((void*) constBLOBElementName);
  free((void*) constEmptyString);
  return;