Summary: The RULE tag is the core tag for defining which commands are available for
recognition. Every grammar must have at least one top-level rule, and
every rule must have at least one rule reference or recognizable text.
XML Attributes:
DYNAMIC (optional, default is FALSE): Specifies whether the rule supports dynamic
modifications at run time. By default, an application cannot modify rules
in an XML grammar. To modify a rule, the rule must be marked DYNAMIC, and
the grammar must be loaded with the dynamic flag (see ISpRecoGrammar and
SPLOADOPTIONS). Dynamic rules cannot be marked EXPORT.
EXPORT (optional, default is FALSE): Specifies whether the rule allows external
grammar to reference it. For example, a grammar author that wants to allow
other grammar author's to reuse her rules must mark each of the reusable
rules with EXPORT="TRUE"). Exported rules cannot be marked DYNAMIC.
ID (required, type=VT_I4): Specifies the numeric identifier of the rule. The ID
or the NAME must be specified, or both. The identifier must be unique in
the rule namespace, which is the entire grammar (see GRAMMAR).
INTERPRETER (optional, default is FALSE): Specifies if the rule should use the
CFG interpreter (see ISpCFGInterpreter) when it is recognized. For example,
a rule might contain semantic properties or text that should be modified
at run time (e.g. replace value of the semantic property named "TODAY" with
the system's current date and time).
NAME (required): Specifies the string identifier of the rule. The NAME
or the ID must be specified, or both. The identifier must be unique in
the rule namespace, which is the entire grammar (see GRAMMAR).
TOPLEVEL (optional): Specifies that the rule is directly recognizable by a user.
If the TOPLEVEL tag is not specified, then the rule is not recognizable
unless it is referenced by another top-level rule structure. For example,
component rules (see RULEREF) do not need to specify the TOPLEVEL attribute.
When a grammar author specifies a rule as TOPLEVEL, she must also specify
if the rule is to be enabled by default. If the rule is enabled by default
(e.g. TOPLEVEL="ACTIVE"), then when the application activates the default
set of rules (e.g. ISpRecoGrammar::SetRuleState(NULL, NULL, SPRS_ACTIVE)),
then the rule will be activated. If a rule is specified as
TOPLEVEL="INACTIVE", then it will only be activated when explicitly set to
active (see ISpRecoGrammar::SetRuleState and
ISpRecoGrammar::SetRuleIdState).
XML Parent Elements:
GRAMMAR: The container for the entire XML grammar.
XML Child Elements:
RULEREF: Import, or reference, another rules contents
PHRASE, P: Specifies text or leaf nodes.
LIST, L: Specifies a list of phrases for recognition.
OPT, O: Specifies an optional piece of text that can be spoken.
TEXTBUFFER: Specifies a reference to the run-time application maintained
text-buffer.
WILDCARD: Specifies a garbage word; one or more non-silence, ignorable words
DICTATION: Specifies a piece of text recognized by the loaded dictation topic.
RESOURCE: Specifies a labeled piece of arbitrary string data which can be
accessed by a special SR engine, or a CFG interpreter.
Detailed Description:
The RULE tag is the core of the XML grammar text format. The purpose of creating
a CFG is to define a specific set of words and phrases that can be
spoken by the user and recognized by the speech recognition engine. The
rules can be written by the grammar author in a way that makes them
reusable, textually maintainable, and conducive to application logic
that is based on semantic properties or actions (not on phrase text).
Each rule must contain at least one piece of text, or a rule reference (which
has the same requirements). Effectively, every rule will eventually end
with a piece of text (i.e. leaf or terminal node).
The rule can be identified by either a numeric identifier (ID) or a string identifier
(NAME). The grammar author can use the DEFINE tag to define constant string
identifiers for numeric values. By using the constant string identifiers,
the grammar author can avoid magic numbers (i.e. hard-coded numbers that can
cause maintenance problems when updating code/grammar). See the ID tag for
more information on constant identifiers.
By using rule importing (references) and rule exporting, grammar authors can
leverage reusable grammar components (e.g. numbers or date grammars).
Similarly, grammar authors can abstract certain portions of the grammar
text away from the semantic content by using semantic properties, or
tags. Semantic properties are name/value pairs which are associated
with rule nodes in the rule hierarchy, and can even contain relevant
information from the recognized text (see SPPHRASEPROPERTY.ulStartingElement
and SPPHRASEPROPERTY.ulCountOfElements).
The grammar author can also use a CFG interpreter, which is a COM object that can
re-process the semantic property tree and phrase text to modify the content
at run time. For example, an application may load a grammar which includes
a "days of the week" rule. By integrating a CFG interpreter with the grammar,
the interpreter could replace the "days of the week" properties (e.g. Sunday,
Monday, Tuesday, etc.) with the actual calendar dates relative to the
application's host system (e.g. GetSystemTime). See ISpCFGInterpreter.
SAPI supports a feature called "semantic property pushing" which enables
applications to detect the semantic property structure more accurately at
recognition time. "Property pushing" is done by SAPI at compile-
time, whereby the compiler moves semantic properties to the last terminal
node within a rule which remains unambiguous. For example, the phrases "a b
c d" and "a b e f g" both have prefixes of "a b". The compiler will
automatically split the phrases into three separate phrases, "a b", "c d",
and "e f g", where the first phrase is the common prefix to both recognizable
phrases. The purpose of this feature is to enable applications that place
properties on the phrases, will be able to detect which branch is being
hypothesized as soon as the first unambiguous (non-common) portion of the
phrase is spoken. When the user speaks "a b" it is not clear if the user will
say "a b c d" or "a b e f g". If the user then says "e", the application
can obviously eliminate the "a b c d" option. If the grammar author attached
properties to the end of both phrases, the semantic property would be
returned as soon as the user spoke the first unambiguous portion of the text
(e.g. "c" or "e"). See Semantic Properties, Hypotheses, and "Property Pushing."
XML Grammar Sample(s):
<GRAMMAR>
<DEFINE>
<ID NAME="RID_Hello" VAL="1"/>
<ID NAME="RID_World" VAL="2"/>
<ID NAME="RID_AddNumbers" VAL="3"/>
<ID NAME="RID_Numbers" VAL="4"/>
<ID NAME="RID_Numbers_Exportable" VAL="5"/>
<ID NAME="RID_Names" VAL="6"/>
</DEFINE>
<!-- create a simple top-level rule that uses a constant defined identifier -->
<RULE ID="RID_Hello" TOPLEVEL="ACTIVE">
<P>hello</P>
</RULE>
<!-- Create a simple top-level rule that is inactive by default -->
<RULE NAME="Hiya" TOPLEVEL="INACTIVE">
<P>hiya</P>
</RULE>
<!-- Create a rule, which a CFG-interpreter can re-process to modify the semantic
properties -->
<RULE NAME="InterpretedRule" TOPLEVEL="ACTIVE" INTERPRETER="TRUE">
<P PROPNAME="TODAY">what is today's date</P>
</RULE>
<!-- Create a simple top-level rule that references another non top-level rule -->
<RULE ID="RID_AddNumbers" TOPLEVEL="ACTIVE">
<P>add</P>
<RULEREF REFID="RID_Numbers"/>
<P>to</P>
<RULEREF REFID="RID_Numbers"/>
</RULE>
<!-- Note that rule is not top-level and is only used as a reusable component rule -->
<RULE ID="RID_Numbers">
<LIST PROPID="PID_Value">
<P VAL="1">one</P>
<P VAL="2">two</P>
<P VAL="3">three</P>
<P VAL="4">four</P>
<P VAL="5">five</P>
</LIST>
</RULE>
<!-- mark the rule as dynamic so the application can update the list of names
at runtime -->
<RULE ID="RID_Names" DYNAMIC="TRUE">
<LIST>
<P>bob</P>
<P>jane</P>
<P>kate</P>
<P>tom</P>
</LIST>
</RULE>
<!-- Mark the rule as exportable, so other external grammars can access it -->
<RULE ID="RID_Numbers_Exportable" EXPORT="TRUE">
<LIST PROPID="PID_Value">
<P VAL="6">six</P>
<P VAL="7">seven</P>
<P VAL="8">eight</P>
<P VAL="9">nine</P>
<P VAL="10">ten</P>
</LIST>
</RULE>
</GRAMMAR>
Programmatic Equivalent:
Application developers can programmatically add rules to a grammar by using the
ISpGrammarBuilder interface inherited by ISpRecoGrammar. The following sample code
shows how to add a rule to a grammar. To choose the rule attributes, see the
ISpGrammarBuilder::GetRule method and SPCFGRULEATTRIBUTES.
SPSTATEHANDLE hHelloWorld;
// Create new rule called "HelloWorld"
// Note that the second parameter is the ID, which can also be specified
// Note also that the rule is marked as top-level and active
hr = cpRecoGrammar->GetRule(L"SpeakNumber", NULL, SPRAF_TopLevel | SPRAF_Active,
TRUE, &hHelloWorld);
// Check hr
// add the text "hello world"
hr = cpRecoGrammar->AddWordTransition(hHelloWorld, NULL, L"hello world",
L" ", SPWT_LEXICAL, 1, NULL);
// Check hr
// save the grammar changes
hr = cpRecoGrammar->Commit(NULL);
// Check hr
The following sample code shows how to modify a rule in an existing grammar. Specifically,
the code will update the list of names rule shown in the XML Sample Grammar
section. By updating the names rule, all rules that reference the names will
automatically be able to recognize the updated names (after calling ::Commit).
SPSTATEHANDLE hNames;
// Get a handle to the existing rule
// Note the use of the constant identifier RID_Names, which was defined in the
// XML sample. See the ID tag for information on generating a C-style header
hr = cpRecoGrammar->GetRule(NULL, RID_Names, NULL, TRUE, &hNames);
// Check hr
// clear the rule to update the entire list
hr = cpRecoGrammar->ClearRule(hNames);
// Check hr
// add name "sally"
hr = cpRecoGrammar->AddWordTransition(hNames, NULL, L"sally", NULL,
SPWT_LEXICAL, NULL, NULL);
// Check hr
// add name "jim"
hr = cpRecoGrammar->AddWordTransition(hNames, NULL, L"jim", NULL,
SPWT_LEXICAL, NULL, NULL);
// Check hr
// add name "diane"
hr = cpRecoGrammar->AddWordTransition(hNames, NULL, L"diane", NULL,
SPWT_LEXICAL, NULL, NULL);
// Check hr
// save grammar changes
hr = cpRecoGrammar->Commit(NULL);
// Check hr
Back to top