cniElementAsBitstream

Gets the bitstream representation of the specified element. The parser that is associated with the element serializes the element and all its children. The result is copied to memory allocated by the caller. In the special case where all options specified match those of the original bit stream, for example, a bit stream that is read from a WebSphere 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 memory allocated by the user. In this case, the parser is not required to parse and re-serialize the message.

The algorithm that is used to generate the bit stream depends on the parser being used, and the options specified. All parsers support the following modes:
  • RootBitStream, in which the bitstream generation algorithm 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 bitstream generation algorithm the same as that used by an output node, but also the following are determined, if not explicitly specified, in the same way as the output node, which means they are determined by searching the previous siblings of element on the assumption that these 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). Specifying a NULL pointer signifies that the node does not want to deal with errors. If input is not NULL, the output signifies the success status of the call. Any exceptions thrown during the execution of this call are re-thrown 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.)
The syntax element to be serialized (input.) Must be last child of the message root.
value
A pointer to a CciByteArray struct containing 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 used to create the bit stream from the element tree (input). A NULL pointer means that this parameter is ignored. Also, if the parser associated with the element has no interest in this value, for example, if it is a generic XML parser, the parameter is ignored.
messageSet
The message set definition used to create the bit stream from the element tree (input). A NULL pointer means that this parameter is ignored. Also, if the parser associated with the element has no interest in this value, for example, if it is a generic XML parser, the parameter is also ignored.
messageFormat
The format used to create the bit stream from the element tree (input). A NULL pointer means that this parameter is ignored. Also, if the parser associated with the element has no interest in this value, for example, if it is a generic XML parser, the parameter is ignored.
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 queue manager's encoding should be used.
ccsid
The coded character set identifier to use when writing the bit stream (input). This parameter is mandatory. You can specify a value of 0 to indicate that the queue manager's ccsid should be used. A ccsid of -1 indicates that the bit stream is to be generated using ccsid information contained in the subtree consisting of the field pointed to by element and its children. Currently no parsers support this option.
options
Integer value which specifies which bitstream generation mode should be used. It can take 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 needed to hold the bit stream is returned.
  • If the memory allocated by the caller was insufficient, returnCode is set to CCI_BUFFER_TOO_SMALL.
  • If an exception occurs during execution, returnCode is set to CCI_EXCEPTION.

Example

The following example demonstrates how the options parameter should be used 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
RFH2
<test><data><stuff>things</stuff></data></test>
the node will propagate 3 messages, one containing a copy of the input message in the BLOB domain. One containing a copy of the input RFH2 as the message body in the BLOB domain. One containing 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 RFH2*/
  /*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 RFH2 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, destinationList, exceptionList, outMsg[0]);
      retvalue = cniPropagate(&rc, terminalObject, destinationList, exceptionList, outMsg[1]);
      retvalue = cniPropagate(&rc, terminalObject, destinationList, 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 may 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 may wish to */
    /* log an error here 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;