📄 grammarmanager.cpp
字号:
/****************License************************************************
*
* Copyright 2000-2003. ScanSoft, Inc.
*
* Use of this software is subject to notices and obligations set forth
* in the SpeechWorks Public License - Software Version 1.2 which is
* included with this software.
*
* ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech,
* SpeechWorks and the SpeechWorks logo are registered trademarks or
* trademarks of SpeechWorks International, Inc. in the United States
* and other countries.
*
***********************************************************************/
#include <vxibuildopts.h>
#if P_VXI
#include "GrammarManager.hpp"
#include "SimpleLogger.hpp"
#include "CommonExceptions.hpp"
#include "PropertyList.hpp"
#include "VXML.h"
#include "DocumentModel.hpp"
#include <sstream>
#ifdef _MSC_VER
#pragma warning(disable:4061)
#endif
//#############################################################################
// Grammar description class
//#############################################################################
const VXIchar * const GrammarManager::DTMFTerm = L"@dtmfterm";
const VXIchar * const GrammarManager::FinalSilence = L"@finalsilence";
const VXIchar * const GrammarManager::MaxTime = L"@maxtime";
const VXIchar * const GrammarManager::RecordingType = L"@rectype";
enum GrammarScope {
GRS_NONE,
GRS_FIELD,
GRS_DIALOG,
GRS_DOC
};
class GrammarInfo {
public:
GrammarInfo(VXIrecGrammar *, const vxistring &, const VXMLElement &,
unsigned long);
~GrammarInfo();
VXIrecGrammar * GetRecGrammar() const { return recgrammar; }
void SetEnabled(bool b, GrammarScope aScope = GRS_NONE)
{
enabled = b;
activatedScope = aScope;
}
GrammarScope GetScope(void) const { return activatedScope; }
unsigned long GetSequence(void) const { return grammarSeq; }
bool IsEnabled() const { return enabled; }
bool IsScope(GrammarScope s) const { return s == scope; }
bool IsField(const vxistring & f) const { return f == field; }
bool IsDialog(const vxistring & d) const { return d == dialog; }
bool IsDoc(const vxistring & d) const { return d == docID; }
void GetElement(VXMLElement & e) const { e = element; }
private:
void _Initialize(const VXMLElement & elem);
// This sets the field & dialog names.
const VXMLElement element;
VXIrecGrammar * recgrammar; // grammar handle returned from rec interface
GrammarScope scope;
vxistring field;
vxistring dialog;
vxistring docID;
bool enabled;
// store current activated info to determine precedence
GrammarScope activatedScope;
unsigned long grammarSeq;
};
GrammarInfo::GrammarInfo(VXIrecGrammar * g,
const vxistring & id,
const VXMLElement & elem,
unsigned long gSeq)
: element(elem), recgrammar(g), scope(GRS_NONE), docID(id), enabled(false),
activatedScope(GRS_NONE), grammarSeq(gSeq)
{
// (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 || name == DEFAULTS_LANGUAGE ||
name == DEFAULTS_ROOT)
{ 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);
}
GrammarInfo::~GrammarInfo()
{
// NOTE: 'recgrammar' must be freed externally.
}
void GrammarInfo::_Initialize(const VXMLElement & elem)
{
if (elem == 0) return;
VXMLElementType name = elem.GetName();
if (name == NODE_FIELD || name == NODE_INITIAL ||
name == NODE_RECORD || 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());
}
//#############################################################################
class GrammarInfoUniv {
public:
GrammarInfoUniv(VXIrecGrammar * g, const VXMLElement & e, const vxistring & l,
const vxistring & n, unsigned long seq)
: element(e), recgrammar(g), languageID(l), name(n), enabled(false),
grammarSeq(seq) { }
~GrammarInfoUniv() { } // NOTE: 'recgrammar' must be freed externally.
public:
void SetEnabled(bool b) { enabled = b; }
bool IsEnabled() const { return enabled; }
VXIrecGrammar * GetRecGrammar() const { return recgrammar; }
unsigned long GetSequence() const { return grammarSeq; }
const vxistring & GetLanguage() const { return languageID; }
const vxistring & GetName() const { return name; }
void GetElement(VXMLElement & e) const { e = element; }
private:
const VXMLElement element;
VXIrecGrammar * recgrammar; // grammar handle returned from rec interface
vxistring languageID;
vxistring name;
bool enabled;
unsigned long grammarSeq;
};
//#############################################################################
// Grammar description class
//#############################################################################
GrammarManager::GrammarManager(VXIrecInterface * r, const SimpleLogger & l)
: log(l), vxirec(r), grammarSequence(0)
{
}
GrammarManager::~GrammarManager()
{
ReleaseGrammars();
}
void GrammarManager::ThrowSpecificEventError(VXIrecResult err, OpType opType)
{
switch (err) {
case VXIrec_RESULT_SUCCESS: break;
case VXIrec_RESULT_NO_RESOURCE:
throw VXIException::InterpreterEvent(EV_ERROR_NORESOURCE);
case VXIrec_RESULT_NO_AUTHORIZATION:
throw VXIException::InterpreterEvent(EV_ERROR_NOAUTHORIZ);
case VXIrec_RESULT_MAX_SPEECH_TIMEOUT:
throw VXIException::InterpreterEvent(EV_MAXSPEECH);
case VXIrec_RESULT_UNSUPPORTED_FORMAT:
throw VXIException::InterpreterEvent(EV_UNSUPPORT_FORMAT);
case VXIrec_RESULT_UNSUPPORTED_LANGUAGE:
throw VXIException::InterpreterEvent(EV_UNSUPPORT_LANGUAGE);
case VXIrec_RESULT_UNSUPPORTED_BUILTIN:
throw VXIException::InterpreterEvent(EV_UNSUPPORT_BUILTIN);
case VXIrec_RESULT_FETCH_TIMEOUT:
case VXIrec_RESULT_FETCH_ERROR:
throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH);
case VXIrec_RESULT_OUT_OF_MEMORY:
throw VXIException::OutOfMemory();
// these events are supported for hotword transfer functionality
case VXIrec_RESULT_CONNECTION_NO_AUTHORIZATION:
throw VXIException::InterpreterEvent(EV_TELEPHONE_NOAUTHORIZ);
case VXIrec_RESULT_CONNECTION_BAD_DESTINATION:
throw VXIException::InterpreterEvent(EV_TELEPHONE_BAD_DEST);
case VXIrec_RESULT_CONNECTION_NO_ROUTE:
throw VXIException::InterpreterEvent(EV_TELEPHONE_NOROUTE);
case VXIrec_RESULT_CONNECTION_NO_RESOURCE:
throw VXIException::InterpreterEvent(EV_TELEPHONE_NORESOURCE);
case VXIrec_RESULT_UNSUPPORTED_URI:
throw VXIException::InterpreterEvent(EV_TELEPHONE_UNSUPPORT_URI);
default:
if( opType == GRAMMAR )
throw VXIException::InterpreterEvent(EV_ERROR_BAD_GRAMMAR);
}
}
void GrammarManager::LoadGrammars(const VXMLElement& doc,
vxistring & documentID,
PropertyList & properties,
bool isDefaults)
{
if (doc == 0) return;
// (1) Retrieve the ID for this document. This is important for grammar
// activation.
if (doc.GetName() == NODE_VXML)
doc.GetAttribute(ATTRIBUTE__ITEMNAME, documentID);
// (2) Recursively find and build all grammars on this page.
if (isDefaults)
BuildUniversals(doc, properties);
else {
VXIMapHolder temp(NULL);
BuildGrammars(doc, documentID, properties, temp);
}
}
VXIrecGrammar * GrammarManager::BuildInlineGrammar(const VXMLElement & element,
const VXIMapHolder & localProps)
{
vxistring text, header, trailer;
// (1) Get CDATA in this element
GetEnclosedText(log, element, text);
// (2) Get attributes
vxistring mimeType, mode, root, tagFormat, xmlBase, xmlLang;
element.GetAttribute(ATTRIBUTE_TYPE, mimeType);
element.GetAttribute(ATTRIBUTE_MODE, mode);
element.GetAttribute(ATTRIBUTE_ROOT, root);
element.GetAttribute(ATTRIBUTE_TAGFORMAT, tagFormat);
element.GetAttribute(ATTRIBUTE_BASE, xmlBase);
element.GetAttribute(ATTRIBUTE_XMLLANG, xmlLang);
// (3) Determine the mimetype.
// if mimetype is empty but root is defined
// assume that this is srgs+xml mimetype
if( mimeType.empty() && !root.empty())
mimeType = L"application/srgs+xml";
if( mimeType.empty() && mode == L"dtmf" )
mimeType = REC_MIME_CHOICE_DTMF;
// (4) Is this an SRGS grammar?
if (mimeType.find(L"application/srgs+xml") == 0 &&
(mimeType.length() == 20 || mimeType[20] == L';'))
{
// All grammars have a language assigned during parsing.
header = L"<?xml version='1.0'?>"
L"<grammar xmlns='http://www.w3.org/2001/06/grammar'"
L" version='1.0' mode='";
header += mode;
header += L"' root='";
header += root;
if (!tagFormat.empty()) {
header += L"' tag-format='";
header += tagFormat;
}
if (!xmlLang.empty()) {
header += L"' xml:lang='";
header += xmlLang;
}
if (!xmlBase.empty()) {
header += L"' xml:base='";
header += xmlBase;
}
header += L"'>";
trailer = L"</grammar>";
}
// (5) Create the grammar.
if (log.IsLogging(2)) {
log.StartDiagnostic(2) << L"GrammarManager::LoadGrammars - type="
<< mimeType << L", grammar=" << header << text << trailer << L">";
log.EndDiagnostic();
}
VXIrecGrammar * vg = NULL;
if (header.empty() && trailer.empty())
vg = GrammarManager::CreateGrammarFromString(vxirec, log, text,
mimeType.c_str(),
localProps);
else
vg = GrammarManager::CreateGrammarFromString(vxirec, log,
header + text + trailer,
mimeType.c_str(),
localProps);
if (vg == NULL)
throw VXIException::InterpreterEvent(EV_ERROR_BAD_INLINE);
return vg;
}
// This function is used to recursively walk through the tree, loading and
// speech or dtmf grammars which are found.
//
// NOTE: There is a rather messy optimization with properties, levelProperties,
// and localProps. This made the code much harder to read but had
// significant performance benefits. Be very careful!
//
void GrammarManager::BuildGrammars(const VXMLElement& doc,
const vxistring & documentID,
PropertyList & properties,
VXIMapHolder & levelProperties,
int menuAcceptLevel)
{
// (1) 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();
// (2) Handle <grammar>
if (elementName == NODE_GRAMMAR) {
vxistring src;
element.GetAttribute(ATTRIBUTE_SRC, src);
// (2.1) Get the recognizer properties associated with this element.
if (levelProperties.GetValue() == NULL)
levelProperties.Acquire(GetRecProperties(properties));
VXIMapHolder localProps(NULL);
localProps = levelProperties;
SetGrammarLoadProperties(element, localProps);
// (2.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();
}
// (2.2.1) Generate error if fragment-only URI in external grammar
if (!src.empty() && src[0] == '#') {
log.LogError(215);
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC,
L"a fragment-only URI is not permited in external grammar");
}
VXIMapHolder fetchobj;
if (fetchobj.GetValue() == NULL) throw VXIException::OutOfMemory();
properties.GetFetchobjCacheAttrs(element, PropertyList::Grammar,
fetchobj);
// (2.2.2) Load the grammar from the URI.
vxistring mimeType;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -