<!-- ** using the wbxml parser

     $Id: sect_wbxml_parser.docbook 801 2005-07-17 12:56:42Z ewald-arnold $
-->

<sect1 id="wbxml-parser">
<title>Using the &wbxml; Parser</title>

<sect2 id="what-is-wbxml">
<title>What is &wbxml;?</title>

<para><ulink url="http://www.w3.org/TR/wbxml">&wbxml;</ulink> differs from
<ulink url="http://www.w3.org/xml">XML</ulink>
mainly in the effort to compress the data in several ways.
Repetive strings can be moved into a string table and are only used by their table index. Numbers
also take as little bytes as possible. XML tags are represented by tokens which are just
predefined numbers depending on the actual application. Sometimes there is a mixture
of string tables indexes, tokens and actual string fragments which makes it quite hard
to parse &wbxml;.</para>

<para>For that reason &ulxmlrpcpp; uses a very small subset of this definition. Since there
are no XML attributes involved and no repetitive strings in use, it is mainly a conversion
of the &xmlrpc; tags into tokens. The big benefit is higher processing speed because parsing
means merely reading a short number instead of searching for opening and closing tags as in
XML. Another positive effect is the smaller packet size that is transfered with the &xmlrpc;
requests.</para>

<para>&ulxmlrpcpp; uses a <systemitem class="library">SAX</systemitem>-like approach to parse
the &wbxml; structure, similar to the built-in xml
parser which is based on <systemitem class="library">expat</systemitem>. This also involves a
simple state machine which models nested elements by deriving parser classes: "outer" elements
derive from "inner" elements.</para>

<para>Parsing of a start tag is done in the following steps:

<procedure>
  <step>Check if the current object is able to handle the current element</step>
  <step>Otherwise delegate to the parent (which may as well call the former parent)</step>
  <step>Process the current element and remember the state for later use on a stack</step>
</procedure>

</para>

<para>Character data between the &xml; tags is stored for later use.</para>

<para>An ending token is handled similarly:

<procedure>
  <step>Check if the current object is able to handle the current element</step>
  <step>Otherwise delegate to the parent</step>
  <step>Process stored character data.</step>
</procedure>

</para>

</sect2>


<sect2 id="creating-a-wbxml-parser">
<title>Creating a &wbxml; parser</title>

<para>When you create a parser you must take care to set up the token values
for your tags correctly. These values only have a limited range. And the range also
varies if attributtes are used or if it is an empty element.</para>

<para><filename class="headerfile">ulxr_wbxmlparse.h</filename> contains constants for
the ranges.

<variablelist>

  <varlistentry>
    <term><constant>wbxml_TAG_FIRST</constant></term>
    <term><constant>wbxml_TAG_LAST</constant></term>
    <listitem><para>boundaries for empty elements without attributes</para></listitem>
  </varlistentry>

  <varlistentry>
    <term><constant>wbxml_TAG_C_FIRST</constant></term>
    <term><constant>wbxml_TAG_C_LAST</constant></term>
    <listitem><para>boundaries for elements with content but without attributes</para></listitem>
  </varlistentry>

  <varlistentry>
    <term><constant>wbxml_TAG_A_FIRST</constant></term>
    <term><constant>wbxml_TAG_A_LAST</constant></term>
    <listitem><para>boundaries for empty elements with attributes. Currently not used as
    attributes are not supported.</para></listitem>
  </varlistentry>

  <varlistentry>
    <term><constant>wbxml_TAG_AC_FIRST</constant></term>
    <term><constant>wbxml_TAG_AC_LAST</constant></term>
    <listitem><para>boundaries for elements with content and attributes. Currently not used as
    attributes are not supported.</para></listitem>
  </varlistentry>

</variablelist>

</para>

<para>&ulxmlrpcpp; uses this technique to model the parsers for the &xmlrpc; tags
<command>MethodResponse</command> or <command>MethodCall</command> which both
include <command>Value</command>.

<programlisting>

  class ValueParserWb : public WbXmlParser
  {
    enum ValueWellKnownToken <co  id="wbx-enum-co" linkends="wbx-enum-link" />
    {
      wbToken_Value     = wbxml_TAG_C_FIRST,   // 0x45 <co  id="wbx-first-co" linkends="wbx-first-link" />
      wbToken_Array,                           // 0x46
      ...
      wbToken_Date,                            // 0x51
      wbToken_ValueParserLast                  // 0x52 <co  id="wbx-last-co" linkends="wbx-last-link" />
    }
  ...


  class MethodResponseParserWb : public ValueParserWb,
  {
    enum RespWellKnownToken
    {
      wbToken_MethodResponse = ValueParserWb::wbToken_ValueParserLast, // 0x52 <co  id="wbx-derive-co" linkends="wbx-derive-link" />
      wbToken_Fault,                                                   // 0x53
      wbToken_Params,                                                  // 0x54
      wbToken_Param,                                                   // 0x55
      wbToken_ResponseParserLast                                       // 0x56
    };

</programlisting>

<calloutlist>

 <callout id="wbx-enum-link" arearefs="wbx-enum-co">
  <para>It is advisable to define the token values as <token>enum</token>
  structures.</para>
 </callout>

 <callout id="wbx-first-link" arearefs="wbx-first-co">
  <para>The first item is assigned a defined start value.</para>
 </callout>

 <callout id="wbx-last-link" arearefs="wbx-last-co">
  <para>You should also create an entry for the token beyond the
  last one.</para>
 </callout>

 <callout id="wbx-derive-link" arearefs="wbx-derive-co">
  <para>This allows to create the start token for a
  potential deriving parser which uses the parent parser as "inner" element.</para>
 </callout>

</calloutlist>

</para>

<para>For more examples on the working method see the various *parse_wb.cpp files.</para>

<caution>
  <title>There is one pitfall:</title>
  <para>
   <calloutlist>
     <callout id="wbx-push-link" arearefs="wbx-push-co">
      <para>The first constructor in a chain of derived parsers must push an
      appropriate element onto the state stack because the parser methods rely
      upon being able to retrieve information about the current state.</para>
    </callout>

    <callout id="wbx-clean-link" arearefs="wbx-clean-co">
     <para>The destructor on the other hand must clean up
     the stack.</para>
    </callout>

   </calloutlist>

  <programlisting>

  WbXmlParser::WbXmlParser()
  {
    states.push(new ValueState(eNone)); <co  id="wbx-push-co" linkends="wbx-push-link" />
  }

  WbXmlParser::~WbXmlParser()
  {
    while (states.size() != 0)<co  id="wbx-clean-co" linkends="wbx-clean-link" />
    {
      delete getTopValueState()->getValue();
      delete getTopValueState();
      states.pop();
    }
  }

  </programlisting>

  </para>

</caution>

</sect2>

</sect1>
