--- - name: whitespace-omission tag: "!*" match: "not(self::m:math) and not($MatchingWhitespace) and (@data-previous-space-width >= 0.7 or @data-following-space-width >= 0.7)" replace: - with: variables: [MatchingWhitespace: "true()"] replace: - test: - if: "@data-previous-space-width > 1.1" then: [t: "⠿"] # non-breaking space width; also avoid spaces added after commas in scripts (78_1) - else_if: "@data-previous-space-width >= 0.7 and ($NewScriptContext='' or not(preceding-sibling::*[1][self::m:mo and .=',']))" then: [t: "W"] - x: "." - test: - if: "@data-following-space-width > 1.1" then: [t: "⠿"] # non-breaking space width; also avoid spaces added after commas in scripts (78_1) - else_if: "@data-following-space-width >= 0.7 and ($NewScriptContext='' or not(self::m:mo and .=','))" then: [t: "W"] - name: default tag: msqrt match: "." replace: - T: "⠩" - x: "*" - T: "⠱" - name: default tag: mroot match: "." replace: - T: "⠩⠔" - test: if: # FIX: need to add arbitrary shapes here (see also msub/msup) - "*[2][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol - " ((self::m:mi or self::m:mo) and string-length(text())=1) or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: - x: "*[2]" else: - T: "⠣" - x: "*[2]" - T: "⠱" - T: "#" # signal end of script/numeric mode - x: "*[1]" - T: "⠱" # Fraction rules # The fraction part of a mixed number is always simple # They also differ because a two character sequence is needed to bracket the fraction # The invisible plus should produce an empty string - name: common-fraction-mixed-number tag: mfrac match: - "preceding-sibling::*[1][self::m:mo][text()='\u2064'] and" # preceding element is invisible plus - "*[1][self::m:mn][not(contains(., '.'))] and" - "*[2][self::m:mn][not(contains(., '.'))]" replace: - T: "#" # signal end of previous numeric mode - x: "*[1]" - test: if: "$Vietnam_UseDropNumbers" then: - x: "BrailleChars(translate(*[2], '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Vietnam')" # drop numbers for the denominator else: - T: "N⠌" - x: "*[2]" - name: simple-number tag: mfrac match: "*[1][self::m:mn] and *[2][self::m:mn]" replace: - T: "#" # signal end of any previous numeric mode (probably not needed, but...) - x: "*[1]" - test: if: "$Vietnam_UseDropNumbers" then: - x: "BrailleChars(translate(*[2], '0123456789', '\ue000\ue001\ue002\ue003\ue004\ue005\ue006\ue007\ue008\ue009'), 'Vietnam')" # drop numbers for the denominator else: - T: "N⠌" - x: "*[2]" - name: default tag: mfrac match: "." replace: - T: "⠆" - x: "*[1]" - T: "⠌" - x: "*[2]" - T: "⠰" - #GTM 14.3.3 (not sure what else vertical juxtaposition applies to) name: binomial-frac tag: mrow match: "IsBracketed(., '(', ')') and *[2][self::m:mfrac][@linethickness=0]" replace: - x: "*[1]" - x: "*[2]/*[1]" - t: "⠰⠻" - x: "*[2]/*[2]" - x: "*[3]" - name: binomial-table tag: mrow match: "IsBracketed(., '(', ')') and *[2][self::m:mtable][count(*)=2 and count(*[1])=1] and contains(@intent, 'binomial(')" replace: - x: "*[1]" - x: "*[2]/*[1]/*[1]/*[1]" - t: "⠰⠻" - x: "*[2]/*[2]/*[1]/*[1]" - x: "*[3]" # # Matrix/Determinant rules # matrix and determinant are the same other than "matrix"/"determinant" based on the bracketing chars # we don't do spatial layout, instead the beginning/ending of each row uses the enlarged bracketing chars - name: default-matrix tag: mrow variables: - RowStart: "*[1]" - RowEnd: "*[3]" match: - "*[2][self::m:mtable] and" - (IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '|', '|')) replace: [x: "*[2]"] - name: default-cases tag: mrow variables: - RowStart: "*[1]" - RowEnd: "''" match: "*[2][self::m:mtable] and count(*)=2 and *[1][.='{' or .='[' or .='(']" replace: [x: "*[2]"] - name: default-mtable tag: mtable match: "." replace: [x: "*"] - name: default tag: [mtr, mlabeledtr] match: "." replace: - test: if: "preceding-sibling::*" then: [t: "⣍"] - test: if: "count(parent::*) > 1" then: [t: "⠠"] - t: "" - x: $RowStart - test: if: .[self::m:mlabeledtr] then: - t: "⠗⠕⠺W⠇⠁⠃⠑⠇⠸⠒" # "row label:" - x: "*[1]/*" # contents of row label - test: if: .[self::m:mlabeledtr] then: [x: "*[position()>1]"] else: {x: "*"} - test: if: "count(parent::*) > 1" then: [t: "⠠"] - x: $RowEnd - name: default tag: mtd match: "." replace: - test: if: "*" then: - test: if: "preceding-sibling::*" then: [t: "W"] - x: "*" # else nothing to braille - name: no-content tag: math match: "not(*)" # empty replace: [t: "W"] # not sure that is right, but this shouldn't happen - name: default tag: math match: "." variables: - RowStart: "''" # empty string -- it needs to be set - RowEnd: "''" # empty string -- it needs to be set - NewScriptContext: "''" # empty string -- it needs to be set - MatchingWhitespace: "false()" replace: [x: "*"] - name: empty-mrow tag: mrow match: "not(*)" replace: [t: "W"] # not sure what is correct -- if in a fraction, probably something is better than nothing - name: default tag: mrow match: "." replace: [x: "*"] - name: chemical-formula-operator-bond tag: mo match: "@data-chemical-bond" replace: # FIX: this might be better/more efficient if in unicode.yaml - bookmark: "@id" - test: - if: "text()='-' or text() = ':'" then: [t: "⠤"] - else_if: "text()='=' or text() = '∷'" then: [t: "⠭"] - else_if: "text()='≡'" then: [t: "⠿"] - else_if: "text()='≣'" then: [t: "⠸⠠⠤"] # see #237 -- not defined, so use UEB else: [x: "text()"] # shouldn't happen - # add space after these ops when they are prefix operators # note: other shapes are s and canonicalization turns them into function calls (which will include spaces after them) name: prefix-geometry-ops tag: mo match: - "parent::*[count(*) = 2 and name()='mrow' and not(preceding-sibling::*)] and" - "IsInDefinition(., 'Braille', 'GeometryPrefixOperators')" replace: - x: "text()" - t: "" - name: default tag: mo # add spaces around comparison operators unless they are in a script position, variables: [MaybeAddSpaces: "parent::*[self::m:mrow] and $NewScriptContext='' and IsInDefinition(., 'Braille', 'NemethComparisonOperators')"] match: "." replace: - test: if: "$MaybeAddSpaces" then: - test: if: "preceding-sibling::* and not(IsInDefinition(preceding-sibling::*[1], 'Braille', 'NemethPunctAndOpenBeforeSymbols'))" #Rule 151 then: [t: ""] - x: "text()" - test: if: "$MaybeAddSpaces and following-sibling::* and not(IsInDefinition(following-sibling::*[1], 'Braille', 'NemethPunctAndOpenAfterSymbols'))" #Rule 151" then: [t: ""] - name: default tag: mn match: "." replace: - x: "BrailleChars(., 'Vietnam')" - name: sin tag: mi match: "text()='sin'" replace: - t: "⠻⠎" - name: cos tag: mi match: "text()='cos'" replace: - t: "⠻⠉" - name: tan tag: mi match: "text()='tan'" replace: - t: "⠻⠞" - name: cot tag: mi match: "text()='cot'" replace: - t: "⠻⠉⠞" - name: arcsin tag: mi match: "text()='arcsin'" replace: - t: "⠁⠗⠉⠻⠎" - name: arccos tag: mi match: "text()='arccos'" replace: - t: "⠁⠗⠉⠻⠉" - name: arctan tag: mi match: "text()='arctan'" replace: - t: "⠁⠗⠉⠻⠞" - name: arccot tag: mi match: "text()='arccot'" replace: - t: "⠁⠗⠉⠻⠉⠞" - # FIX: need to deal with all caps name: default tag: [mi, mtext] match: "." replace: - test: if: - "IsInDefinition(., 'Braille', 'Units') or" - "(string-length(.)=1 and @mathvariant='normal' and" # avoid chemical elements and also states (e.g., "(g)") - " not(@data-chem-element) and parent::*[1][not(@data-chem-equation>='1')]" - ")" then: [t: "W"] - x: "BrailleChars(., 'Vietnam')" - name: default tag: mstyle match: "." replace: - test: if: "*" then: [x: "*"] # else do nothing -- no content - # 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: - test: if: "*[1][self::m:mrow]" then_test: if: "*[2][self::m:mrow]" then: [x: "'🣑'"] # \u1f8d1 this is currently unassigned and may get used by UTC at some point (<=>) else: [x: "'🣓'"] # \u1f8d3 this is currently unassigned and may get used by UTC at some point (<<=>) else: [x: "'🣒'"] # \u1f8d2 this is currently unassigned and may get used by UTC at some point (<==>>) - name: angle # angles need a shape indicator -- not sure this is the best test (three letters in base, have invisible separators) tag: mover match: "*[2][text()='^'] and *[1][ self::m:mrow and count(*)=5 and *[1][self::m:mi] and *[2][text()='\u2063'] and *[3][self::m:mi] and *[4][text()='\u2063'] and *[5][self::m:mi] ]" replace: - t: "⠫⠛" # shape indicator, g - x: "*[1]" - name: overparen tag: mover match: "*[2][.='⏜']" replace: - t: "⠫⠠⠗" # shape indicator, overparen - x: "*[1]" - name: single-char-exceptions # GTM 12 tag: [mover, munder] match: "*[2][string-length(.) = 1 and ( translate(., '_¯→.˙~^','')='' or (self::m:mover and text()='⌒') )]" replace: - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "(*[1][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol - " ((self::m:mi or self::m:mo) and string-length(text())=1) or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]) and" - "not(*[1][self::m:mn] and preceding-sibling::*[1][text()='\u2062'][preceding-sibling::*[1][self::m:mn]])" # need to make clear this 'mn' is base then: [x: "*[1]"] else: - t: "⠣" - x: "*[1]" - t: "⠜" - test: if: "*[2][translate(., '_¯→^', '') = '']" then: [t: ""] - test: if: "self::m:munder" then: [t: "⠠"] - test: - if: "*[2][text()='_' or text()='¯']" then: [T: "⠨⠱"] - else_if: "*[2][text()='→']" then: [T: "⠨⠔⠳⠕"] - else_if: "*[2][text()='.' or text()='˙']" then: [t: "⠘⠲"] - else_if: "*[2][text()='~']" then: [t: "⠸⠱"] - else_if: "*[2][text()='^']" then: [t: "⠐⠱ "] else: [t: "⠨⠸⠱"] # arc/⌒ - name: single-char-exceptions # RUEB 3.11 -- ° and various prime/minute/seconds aren't treated as if superscripts tag: msup match: "*[2][translate(., \"'*`ª°²³´¹º‘’“”‟′″‴‵‶‷⁗\",'')='']" replace: [x: "*"] - name: default tag: [msub, msup, munder, mover] match: "." replace: - test: # omit grouping indicators in the following cases if: - "not((self::m:mover or self::m:munder) and " - " *[1][self::m:mn] and preceding-sibling::*[1][text()='\u2062'][preceding-sibling::*[1][self::m:mn]]" # need to make clear this 'mn' is base - " )" then: [x: "*[1]"] else: - t: "⠣" - x: "*[1]" - t: "⠜" - with: # this could be tighter and be just around the *[2] part, but this is consistent with msubsup below variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - test: - if: "self::m:msup" then: [T: "⠔"] - else_if: "self::m:msub" then: [T: "⠢"] - else_if: "self::m:munder" then: [T: "⠢"] else: [T: "⠔"] # mover - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) also multi-char leaf translations except mi - "*[2][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "*[2]"] else: - t: "⠣" - x: "*[2]" - t: "⠱" - t: "#" # signal end script/numeric mode - name: log-base-power tag: msubsup match: "*[1][.='log']" replace: - x: "*[1]" # log - T: "⠔" - x: "*[3]" # superscript - T: "⠢" - x: "*[2]" # supscript - name: msubsup_default_mmultiscripts_equiv tag: [msubsup, munderover] # mmultiscripts with only sub/sup postscript match: "count(*)=3" # catches mmultiscripts equiv replace: - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "*[1][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "*[1]"] else: - t: "⠣" - x: "*[1]" - t: "⠜" - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - test: - if: "self::m:munderover" then: [t: "⠢"] else: [t: "⠢"] - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) also multi-char leaf translations except mi - "*[2][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "*[2]"] else: - t: "⠣" - x: "*[2]" - t: "⠜" - test: - if: "self::m:munderover" then: [T: "⠔"] else: [T: "⠔"] - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) also multi-char leaf translations except mi - "*[3][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "*[3]"] else: - t: "⠣" - x: "*[3]" - t: "⠜" - t: "#" # signal end script/numeric mode - name: default tag: mmultiscripts match: "." variables: # computing the number of postscripts is messy because of being optionally present -- we use "mod" to get the count right - Prescripts: "m:mprescripts/following-sibling::*" - NumChildren: "count(*)" # need to stash this since the count is wrong inside '*[...]' below - Postscripts: "*[position()>1 and position() < (last() + ($NumChildren mod 2) -count($Prescripts))]" replace: - x: "*[1]" - test: if: "$Prescripts" then: - test: if: "not($Prescripts[1][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢⠮" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Prescripts[1][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Prescripts[1]"] else: - t: "⠣" - x: "$Prescripts[1]" - t: "⠜" - test: if: "not($Prescripts[2][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔⠞" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Prescripts[2][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Prescripts[2]"] else: - t: "⠣" - x: "$Prescripts[2]" - t: "⠜" - test: if: "count($Prescripts)>2" then: - test: if: "not($Prescripts[3][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢⠮" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Prescripts[3][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Prescripts[3]"] else: - t: "⠣" - x: "$Prescripts[3]" - t: "⠜" - test: if: "not($Prescripts[4][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔⠞" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Prescripts[4][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Prescripts[4]"] else: - t: "⠣" - x: "$Prescripts[4]" - t: "⠜" - test: if: "count($Prescripts) > 4" # give up and just dump them out so at least the content is there then: [x: "$Prescripts[position() > 4]"] - test: if: "$Postscripts" then: - test: if: "not($Postscripts[1][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[1][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[1]"] else: - t: "⠣" - x: "$Postscripts[1]" - t: "⠱" - test: if: "not($Postscripts[2][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[2][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[2]"] else: - t: "⠣" - x: "$Postscripts[2]" - t: "⠱" - test: if: "count($Postscripts)>2" then: - test: if: "not($Postscripts[3][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[3][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[3]"] else: - t: "⠣" - x: "$Postscripts[3]" - t: "⠱" - test: if: "not($Postscripts[4][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[4][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[4]"] else: - t: "⠣" - x: "$Postscripts[4]" - t: "⠱" - test: if: "count($Postscripts)>4" then: - test: if: "not($Postscripts[5][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[5][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[5]"] else: - t: "⠣" - x: "$Postscripts[5]" - t: "⠱" - test: if: "not($Postscripts[6][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[6][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[6]"] else: - t: "⠣" - x: "$Postscripts[6]" - t: "⠱" - test: if: "count($Postscripts)>6" then: - test: if: "not($Postscripts[7][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠢" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[7][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[7]"] else: - t: "⠣" - x: "$Postscripts[7]" - t: "⠱" - test: if: "not($Postscripts[8][self::m:none])" then: - with: variables: [NewScriptContext: "in"] # value doesn't matter -- just can't be empty string replace: - t: "⠔" - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) - "$Postscripts[8][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "$Postscripts[8]"] else: - t: "⠣" - x: "$Postscripts[8]" - t: "⠱" - test: if: "count($Postscripts) > 8" # give up and just dump them out so at least the content is there then: - t: "b" # 82.b -- need to add level indicator between adjacent (not simultaneous) scripts (assumes one of sub/super is not 'none') - x: "$Postscripts[position() > 8]" - t: "#" # signal end script/numeric mode - # Note: @notation can contain more than one value # I don't think UEB has a good way to represent all notations, especially when in combination # Note: # Shape indicator: ⠫ # Physical enclosure: ⠪ (think plus inside of a circle) # Superposition indicator: ⠯ (think contour integral) # Cancellation: ⠈⠱ (line through previous char -- will use for horizontal, vertical, diagonal lines) # Line over/under: use GTM 12 bar rule (over ⠱, under ⠠⠱) # Horizontal juxtaposition indicator: ⠿ # Vertical juxtaposition indicator: ⠻ (think ≗) # Termination indicator: ⠱ # # We place left and right outside of other notations # Boxes and circle are does as physical enclosure (shape before base) # Arrows are done as superposition (after base) # top and bottom are done as "bars" (GTM 12) (after base) name: default tag: menclose match: "." # FIX: can't find a rule that says anything about comparison operator spacing and enclosure variables: [AddSpaces: "parent::*[self::m:mrow] and *[1][ self::m:mo and IsInDefinition(., 'Braille', 'NemethComparisonOperators')]"] replace: - test: if: "contains(concat(' ', normalize-space(@notation), ' '), ' left ')" #avoid 'leftarrow' then: [t: "⠸"] - test: if: "contains(@notation,'box')" # box and roundedbox then: # - test: # if: "$AddSpaces" # then: [t: " "] - T: "⠫⠼⠙" # square (no rectangle in UEB) - test: if: "contains(@notation,'circle')" then: # - test: # if: "$AddSpaces" # then: [t: " "] - t: "⠫⠿" # circle (no oval in UEB) # ??? What should happen with arrow? # If there is a box/circle with arrows only and an empty child, # then it acts like the arrow is the child # If there are only arrows for 'notation', then maybe rule 112 applies (superposition), # but the examples aren't similar. In that case, the arrow acts like 'box' and the child is the content... maybe # # - test: # if: "contains(@notation,'leftarrow')" # then: [t: left arrow, pause: short] # - test: # if: "contains(concat(' ', normalize-space(@notation), ' '), ' rightarrow ')" # then: [t: right arrow, pause: short] # - test: # if: "contains(@notation,'northeastarrow')" # then: [t: northeast arrow, pause: short] # - test: # if: "contains(concat(' ', normalize-space(@notation), ' '), ' southeastarrow ')" # then: [t: southeast arrow, pause: short] # - test: # if: "contains(concat(' ', normalize-space(@notation), ' '), ' southwestarrow ')" # then: [t: southwest arrow, pause: short] # - test: # if: "contains(@notation,'northwestarrow')" # then: [t: northwest arrow, pause: short] # - test: # if: "contains(@notation,'updownarrow')" # then: [t: double ended vertical arrow, pause: short] # - test: # if: "contains(@notation,'leftrightarrow')" # then: [t: double ended horizontal arrow, pause: short] # - test: # if: "contains(@notation,'northeastsouthwestarrow')" # then: [t: double ended up diagonal arrow, pause: short] # - test: # if: "contains(@notation,'northwestsoutheastarrow')" # then: [t: double ended down diagonal arrow, pause: short] # - test: # if: ".[contains(@notation,'actuarial')]" # then: [t: actuarial symbol, pause: short] # - test: # if: ".[contains(@notation,'madrub')]" # then: [t: arabic factorial symbol, pause: short] # - test: # if: ".[contains(@notation,'longdiv') or not(@notation) or normalize-space(@notation) ='']" # default # then: [t: long division symbol, pause: short] # - test: # if: ".[contains(@notation,'radical')]" # then: [t: square root, pause: short] - test: # omit grouping indicators in the following cases if: # FIX: need to add arbitrary shapes here (also for mroot) also multi-char leaf translations except mi # next test is to make sure there is just one symbol # FIX: the double dot test is likely wrong, but I can't find what other exceptions there are - "*[1][(self::m:mn and not(@data-roman-numeral and string-length(text())>1)) or" - " ((self::m:mi or self::m:mo) and string-length(text())=1 and text()!='¨') or" - " self::m:mfrac or self::m:msqrt or self::m:mroot or" - " IsBracketed(., '(', ')') or IsBracketed(., '[', ']') or IsBracketed(., '{', '}') or" - " IsInDefinition(., 'Braille', 'Arrows')" - " ]" then: [x: "*[1]"] else: - t: "⠣" - x: "*[1]" - t: "⠜" # - test: # if: "contains(@notation,'phasorangle')" #FIX: what should this be??? # then: [t: "⠫⠪⠸⠫"] - test: if: "contains(@notation,'arrow')" # all the arrows then: - test: - if: "contains(@notation,'rightarrow')" then: [t: "⠳⠕"] - else_if: "contains(@notation,'leftarrow')" then: [t: "⠳⠪"] - else_if: "contains(@notation,'uparrow')" then: [t: "⠳⠬ "] - else_if: "contains(@notation,'downarrow')" then: [t: "⠳⠩"] - else_if: "contains(@notation,'northeastarrow')" then: [t: "⠳⠎"] - else_if: "contains(@notation,'southeastarrow')" then: [t: "⠳⠣"] - else_if: "contains(@notation,'northwestarrow')" then: [t: "⠳⠱"] - else_if: "contains(@notation,'southwestarrow')" then: [t: "⠳⠜"] - else_if: "contains(@notation,'leftrightarrow')" then: [t: "⠳⠺⠗⠕"] - else_if: "contains(@notation,'updownarrow')" then: [t: "⠳⠺⠗⠬"] - else_if: "contains(@notation,'northeastsouthwestarrow')" then: [t: "⠳⠺⠗⠎"] - else_if: "contains(@notation,'northwestsoutheastarrow')" then: [t: "⠳⠺⠗⠣"] - test: if: "contains(@notation,'top')" then: [T: "⠨⠱"] - test: if: "contains(@notation,'bottom')" then: [t: "⠠⠱"] - test: if: "contains(@notation,'updiagonalstrike') or contains(@notation,'downdiagonalstrike') or contains(@notation,'verticalstrike') or contains(@notation,'horizontalstrike')" then: - t: "⠈⠱" # cancellation - test: if: - "not($AddSpaces) and contains(@notation,'box') or contains(@notation,'circle') or" - "contains(@notation,'arrow') or contains(@notation,'phasorangle')" then: - t: "⠻" # terminate shape # - test: # if: "$AddSpaces" # then: [t: " "] - test: if: "contains(concat(' ', normalize-space(@notation), ' '), ' right ')" #avoid 'rightarrow' then: [t: "⠸"] - name: default tag: ms match: "." replace: - test: if: "string(@lquote)!=''" then: [x: "@lquote"] else: [t: "⠄⠄"] - x: "BrailleChars(., 'Vietnam')" - test: if: "string(@rquote)!=''" then: [x: "@rquote"] else: [t: "⠄⠄"] - name: default tag: semantics match: "." replace: - x: "*[1]" #/ FIX: should prioritize @encoding="MathML-Presentation" and @encoding="application/mathml-presentation+xml" - name: default-children tag: "*" match: "*" # make sure there are children replace: - t: "unknown math m l element" - x: "name(.)" - x: "*" - # at this point, we know there are no children -- might be no text name: default-no-children tag: "*" match: "text()" replace: - t: unknown math m l element - x: "name(.)" - x: "text()" - name: default-no-text tag: "*" match: "." replace: - t: "empty unknown math m l element" - x: "name(.)"