예제 #1
0
GrammarInfo::GrammarInfo(VXIrecGrammar * g,
                         const vxistring & id,
                         const VXMLElement & elem)
  : element(elem), recgrammar(g), scope(GRS_NONE), docID(id), enabled(false)
{
  // (1) Determine the grammar scope.
  
  // (1.1) Obtain default from position in the tree.
  VXMLElement par = elem;
  while (par != 0) {
    VXMLElementType name = par.GetName();
    if (name == NODE_INITIAL || name == NODE_FIELD ||
        name == NODE_RECORD  || name == NODE_TRANSFER)
      { scope = GRS_FIELD;  break; }
    else if (name == NODE_FORM || name == NODE_MENU)
      { scope = GRS_DIALOG; break; }
    else if (name == NODE_VXML)
      { scope = GRS_DOC;    break; }
    par = par.GetParent();
  }

  // (1.2) if scope explicitly specified in grammar or parent, override!
  vxistring str;
  elem.GetAttribute(ATTRIBUTE_SCOPE, str);
  if (str.empty() && par != 0) {
    par.GetAttribute(ATTRIBUTE_SCOPE, str);
  }
  if (!str.empty()) {
    if (str == L"dialog")        scope = GRS_DIALOG;
    else if (str == L"document") scope = GRS_DOC;
  }

  // (2) Do remaining initialization.
  _Initialize(elem);
}
예제 #2
0
void GrammarInfo::_Initialize(const VXMLElement & elem)
{
  if (elem == 0) return;

  VXMLElementType name = elem.GetName();
  if (name == NODE_FIELD || name == NODE_INITIAL || name == NODE_TRANSFER)
    elem.GetAttribute(ATTRIBUTE__ITEMNAME, field);
  else if (name == NODE_FORM || name == NODE_MENU) {
    elem.GetAttribute(ATTRIBUTE__ITEMNAME, dialog);
    return;
  }

  _Initialize(elem.GetParent());
}
예제 #3
0
// -2: Internal error
int DocumentParser::FetchDocument(const VXIchar * url,
                                  const VXIMapHolder & properties,
                                  VXIinetInterface * inet,
                                  VXIcacheInterface * cache,
                                  SimpleLogger & log,
                                  VXMLDocument & document,
                                  VXIMapHolder & docProperties,
                                  bool isDefaults,
                                  bool isRootApp,
                                  VXIbyte **content,
                                  VXIulong *size)
{
  int result;
  int path_only = 0;
  VXMLDocument *cached_parse_tree = NULL;

  if (log.IsLogging(2)) {
    log.StartDiagnostic(2) << L"DocumentParser::FetchDocument(" << url << L")";
    log.EndDiagnostic();
  }

  // (1) Load the VXML DTD for validation.  This will override an externally
  // specified DTD if the user provides a link.

  try {
    if (isDefaults) {
      MemBufInputSource membuf(
          VALIDATOR_DATA + DUMMY_VXML_DEFAULTS_DOC,
          DUMMY_VXML_DEFAULTS_DOC_SIZE,
          "vxml 1.0 defaults");
      parser->parse(membuf);
      converter->ResetDocument(); // Throw this document away.
    }

    if (!isDefaults && !loadedVXML20) {
      // Preload the VXML 2.1 schema.
      VXIcharToXMLCh name(L"http://www.w3.org/TR/voicexml21/vxml.xsd");
      LockLoadGrammar();
      parser->loadGrammar(name.c_str(), Grammar::SchemaGrammarType, true);
      // Reuse cached grammars if available.
      parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);      
      UnlockLoadGrammar(); 
      loadedVXML20 = true;
    }
  }
  catch (const XMLException & exception) {
    if (!isDefaults && !loadedVXML20) 
      UnlockLoadGrammar();  
      
    XMLChToVXIchar message(exception.getMessage());
    log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - XML parsing "
      L"error from DOM: " << message;
    log.EndDiagnostic();
    log.LogError(999, SimpleLogger::MESSAGE, L"unable to load VXML DTD");
    return 4;
  }
  catch (const SAXParseException & exception) {
    if (!isDefaults && !loadedVXML20) 
      UnlockLoadGrammar();  
      
    XMLChToVXIchar sysid(exception.getSystemId());
    XMLChToVXIchar message(exception.getMessage());
    log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - Parse error "
                           << L"in file \"" 
                           << sysid 
                           << L"\", line " << exception.getLineNumber()
                           << L", column " << exception.getColumnNumber()
                           << L" - " << message;
    log.EndDiagnostic();
    log.LogError(999, SimpleLogger::MESSAGE, L"unable to load VXML DTD");
    return 4;
  }
  catch (...) {
    if (!isDefaults && !loadedVXML20) 
      UnlockLoadGrammar();  

    log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - Unknown Parse error";
    log.EndDiagnostic();
    log.LogError(999, SimpleLogger::MESSAGE, L"unable to load VXML DTD");
    return 4;          
  }

  // (2) Load the url's content into memory.

  const VXIbyte * buffer = NULL;
  VXIulong bufSize = 0;
  vxistring docURL;
  bool isDefaultDoc = false;
  
  if (isDefaults && wcslen(url) == 0)
  {
    buffer  = VALIDATOR_DATA + VXML_DEFAULTS;
    bufSize = VXML_DEFAULTS_SIZE;
    docURL = L"builtin defaults";
    result = 0;
    isDefaultDoc = true;
  }
  else
  {
      path_only = 1;
      result = DocumentParser::FetchBuffer
	  (url, properties, docProperties, inet, log,
	   buffer, bufSize, docURL, 1, &cached_parse_tree);
  }

  if (result != 0) {
    if (log.IsLogging(0)) {
      log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - exiting "
        L"with error result " << result;
      log.EndDiagnostic();
    }
    return result; // may return { -1, 1, 2, 3 }
  }

  // store buffer for reference
  if (content) {
    VXIbyte *tempbuf = new VXIbyte[bufSize];
    if(tempbuf == NULL) {
      log.LogError(202);
      if( !isDefaultDoc ) DocumentParser::ReleaseBuffer(buffer);
      return -1;
    }

    if (voiceglue_loglevel() >= LOG_DEBUG)
    {
	std::ostringstream logstring;
	logstring << "(Copy) Allocated http_get buffer "
		  << Pointer_to_Std_String((const void *) tempbuf)
		  << " of size " << bufSize;
	voiceglue_log ((char) LOG_DEBUG, logstring);
    };

    memcpy(tempbuf, buffer, bufSize);
    if (size != NULL) *size = bufSize;
    *content = tempbuf;
  }
  
  // (3) Pull the document from cache.

  vxistring baseURL;
  VXMLDocument doc;
  // if (!DocumentStorageSingleton::Instance()->Retrieve(doc, buffer, bufSize, docURL.c_str())) {
  if (cached_parse_tree == NULL)
  {
      //  No cached parse tree, must perform my own parse
      //  and return results to voiceglue perl

      // (3.1) Set the base uri for this document, but
      // ignore if it is the default doc. Note: only want to do this if
      // not pulling from the cache otherwise the base is messed up
      if(!isDefaultDoc) 
        converter->SetBaseUri(docURL.c_str());

    // (4) Not in cache; parse buffer into our VXML document representation
    try
    {
      VXIcharToXMLCh membufURL(docURL.c_str());
      // Set Document level
      if( isDefaults ) 
        converter->SetDocumentLevel(DEFAULTS);
      else if( isRootApp )
        converter->SetDocumentLevel(APPLICATION);
      else
        converter->SetDocumentLevel(DOCUMENT);
      // Parse the script
      if (path_only)
      {
	  vxistring vxi_string_path =
	      Std_String_to_vxistring ((const char *) buffer);
	  VXIcharToXMLCh wide_path(vxi_string_path.c_str());
	  LocalFileInputSource filesource(wide_path.c_str());
	  parser->parse(filesource);
      }
      else
      {
	  MemBufInputSource membuf(buffer, bufSize, membufURL.c_str(), false);
	  parser->parse(membuf);
      };
    }
    catch (const XMLException & exception) {
      if( !isDefaultDoc ) DocumentParser::ReleaseBuffer(buffer);
      if (path_only) voiceglue_sendipcmsg ("VXMLParse 0 -\n");
      if (log.IsLogging(0)) {
        XMLChToVXIchar message(exception.getMessage());
        log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - XML "
          L"parsing error from DOM: " << message;
        log.EndDiagnostic();
      }
      return 4;
    }
    catch (const SAXParseException & exception) {
      VXIString *key = NULL, *value = NULL;
      if (log.LogContent(VXI_MIME_XML, buffer, bufSize, &key, &value)) 
      {
        vxistring temp(L"");
        temp += VXIStringCStr(key);
        temp += L": ";
        temp += VXIStringCStr(value);
        log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - buffer is saved in: "
                               << temp;
        log.EndDiagnostic();
      }        
      if (key) VXIStringDestroy(&key);
      if (value) VXIStringDestroy(&value);
      
      if( !isDefaultDoc ) DocumentParser::ReleaseBuffer(buffer);
      if (path_only) voiceglue_sendipcmsg ("VXMLParse 0 -\n");
      if (log.IsLogging(0)) {
        XMLChToVXIchar sysid(exception.getSystemId());
        XMLChToVXIchar message(exception.getMessage());
        log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - Parse "
                               << L"error in file \"" 
                               << sysid
                               << L"\", line " << exception.getLineNumber()
                               << L", column " << exception.getColumnNumber()
                               << L" - " 
                               << message;
        log.EndDiagnostic();
      }
      return 4;
    }

    // (5) Write the parsed tree address out to the voiceglue cache
    doc = converter->GetDocument();
    // Set the current uri as base uri if there isn't a "xml:base" attribute
    doc.GetBaseURL(baseURL);
    if( baseURL.empty() ) doc.SetBaseURL(docURL);
    
    // store default language
    if( isDefaults ) {
      vxistring dlang;
      converter->GetDefaultLang(dlang);
      doc.SetDefaultLang(dlang);
    }        

    // Put into voiceglue cache as standalone persistent VXMLDocument object
    if (path_only)
    {
	VXMLDocument *permanent_doc = new VXMLDocument (doc);
	std::ostringstream ipc_msg_out;
	ipc_msg_out
	    << "VXMLParse 1 "
	    << Pointer_to_Std_String ((void *) permanent_doc)
	    << "\n";
	voiceglue_sendipcmsg (ipc_msg_out);
    }
    // DocumentStorageSingleton::Instance()->Store(doc, buffer, bufSize, docURL.c_str());
  }
  else {
    // The document is already in the memory cache
      doc = *cached_parse_tree;
    // Need to set the base uri
    converter->RestoreBaseURLFromCache(doc);
    // Restore default language
    if( isDefaults ) {
      converter->RestoreDefaultLangFromCache(doc);
    }
  }

  if( !isDefaultDoc ) DocumentParser::ReleaseBuffer(buffer);

  // (6) Parse was successful, process document.  We want only the top level
  // <vxml> node.

  const VXMLElement root = doc.GetRoot();
  VXMLElementType nodeName = root.GetName();

  // If we're looking for the defaults, we can exit early.
  if (isDefaults && nodeName == DEFAULTS_ROOT) {
    log.LogDiagnostic(2, L"DocumentParser::FetchDocument(): Default document - success");
    document = doc;
    return 0;
  }
  else if (nodeName != NODE_VXML) {
    document = VXMLDocument();
    if (log.IsLogging(0)) {
      log.StartDiagnostic(0) << L"DocumentParser::FetchDocument - unable to "
        L"find " << NODE_VXML << L" in document.";
      log.EndDiagnostic();
    }
    return 4;
  }

  vxistring temp;

  // If the properties map is NULL, don't bother with the remaining settings
  if (docProperties.GetValue() != NULL) {
    // Retrieve the properties and put them into the map.

    VXIString * str = NULL;
    temp = docURL;
    str = VXIStringCreate(temp.c_str());
    if (str == NULL) 
      throw VXIException::OutOfMemory();

    VXIMapSetProperty(docProperties.GetValue(), PropertyList::AbsoluteURI,
                      reinterpret_cast<VXIValue *>(str));

    str = VXIStringCreate(converter->GetBaseUri().empty() ? L"" : 
                          converter->GetBaseUri().c_str());
    
    if (str == NULL)
      throw VXIException::OutOfMemory();

    VXIMapSetProperty(docProperties.GetValue(), PropertyList::BaseURI,
                      reinterpret_cast<VXIValue *>(str));

	// store encoding
    str = VXIStringCreate(encoding.empty() ? L"UTF-8" : encoding.c_str());
    if (str == NULL)
      throw VXIException::OutOfMemory();
    VXIMapSetProperty(docProperties.GetValue(), PropertyList::SourceEncoding,
                      reinterpret_cast<VXIValue *>(str));

	// store xml:lang
	if (root.GetAttribute(ATTRIBUTE_XMLLANG, temp)) {
      str = VXIStringCreate(temp.c_str());
      if (str == NULL)
        throw VXIException::OutOfMemory();

      VXIMapSetProperty(docProperties.GetValue(), PropertyList::Language,
                        reinterpret_cast<VXIValue *>(str));
    }
  }

  log.LogDiagnostic(2, L"DocumentParser::FetchDocument(): VXML document - success");

  document = doc;
  return 0;
}
예제 #4
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();
    }
  }
}