扩展 C 解析器的功能

开始之前

确保您已阅读并理解以下主题:

实现解析器功能

解析器需要实现下列类型的实施函数:
  1. 输入函数
  2. 解析函数
  3. 输出函数

每种类型的函数在下面描述。

实现输入函数

有三种 input 函数: 您的解析器必须实施一个且只能实施这些输入函数中的一个。

当需要用户定义的解析器来解析输入消息时,代理将调用 input 函数。 解析器必须告诉代理它声明有多少输入位流缓冲区属于它。在固定大小头的情况下,解析器声明头的大小。如果解析器要用于处理整条消息,它声明缓冲区的剩余部分。

例如:
  1. 代理调用 cpiParseBufferEncoded 输入函数:
    int cpiParseBufferEncoded(
        CciParser*  parser,
        CciContext* context,                
        int         encoding,
        int         ccsid
    ){
        PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
        int             rc;
  2. 获取到消息缓冲区的指针,然后使用 cpiBufferPointer 实用程序函数设置偏移量:
      pc->iBuffer = (void *)cpiBufferPointer(&rc, parser);
      pc->iIndex = 0;
  3. 保存缓冲区的格式:
      pc->iEncoding = encoding;
      pc->iCcsid = ccsid;
  4. 使用 cpiBufferSize 实用程序函数保存缓冲区的大小:
      pc->iSize = cpiBufferSize(&rc, parser);
  5. 使用 cpiBufferByte 实用程序函数填入流中的第一个字节:
      pc->iCurrentCharacter = cpiBufferByte(&rc, parser, pc->iIndex);
  6. 使用 cpiRootElement 实用程序函数将当前元素设置为根元素:
      pc->iCurrentElement = cpiRootElement(&rc, parser);
  7. 重置该标志以确保解析正确重置:
      pc->iInTag = 0;
  8. 声明缓冲区余下部分的所有权:
      return(pc->iSize);
    }

实现解析函数

常规解析函数(例如,cpiParseFirstChild)是当需要创建语法元素树以对 ESQL 或 Java 表达式求值时由代理调用的那些函数。例如,filter 节点在 ESQL 表达式中使用 ESQL 字段引用。必须解析此字段引用以求值表达式。将调用您的解析器的常规解析函数(可能是重复地),直到创建了请求的元素或者解析器知道它不存在。

例如:
void cpiParseFirstChild(
    CciParser*  parser,
    CciContext* context,                
    CciElement* element
){
    PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
    int             rc;

    if ((!cpiElementCompleteNext(&rc, element)) &&
            (cpiElementType(&rc, element) == CCI_ELEMENT_TYPE_NAME)) {

        while ((!cpiElementCompleteNext(&rc, element))     &&
                      (!cpiFirstChild(&rc, element)) &&
           (pc->iCurrentElement))    {
      pc->iCurrentElement = parseNextItem(parser, context, pc->iCurrentElement);
    }
  }
    return;
}

实现输出函数

有三种 output 函数: 您的解析器必须实施一个且只能实施这些输出函数中的一个。

当需要用户定义的解析器将语法元素树序列化为一个输出位流时,代理将调用 output 函数。 例如,Compute 节点可能在您用户定义的解析器的域中创建了树。例如,当需要由 MQOutput 节点输出此树时,解析器负责将表示构建的树的数据附加到输出位流缓冲区。

例如:
int cpiWriteBufferEncoded(
    CciParser*  parser,
    CciContext* context,                
    int         encoding,
    int         ccsid
){
    PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
    int                initialSize = 0;
    int                rc = 0;
    const void* a;
    CciByte b;

    initialSize = cpiBufferSize(&rc, parser);
    a = cpiBufferPointer(&rc, parser);
    b = cpiBufferByte(&rc, parser, 0);

    cpiAppendToBuffer(&rc, parser, (char *)"Some test data", 14);

    return cpiBufferSize(0, parser) - initialSize;
}

实施消息头解析器

通常,进入消息数据是单个消息格式的,因此一个解析器负责解析消息的全部内容。所需的解析器的类名在输入消息的 MQMD 或 MQRFH2 头中的 Format 字段中定义。

但是,消息可能由多种格式组成,例如,有的一种格式的头,它后跟另一种格式的数据。在这种情况下,第一个解析器必须标识负责链中下一种格式的解析器的类名,依此类推。在用户定义的解析器中,当它需要为包含多种消息格式的消息向下浏览解析器类的链时,代理将调用 cpiNextParserClassName 实施函数。

如果您的用户定义的解析器支持解析是多种消息格式的一部分的消息格式,用户定义的解析器必须实现 cpiNextParserClassName 函数。

例如:
  1. 调用 cpiNextParserClassName 函数:
    void cpiNextParserClassName(
        CciParser*  parser,
        CciContext* context,                
        CciChar*    buffer,
        int         size
    ){
        PARSER_CONTEXT_ST* pc = (PARSER_CONTEXT_ST *)context ;
        int                rc = 0;
  2. 将下一个解析器类的名称复制到代理:
      CciCharNCpy(buffer, pc->iNextParserClassName, size);
    
        return;
    }
声明 | 商标 | 下载 | 书库 | 支持 | 反馈
Copyright IBM Corporation 1999, 2006 最后一次更新时间:2006/08/14
as24980_