📄 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 "GrammarManager.hpp" #include "SimpleLogger.hpp" #include "CommonExceptions.hpp" #include "PropertyList.hpp" #include "VXML.h" #include "DocumentModel.hpp" #include <sstream> //############################################################################# // 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; element.GetAttribute(ATTRIBUTE_TYPE, mimeType); VXIrecGrammar * vg = GrammarManager::CreateGrammarFromURI(vxirec, log, src,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -