123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807 |
- /*************************************************************
- *
- * Copyright (c) 2021-2022 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview Implements the elementary MathML3 support (experimental)
- * using David Carlisle's XLST transform.
- *
- * @author dpvc@mathjax.org (Davide Cervone)
- */
- import {MathItem} from '../../../core/MathItem.js';
- import {MathDocument} from '../../../core/MathDocument.js';
- import {Handler} from '../../../core/Handler.js';
- import {OptionList} from '../../../util/Options.js';
- import {createTransform} from './mml3-node.js';
- import {MathML} from '../../mathml.js';
- /**
- * The data for a MathML prefilter.
- *
- * @template N The HTMLElement node class
- * @template T The Text node class
- * @template D The Document class
- */
- export type FILTERDATA<N, T, D> = {math: MathItem<N, T, D>, document: MathDocument<N, T, D>, data: N};
- /**
- * Class that handles XSLT transform for MathML3 elementary math tags.
- */
- export class Mml3<N, T, D> {
- /**
- * The XSLT transform as a string;
- */
- public static XSLT: string; // added below (it is huge)
- /**
- * The function to convert serialized MathML using the XSLT.
- * (Different for browser and node environments.)
- */
- protected transform: (node: N, doc: MathDocument<N, T, D>) => N;
- /**
- * @param {MathDocument} document The MathDocument for the transformation
- * @constructor
- */
- constructor(document: MathDocument<N, T, D>) {
- if (typeof XSLTProcessor === 'undefined') {
- //
- // For Node, get the trasnform from the external module
- //
- this.transform = createTransform();
- } else {
- //
- // For in-browser use, use the browser's XSLTProcessor
- //
- const processor = new XSLTProcessor();
- const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node;
- processor.importStylesheet(parsed);
- this.transform = (node: N) => {
- const adaptor = document.adaptor;
- const div = adaptor.node('div', {}, [adaptor.clone(node)]);
- const mml = processor.transformToDocument(div as any as Node) as any as N;
- return adaptor.tags(mml, 'math')[0];
- };
- }
- }
- /**
- * The mathml filter for the MathML input jax
- *
- * @param {FILTERDATA} args The data from the pre-filter chain.
- */
- public mmlFilter(args: FILTERDATA<N, T, D>) {
- if (args.document.options.enableMml3) {
- args.data = this.transform(args.data, args.document);
- }
- }
- }
- /**
- * Add Mml3 support into the handler.
- */
- export function Mml3Handler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D> {
- handler.documentClass = class extends handler.documentClass {
- /**
- * @override
- */
- public static OPTIONS: OptionList = {
- ...handler.documentClass.OPTIONS,
- enableMml3: true,
- };
- /**
- * Add a prefilter to the MathML input jax, if there is one.
- *
- * @override
- * @constructor
- */
- constructor(...args: any[]) {
- super(...args);
- for (const jax of this.inputJax || []) {
- if (jax.name === 'MathML') {
- if (!jax.options._mml3) { // prevent filter being added twice (e.g., when a11y tools load)
- const mml3 = new Mml3(this);
- (jax as MathML<N, T, D>).mmlFilters.add(mml3.mmlFilter.bind(mml3));
- jax.options._mml3 = true;
- }
- break;
- }
- }
- }
- };
- return handler;
- }
- //
- // The actual XSLT transform
- //
- Mml3.XSLT = `
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:m="http://www.w3.org/1998/Math/MathML"
- xmlns:c="http://exslt.org/common"
- exclude-result-prefixes="m c">
- <xsl:output indent="yes" omit-xml-declaration="yes"/>
- <xsl:output indent="yes" omit-xml-declaration="yes"/>
- <xsl:template match="*">
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates/>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="m:*[@dir='rtl']" priority="10">
- <xsl:apply-templates mode="rtl" select="."/>
- </xsl:template>
- <xsl:template match="@*" mode="rtl">
- <xsl:copy-of select="."/>
- <xsl:attribute name="dir">ltr</xsl:attribute>
- </xsl:template>
- <xsl:template match="*" mode="rtl">
- <xsl:copy>
- <xsl:apply-templates select="@*" mode="rtl"/>
- <xsl:for-each select="node()">
- <xsl:sort data-type="number" order="descending" select="position()"/>
- <xsl:text> </xsl:text>
- <xsl:apply-templates mode="rtl" select="."/>
- </xsl:for-each>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="@open" mode="rtl">
- <xsl:attribute name="close"><xsl:value-of select="."/></xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.='(']" mode="rtl">
- <xsl:attribute name="close">)</xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.=')']" mode="rtl">
- <xsl:attribute name="close">(</xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.='[']" mode="rtl">
- <xsl:attribute name="close">]</xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.=']']" mode="rtl">
- <xsl:attribute name="close">[</xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.='{']" mode="rtl">
- <xsl:attribute name="close">}</xsl:attribute>
- </xsl:template>
- <xsl:template match="@open[.='}']" mode="rtl">
- <xsl:attribute name="close">{</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close" mode="rtl">
- <xsl:attribute name="open"><xsl:value-of select="."/></xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.='(']" mode="rtl">
- <xsl:attribute name="open">)</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.=')']" mode="rtl">
- <xsl:attribute name="open">(</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.='[']" mode="rtl">
- <xsl:attribute name="open">]</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.=']']" mode="rtl">
- <xsl:attribute name="open">[</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.='{']" mode="rtl">
- <xsl:attribute name="open">}</xsl:attribute>
- </xsl:template>
- <xsl:template match="@close[.='}']" mode="rtl">
- <xsl:attribute name="open">{</xsl:attribute>
- </xsl:template>
- <xsl:template match="m:mfrac[@bevelled='true']" mode="rtl">
- <m:mrow>
- <m:msub><m:mi></m:mi><xsl:apply-templates select="*[2]" mode="rtl"/></m:msub>
- <m:mo>\</m:mo>
- <m:msup><m:mi></m:mi><xsl:apply-templates select="*[1]" mode="rtl"/></m:msup>
- </m:mrow>
- </xsl:template>
- <xsl:template match="m:mfrac" mode="rtl">
- <xsl:copy>
- <xsl:apply-templates mode="rtl" select="@*|*"/>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="m:mroot" mode="rtl">
- <m:msup>
- <m:menclose notation="top right">
- <xsl:apply-templates mode="rtl" select="@*|*[1]"/>
- </m:menclose>
- <xsl:apply-templates mode="rtl" select="*[2]"/>
- </m:msup>
- </xsl:template>
- <xsl:template match="m:msqrt" mode="rtl">
- <m:menclose notation="top right">
- <xsl:apply-templates mode="rtl" select="@*|*[1]"/>
- </m:menclose>
- </xsl:template>
- <xsl:template match="m:mtable|m:munder|m:mover|m:munderover" mode="rtl" priority="2">
- <xsl:copy>
- <xsl:apply-templates select="@*" mode="rtl"/>
- <xsl:apply-templates mode="rtl">
- </xsl:apply-templates>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="m:msup" mode="rtl" priority="2">
- <m:mmultiscripts>
- <xsl:apply-templates select="*[1]" mode="rtl"/>
- <m:mprescripts/>
- <m:none/>
- <xsl:apply-templates select="*[2]" mode="rtl"/>
- </m:mmultiscripts>
- </xsl:template>
- <xsl:template match="m:msub" mode="rtl" priority="2">
- <m:mmultiscripts>
- <xsl:apply-templates select="*[1]" mode="rtl"/>
- <m:mprescripts/>
- <xsl:apply-templates select="*[2]" mode="rtl"/>
- <m:none/>
- </m:mmultiscripts>
- </xsl:template>
- <xsl:template match="m:msubsup" mode="rtl" priority="2">
- <m:mmultiscripts>
- <xsl:apply-templates select="*[1]" mode="rtl"/>
- <m:mprescripts/>
- <xsl:apply-templates select="*[2]" mode="rtl"/>
- <xsl:apply-templates select="*[3]" mode="rtl"/>
- </m:mmultiscripts>
- </xsl:template>
- <xsl:template match="m:mmultiscripts" mode="rtl" priority="2">
- <m:mmultiscripts>
- <xsl:apply-templates select="*[1]" mode="rtl"/>
- <xsl:for-each select="m:mprescripts/following-sibling::*[position() mod 2 = 1]">
- <xsl:sort data-type="number" order="descending" select="position()"/>
- <xsl:apply-templates select="." mode="rtl"/>
- <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
- </xsl:for-each>
- <m:mprescripts/>
- <xsl:for-each select="m:mprescripts/preceding-sibling::*[position()!=last()][position() mod 2 = 0]">
- <xsl:sort data-type="number" order="descending" select="position()"/>
- <xsl:apply-templates select="." mode="rtl"/>
- <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
- </xsl:for-each>
- </m:mmultiscripts>
- </xsl:template>
- <xsl:template match="m:mmultiscripts[not(m:mprescripts)]" mode="rtl" priority="3">
- <m:mmultiscripts>
- <xsl:apply-templates select="*[1]" mode="rtl"/>
- <m:mprescripts/>
- <xsl:for-each select="*[position() mod 2 = 0]">
- <xsl:sort data-type="number" order="descending" select="position()"/>
- <xsl:apply-templates select="." mode="rtl"/>
- <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
- </xsl:for-each>
- </m:mmultiscripts>
- </xsl:template>
- <xsl:template match="text()[.='(']" mode="rtl">)</xsl:template>
- <xsl:template match="text()[.=')']" mode="rtl">(</xsl:template>
- <xsl:template match="text()[.='{']" mode="rtl">}</xsl:template>
- <xsl:template match="text()[.='}']" mode="rtl">{</xsl:template>
- <xsl:template match="text()[.='<']" mode="rtl">></xsl:template>
- <xsl:template match="text()[.='>']" mode="rtl"><</xsl:template>
- <xsl:template match="text()[.='∈']" mode="rtl">∋</xsl:template>
- <xsl:template match="text()[.='∋']" mode="rtl">∈</xsl:template>
- <xsl:template match="@notation[.='radical']" mode="rtl">
- <xsl:attribute name="notation">top right</xsl:attribute>
- </xsl:template>
- <xsl:template match="m:mlongdiv|m:mstack" mode="rtl">
- <m:mrow dir="ltr">
- <xsl:apply-templates select="."/>
- </m:mrow>
- </xsl:template>
- <xsl:template match="m:mstack" priority="11">
- <xsl:variable name="m">
- <m:mtable columnspacing="0em" rowspacing="0em">
- <xsl:copy-of select="@align"/>
- <xsl:variable name="t">
- <xsl:apply-templates select="*" mode="mstack1">
- <xsl:with-param name="p" select="0"/>
- </xsl:apply-templates>
- </xsl:variable>
- <xsl:variable name="maxl">
- <xsl:for-each select="c:node-set($t)/*/@l">
- <xsl:sort data-type="number" order="descending"/>
- <xsl:if test="position()=1">
- <xsl:value-of select="."/>
- </xsl:if>
- </xsl:for-each>
- </xsl:variable>
- <xsl:for-each select="c:node-set($t)/*[not(@class='mscarries') or following-sibling::*[1]/@class='mscarries']">
- <xsl:variable name="c" select="preceding-sibling::*[1][@class='mscarries']"/>
- <xsl:text> </xsl:text>
- <m:mtr>
- <xsl:copy-of select="@class[.='msline']"/>
- <xsl:variable name="offset" select="$maxl - @l"/>
- <xsl:choose>
- <xsl:when test="@class='msline' and @l='*'">
- <xsl:variable name="msl" select="*[1]"/>
- <xsl:for-each select="(//node())[position()<=$maxl]">
- <xsl:copy-of select="$msl"/>
- </xsl:for-each>
- </xsl:when>
- <xsl:when test="$c">
- <xsl:variable name="ldiff" select="$c/@l - @l"/>
- <xsl:variable name="loffset" select="$maxl - $c/@l"/>
- <xsl:for-each select="(//*)[position()<= $offset]">
- <xsl:variable name="pn" select="position()"/>
- <xsl:variable name="cy" select="$c/*[position()=$pn - $loffset]"/>
- <m:mtd>
- <xsl:if test="$cy/*">
- <m:mover><m:mphantom><m:mn>0</m:mn></m:mphantom><m:mpadded width="0em" lspace="-0.5width">
- <xsl:copy-of select="$cy/*"/></m:mpadded></m:mover>
- </xsl:if>
- </m:mtd>
- </xsl:for-each>
- <xsl:for-each select="*">
- <xsl:variable name="pn" select="position()"/>
- <xsl:variable name="cy" select="$c/*[position()=$pn + $ldiff]"/>
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:variable name="b">
- <xsl:choose>
- <xsl:when test="not(string($cy/@crossout) or $cy/@crossout='none')"><xsl:copy-of select="*"/></xsl:when>
- <xsl:otherwise>
- <m:menclose notation="{$cy/@crossout}"><xsl:copy-of select="*"/></m:menclose>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="$cy/m:none or not($cy/*)"><xsl:copy-of select="$b"/></xsl:when>
- <xsl:when test="not(string($cy/@location)) or $cy/@location='n'">
- <m:mover>
- <xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width">
- <xsl:copy-of select="$cy/*"/>
- </m:mpadded>
- </m:mover>
- </xsl:when>
- <xsl:when test="$cy/@location='nw'">
- <m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:none/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:mmultiscripts>
- </xsl:when>
- <xsl:when test="$cy/@location='s'">
- <m:munder><xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width"><xsl:copy-of select="$cy/*"/></m:mpadded></m:munder>
- </xsl:when>
- <xsl:when test="$cy/@location='sw'">
- <m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded><m:none/></m:mmultiscripts>
- </xsl:when>
- <xsl:when test="$cy/@location='ne'">
- <m:msup><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
- </xsl:when>
- <xsl:when test="$cy/@location='se'">
- <m:msub><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msub>
- </xsl:when>
- <xsl:when test="$cy/@location='w'">
- <m:msup><m:mrow/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
- <xsl:copy-of select="$b"/>
- </xsl:when>
- <xsl:when test="$cy/@location='e'">
- <xsl:copy-of select="$b"/>
- <m:msup><m:mrow/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy-of select="$b"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:copy>
- </xsl:for-each>
- </xsl:when>
- <xsl:otherwise>
- <xsl:for-each select="(//*)[position()<= $offset]"><m:mtd/></xsl:for-each>
- <xsl:copy-of select="*"/>
- </xsl:otherwise>
- </xsl:choose>
- </m:mtr>
- </xsl:for-each>
- </m:mtable>
- </xsl:variable>
- <xsl:apply-templates mode="ml" select="c:node-set($m)"/>
- </xsl:template>
- <xsl:template match="m:none" mode="ml">
- <m:mrow/>
- </xsl:template>
- <xsl:template match="*" mode="ml">
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <xsl:apply-templates mode="ml"/>
- </xsl:copy>
- </xsl:template>
- <xsl:template mode="ml" match="m:mtr[following-sibling::*[1][@class='msline']]">
- <m:mtr>
- <xsl:copy-of select="@*"/>
- <xsl:variable name="m" select="following-sibling::*[1]/m:mtd"/>
- <xsl:for-each select="m:mtd">
- <xsl:variable name="p" select="position()"/>
- <m:mtd>
- <xsl:copy-of select="@*"/>
- <xsl:choose>
- <xsl:when test="$m[$p]/m:mpadded">
- <m:mpadded depth="+.2em">
- <m:menclose notation="bottom">
- <m:mpadded depth=".1em" height=".8em" width=".8em">
- <m:mspace width=".15em"/>
- <xsl:copy-of select="*"/>
- </m:mpadded>
- </m:menclose>
- </m:mpadded>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy-of select="*"/>
- </xsl:otherwise>
- </xsl:choose>
- </m:mtd>
- </xsl:for-each>
- </m:mtr>
- </xsl:template>
- <xsl:template mode="ml" match="m:mtr[not(preceding-sibling::*)][@class='msline']" priority="3">
- <m:mtr>
- <xsl:copy-of select="@*"/>
- <xsl:for-each select="m:mtd">
- <m:mtd>
- <xsl:copy-of select="@*"/>
- <xsl:if test="m:mpadded">
- <m:menclose notation="bottom">
- <m:mpadded depth=".1em" height="1em" width=".5em">
- <m:mspace width=".2em"/>
- </m:mpadded>
- </m:menclose>
- </xsl:if>
- </m:mtd>
- </xsl:for-each>
- </m:mtr>
- </xsl:template>
- <xsl:template mode="ml" match="m:mtr[@class='msline']" priority="2"/>
- <xsl:template mode="mstack1" match="*">
- <xsl:param name="p"/>
- <xsl:param name="maxl" select="0"/>
- <m:mtr l="{1 + $p}">
- <xsl:if test="ancestor::mstack[1]/@stackalign='left'">
- <xsl:attribute name="l"><xsl:value-of select="$p"/></xsl:attribute>
- </xsl:if>
- <m:mtd><xsl:apply-templates select="."/></m:mtd>
- </m:mtr>
- </xsl:template>
- <xsl:template mode="mstack1" match="m:msrow">
- <xsl:param name="p"/>
- <xsl:param name="maxl" select="0"/>
- <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
- <xsl:variable name="align">
- <xsl:choose>
- <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
- <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="row">
- <xsl:apply-templates mode="mstack1" select="*">
- <xsl:with-param name="p" select="0"/>
- </xsl:apply-templates>
- </xsl:variable>
- <xsl:text> </xsl:text>
- <xsl:variable name="l1">
- <xsl:choose>
- <xsl:when test="$align='decimalpoint' and m:mn">
- <xsl:for-each select="c:node-set($row)/m:mtr[m:mtd/m:mn][1]">
- <xsl:value-of select="number(sum(@l))+count(preceding-sibling::*/@l)"/>
- </xsl:for-each>
- </xsl:when>
- <xsl:when test="$align='right' or $align='decimalpoint'">
- <xsl:value-of select="count(c:node-set($row)/m:mtr/m:mtd)"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="0"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <m:mtr class="msrow" l="{number($l1) + number(sum(@position)) +$p}">
- <xsl:copy-of select="c:node-set($row)/m:mtr/*"/>
- </m:mtr>
- </xsl:template>
- <xsl:template mode="mstack1" match="m:mn">
- <xsl:param name="p"/>
- <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
- <xsl:variable name="dp1" select="ancestor::*[@decimalpoint][1]/@decimalpoint"/>
- <xsl:variable name="align">
- <xsl:choose>
- <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
- <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="dp">
- <xsl:choose>
- <xsl:when test="string($dp1)=''">.</xsl:when>
- <xsl:otherwise><xsl:value-of select="$dp1"/></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <m:mtr l="$p">
- <xsl:variable name="mn" select="normalize-space(.)"/>
- <xsl:variable name="len" select="string-length($mn)"/>
- <xsl:choose>
- <xsl:when test="$align='right' or ($align='decimalpoint' and not(contains($mn,$dp)))">
- <xsl:attribute name="l"><xsl:value-of select="$p + $len"/></xsl:attribute>
- </xsl:when>
- <xsl:when test="$align='center'">
- <xsl:attribute name="l"><xsl:value-of select="round(($p + $len) div 2)"/></xsl:attribute>
- </xsl:when>
- <xsl:when test="$align='decimalpoint'">
- <xsl:attribute name="l"><xsl:value-of select="$p + string-length(substring-before($mn,$dp))"/></xsl:attribute>
- </xsl:when>
- </xsl:choose>
- <xsl:for-each select="(//node())[position() <=$len]">
- <xsl:variable name="pos" select="position()"/>
- <xsl:variable name="digit" select="substring($mn,$pos,1)"/>
- <m:mtd>
- <xsl:if test="$digit='.' or $digit=','">
- <m:mspace width=".15em"/>
- </xsl:if>
- <m:mn><xsl:value-of select="$digit"/></m:mn>
- </m:mtd>
- </xsl:for-each>
- </m:mtr>
- </xsl:template>
- <xsl:template match="m:msgroup" mode="mstack1">
- <xsl:param name="p"/>
- <xsl:variable name="s" select="number(sum(@shift))"/>
- <xsl:variable name="thisp" select="number(sum(@position))"/>
- <xsl:for-each select="*">
- <xsl:apply-templates mode="mstack1" select=".">
- <xsl:with-param name="p" select="number($p)+$thisp+(position()-1)*$s"/>
- </xsl:apply-templates>
- </xsl:for-each>
- </xsl:template>
- <xsl:template match="m:msline" mode="mstack1">
- <xsl:param name="p"/>
- <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
- <xsl:variable name="align">
- <xsl:choose>
- <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
- <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <m:mtr class="msline">
- <xsl:attribute name="l">
- <xsl:choose>
- <xsl:when test="not(string(@length)) or @length=0">*</xsl:when>
- <xsl:when test="string($align)='right' or string($align)='decimalpoint' "><xsl:value-of select="$p+ @length"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$p"/></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- <xsl:variable name="w">
- <xsl:choose>
- <xsl:when test="@mslinethickness='thin'">0.1em</xsl:when>
- <xsl:when test="@mslinethickness='medium'">0.15em</xsl:when>
- <xsl:when test="@mslinethickness='thick'">0.2em</xsl:when>
- <xsl:when test="@mslinethickness"><xsl:value-of select="@mslinethickness"/></xsl:when>
- <xsl:otherwise>0.15em</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="not(string(@length)) or @length=0">
- <m:mtd class="mslinemax">
- <m:mpadded lspace="-0.2em" width="0em" height="0em">
- <m:mfrac linethickness="{$w}">
- <m:mspace width=".5em"/>
- <m:mrow/>
- </m:mfrac>
- </m:mpadded>
- </m:mtd>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="l" select="@length"/>
- <xsl:for-each select="(//node())[position()<=$l]">
- <m:mtd class="msline">
- <m:mpadded lspace="-0.2em" width="0em" height="0em">
- <m:mfrac linethickness="{$w}">
- <m:mspace width=".5em"/>
- <m:mrow/>
- </m:mfrac>
- </m:mpadded>
- </m:mtd>
- </xsl:for-each>
- </xsl:otherwise>
- </xsl:choose>
- </m:mtr>
- </xsl:template>
- <xsl:template match="m:mscarries" mode="mstack1">
- <xsl:param name="p"/>
- <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
- <xsl:variable name="l1">
- <xsl:choose>
- <xsl:when test="string($align1)='left'">0</xsl:when>
- <xsl:otherwise><xsl:value-of select="count(*)"/></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <m:mtr class="mscarries" l="{$p + $l1 + sum(@position)}">
- <xsl:apply-templates select="*" mode="msc"/>
- </m:mtr>
- </xsl:template>
- <xsl:template match="*" mode="msc">
- <m:mtd>
- <xsl:copy-of select="../@location|../@crossout"/>
- <xsl:choose>
- <xsl:when test="../@scriptsizemultiplier">
- <m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
- <xsl:apply-templates select="."/>
- </m:mstyle>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates select="."/>
- </xsl:otherwise>
- </xsl:choose>
- </m:mtd>
- </xsl:template>
- <xsl:template match="m:mscarry" mode="msc">
- <m:mtd>
- <xsl:copy-of select="@location|@crossout"/>
- <xsl:choose>
- <xsl:when test="../@scriptsizemultiplier">
- <m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
- <xsl:apply-templates/>
- </m:mstyle>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
- </m:mtd>
- </xsl:template>
- <xsl:template match="m:mlongdiv" priority="11">
- <xsl:variable name="ms">
- <m:mstack>
- <xsl:copy-of select="(ancestor-or-self::*/@decimalpoint)[last()]"/>
- <xsl:choose>
- <xsl:when test="@longdivstyle='left)(right'">
- <m:msrow>
- <m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
- <m:mo>)</m:mo>
- <xsl:copy-of select="*[3]"/>
- <m:mo>(</m:mo>
- <xsl:copy-of select="*[2]"/>
- </m:msrow>
- </xsl:when>
- <xsl:when test="@longdivstyle='left/\right'">
- <m:msrow>
- <m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
- <m:mo>/</m:mo>
- <xsl:copy-of select="*[3]"/>
- <m:mo>\</m:mo>
- <xsl:copy-of select="*[2]"/>
- </m:msrow>
- </xsl:when>
- <xsl:when test="@longdivstyle=':right=right'">
- <m:msrow>
- <xsl:copy-of select="*[3]"/>
- <m:mo>:</m:mo>
- <xsl:copy-of select="*[1]"/>
- <m:mo>=</m:mo>
- <xsl:copy-of select="*[2]"/>
- </m:msrow>
- </xsl:when>
- <xsl:when test="@longdivstyle='stackedrightright'
- or @longdivstyle='mediumstackedrightright'
- or @longdivstyle='shortstackedrightright'
- or @longdivstyle='stackedleftleft'
- ">
- <xsl:attribute name="align">top</xsl:attribute>
- <xsl:copy-of select="*[3]"/>
- </xsl:when>
- <xsl:when test="@longdivstyle='stackedleftlinetop'">
- <xsl:copy-of select="*[2]"/>
- <m:msline length="{string-length(*[3])}"/>
- <m:msrow>
- <m:mrow>
- <m:menclose notation="bottom right">
- <xsl:copy-of select="*[1]"/>
- </m:menclose>
- </m:mrow>
- <xsl:copy-of select="*[3]"/>
- </m:msrow>
- </xsl:when>
- <xsl:when test="@longdivstyle='righttop'">
- <xsl:copy-of select="*[2]"/>
- <m:msline length="{string-length(*[3])}"/>
- <m:msrow>
- <xsl:copy-of select="*[3]"/>
- <m:menclose notation="top left bottom">
- <xsl:copy-of select="*[1]"/></m:menclose>
- </m:msrow>
- </xsl:when>
- <xsl:otherwise>
- <xsl:copy-of select="*[2]"/>
- <m:msline length="{string-length(*[3])+1}"/>
- <m:msrow>
- <m:mrow><xsl:copy-of select="*[1]"/><m:mspace width=".2em"/></m:mrow>
- <m:mpadded voffset=".1em" lspace="-.15em" depth="-.2em" height="-.2em">
- <m:mo minsize="1.2em">)</m:mo>
- </m:mpadded>
- <xsl:copy-of select="*[3]"/>
- </m:msrow>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:copy-of select="*[position()>3]"/>
- </m:mstack>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="@longdivstyle='stackedrightright'">
- <m:menclose notation="right">
- <xsl:apply-templates select="c:node-set($ms)"/>
- </m:menclose>
- <m:mtable align="top">
- <m:mtr>
- <m:menclose notation="bottom">
- <xsl:copy-of select="*[1]"/>
- </m:menclose>
- </m:mtr>
- <m:mtr>
- <mtd><xsl:copy-of select="*[2]"/></mtd>
- </m:mtr>
- </m:mtable>
- </xsl:when>
- <xsl:when test="@longdivstyle='mediumstackedrightright'">
- <xsl:apply-templates select="c:node-set($ms)"/>
- <m:menclose notation="left">
- <m:mtable align="top">
- <m:mtr>
- <m:menclose notation="bottom">
- <xsl:copy-of select="*[1]"/>
- </m:menclose>
- </m:mtr>
- <m:mtr>
- <mtd><xsl:copy-of select="*[2]"/></mtd>
- </m:mtr>
- </m:mtable>
- </m:menclose>
- </xsl:when>
- <xsl:when test="@longdivstyle='shortstackedrightright'">
- <xsl:apply-templates select="c:node-set($ms)"/>
- <m:mtable align="top">
- <m:mtr>
- <m:menclose notation="left bottom">
- <xsl:copy-of select="*[1]"/>
- </m:menclose>
- </m:mtr>
- <m:mtr>
- <mtd><xsl:copy-of select="*[2]"/></mtd>
- </m:mtr>
- </m:mtable>
- </xsl:when>
- <xsl:when test="@longdivstyle='stackedleftleft'">
- <m:mtable align="top">
- <m:mtr>
- <m:menclose notation="bottom">
- <xsl:copy-of select="*[1]"/>
- </m:menclose>
- </m:mtr>
- <m:mtr>
- <mtd><xsl:copy-of select="*[2]"/></mtd>
- </m:mtr>
- </m:mtable>
- <m:menclose notation="left">
- <xsl:apply-templates select="c:node-set($ms)"/>
- </m:menclose>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates select="c:node-set($ms)"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
- <xsl:template match="m:menclose[@notation='madruwb']" mode="rtl">
- <m:menclose notation="bottom right">
- <xsl:apply-templates mode="rtl"/>
- </m:menclose>
- </xsl:template>
- </xsl:stylesheet>
- `;
|