📄 documentconverter.cpp
字号:
ParseException(L"exactly one of 'aai' or 'aaiexpr' may be specified"); break; } // (6) Verify the node. ProcessNodeFinal(elemType); } void DocumentConverter::endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname) { // (0) Just ignore this? if (ignoreDepth > 0) { --ignoreDepth; return; } // (1) Copy this element or look it up? // (1.1) Inside a <grammar>, we can blindly copy this data. if (inGrammar && copyDepth == 0) inGrammar = false; if (inGrammar) { CopyElementClose(localname); return; } // (1.2) Convert name string to integer value. XMLChToVXIchar elementName(localname); int elemType; bool conversionFailed = !ConvertElement(elementName.c_str(), elemType); // (1.3) Copy almost anything inside a <prompt>. if (explicitPrompt) { if (conversionFailed) { CopyElementClose(localname); return; } switch (elemType) { case NODE_AUDIO: case NODE_VALUE: case NODE_ENUMERATE: break; case NODE_PROMPT: doc->AddContent(L"</speak>", 8); explicitPrompt = false; break; default: CopyElementClose(localname); return; } } // (1.4) Print errors for all other conversion failures. if (conversionFailed) { vxistring temp(L"unrecognized element - "); temp += elementName.c_str(); ParseException(temp.c_str()); } // (2) Handle implicit prompts. if (implicitPrompt) { switch (elemType) { case NODE_AUDIO: case NODE_VALUE: case NODE_ENUMERATE: break; case PRIV_ELEM_BREAK: // These implicitly imply a prompt. case PRIV_ELEM_EMPHASIS: case PRIV_ELEM_MARK: case PRIV_ELEM_PARAGRAPH: case PRIV_ELEM_PHONEME: case PRIV_ELEM_PROSODY: case PRIV_ELEM_SAYAS: case PRIV_ELEM_SENTENCE: case PRIV_ELEM_VOICE: CopyElementClose(localname); return; default: EndImplicitPrompt(); break; } } // (3) Reverse special handling from startElement() switch (elemType) { case NODE_CHOICE: // These may have PCDATA which is not a prompt case NODE_OPTION: doc->PruneWhitespace(); pcdataImpliesPrompt = true; case NODE_LOG: pcdataImpliesPrompt = true; break; case NODE_SCRIPT: pcdataImpliesPrompt = true; // Intentional fall through! case NODE_GRAMMAR: if (contentForbidden ^ hasContent) contentForbidden = false; else ParseException(L"either the 'src' attribute or inlined content " L"may be provided, not both"); break; default: break; } // (4) This element is complete. try { doc->EndElement(); } catch (const VXMLDocumentModel::InternalError &) { ParseException(L"corrupted document tree; unable to complete element"); } } void DocumentConverter::characters(const XMLCh* const chars, const unsigned int length) { // (0) Just ignore this? if (chars == NULL || length == 0 || ignoreDepth > 0) return; // (1) Ignore non-empty prompts consisting of pure whitespace unsigned int l; for (l = 0; l < length; ++l) { XMLCh c = chars[l]; if (c == ' ' || c == '\n' || c == '\r' || c == '\t') continue; break; } if (l == length) return; // (2) Is this an implicit prompt? if (pcdataImpliesPrompt && !explicitPrompt && !implicitPrompt && !inGrammar) StartImplicitPrompt(); // (3) Add content to the document model. try { // This conversion should be safe. CDATA may only contain valid XML // characters. These are defined in the XML 1.0 specification as the set // 0x9, 0xA, 0xD, 0x20-0xD7FF, 0xE000-0xFFFD, 0x10000-0x10FFFF. XMLChToVXIchar data(chars); hasContent = true; unsigned int start = 0; unsigned int pos = 0; VXIchar c; // We need to escape two characters: (<,&) -> (<, &) if((inGrammar && (GetGrammarType().empty() || GetGrammarType() == L"application/srgs+xml")) || (explicitPrompt || implicitPrompt) ) { do { c = *(data.c_str() + pos); if (c == L'<') { if (start != pos) doc->AddContent(data.c_str() + start, pos - start); start = pos + 1; doc->AddContent(L"<", 4); } else if (c == L'&') { if (start != pos) doc->AddContent(data.c_str() + start, pos - start); start = pos + 1; doc->AddContent(L"&", 5); } ++pos; } while (c != L'\0'); if (pos > start) doc->AddContent(data.c_str() + start, pos - start - 1); // -1 to kill off final \0 } else { doc->AddContent(data.c_str(), wcslen(data.c_str())); } } catch (const VXMLDocumentModel::OutOfMemory &) { ParseException(L"unable to allocate memory for content"); } catch (const VXMLDocumentModel::InternalError &) { ParseException(L"corrupted document tree; unable to add content"); } } void DocumentConverter::ignorableWhitespace(const XMLCh* const chars, const unsigned int l) { } void DocumentConverter::processingInstruction(const XMLCh* const target, const XMLCh* const data) { } //############################################################################# void DocumentConverter::ProcessNodeAttribute(VXMLElementType elemType, int attrType, const VXIchar* const value) { // This shouldn't ever happen, if it does, we'll just ignore it. if (value == NULL) return; switch (elemType) { case NODE_BLOCK: case NODE_FIELD: case NODE_INITIAL: case NODE_OBJECT: case NODE_RECORD: case NODE_TRANSFER: // We associate a hidden interal name with this element. if (attrType == ATTRIBUTE_NAME) attrType = ATTRIBUTE__ITEMNAME; break; case NODE_CLEAR: if (attrType == ATTRIBUTE_NAMELIST && !value[0]) ParseException(L"the namelist attribute on clear cannot be empty"); break; case NODE_FORM: case NODE_MENU: // We associate a hidden interal name with this element. if (attrType == ATTRIBUTE_ID) attrType = ATTRIBUTE__ITEMNAME; break; case NODE_FILLED: if (doc->GetParentType() != NODE_FORM) ParseException(L"attributes valid on filled only at form level"); if (attrType == ATTRIBUTE_NAMELIST && !value[0]) ParseException(L"the namelist attribute on filled cannot be empty"); break; case NODE_GRAMMAR: if (doc->GetParentType() != NODE_FORM && attrType == ATTRIBUTE_SCOPE) ParseException(L"the scope attribute is valid only on grammars at form " L"level"); break; case NODE_SUBDIALOG: // We associate a hidden interal name with this element. if (attrType == ATTRIBUTE_NAME) attrType = ATTRIBUTE__ITEMNAME; // modal was dropped in 2.0. if (attrType == ATTRIBUTE_MODAL && version != 1.0f) ParseException(L"the modal attribute on subdialog was dropped after " L"1.0"); break; case NODE_VALUE: if (attrType == ATTRIBUTE_EXPR) break; if (doc->GetParentType() == NODE_LOG) ParseException(L"only the expr attribute is valid on value elements " L"within a log element"); #pragma message("JC: Obsolete???") /* if (doc->GetParentType() == NODE_SAYAS) ParseException(L"only the expr attribute is valid on value elements " L"within a say-as element"); */ break; case NODE_VXML: // version is processed elsewhere and may be ignored. if (attrType == ATTRIBUTE_VERSION) return; if (attrType == PRIV_ATTRIB_SCHEMALOC) return; break; default: break; } // (4.3) Add the attribute to the element. if (attrType > PRIV_ATTRIB_RangeStart) ParseException(L"internal error during attribute processing"); doc->AddAttribute(VXMLAttributeType(attrType), value); } void DocumentConverter::ProcessNodeFinal(VXMLElementType elemType) { // Convert attributes. vxistring attr; switch (elemType) { case NODE_BLOCK: case NODE_FIELD: case NODE_FORM: case NODE_INITIAL: case NODE_MENU: case NODE_OBJECT: case NODE_RECORD: case NODE_SUBDIALOG: case NODE_TRANSFER: // Name the 'unnamed' elements as neccessary. if (!doc->GetAttribute(ATTRIBUTE__ITEMNAME, attr)) { vxistring variable; VXMLDocumentModel::CreateHiddenVariable(variable); doc->AddAttribute(ATTRIBUTE__ITEMNAME, variable); } break; case NODE_FILLED: if (!doc->GetAttribute(ATTRIBUTE_MODE, attr)) doc->AddAttribute(ATTRIBUTE_MODE, L"all"); break; case NODE_VXML: case DEFAULTS_ROOT: VXMLDocumentModel::CreateHiddenVariable(attr); doc->AddAttribute(ATTRIBUTE__ITEMNAME, attr); break; default: break; } // Generate DTMF sequences for <choice> elements in <menu> if necessary. if (elemType == NODE_MENU) { if (doc->GetAttribute(ATTRIBUTE_DTMF, attr) && attr == L"true") choiceNumber = 1; else choiceNumber = 0; } if (elemType == NODE_CHOICE && choiceNumber > 0 && choiceNumber < 10 && !doc->GetAttribute(ATTRIBUTE_DTMF, attr)) { std::basic_stringstream<VXIchar> countString; countString << choiceNumber; doc->AddAttribute(ATTRIBUTE_DTMF, countString.str()); ++choiceNumber; } if (elemType == NODE_PROMPT) { vxistring base, lang; doc->GetAttribute(ATTRIBUTE_BASE, base); doc->GetAttribute(ATTRIBUTE_XMLLANG, lang); doc->AddContent(L"<?xml version='1.0'?><speak version='1.0' xmlns=" L"'http://www.w3.org/2001/10/synthesis' xml:base='", 96); doc->AddContent(base.c_str(), base.length()); doc->AddContent(L"' xml:lang='", 12); doc->AddContent(lang.c_str(), lang.length()); doc->AddContent(L"'>", 2); } } void DocumentConverter::CopyElementStart(const XMLCh* const localname, const Attributes &attrs) { ++copyDepth; doc->AddContent(L"<", 1); XMLChToVXIchar data(localname); doc->AddContent(data.c_str(), wcslen(data.c_str())); for (unsigned int index = 0; index < attrs.getLength(); ++index) { doc->AddContent(L" ", 1); // Determine the attribute name if (Compare(attrs.getQName(index), L"xml:lang")) doc->AddContent(L"xml:lang", 8); else { XMLChToVXIchar name(attrs.getLocalName(index)); doc->AddContent(name.c_str(), wcslen(name.c_str())); } doc->AddContent(L"=\"", 2); XMLChToVXIchar value(attrs.getValue(index)); unsigned int start = 0; unsigned int pos = 0; VXIchar c; // We need to escape three characters: (<,>,&) -> (<,>,&) do { c = *(value.c_str() + pos); if (c == L'<') { if (start != pos) doc->AddContent(value.c_str() + start, pos - start); start = pos + 1; doc->AddContent(L"<", 4); } else if (c == L'>') { if (start != pos) doc->AddContent(value.c_str() + start, pos - start); start = pos + 1; doc->AddContent(L">", 4); } else if (c == L'&') { if (start != pos) doc->AddContent(value.c_str() + start, pos - start); start = pos + 1; doc->AddContent(L"&", 5); } ++pos; } while (c != L'\0'); if (pos > start) doc->AddContent(value.c_str() + start, pos - start - 1); // -1 to kill off final \0 doc->AddContent(L"\"", 1); } doc->AddContent(L">", 1); } void DocumentConverter::CopyElementClose(const XMLCh* const localname) { doc->AddContent(L"</", 2); XMLChToVXIchar data(localname); doc->AddContent(data.c_str(), wcslen(data.c_str())); doc->AddContent(L">", 1); --copyDepth; } void DocumentConverter::StartImplicitPrompt() { implicitPrompt = true; doc->StartElement(NODE_PROMPT); doc->AddContent(L"<?xml version='1.0'?><speak version='1.0' xmlns=" L"'http://www.w3.org/2001/10/synthesis' xml:base='", 96); doc->AddContent(baseUri.c_str(), baseUri.length()); doc->AddContent(L"' xml:lang='", 12); doc->AddContent(documentLang.c_str(), documentLang.length()); doc->AddContent(L"'>", 2); copyDepth = 0; } void DocumentConverter::EndImplicitPrompt() { doc->AddContent(L"</speak>", 8); doc->EndElement(); implicitPrompt = false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -