aboutsummaryrefslogtreecommitdiff
path: root/examples/cxx/parser/wildcard/driver.cxx
blob: 7ed7aa6142546644bcdfa5545d971f4021834580 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
// file      : examples/cxx/parser/wildcard/driver.cxx
// author    : Boris Kolpackov <boris@codesynthesis.com>
// copyright : not copyrighted - public domain

#include <string>
#include <memory>
#include <iostream>

#include "email-pskel.hxx"

#ifndef XSDE_REUSE_STYLE_TIEIN
#  error this example requires the tiein parser reuse support
#endif

using namespace std;
using xml_schema::ro_string;

namespace email
{
  class binary_pimpl: public binary_pskel
  {
  public:
    binary_pimpl ()
        : binary_pskel (&base_impl_)
    {
    }

    virtual void
    name (const string& n)
    {
      cerr << "binary: " << n << endl;
    }

    virtual void
    mime (const string& t)
    {
      cerr << "type:   " << t << endl;
    }

    virtual void
    post_binary ()
    {
      std::auto_ptr<xml_schema::buffer> buf (post_base64_binary ());

      cerr << "size:   " << buf->size () << endl
           << endl;
    }

  private:
    xml_schema::base64_binary_pimpl base_impl_;
  };

  class envelope_pimpl: public envelope_pskel
  {
  public:
    envelope_pimpl (xml_schema::unsigned_int_pskel& uint_p,
                    xml_schema::string_pskel& string_p,
                    binary_pskel& binary_p)
        : depth_ (0),
          uint_p_ (uint_p), string_p_ (string_p), binary_p_ (binary_p)
    {
    }

    virtual void
    to (const string& addr)
    {
      cerr << "To:        " << addr << endl;
    }

    virtual void
    from (const string& addr)
    {
      cerr << "From:      " << addr << endl;
    }

    virtual void
    subject (const string& s)
    {
      cerr << "Subject:   " << s << endl;
    }

    // Wildcard handling. All wildcard events are routed to the
    // _start_any_element, _end_any_element, _any_attribute, and
    // _any_characters functions. We can dynamically select a
    // parser from the _start_any_element after which all inner
    // content will be automatically routed to this parser. At
    // the end we will get a call to _end_any_element in which
    // we can call post(), clean up, etc.
    //
    // If we are not using exceptions or XML Schema validation
    // is enabled then we need to check for the error condition
    // and, if the (user) error was set in pre() or post(),
    // also copy the error code to the context. The _error_type()
    // function returns non-0 value if there an error pending.
    // The _copy_error() functions copies the error state to
    // the context.
    //
    // Finally, if the XSD runtime library was configured with
    // polymorphism support, then _start_any_element has a third
    // argument which is a dynamic type id that comes from xsi:type
    // or substitution groups.
    //
    virtual void
#ifndef XSDE_POLYMORPHIC
    _start_any_element (const ro_string& ns, const ro_string& name)
#else
    _start_any_element (const ro_string& ns,
                        const ro_string& name,
                        const char*)
#endif
    {
      // We use the depth_ counter to filter out nested elements
      // and attributes for the content matched by the wildcard
      // but which we don't know how to handle.
      //

      if (depth_++ == 0)
      {
        // Top-level (relative to this type) element matched by the
        // any wildcard.
        //
        xml_schema::parser_base* p = 0;

        if (ns == "http://www.codesynthesis.com/email")
        {
          if (name == "text")
          {
            p = &string_p_;
          }
          else if (name == "binary")
          {
            p = &binary_p_;
          }

          if (p != 0)
          {
            xml_schema::parser_context& ctx = _context ();

            p->pre ();

#ifndef XSDE_EXCEPTIONS
            if (p->_error_type ())
            {
              // Propagate the error.
              //
              p->_copy_error (ctx);
              return;
            }
#endif
            // Indicate transition to the nested parser.
            //
            ctx.nested_parser (p);
          }
        }

        if (p == 0)
        {
          cerr << "Unknown wildcard content: " << ns << "#" << name << endl;
        }
      }
    }

    virtual void
    _end_any_element (const ro_string& ns, const ro_string& name)
    {
      if (--depth_ == 0)
      {
        if (ns == "http://www.codesynthesis.com/email")
        {
          if (name == "text")
          {
            string text (string_p_.post_string ());

#ifndef XSDE_EXCEPTIONS
            if (string_p_._error_type ())
            {
              // Propagate the error.
              //
              string_p_._copy_error (_context ());
              return;
            }
#endif
            cerr << text << endl
                 << endl;
          }
          else if (name == "binary")
          {
            binary_p_.post_binary ();

#ifndef XSDE_EXCEPTIONS
            if (binary_p_._error_type ())
            {
              // Propagate the error.
              //
              binary_p_._copy_error (_context ());
              return;
            }
#endif
          }
        }
      }
    }

    virtual void
    _any_attribute (const ro_string& ns,
                    const ro_string& name,
                    const ro_string& value)
    {
      if (depth_ == 0)
      {
        // Top-level (relative to this type) attribute matched by the
        // anyAttribute wildcard.
        //
        if (ns == "http://www.codesynthesis.com/email" && name == "thread-id")
        {
          xml_schema::parser_context& ctx = _context ();

          uint_p_.pre ();

#ifndef XSDE_EXCEPTIONS
          if (uint_p_._error_type ())
          {
            uint_p_._copy_error (ctx);
            return;
          }
#endif

          uint_p_._pre_impl (ctx);

#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS)
          if (ctx.error_type ())
            return;
#endif

          uint_p_._characters (value);

#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS)
          if (ctx.error_type ())
            return;
#endif

          uint_p_._post_impl ();

#if defined(XSDE_PARSER_VALIDATION) || !defined(XSDE_EXCEPTIONS)
          if (ctx.error_type ())
            return;
#endif

          unsigned int tid = uint_p_.post_unsigned_int ();

#ifndef XSDE_EXCEPTIONS
          if (uint_p_._error_type ())
          {
            uint_p_._copy_error (ctx);
            return;
          }
#endif

          cerr << "Thread-id: " << tid << endl;
        }
      }
    }

    // If we need to be able to reset and reuse the parser after
    // an error then we also need to override _reset() and reset
    // the parsers that are used to handle wildcards. Note that
    // you always need to call _reset() from the base.
    //
    virtual void
    _reset ()
    {
      envelope_pskel::_reset ();

      depth_ = 0;
      uint_p_._reset ();
      string_p_._reset ();
      binary_p_._reset ();
    }

  private:
    std::size_t depth_;

    // Parsers for the unsigned int, string and binary types.
    //
  private:
    xml_schema::unsigned_int_pskel& uint_p_;
    xml_schema::string_pskel& string_p_;
    binary_pskel& binary_p_;
  };
}


int
main (int argc, char* argv[])
{
  const char* input;

  if (argc < 2)
  {
    input = "STDIN";
    cerr << "XML file not specified, reading from STDIN" << endl;
  }
  else
    input = argv[1];

  try
  {
    // Construct the parser.
    //
    xml_schema::unsigned_int_pimpl unsigned_int_p;
    xml_schema::string_pimpl string_p;
    email::binary_pimpl binary_p;
    email::envelope_pimpl envelope_p (unsigned_int_p, string_p, binary_p);

    binary_p.parsers (string_p,  // name
                      string_p); // mime

    envelope_p.parsers (string_p,  // to
                        string_p,  // from
                        string_p); // subject

    // Parse the XML instance document.
    //
    xml_schema::document_pimpl doc_p (
      envelope_p,
      "http://www.codesynthesis.com/email",
      "message");

    envelope_p.pre ();

    if (argc < 2)
      doc_p.parse (cin);
    else
      doc_p.parse (argv[1]);

    envelope_p.post_envelope ();
  }
  catch (const xml_schema::parser_exception& e)
  {
    cerr << input << ":" << e.line () << ":" << e.column () << ": "
         << e.text () << endl;
    return 1;
  }
  catch (const std::ios_base::failure&)
  {
    cerr << input << ": unable to open or read failure" << endl;
    return 1;
  }

  return 0;
}