Example #1
0
// This function is used to recursively walk through the tree, loading and
// speech or dtmf grammars which are found.
//
void GrammarManager::LoadGrammars(const VXMLElement& doc,
                                  vxistring & documentID,
                                  PropertyList & properties)
{
  if (doc == 0) return;

  VXIMapHolder recProps(NULL);  // Initialize an empty holder.

  // (1) Retrieve the ID for this document.  This is important for grammar
  // activation.

  if (doc.GetName() == NODE_VXML)
    doc.GetAttribute(ATTRIBUTE__ITEMNAME, documentID);

  // (2) Look for grammars in current nodes.

  for (VXMLNodeIterator it(doc); it; ++it) {
    VXMLNode child = *it;

    if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
    const VXMLElement & element = reinterpret_cast<const VXMLElement &>(child);

    VXMLElementType elementName = element.GetName();
    VXIrecGrammar * vg = NULL;

    if (recProps.GetValue() == NULL)
      recProps.Acquire(GetRecProperties(properties));

    // (3) Handle <grammar> & <dtmf>

    if (elementName == NODE_GRAMMAR || elementName == NODE_DTMF) {
      vxistring src;
      element.GetAttribute(ATTRIBUTE_SRC, src);

      // (3.1) Override the language setting (if specified as an attribute)
      vxistring lang;
      if (element.GetAttribute(ATTRIBUTE_XMLLANG, lang) == true)
        AddParamValue(recProps, REC_LANGUAGE, lang);

      // (3.2) Does the grammar come from an external URI?
      if (!src.empty()) {
        if (log.IsLogging(2)) {
          log.StartDiagnostic(2) << L"GrammarManager::LoadGrammars - <grammar "
            L"src=\"" << src << L"\">";
          log.EndDiagnostic();
        }

        VXIMapHolder fetchobj;
        if (fetchobj.GetValue() == NULL) throw VXIException::OutOfMemory();

        vxistring fragment;
        properties.GetFetchobjCacheAttrs(element, PropertyList::Grammar,
                                         fetchobj);
        properties.GetFetchobjURIs(element, fetchobj, src, fragment);

        if (!fragment.empty())
          log.LogError(215);

        vxistring mimeType;
        element.GetAttribute(ATTRIBUTE_TYPE, mimeType);

        VXIrecResult err = vxirec->LoadGrammarURI(vxirec, recProps.GetValue(),
                                                  mimeType.c_str(),
                                                  src.c_str(),
                                                  fetchobj.GetValue(), &vg);
        if (err != VXIrec_RESULT_SUCCESS)
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_GRAMMAR);

        if (vg) AddGrammar(vg, documentID, element);
      }
      // (3.3) Otherwise this is an inlined grammar.
      else {
        log.LogDiagnostic(2, L"GrammarManager::LoadGrammars - <grammar>");

        vxistring text;
        GetEnclosedText(log, element, text);
        
        vxistring mimeType;
        element.GetAttribute(ATTRIBUTE_TYPE, mimeType);

        if (mimeType.empty() && elementName == NODE_DTMF)
          vg = GrammarManager::CreateGrammarFromString(vxirec, log, text,
                                                       REC_MIME_GENERIC_DTMF,
                                                       recProps);
        else
          vg = GrammarManager::CreateGrammarFromString(vxirec, log, text,
                                                       mimeType.c_str(),
                                                       recProps);
        
        if (vg == NULL) // "Error loading in-line grammar %s",text
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_INLINE);

        AddGrammar(vg, documentID, element);
      }
    }

    // (4) Handle <choice>

    else if (elementName == NODE_CHOICE) {
      log.LogDiagnostic(2, L"GrammarManager::LoadGrammars - <choice>");

      // (4.1) If there is a <grammar> tag, it overrides any implicit grammar.

      // (4.1.1) Check for <grammar> element.
      bool foundGrammar = false;

      for (VXMLNodeIterator it(element); it; ++it) {
        VXMLNode child = *it;

        if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
        const VXMLElement & temp = reinterpret_cast<const VXMLElement&>(child);
        if (temp.GetName() != NODE_GRAMMAR) continue;
        foundGrammar = true;
        break;
      }
      // (4.1.2) If found, apply recursion.
      if (foundGrammar) {
        // <choice> nodes can't contain properties.  Don't need to call Push.
        LoadGrammars(element, documentID, properties);
      }

      // (4.1.3) Otherwise, construct a grammar from the prompt text.
      else {
        vxistring text;
        GetEnclosedText(log, element, text);

        // The text may be empty, e.g. for a dtmf only grammar.
        if (!text.empty()) {
          VXIrecGrammar * vg = NULL;

          vg = GrammarManager::CreateGrammarFromString(vxirec, log, text,
                                                       REC_MIME_CHOICE,
                                                       recProps);
          if (vg == NULL) // "Error loading in-line grammar %s",text
            throw VXIException::InterpreterEvent(EV_ERROR_BAD_CHOICE);

          AddGrammar(vg, documentID, element);
        }
      }

      // (4.2) Create associated DTMF grammar.
      //
      // Either an explict dtmf choice is given or implicit numbers are
      // generated for the first nine.  When both are specified, the explicit
      // choice wins.  This will quite possibly create unintentional (and
      // undetected) duplicates....

      vxistring dtmf;
      element.GetAttribute(ATTRIBUTE_DTMF, dtmf);

      if (!dtmf.empty()) {
        VXIrecGrammar * vg = NULL;

        vg = GrammarManager::CreateGrammarFromString(vxirec, log, dtmf,
                                                     REC_MIME_CHOICE_DTMF,
                                                     recProps);
        if (vg == NULL)
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_CHOICE);

        AddGrammar(vg, documentID, element);
      }
    }

    // (5) Handle <field>.

    else if (elementName == NODE_FIELD) { 
      log.LogDiagnostic(2, L"GrammarManager::LoadGrammars - <field>");

      vxistring gram;
      VXIrecGrammar * vg;

      // Build option grammar (if one exists).
      GrammarManager::BuildOptionGrammar(log, element, false, gram);
      if (!gram.empty()) {
        vg = GrammarManager::CreateGrammarFromString(vxirec, log, gram,
                                                     REC_MIME_OPTION,
                                                     recProps);
        if (vg == NULL)
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_OPTION);
        AddGrammar(vg, documentID, element);
      }

      // Build option dtmf grammar (if one exists).
      gram = L"";
      GrammarManager::BuildOptionGrammar(log, element, true, gram);
      if (gram.length() != 0) {
        vg = GrammarManager::CreateGrammarFromString(vxirec, log, gram,
                                                     REC_MIME_OPTION_DTMF,
                                                     recProps);
        if (vg == NULL)
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_OPTION);
        AddGrammar(vg, documentID, element);
      }

      // Add the built-in grammars (if they exist).
      vg = NULL;
      vxistring type;
      element.GetAttribute(ATTRIBUTE_TYPE, type);
      if (!type.empty()) {
        vxistring newuri(L"builtin:grammar/");
        newuri += type;
        if (vxirec->LoadGrammarURI(vxirec, recProps.GetValue(), NULL,
                                   newuri.c_str(), NULL, &vg)
            != VXIrec_RESULT_SUCCESS)
        {
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_GRAMMAR);
        }
        if (vg) AddGrammar(vg, documentID, element);

        newuri = L"builtin:dtmf/";
        newuri += type;
        if (vxirec->LoadGrammarURI(vxirec, recProps.GetValue(), NULL,
                                   newuri.c_str(), NULL, &vg)
            != VXIrec_RESULT_SUCCESS)
        {
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_GRAMMAR);
        }
        if (vg) AddGrammar(vg, documentID, element);
      }

      // Recursively add grammars (this handles <grammar>)
      bool doPop = properties.PushProperties(element);
      LoadGrammars(element, documentID, properties);
      if (doPop) properties.PopProperties();
    }

    // (6) Handle <link>.

    else if (elementName == NODE_LINK) {
      log.LogDiagnostic(2, L"GrammarManager::LoadGrammars - <link>");

      // (6.1) Get properties at this level.
      bool doPop = properties.PushProperties(element);

      // (6.2) Create DTMF grammar is specified.
      vxistring dtmf;
      element.GetAttribute(ATTRIBUTE_DTMF, dtmf);
      if (!dtmf.empty()) {
        VXIrecGrammar * vg = NULL;
        vg = GrammarManager::CreateGrammarFromString(vxirec, log, dtmf,
                                                     REC_MIME_CHOICE_DTMF,
                                                     recProps);
        if (vg == NULL)
          throw VXIException::InterpreterEvent(EV_ERROR_BAD_CHOICE);

        AddGrammar(vg, documentID, element);
      }

      // (6.3) Create child grammars.
      LoadGrammars(element, documentID, properties);
      if (doPop) properties.PopProperties();
    }

    // (7) Handle <record> and <transfer>.

    else if (elementName == NODE_RECORD || elementName == NODE_TRANSFER) { 
      // The DTD allows <grammar> elements, but these don't make sense.  We
      // will therefore ignore them.
    }

    // (8) Handle <transfer>
    else if ( elementName == NODE_TRANSFER ) {
       bool doPop = properties.PushProperties(element);
       LoadGrammars(element, documentID, properties);
       if (doPop) properties.PopProperties();
    }
 
    // (9) Otherwise, nothing was found at this level.  Use recursion to check
    //     the next level down.

    else {
      bool doPop = properties.PushProperties(element);
      LoadGrammars(element, documentID, properties);
      if (doPop) properties.PopProperties();
    }
  }
}