AnswerParser.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:27k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #include "GrammarManager.hpp"
  23. #include "AnswerParser.hpp"
  24. #include "CommonExceptions.hpp"
  25. #include "SimpleLogger.hpp"
  26. #include "VXIrec.h"                     // for a single type name (eliminate?)
  27. #include "XMLChConverter.hpp"           // for xmlcharstring
  28. #include <sstream>
  29. #include <map>
  30. #include <list>
  31. #include <vector>
  32. #include <framework/MemBufInputSource.hpp>
  33. #include <sax/ErrorHandler.hpp>         // by XMLErrorReporter
  34. #include <dom/DOM.hpp>
  35. #include <sax/SAXParseException.hpp>
  36. #include <util/XMLChar.hpp>
  37. using namespace xercesc;
  38. #ifndef WIN32
  39. inline bool Compare(const XMLCh * a, const XMLCh * b)
  40. {
  41.   return XMLString::compareString(a, b) == 0;
  42. }
  43. #endif
  44. // ---------------------------------------------------------------------------
  45. class AnswerHolder {
  46. public:
  47.   AnswerHolder(const XMLCh* ut, const XMLCh* im, 
  48.                const XMLCh* gid, const XMLCh* cf, float fCf,             
  49.                GrammarManager & gm)
  50.     : utterance(ut), inputmode(im), grammarid(gid), confidence(cf),       
  51.       fConfidence(fCf), grammarInfo(0), gramMgr(gm), answerElement() { }
  52.   
  53.   void SetInstance(DOMElement *is) { instanceDomList.push_back(is); }
  54.   void SetInstance(const xmlcharstring & is){ instanceStrList.push_back(is); }  
  55.   bool operator<(const AnswerHolder & x) 
  56.   {
  57.     // Compare conf. score first
  58.     if( fConfidence < x.fConfidence ) 
  59.       return true;
  60.     else if( fConfidence > x.fConfidence ) 
  61.       return false;
  62.     
  63.     // Otherwise compare precedence if conf. score is the same
  64.     switch(gramMgr.CompareGrammar(grammarInfo, x.grammarInfo)) {
  65.       case -1: return false;
  66.       default: return true;
  67.     }
  68.   }
  69.   bool operator>(const AnswerHolder & x) 
  70.   {
  71.     return !operator<(x);
  72.   }
  73.   AnswerHolder & operator=(const AnswerHolder &x)
  74.   {
  75.     if (this != &x) {
  76.       utterance = x.utterance;
  77.       inputmode = x.inputmode;
  78.       grammarid = x.grammarid;
  79.       grammarInfo = x.grammarInfo;
  80.       confidence = x.confidence;
  81.       fConfidence = x.fConfidence;
  82.       instanceDomList = x.instanceDomList;
  83.       instanceStrList = x.instanceStrList;
  84.       answerElement = x.answerElement;
  85.     }
  86.     return *this;
  87.   }
  88.   
  89.   xmlcharstring utterance;
  90.   const XMLCh* inputmode;
  91.   const XMLCh* grammarid;
  92.   const XMLCh* confidence;
  93.   float fConfidence;
  94.   unsigned long grammarInfo;
  95.   GrammarManager & gramMgr;
  96.   VXMLElement answerElement;
  97.   
  98.   typedef std::list<DOMElement*> DOMLIST;
  99.   DOMLIST instanceDomList;
  100.   typedef std::list<xmlcharstring> STRLIST;
  101.   STRLIST instanceStrList;    
  102. };  
  103. typedef std::vector<AnswerHolder > ANSWERHOLDERVECTOR;
  104. typedef std::map<VXIflt32, ANSWERHOLDERVECTOR, std::greater<VXIflt32> > ANSWERHOLDERMAP;
  105. class AnswerParserErrorReporter : public ErrorHandler {
  106. public:
  107.   AnswerParserErrorReporter()  { }
  108.   ~AnswerParserErrorReporter() { }
  109.   void warning(const SAXParseException& toCatch)     { /* Ignore */ }
  110.   void fatalError(const SAXParseException& toCatch)  { error(toCatch); }
  111.   void resetErrors() { }
  112.   void error(const SAXParseException & toCatch)
  113.   { throw SAXParseException(toCatch); }
  114. private:
  115.   AnswerParserErrorReporter(const AnswerParserErrorReporter &);
  116.   void operator=(const AnswerParserErrorReporter &);
  117. };
  118. // ---------------------------------------------------------------------------
  119. AnswerParser::AnswerParser()
  120. {
  121.   nlsmlParser = new XercesDOMParser();
  122.   if (nlsmlParser == NULL)
  123.     throw VXIException::OutOfMemory();
  124.   nlsmlParser->setValidationScheme( XercesDOMParser::Val_Never);
  125.   nlsmlParser->setDoNamespaces(false);
  126.   nlsmlParser->setDoSchema(false);
  127.   nlsmlParser->setValidationSchemaFullChecking(false);
  128.   nlsmlParser->setCreateEntityReferenceNodes(false);
  129.   // nlsmlParser->setToCreateXMLDeclTypeNode(true);
  130.   ErrorHandler *errReporter = new AnswerParserErrorReporter();
  131.   if (errReporter == NULL) {
  132.     delete nlsmlParser;
  133.     throw VXIException::OutOfMemory();
  134.   }
  135.   nlsmlParser->setErrorHandler(errReporter);
  136. }
  137. AnswerParser::~AnswerParser()
  138. {
  139.   if (nlsmlParser != NULL) {
  140.     const ErrorHandler * reporter = nlsmlParser->getErrorHandler();
  141.     nlsmlParser->setErrorHandler(NULL);
  142.     delete reporter;
  143.     delete nlsmlParser;
  144.     nlsmlParser = NULL;
  145.   }
  146. }
  147. inline bool AnswerParser::IsAllWhiteSpace(const XMLCh* str)
  148. {
  149.   if( !str ) return true;
  150.   while( *str != 0 ) {
  151.     if( *str != 'r' && *str != 'n' && *str != 't' && *str != ' ')
  152.       return false;
  153.     ++str;  
  154.   }
  155.   return true;
  156. }
  157. AnswerParser::ParseResult AnswerParser::Parse(SimpleLogger & log, AnswerTranslator & translator,
  158.                         GrammarManager & gm, int maxnbest,
  159.                         VXIContent * document, VXMLElement & bestAnswer)
  160. {
  161.   if (document == NULL) return AnswerParser::InvalidParameter;
  162.   // (1) Get document contents.
  163.   const VXIchar * docType;
  164.   const VXIbyte * docContent;
  165.   VXIulong docContentSize = 0;
  166.   if (VXIContentValue(document, &docType, &docContent, &docContentSize) !=
  167.       VXIvalue_RESULT_SUCCESS) return AnswerParser::InvalidParameter;
  168.   if (docContent == NULL || docContentSize == 0) return AnswerParser::InvalidParameter;
  169.   if (log.IsLogging(3)) {
  170.     VXIString *key = NULL, *value = NULL;
  171.     if (log.LogContent(docType, docContent, docContentSize,
  172.                        &key, &value))
  173.     {
  174.       vxistring temp = VXIStringCStr(key);
  175.       temp += L": ";
  176.       temp += VXIStringCStr(value);
  177.       log.StartDiagnostic(0) << L"AnswerParser::Parse - Raw NLSML result saved in: "
  178.                              << temp.c_str();
  179.       log.EndDiagnostic();
  180.     }
  181.     if( key ) VXIStringDestroy(&key);
  182.     if( value ) VXIStringDestroy(&value);
  183.   }
  184.   // (2) Parse NLSML format.
  185.   vxistring type(docType);
  186.   if (type != VXIREC_MIMETYPE_XMLRESULT) {
  187.   log.StartDiagnostic(0) << L"AnswerParser::Parse - unsupported content: "
  188.                              << type.c_str();
  189.       log.EndDiagnostic();
  190.   return AnswerParser::UnsupportedContent;
  191.   }
  192.   else {
  193.     try {
  194.       VXIcharToXMLCh membufURL(L"nlsml recognition result");
  195.       MemBufInputSource buf(docContent,docContentSize,membufURL.c_str(),false);
  196.       nlsmlParser->parse(buf);
  197.     }
  198.     catch (const XMLException & exception) {
  199.       if (log.IsLogging(0)) {
  200.         XMLChToVXIchar message(exception.getMessage());
  201.         log.StartDiagnostic(0) << L"AnswerParser::Parse - XML parsing "
  202.           L"error from DOM: " << message;
  203.         log.EndDiagnostic();
  204.       }
  205.   return AnswerParser::ParseError;
  206.     }
  207.     catch (const SAXParseException & exception) {
  208.       if (log.IsLogging(0)) {
  209.         XMLChToVXIchar message(exception.getMessage());
  210.         log.StartDiagnostic(0) << L"AnswerParser::Parse - Parse error at line "
  211.                                << exception.getLineNumber()
  212.                                << L", column " << exception.getColumnNumber()
  213.                                << L" - " << message;
  214.         log.EndDiagnostic();
  215.       }
  216.       return AnswerParser::ParseError;
  217.     }
  218.     switch (ProcessNLSML(log, translator, gm, maxnbest, bestAnswer)) {
  219.     case -1:
  220.       return AnswerParser::ParseError;
  221.     case 0:
  222.       return AnswerParser::Success;
  223.     case 1:
  224.       return AnswerParser::NoInput;
  225.     case 2:
  226.       return AnswerParser::NoMatch;
  227.     default:
  228.       break;
  229.     }
  230.   }
  231.   return AnswerParser::Success;
  232. }
  233. // ---------------------------------------------------------------------------
  234. // NLSML Parser
  235. // ---------------------------------------------------------------------------
  236. static const XMLCh NODE_RESULT[]
  237.     = { 'r','e','s','u','l','t','' };
  238. static const XMLCh NODE_INTERPRETATION[]
  239.     = { 'i','n','t','e','r','p','r','e','t','a','t','i','o','n','' };
  240. static const XMLCh NODE_INPUT[]
  241.     = { 'i','n','p','u','t','' };
  242. static const XMLCh NODE_INSTANCE[]
  243.     = { 'i','n','s','t','a','n','c','e','' };
  244. static const XMLCh NODE_NOINPUT[]
  245.     = { 'n','o','i','n','p','u','t','' };
  246. static const XMLCh NODE_NOMATCH[]
  247.     = { 'n','o','m','a','t','c','h','' };
  248. static const XMLCh ATTR_GRAMMAR[]
  249.     = { 'g','r','a','m','m','a','r','' };
  250. static const XMLCh ATTR_CONFIDENCE[]
  251.     = { 'c','o','n','f','i','d','e','n','c','e','' };
  252. static const XMLCh ATTR_MODE[]
  253.     = { 'm','o','d','e','' };
  254. static const XMLCh DEFAULT_CONFIDENCE[]
  255.     = { '1','0','0','' };
  256. static const XMLCh DEFAULT_MODE[]
  257.     = { 's','p','e','e','c','h','' };
  258. // This function is used by the other NLSMLSetVars functions to set everything
  259. // but the 'interpretation'.
  260. //
  261. void NLSMLSetSomeVars(vxistring variable, AnswerTranslator & translator,
  262.                       const XMLCh * confidence, const XMLCh *utterance,
  263.                       const XMLCh * mode)
  264. {
  265.   // (1) Set the 'confidence'.
  266.   vxistring expr = variable + L".confidence = ";
  267.   expr += XMLChToVXIchar(confidence).c_str();
  268.   expr += L" / 100;";
  269.   translator.EvaluateExpression(expr);
  270.   // (2) Set the 'utterance'
  271.   translator.SetString(variable + L".utterance",
  272.                        XMLChToVXIchar(utterance).c_str());
  273.   // (3) Set the 'inputmode'
  274.   if (Compare(mode, DEFAULT_MODE))
  275.     translator.SetString(variable + L".inputmode", L"voice");
  276.   else
  277.     translator.SetString(variable + L".inputmode",
  278.                          XMLChToVXIchar(mode).c_str());
  279. }
  280. // This sets all of the application.lastresult$ array when the interpretation
  281. // is a simple result.
  282. //
  283. bool NLSMLSetVars(AnswerTranslator & translator, int nbest,
  284.                   const XMLCh * confidence, const XMLCh * utterance,
  285.                   const XMLCh * mode, const XMLCh * interp)
  286. {
  287.   std::basic_ostringstream<VXIchar> out;
  288.   out << L"application.lastresult$[" << nbest << L"]";
  289.   translator.EvaluateExpression(out.str() + L" = new Object();");
  290.   // Set everything but interpretation.
  291.   NLSMLSetSomeVars(out.str(), translator, confidence, utterance, mode);
  292.   // Set 'interpretation'.
  293.   translator.SetString(out.str() + L".interpretation",
  294.                        XMLChToVXIchar(interp).c_str());
  295.   return true;
  296. }
  297. // This function recursively processes the data within an <instance>.
  298. //
  299. bool NLSMLSetInterp(AnswerTranslator & translator, SimpleLogger & log,
  300.                     vxistring & path, const DOMNode * interp)
  301. {
  302.   bool foundText = false;
  303.   // Look for text first.
  304.   DOMNode * temp = NULL;
  305.   vxistring textValue(L"");
  306.   for (temp = interp->getFirstChild(); temp != NULL;
  307.        temp = temp->getNextSibling())
  308.   {
  309.     if (temp->getNodeType() != DOMNode::TEXT_NODE &&
  310.         temp->getNodeType() != DOMNode::CDATA_SECTION_NODE ) continue;
  311.     foundText = true;
  312.     textValue += XMLChToVXIchar(temp->getNodeValue()).c_str();
  313.   }
  314.   
  315.   if( foundText )
  316.     translator.SetString(path, textValue.c_str());
  317.   
  318.   bool foundElement = false;
  319.   // Now try for elements.
  320.   for (temp = interp->getFirstChild(); temp != NULL;
  321.        temp = temp->getNextSibling())
  322.   {
  323.     if (temp->getNodeType() != DOMNode::ELEMENT_NODE) continue;
  324.     if (foundText) {
  325.       log.StartDiagnostic(0)
  326.         << L"AnswerParser::ProcessNLSML - malformed <instance> at "
  327.         << path << L"; mixed text and elements";
  328.       log.EndDiagnostic();
  329.       return false;
  330.     }
  331.     if (!foundElement) {
  332.       translator.EvaluateExpression(path + L" = new Object();");
  333.       foundElement = true;
  334.     }
  335.     // Although ECMAScript arrays are treated like properties, calling
  336.     // x.1 = 'val' is invalid.  Instead, x[1] = 'val' must be used.
  337.     XMLChToVXIchar name(temp->getNodeName());
  338.     VXIchar first = *(name.c_str());
  339.     bool isArray = (first=='0' || first=='1' || first=='2' || first=='3' || 
  340.                     first=='4' || first=='5' || first=='6' || first=='7' ||
  341.                     first=='8' || first=='9');
  342.     vxistring newPath = path;
  343.     if (isArray)
  344.       newPath += L"[";
  345.     else
  346.       newPath += L".";
  347.     newPath += name.c_str();
  348.     if (isArray)
  349.       newPath += L"]";
  350.     NLSMLSetInterp(translator, log, newPath, temp);
  351.   }
  352.   if (!foundElement && !foundText) {
  353.     log.StartDiagnostic(0)
  354.       << L"AnswerParser::ProcessNLSML - malformed <instance> at "
  355.       << path << L"; no data found";
  356.     log.EndDiagnostic();
  357.     return false;
  358.   }
  359.   return true;
  360. }
  361. // This sets all of the application.lastresult$ array when <instance> contains
  362. // a complex result.
  363. //
  364. bool NLSMLSetVars(AnswerTranslator & translator, SimpleLogger & log,
  365.                   int nbest, const XMLCh * confidence,
  366.                   const XMLCh * utterance, const XMLCh * mode,
  367.                   const DOMNode * interp)
  368. {
  369.   std::basic_ostringstream<VXIchar> out;
  370.   out << L"application.lastresult$[" << nbest << L"]";
  371.   translator.EvaluateExpression(out.str() + L" = new Object();");
  372.   // Set everything but interpretation.
  373.   NLSMLSetSomeVars(out.str(), translator, confidence, utterance, mode);
  374.   // Set 'interpretation'.
  375.   vxistring path = out.str() + L".interpretation";
  376.   return NLSMLSetInterp(translator, log, path, interp);
  377. }
  378. // This function set up lastresult$ n best
  379. //
  380. static bool SetUpNBestList(int *nbest, bool *isAmbigous, SimpleLogger & log, 
  381.                           AnswerTranslator & translator, AnswerHolder & ans) 
  382. {
  383.   // if there is an instance of DOMElement type
  384.   // setting these instance
  385.   int index = 0;
  386.   if( ans.instanceStrList.empty() ) {
  387.     AnswerHolder::DOMLIST::iterator pos;
  388.     for(pos = ans.instanceDomList.begin(); 
  389.         pos != ans.instanceDomList.end(); ++pos, ++index) {
  390.       if (index > 0)
  391.         *isAmbigous = true;
  392.       if (log.IsLogging(2)) {
  393.          log.StartDiagnostic(2) << L"SetUpNBestList(" << *nbest
  394.          << L", " << XMLChToVXIchar(ans.grammarid).c_str() << L")";
  395.          log.EndDiagnostic();
  396.       }     
  397.       if (!NLSMLSetVars(translator, log, *nbest, ans.confidence, 
  398.                         ans.utterance.c_str(), ans.inputmode, (*pos)))
  399.       {
  400.         log.LogDiagnostic(0, L"AnswerParser: <instance> element "
  401.                       L"processing failed");
  402.         return false;
  403.       }
  404.       ++(*nbest);
  405.     }  
  406.   } 
  407.   else {
  408.     // Use the input text(utterance) as instance
  409.     AnswerHolder::STRLIST::iterator pos;
  410.     for(pos = ans.instanceStrList.begin(); 
  411.         pos != ans.instanceStrList.end(); ++pos, ++index) {
  412.       if (index > 0)
  413.         *isAmbigous = true;
  414.       if (log.IsLogging(2)) {
  415.          log.StartDiagnostic(2) << L"SetUpNBestList(" << *nbest
  416.          << L", " << XMLChToVXIchar(ans.grammarid).c_str() << L")";
  417.          log.EndDiagnostic();
  418.       }
  419.       NLSMLSetVars(translator, *nbest, ans.confidence, 
  420.                    ans.utterance.c_str(), ans.inputmode, (*pos).c_str());
  421.       ++(*nbest);
  422.     }
  423.   } 
  424.   return true;
  425. }
  426. // This function converts an NLSML result into ECMAScript.
  427. //
  428. int AnswerParser::ProcessNLSML(SimpleLogger & log,
  429.                                AnswerTranslator & translator,
  430.                                GrammarManager & gm, int maxnbest,
  431.                                VXMLElement & bestAnswer)
  432. {
  433.   DOMNode * doc = nlsmlParser->getDocument();
  434.   if (doc == NULL || !doc->hasChildNodes()) {
  435.     log.LogDiagnostic(0, L"AnswerParser::ProcessNLSML - "
  436.                       L"Document parse failed");
  437.     return -1;
  438.   }
  439.   // (1) <result> element
  440.   DOMElement * result = NULL;
  441.   DOMNode * temp = NULL;
  442.   for (temp = doc->getFirstChild(); temp != NULL;
  443.        temp = temp->getNextSibling())
  444.   {
  445.     switch (temp->getNodeType()) {
  446.     case DOMNode::ELEMENT_NODE:
  447.       if (result == NULL)
  448.         result = reinterpret_cast<DOMElement *>(temp);
  449.       else {
  450.         log.LogDiagnostic(0,L"AnswerParser: document must have a single root");
  451.         return -1;
  452.       }
  453.       break;
  454.     case DOMNode::TEXT_NODE:
  455.       log.LogDiagnostic(0, L"AnswerParser: PCDATA not allowed after <xml>");
  456.       return -1;
  457.     default:
  458.       continue;
  459.     }
  460.   }
  461.   if (result == NULL || !Compare(result->getNodeName(), NODE_RESULT)) {
  462.     log.LogDiagnostic(0, L"AnswerParser: document must have a single "
  463.                       L"root named 'result'");
  464.     return -1;
  465.   }
  466.   const XMLCh * resultGrammar = result->getAttribute(ATTR_GRAMMAR);
  467.   // (2) <interpretation> elements
  468.   int nbest = -1;
  469.   ANSWERHOLDERMAP answerMap;
  470.   for (DOMNode * temp2 = result->getFirstChild(); temp2 != NULL;
  471.        temp2 = temp2->getNextSibling())
  472.   {
  473.     switch (temp2->getNodeType()) {
  474.     case DOMNode::ELEMENT_NODE:
  475.       break;   
  476.     case DOMNode::TEXT_NODE: 
  477.       // check for white space
  478.       if (IsAllWhiteSpace(temp2->getNodeValue())) continue;               
  479.       log.LogDiagnostic(0, L"AnswerParser: PCDATA not allowed after <result>");
  480.       return -1;
  481.     default:
  482.       continue;
  483.     }
  484.     DOMElement * interpretation = reinterpret_cast<DOMElement *>(temp2);
  485.     // (2.1) Is this an interpretation element?
  486.     if (!Compare(interpretation->getNodeName(), NODE_INTERPRETATION)) {
  487.       log.LogDiagnostic(0, L"AnswerParser: only <interpretation> elements may "
  488.                         L"follow <result>");
  489.       return -1;
  490.     }
  491.     // (2.2) Get the grammar attribute.
  492.     const XMLCh * grammar = interpretation->getAttribute(ATTR_GRAMMAR);
  493.     if (grammar == NULL || grammar[0] == 0) grammar = resultGrammar;
  494.     // (2.3) Get the confidence attribute.
  495.     const XMLCh * interpretationConfidence
  496.       = interpretation->getAttribute(ATTR_CONFIDENCE);
  497.     // (3) <input> element.
  498.     // (3.1) Find the <input> element.  There can be only one.
  499.     DOMElement * input = NULL;
  500.     for (temp = interpretation->getFirstChild(); temp != NULL;
  501.          temp = temp->getNextSibling())
  502.     {
  503.       switch (temp->getNodeType()) {
  504.       case DOMNode::TEXT_NODE:
  505.         // check for white space
  506.         if( IsAllWhiteSpace(temp->getNodeValue())) continue;               
  507.         log.LogDiagnostic(0, L"AnswerParser: PCDATA not allowed after "
  508.                           L"<interpretation>");
  509.         return -1;
  510.       case DOMNode::ELEMENT_NODE:
  511.         if (Compare(temp->getNodeName(), NODE_INSTANCE)) continue;
  512.         if (!Compare(temp->getNodeName(), NODE_INPUT)) {
  513.           log.LogDiagnostic(0, L"AnswerParser: Only <input> and <instance> "
  514.                             L"elements are allowed in an <interpretation>");
  515.           return -1;
  516.         }
  517.         if (input != NULL) {
  518.           log.LogDiagnostic(0, L"AnswerParser: Only one <input> element is "
  519.                             L"allowed in an <interpretation>");
  520.           return -1;
  521.         }
  522.         input = reinterpret_cast<DOMElement *>(temp);
  523.         break;
  524.       default:
  525.         continue;
  526.       }
  527.     }
  528.     // (3.1.5) Get the input mode.
  529.     const XMLCh * mode = input->getAttribute(ATTR_MODE);
  530.     if (mode == NULL || mode[0] == 0) mode = DEFAULT_MODE;
  531.     // (3.2) Look at the data inside of <input>.  Is this an event?
  532.     xmlcharstring inputText;
  533.     for (temp = input->getFirstChild(); temp != NULL;
  534.          temp = temp->getNextSibling())
  535.     {
  536.       short type = temp->getNodeType();
  537.       switch (type) {
  538.       case DOMNode::CDATA_SECTION_NODE:
  539.       case DOMNode::TEXT_NODE:
  540.         inputText += temp->getNodeValue();
  541.         break;
  542.       case DOMNode::ELEMENT_NODE:
  543.         // NOTE: The nbest count here is one less than the array value.  The
  544.         //       value is not incremented until the <instance> element is
  545.         //       processed.  Thus, the checks are against -1 NOT 0.
  546.         //
  547.         if (Compare(temp->getNodeName(), NODE_NOINPUT)) {
  548.           if (nbest == -1) return 1;
  549.           return 0; // Ignore this and subsequent interpretations.
  550.         }
  551.         if (Compare(temp->getNodeName(), NODE_NOMATCH)) {
  552.           //special case of setting lastresult$ input mode
  553.           translator.EvaluateExpression(L"application.lastresult$ = "
  554.                                         L"new Array();");
  555.           translator.EvaluateExpression(L"application.lastresult$[0] = new Object();");
  556.           if (Compare(mode, DEFAULT_MODE))
  557.             translator.SetString(L"application.lastresult$[0].inputmode", L"voice");
  558.           else
  559.             translator.SetString(L"application.lastresult$[0].inputmode", XMLChToVXIchar(mode).c_str());
  560.           if (nbest == -1) return 2;
  561.           return 0; // Ignore this and subsequent interpretations.
  562.         }
  563.         log.LogDiagnostic(0, L"AnswerParser: Only <noinput> and <nomatch> "
  564.                           L"elements or PCDATA is allowed in an <input>");
  565.         return -1;
  566.       default:
  567.         continue;
  568.       }
  569.     }
  570.      
  571.     if (inputText.empty()) {
  572.       log.LogDiagnostic(0, L"AnswerParser: <input> element may not be empty");
  573.       return -1;
  574.     }
  575.     if (grammar == NULL) {
  576.       log.LogDiagnostic(0, L"AnswerParser: the grammar attribute must be "
  577.                         L"defined in either <result> or <interpretation>");
  578.       return -1;
  579.     }
  580.     // (3.3) Get the confidence.
  581.     const XMLCh * confidence = input->getAttribute(ATTR_CONFIDENCE);
  582.     if (confidence == NULL || confidence[0] == 0)
  583.       confidence = interpretationConfidence;
  584.     if (confidence == NULL || confidence[0] == 0)
  585.       confidence = DEFAULT_CONFIDENCE;
  586.     
  587.     // (3.3.1) convert confidence score to float
  588.     VXIflt32 vConfidence = 0.5;
  589.     std::basic_stringstream<VXIchar> confStream(XMLChToVXIchar(confidence).c_str());
  590.     confStream >> vConfidence;    
  591.     
  592.     // (3.5) Determine precedence of this grammar
  593.     
  594.     // (3.5.1) retrieve the grammar for this interpretation
  595.     // create the answer info.
  596.     AnswerHolder newanswer(inputText.c_str(), mode, grammar, confidence, vConfidence, gm);
  597.     
  598.     // find this answer grammar
  599.     VXMLElement answerElement;
  600.     if (!gm.FindMatchedElement(XMLChToVXIchar(newanswer.grammarid).c_str(), 
  601.                                answerElement, newanswer.grammarInfo) ||
  602.         answerElement == 0)
  603.     {
  604.       // No match found!
  605.       log.LogError(433);
  606.       return 2;
  607.     }
  608.     
  609.     // set the answer element here
  610.     newanswer.answerElement = answerElement;
  611.     
  612.     // find the current confidence in answer map
  613.     ANSWERHOLDERMAP::iterator mit = answerMap.find(vConfidence);
  614.     AnswerHolder *newAnswerPtr = NULL;
  615.     // insert answer with confidence sorted in order
  616.     if( mit == answerMap.end()) {
  617.       // this score is first one in this list, create it
  618.       ANSWERHOLDERVECTOR newlist;
  619.       newlist.push_back(newanswer);
  620.       answerMap[vConfidence] = newlist;
  621.       newAnswerPtr = &(answerMap[vConfidence].back());
  622.     } 
  623.     else {      
  624.       (*mit).second.push_back(newanswer);
  625.       newAnswerPtr = &((*mit).second.back());     
  626.     }         
  627.     // (4) Look at each <instance>.
  628.     //
  629.     // At this point, we have DOMStrings with the 'grammar' name, 'confidence'
  630.     // score, input 'mode', and 'inputText'.  We have already verified that
  631.     // only <input> and <instance> nodes exist at this level.
  632.     bool hasInstance = false;
  633.     for (DOMNode * temp3 = interpretation->getFirstChild(); temp3 != NULL;
  634.          temp3 = temp3->getNextSibling())
  635.     {
  636.       if (temp3->getNodeType() != DOMNode::ELEMENT_NODE) continue;
  637.       if (!Compare(temp3->getNodeName(), NODE_INSTANCE)) continue;
  638.       hasInstance = true;
  639.       ++nbest;
  640.       // (4.2) Process the instance
  641.       // (4.2.1) Does the instance have data?
  642.       DOMElement * instance = reinterpret_cast<DOMElement *>(temp3);
  643.       bool hasInstanceData = false;
  644.       for (DOMNode * temp4 = instance->getFirstChild();
  645.            temp4 != NULL && !hasInstanceData;
  646.            temp4 = temp4->getNextSibling())
  647.       {
  648.         short type = temp4->getNodeType();
  649.         switch (type) {
  650.         case DOMNode::CDATA_SECTION_NODE:
  651.         case DOMNode::TEXT_NODE:
  652.         case DOMNode::ELEMENT_NODE:
  653.           newAnswerPtr->SetInstance(instance);
  654.           hasInstanceData = true;
  655.           break;
  656.         default:
  657.           continue;
  658.         }
  659.       }
  660.       
  661.       // (4.2.2) If the contents were empty - use input text as interpretation.
  662.       if (!hasInstanceData) {
  663.         newAnswerPtr->SetInstance(inputText);       
  664.       }
  665.     }
  666.     
  667.     // (4.2.3) If <instance> did not appear - use input text as interpretation.
  668.     if (!hasInstance) {
  669.       newAnswerPtr->SetInstance(inputText);             
  670.     }
  671.   }
  672.   // Setting up the lastresult$ structure
  673.   ANSWERHOLDERMAP::iterator it = answerMap.begin();
  674.   if( it == answerMap.end() ) {
  675.     // something is wrong, return error
  676.     log.LogDiagnostic(0, L"AnswerParser: the result structure is corrupted");                         
  677.     return -1;
  678.   }
  679.   else {    
  680.     // go through the vector and sort its precedence using selection sort
  681.     for( it = answerMap.begin(); it != answerMap.end(); ++it ) {
  682.       ANSWERHOLDERVECTOR & a = (*it).second;
  683.       int vsize = a.size();
  684.       if( vsize <= 1 ) continue;
  685.       for(int i = 0; i < vsize; i++ ) {
  686.         int min = i;
  687.         for( int j = i+1; j < vsize; j++)
  688.           if (a[j] < a[min]) min = j;       
  689.         AnswerHolder t = a[min]; a[min] = a[i]; a[i] = t;
  690.       }
  691.     }
  692.     
  693.     // go through the vector and setup lastresult structure
  694.     int nbestIndex = 0;
  695.     bool done = false, isAmbigous = false;
  696.     for( it = answerMap.begin(); !done && it != answerMap.end(); ++it ) {
  697.       ANSWERHOLDERVECTOR & a = (*it).second;
  698.       int vsize = a.size();
  699.       for( int i = 0; !done && i < vsize; i++) {
  700.         if( nbestIndex == 0 ) {
  701.           // create the result structure at first element
  702.           translator.EvaluateExpression(L"application.lastresult$ = "
  703.                                         L"new Array();");
  704.           bestAnswer = a[i].answerElement;
  705.         }                 
  706.         if( !SetUpNBestList(&nbestIndex, &isAmbigous, log, translator, a[i]))
  707.           return -1;
  708.         // check for maxnbest, if there is ambiguity, ignore maxnbest
  709.         // and setup appropriate nbest list
  710.         if( isAmbigous && nbestIndex > maxnbest-1 ) done = true;
  711.         else if( nbestIndex > maxnbest -1 ) done = true;
  712.       }       
  713.     }     
  714.   }
  715.   return 0;
  716. }