nvdaportable/NVDA/include/nvda-mathcat/assets/Rules/Intent/general.yaml

890 lines
30 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
-
name: simple-number-set
tag: mi
match: "string-length(text())=1 and translate(text(), '', '')=''" # tricky way to match any of the letters instead of using 'or'
replace:
- intent:
name: number-sets
children: [x: "text()"]
-
name: sup-number-set
tag: msup
match:
- "*[1][string-length(text())=1 and translate(., '', '')=''] and"
- "*[2][string-length(text())=1 and (.='+' or .='-' or self::m:mn)]"
replace:
- intent:
name: number-sets
children:
- x: "*[1]"
- x: "*[2]"
-
name: real-part
tag: mi
match: "(.='Re' or .='re' or .='') and following-sibling::*[1][.='\u2061']" # before function apply
replace:
- intent:
name: real-part
children: []
-
name: imaginary-part
tag: mi
match: "(.='Im' or .='im' or .='') and following-sibling::*[1][.='\u2061']" # before function apply
replace:
- intent:
name: imaginary-part
children: []
-
name: roman_numeral
tag: [mi, mn, mtext]
match: "@data-number"
replace:
- intent:
name: mn
children: [x: "@data-number"]
-
name: positive-or-negative
tag: mrow
match: "count(*)=2 and *[1][self::m:mo][.='+' or .='-']"
variables:
- AtLeftEdge: "EdgeNode(., 'left', 'mtd')"
- AtLeftEdgeOfMTD: "name($AtLeftEdge) = 'mtd'"
- ContinuedColumn: "$TableProperty='lines' or $TableProperty='system-of-equations' or $TableProperty='piecewise'"
- InContinuedRow: "parent::m:mtd[parent::m:mtr[@data-intent-property[contains(., ':continued-row:')]]]"
- FirstColumn: "$AtLeftEdge/../*[1]=$AtLeftEdge" # first child of mtr...
replace:
- test:
# don't use positive/negative if a continued data cell
if: "$AtLeftEdgeOfMTD and $ContinuedColumn and (not($FirstColumn) or $InContinuedRow)"
then:
- intent:
xpath-name: "IfThenElse(*[1][self::m:mo][.='+'], 'plus', 'minus')"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children: [x: "*[2]"]
else:
- intent:
xpath-name: "IfThenElse(*[1][self::m:mo][.='+'], 'plus', 'minus')"
attrs: "data-intent-property='concat(data-intent-property, \":prefix:\")'"
children: [x: "*[2]"]
-
# (a,b) has many interpretations; (a, b] (etc) have fewer interpretations.
# as an interval, it represents a set and hence a clue that it is an interval is that a set operator comes
# before or after it. '=' is also common.
# They also commonly stand by themselves, but so does the interpretation as a point or gcd, so we don't include (xxx, yyy) in the inference
# Note [x,y] is also a commutator.
# Intervals are never contained in other intervals, so rule them out if there is an ancestor that could be an interval
name: interval
tag: mrow
match:
- "count(*)=3 and "
# FIX: consider adding ]...[ versions
- "(*[1][.='(' or .='['] and *[3][.=')' or .=']']) and" # match bracketing
- "(*[2][count(*)=3 and *[2][.=',']]) and" # inside should have ','
# intervals are not part of set notation (e.g, { (x,y)∈L | ...}) nor are they nested
- "not(ancestor::*[IsBracketed(., '{', '}') or IsBracketed(., '[', ']') or IsBracketed(., '(', ')')]) and "
- "not(descendant::*[IsBracketed(., '{', '}') or IsBracketed(., '[', ']') or IsBracketed(., '(', ')')]) and "
# FIX: if both the first and third children of *[2] are mn, then make sure first <= third
- "("
- " not(IsBracketed(., '(', ')')) or " # (.,.) is very ambiguous -- need more clues
- " $ClearSpeak_Paren = 'Interval' or " # pref is set
- " *[2]/*[1][contains(., '∞')] or " # starts with infinity
- " *[2]/*[3][contains(., '∞')] or " # ends with infinity
- " preceding-sibling::*[1][self::m:mo and ( .='=' or IsInDefinition(., 'SubsetOperators') )] or " # context hint
- " following-sibling::*[1][self::m:mo and ( .='=' or IsInDefinition(., 'SubsetOperators') )]" # context hint
- ")"
replace:
- test:
- if: "*[1][.='('] and *[3][.=')']"
then:
- intent:
name: "open-interval"
children: [x: "*[2]/*[1]", x: "*[2]/*[3]"]
- else_if: "*[1][.='('] and *[3][.=']']"
then:
- intent:
name: "open-closed-interval"
children: [x: "*[2]/*[1]", x: "*[2]/*[3]"]
- else_if: "*[1][.='['] and *[3][.=']']"
then:
- intent:
name: "closed-interval"
children: [x: "*[2]/*[1]", x: "*[2]/*[3]"]
else:
- intent:
name: "closed-open-interval"
children: [x: "*[2]/*[1]", x: "*[2]/*[3]"]
-
name: binomial-frac
tag: mrow
# "translate()" is used because it might be "0em" and we need to get rid of the "em"
match: "IsBracketed(., '(', ')') and *[2][self::m:mfrac][translate(@linethickness, 'abcdefghijklmnopqrstuvwxyz', '')=0]"
replace:
- intent:
name: binomial
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[2]/*[1]"
- x: "*[2]/*[2]"
-
# C with pre-subscript 'n' and post-subscript 'm'. The 'n' can be either in the sub or super position
# See https://en.wikipedia.org/wiki/Binomial_coefficient#History_and_notation
name: binomial-mmultiscripts
tag: mmultiscripts
variables:
- Prescripts: "m:mprescripts/following-sibling::*"
- Postscripts: "m:mprescripts/preceding-sibling::*[position() < last()]"
match:
- "*[1][self::m:mi and .='C'] and"
- "count($Prescripts)=2 and ($Prescripts[1][self::m:none] or $Prescripts[2][self::m:none]) and "
- "count($Postscripts)=2 and $Postscripts[2][self::m:none]"
replace:
- intent:
name: binomial
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "IfThenElse(name($Prescripts[2])='none', $Prescripts[1], $Prescripts[2])"
- x: "$Postscripts[1]"
-
name: binomial-msub # C_{n,k}
tag: msub
match:
- "*[1][self::m:mi and .='C'] and"
- "*[2][self::m:mrow and count(*)=3 and *[2][.=',']]"
replace:
- intent:
name: binomial
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[2]/*[1]"
- x: "*[2]/*[3]"
-
# P with pre-sub or superscript 'n' and post-subscript 'k' (https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n)
name: permutation-mmultiscripts
tag: mmultiscripts
variables:
- Prescripts: "m:mprescripts/following-sibling::*"
- Postscripts: "m:mprescripts/preceding-sibling::*[position() < last()]"
match:
- "*[1][self::m:mi and .='P'] and"
- "count($Prescripts)=2 and ($Prescripts[1][self::m:none] or $Prescripts[2][self::m:none]) and "
- "count($Postscripts)=2 and $Postscripts[2][self::m:none]"
replace:
- intent:
name: pochhammer
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- test:
if: "$Prescripts[1][self::m:none]"
then: [x: "$Prescripts[2]"]
else: [x: "$Prescripts[1]"]
- x: "$Postscripts[1]"
-
# P with superscript 'n' and subscript 'k' (https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n)
name: permutation-msubsup
tag: msubsup
match:
- "*[1][self::m:mi and .='P']"
replace:
- intent:
name: pochhammer
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[3]"
- x: "*[2]"
# rules on scripted vertical bars ('evaluated at')
-
name: evaluated-at-msub
tag: mrow
match: "count(*)=2 and *[2][self::m:msub and *[1][self::m:mo][.='|']]"
replace:
- intent:
name: "evaluate"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[1]"
- x: "*[2]/*[2]"
-
name: evaluated-at-msubsup
tag: mrow
match: "count(*)=2 and *[2][self::m:msubsup and *[1][self::m:mo][.='|']]"
replace:
- intent:
name: "evaluate"
children:
- x: "*[1]"
- x: "*[2]/*[2]"
- x: "*[2]/*[3]"
# it is also used outside of brackets
-
name: bracketed-evaluated-at
tag: msubsup
match: "IsBracketed(*[1], '[', ']')"
replace:
- intent:
name: "evaluate"
children:
- x: "*[1]/*[1]"
- x: "*[2]"
- x: "*[3]"
-
# vertical bars otherwise
# could also be cardinality, length, ...
name: absolute-value
tag: mrow
match: "count(*) = 3 and not(*[2][self::m:mtable]) and IsBracketed(., '|', '|')"
replace:
- intent:
name: "absolute-value"
attrs: "data-intent-property='concat(data-intent-property, \":function:\")'"
children: [x: "*[2]"]
-
name: default
tag: msqrt
match: "."
replace:
- intent:
name: "square-root"
attrs: "data-intent-property='concat(data-intent-property, \":function:\")'"
children: [x: "*[1]"]
-
name: sqrt
tag: mroot
match: "*[2][self::m:mn and .='2']"
replace:
- intent:
name: "square-root"
attrs: "data-intent-property='concat(data-intent-property, \":function:\")'"
children: [x: "*[1]"]
-
name: default
tag: mroot
match: "."
replace:
- intent:
name: "root"
children:
- x: "*[1]"
- x: "*[2]"
- # handle log with a base
name: log-with-base
tag: [msub, msubsup]
match: "*[1][self::m:mi and .='log']"
replace:
- test:
if: "self::m:msub"
then:
- intent:
name: "logarithm-with-base"
attrs: "data-intent-property='concat(data-intent-property, \":prefix\")'"
children: [x: "*[2]"] # grab the base
else:
- intent:
name: "power"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- intent:
name: "logarithm-with-base"
attrs: "data-intent-property='concat(data-intent-property, \":prefix:\")'"
children: [x: "*[2]"] # grab the base
- x: "*[3]" # grab the exponent
-
name: bigop
tag: [msub, munder]
match: "IsInDefinition(*[1], 'LargeOperators') or contains(@data-intent-property, ':largeop:')"
replace:
- intent:
name: "large-op" # Fix: the name in the spreadsheet needs updating/fixing
children:
- x: "*[1]"
- x: "*[2]"
-
name: limit
tag: [msub, munder]
variables: [NoSpacesBase: "translate(*[1], ' \u00A0\u2004\u2005\u2006\u2007\u2008\u2009\u200A','')"] # Sometimes these have (weird) spaces in them
match: "*[1][$NoSpacesBase='lim' or $NoSpacesBase='limsup' or $NoSpacesBase='liminf']"
replace:
- intent:
xpath-name: "IfThenElse($NoSpacesBase='lim', 'limit', IfThenElse($NoSpacesBase='limsup', 'limit-sup', 'limit-inf'))"
attrs: "data-intent-property='concat(data-intent-property, \":prefix:\")'"
children: [x: "*[2]"]
- name: repeating-decimal
tag: mrow
match: "count(*)=3 and *[1][self::m:mn] and
*[2][.='\u2062'] and
*[3][self::m:mover][*[1][self::m:mn] and *[2][.='\u00AF']]"
replace:
- intent:
name: "repeating-decimal"
children:
- x: "*[1]"
- x: "*[3]/*[1]"
-
name: modified-var
tag: mover
# breve, check, dot, double-dot, triple-dot, quadruple-dot, grave, hat, tilde, line/bar
match: "*[1][self::m:mi] and *[2][translate(., '\u0306\u030c.\u00A8\u02D9\u20DB\u20DC`^~¯_', '')='']"
replace:
- intent:
name: "modified-variable"
attrs: "data-intent-property='concat(data-intent-property, \":silent:\")'"
children:
- x: "*[1]"
- x: "*[2]"
-
name: vector
tag: mover
match: "*[1][self::m:mi] and *[2][.='→' or .='⇀']"
replace:
- intent:
name: "vector"
attrs: "data-intent-property='concat(data-intent-property, \":prefix:\")'"
children:
- x: "*[1]"
-
# this captures the output for the mhchem's "<=>", "<<=>", and "<=>>" output (there are no Unicode arrows for them)
# this isn't a perfect match, but should be good enough and allows merging all three (see github.com/NSoiffer/MathCAT/issues/60)
name: chemistry-mhchem-equilibrium-arrow
tag: mover
match:
- "*[1][substring(., 1, 1)='↽'] and"
- "*[2][substring(., string-length(), 1)='⇀']"
replace:
- intent:
name: "chemical-arrow-operator"
children:
- test:
if: "*[1][self::m:mrow]"
then_test:
if: "*[2][self::m:mrow]"
then: [t: "\u1f8d2"] # this is currently unassigned and may get used by UTC at some point (<=>)
else: [t: "\u1f8d4"] # this is currently unassigned and may get used by UTC at some point (<<=>)
else: [t: "\u1f8d3"] # this is currently unassigned and may get used by UTC at some point (<==>>)
-
# need to include the name of the element so the rules know whether to say "sub" or "super"
name: chemistry
tag: [msub, msup]
match: "@data-chem-formula"
replace:
- intent:
name: "chemical-formula"
children: # have to list individual children because "*" results in an internal error (children aren't flat)
- x: "name(.)"
- x: "*[1]"
- x: "*[2]"
-
name: chemistry-prescripts
tag: mmultiscripts
match: "@data-chem-formula"
replace:
- test:
- if: "count(*)=4 or count(*)=6"
then:
- intent:
name: "chemical-nuclide"
children:
- x: "*"
else: # FIX: what other cases are there???
- intent:
name: "chemical-formula"
children:
- x: "*"
-
name: chemical-element
tag: [mi, mtext]
match: "@data-chem-element"
replace:
- intent:
name: "chemical-element"
children:
- x: "text()"
-
name: unit
tag: [mi, mtext]
match: "@class='MathML-unit' or contains(@data-intent-property, ':unit')"
replace:
- intent:
name: "unit"
attrs: "data-intent-property='\":unit:\"'" # the value ":unit:" needs to be an xpath string, hence the escaped quotes
children:
- x: "text()"
- # this is attempt to catch units when some has created a non-italic word that matches a unit
# other mtext unit cases were caught above.
# This has a guard to make sure it is positionally a unit.
# Currently only checking for a simple mrow like "3 s or 3/4 km"
# Other checks would be an mfrac with a unit in both parts (complicated to check) or msup with a unit in the base and that inside an mrow
name: mtext-inference-unit
tag: [mtext, mi]
match: "not(@data-chem-element) and
(self::m:mtext or string-length(.) > 1 or @mathvariant='normal') and
(parent::*[1][self::m:mrow and count(*)=3 and *[2][.='\u2062'] and
*[1][self::m:mn or (self::m:mfrac and *[1][self::m:mn] and *[2][self::m:mn])]]) and
count(preceding-sibling::*) = 2 and
(DefinitionValue(., 'Speech', 'SIUnits') != '' or
DefinitionValue(., 'Speech', 'UnitsWithoutPrefixes') != '' or
DefinitionValue(., 'Speech', 'EnglishUnits') != '' or
(string-length(.) >= 3 and
substring(., 1, 2) = 'da' and
DefinitionValue(substring(., 3), 'Speech', 'SIUnits') != '') or
(string-length(.) >= 2 and
DefinitionValue(substring(., 1, 1), 'Speech', 'SIPrefixes') != '' and
DefinitionValue(substring(., 2), 'Speech', 'SIUnits') != ''))"
replace:
- intent:
name: "unit"
attrs: "data-intent-property='\":unit:\"'" # the value ":unit:" needs to be an xpath string, hence the escaped quotes
children:
- x: "text()"
-
name: chemical-formula-op
tag: [mo]
match: "@data-chem-formula-op"
replace:
- intent:
name: "chemical-formula-operator"
children:
- x: "text()"
-
name: chemical-arrow-op
tag: [mo]
# FIX: this is a duplicate of the list in chemistry.rs. Probably should pull out and add to definitions.yaml
match: "@data-chem-equation-op and translate(., '→➔←⟶⟵⤻⇋⇌↿↾⇃⇂⥮⥯⇷⇸⤉⤈⥂⥄', '')=''"
replace:
- intent:
name: "chemical-arrow-operator"
children:
- x: "text()"
-
name: chemical-equation-op
tag: [mo]
match: "@data-chem-equation-op"
replace:
- intent:
name: "chemical-equation-operator"
children:
- x: "text()"
-
name: chemistry-concentration
tag: mrow
match: "ancestor-or-self::*[@data-chem-equation] and IsBracketed(., '[', ']')"
replace:
- intent:
name: "chemistry-concentration"
attrs: "data-intent-property='concat(data-intent-property, \":function:\")'"
children:
- x: "*[2]"
-
name: chemistry-state
tag: mrow
match:
- "(@data-chem-formula or @data-chem-equation) and"
- "IsBracketed(., '(', ')') and"
- "*[2][.='s' or .='l' or .='g' or .='aq']"
replace:
- intent:
name: "chemical-state"
children:
- x: "*[2]"
# This needs to be before the simple "x prime" rule
# minutes/seconds or feet/inches
# If ' or " follows a number, then it is not "prime", but is a unit
# Note the ASCII ' and " are converted to prime during canonicalization if in a superscript
# Handles single, double, primes, and also double quote, which don't have to be in an msup
# The rules are:
# 1. If the prime follows a degree sign with a number (in various forms) or letter after it,
# then it is minutes/seconds
# 2. Else, if it follows a *number* (in various forms), then it feet/inches
# 3. Else it is 'prime'
# any ? ( count(match)==2 &&
# (name(match)=="mrow" || name(match)=="msup") &&
# (MatchString($1, "mo", "'") || MatchString($1, "mo", "") || // apostrophe or prime
# MatchString($1, "mo", "″") || MatchString($1, "mo", "\"")) && // double quote or double prime
# (
# // '1': degree sign check
# ( has_previous(match) &&
# ( (MatchString($1, "mo", "") &&
# ( name(previous(match))=="msup" ||
# (name(previous(match))=="mrow" && count(previous(match))==2)) &&
# MatchString(previous(match)[1], "mo", "°")) ||
# ( has_previous(previous(match)) &&
# (MatchString($1, "mo", "″") || MatchString($1, "mo", "\"")) &&
# ( name(previous(match, 2))=="msup" ||
# (name(previous(match, 2))=="mrow" && count(previous(match, 2))==2)) &&
# MatchString(previous(match, 2)[1], "mo", "°"))
# )
# ) ||
#
# // '2': number or numeric fraction in front
# name($0)=="mn" ||
# (name($0)=="mfrac" && name($0[0])=="mn" && name($0[1])=="mn")
# )
# )
# => structure(
# $0,
# UIWord([$1[0],$1[-1]])
# {ruleRef="RR_unitsBase";
# singular=MatchString($0, "mn", "1");
# // if this follows a degree sign, then it is an angle notation (min/secs) regardless of the pref setting
# // we have to either look at the previous entry for mins or the one prior to that for secs
# pref= ( has_previous(match) &&
# ( (MatchString($1, "mo", "") &&
# ( name(previous(match))=="msup" ||
# (name(previous(match))=="mrow" && count(previous(match))==2)) &&
# MatchString(previous(match)[1], "mo", "°")) ||
# ( has_previous(previous(match)) &&
# (MatchString($1, "mo", "″") || MatchString($1, "mo", "\"")) &&
# ( name(previous(match, 2))=="msup" ||
# (name(previous(match, 2))=="mrow" && count(previous(match, 2))==2)) &&
# MatchString(previous(match, 2)[1], "mo", "°"))
# )
# ) ? "Angle" : "Length";
# }
# );
# Pseudo-script characters are characters such as "degree sign" ('°') that are raised but in MathML should be in a superscript.
# They are not spoken as if in a superscript (e.g "x degrees", not "x superscripts degrees")
-
name: skip-super
tag: [msup, msubsup]
match: "*[last()][translate(., '′″‴⁗\"†‡°*', '')='' or .=\"'\"]" # you can't have both ' and " in an xpath string
replace:
- intent:
name: "skip-super"
attrs: "data-intent-property='concat(data-intent-property, \":silent:\")'"
children: [x: "*"]
-
name: mo-super
tag: [msup, msubsup]
match: "*[last()][self::m:mo]"
replace:
- intent:
name: "say-super"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children: [x: "*"]
# rules for functions raised to a power
# these could have been written on 'mrow' but putting them on msup seems more specific
# to see if it is a function, we look right to see if the following sibling is apply-function
-
name: function-inverse
tag: msup
match:
- "*[2][self::m:mrow][count(*)=2] and" # exponent is an mrow with children...
- "*[2]/*[1][self::m:mo][.='-'] and" # '-'
- "*[2]/*[2][self::m:mn][.=1] and" # and '1'
- "*[1][self::m:mi] and IsInDefinition(*[1], 'TrigFunctionNames') and" # base is a trig function name (e.g, sin, sinh)
- "following-sibling::*[1][self::m:mo][.='\u2061']" # and msup is followed by invisible function apply
replace:
- intent:
name: "inverse-function"
children:
- x: "*[1]"
-
name: bigop
tag: [msubsup, munderover]
match: "IsInDefinition(*[1], 'LargeOperators') or contains(@data-intent-property, ':largeop:')"
replace:
- intent:
name: "large-op" # Fix: the name in the spreadsheet needs updating/fixing
children:
- x: "*[1]"
- x: "*[2]"
- x: "*[3]"
-
name: set
tag: mrow
# sets have { }s and should have at least one of ",∈∉|" (vertical bar is "such that") or be the empty set
match: "IsBracketed(., '{', '}') and
(count(*)=2 or (count(*)=3 and IsNode(*[2], 'leaf')) or . != translate(., ',∈∉|:', ''))"
replace:
- intent:
name: "set"
children:
- test:
if: count(*) = 2
then: []
else: [x: "*[2]"]
-
name: default
tag: msub
match: "."
replace:
- intent:
name: "indexed-by"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[1]"
- x: "*[2]"
-
# this adds a :unit property to the fraction if its children are units -- simplifies things downstream
# we have to this is the attr calculation because at that point, the children have been replaced so they will be marked as units if there are units
# at the point of 'match', the replacement has yet to be done so they may not have inferred units.
# this catches s^2 as in m/s^2
name: default
tag: msup
match: "."
replace:
- intent:
name: "power"
attrs: "data-intent-property='IfThenElse(*[1][contains(@data-intent-property, \":unit:\")], \":unit:\", \"\")'"
children:
- x: "*[1]"
- x: "*[2]"
-
name: default
tag: msubsup
match: "."
replace:
- intent:
name: "power"
children:
- intent:
name: "indexed-by"
attrs: "data-intent-property='concat(data-intent-property, \":infix:\")'"
children:
- x: "*[1]"
- x: "*[2]"
- x: "*[3]"
-
# this adds a :unit property to the fraction if its children are units -- simplifies things downstream
# we have to this is the attr calculation because at that point, the children have been replaced so they will be marked as units if there are units
# at the point of 'match', the replacement has yet to be done so they may not have inferred units.
name: default
tag: mfrac
match: "."
replace:
- intent:
name: "fraction"
attrs: "data-intent-property='IfThenElse(*[1][contains(@data-intent-property, \":unit:\")] and
DEBUG(*[2])[contains(@data-intent-property, \":unit:\")],
\":unit:\",
\"\")'"
children:
- x: "*[1]"
- x: "*[2]"
# generic mtable: treat as multiline equations of some sort
# if a property is set, handle that first
-
name: mtable-property-is-set
tag: mtable
# any 'intent' property set overrides the inferred property
variables: [TableProperty: "IfThenElse(contains(@data-intent-property, ':array:'), 'array',
IfThenElse(contains(@data-intent-property, ':matrix:'), 'matrix',
IfThenElse(contains(@data-intent-property, ':determinant:'), 'determinant',
IfThenElse(contains(@data-intent-property, ':piecewise:'), 'piecewise',
IfThenElse(contains(@data-intent-property, ':system-of-equations:'), 'system-of-equations',
IfThenElse(contains(@data-intent-property, ':lines:'), 'lines',
$TableProperty))))))"] # '' is what to say if none match"
match: "$TableProperty !=''"
replace:
- intent:
xpath-name: "$TableProperty"
children:
- x: "*"
-
name: "piecewise"
tag: mrow
match: "count(*)=2 and *[1][.='{'] and
*[2][self::m:mtable and not(
contains(@data-intent-property, ':array:') or
contains(@data-intent-property, ':matrix:') or
contains(@data-intent-property, ':determinant:') or
contains(@data-intent-property, 'system-of-equations:') or
contains(@data-intent-property, ':lines:') )
]"
replace:
- with:
variables: [TableProperty: "'piecewise'"]
replace: [x: "*[2]"]
-
name: matrix
tag: mrow
match:
- "count(*)=3 and (IsBracketed(., '(', ')') or IsBracketed(., '[', ']')) and
*[2][self::m:mtable and not(
contains(@data-intent-property, ':piecewise:') or
contains(@data-intent-property, ':matrix:') or
contains(@data-intent-property, ':determinant:') or
contains(@data-intent-property, 'system-of-equations:') or
contains(@data-intent-property, ':lines:') )
]"
replace:
- with:
variables: [TableProperty: "'matrix'"]
replace: [x: "*[2]"]
-
name: determinant
tag: mrow
match:
- "count(*)=3 and IsBracketed(., '|', '|') and
*[2][self::m:mtable and not(
contains(@data-intent-property, ':array:') or
contains(@data-intent-property, ':matrix:') or
contains(@data-intent-property, ':piecewise:') or
contains(@data-intent-property, 'system-of-equations:') or
contains(@data-intent-property, ':lines:') )
]"
replace:
- with:
variables: [TableProperty: "'determinant'"]
replace: [x: "*[2]"]
-
name: mtable-equations-property
tag: mtable
match: "count(*) > 0 and *[1][contains(translate(., '=≠<>≤≥≦≧', '='), '=')]"
replace:
- with:
variables:
- TableProperty: "'system-of-equations'"
replace:
- intent:
name: "system-of-equations"
children:
- x: "*"
-
name: mtable-lines-property
tag: mtable
match: "count(*) > 0 and not(descendant::*[self::m:mo and not(.='-' or .='+')])"
replace:
- with:
variables:
- TableProperty: "'lines'"
replace:
- intent:
name: "lines"
children:
- x: "*"
-
# merge all the mtd into a single mtd
name: consolidate-labeled-mtd-entries
tag: [mlabeledtr, mtr]
# Note: child hasn't been processed, so 'intent' hasn't been processed/turned into data-intent-property
match: "count(*) > 1 and
($TableProperty = 'piecewise' or $TableProperty = 'system-of-equations' or $TableProperty = 'lines') and
(self::m:mlabeledtr or *[contains(@intent, ':equation-label')])"
replace:
- intent:
name: "mlabeledtr"
children:
- x: "*[contains(@intent, ':equation-label')]"
- intent:
name: "mtd"
attrs: "id=*[not(contains(@intent, ':equation-label'))][1]/*[1]/@id"
children:
- intent:
name: "mrow"
attrs: "id=*[not(contains(@intent, ':equation-label'))][1]/*[1]/@id"
children: [x: "*[not(contains(@intent, ':equation-label'))]"]
-
# convert a mtr to a mlabeledtr
name: mlabeledtr
tag: mtr
# Note: child hasn't been processed, so 'intent' hasn't been processed/turned into data-intent-property
match: "count(*) > 1 and *[contains(@intent, ':equation-label')]"
replace:
- intent:
name: "mlabeledtr"
children:
- x: "*[contains(@intent, ':equation-label')]"
- x: "*[not(contains(@intent, ':equation-label'))]"
-
# merge all the mtd into a single mtd
name: consolidate-mtd-entries
tag: mtr
match: "count(*) > 1 and
($TableProperty = 'piecewise' or $TableProperty = 'system-of-equations' or $TableProperty = 'lines')"
replace:
- intent:
name: "mtr"
attrs: "id='@id'"
children:
- intent:
name: "mtd"
attrs: "id='*[1]/@id'"
children:
- intent:
name: "mrow"
attrs: "id='*[2]/@id'"
children: [x: "*"]
-
# We need to preserve any intent properties that are on the mtd (e.g., :pause)
# Note: at this point "intent" has been processed so we look at @data-intent-property
name: mtd-to-mrow
tag: mtd
match: "($TableProperty = 'piecewise' or $TableProperty = 'system-of-equations' or $TableProperty = 'lines') and
not(contains(@data-intent-property, ':equation-label'))"
replace:
- test:
if: "@data-intent-property"
then:
- intent:
name: "mrow"
attrs: "id=@id data-intent-property=@data-intent-property"
children: [x: "*"]
else:
- x: "*"