mathjax / MathJax

Beautiful and accessible math in all browsers
http://www.mathjax.org/
Apache License 2.0
10.18k stars 1.16k forks source link

Could not render math formula with mathml #3030

Open chrisooo3 opened 1 year ago

chrisooo3 commented 1 year ago

I have the following code to convert MathML to svg:

function convertMMlToSvg() {
    var mml = `<math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>F</mi><mrow><mi>w</mi><mo>&#160;</mo></mrow></msub><mo>=</mo><mo>&#160;</mo><msqrt><msubsup><mi>F</mi><mn>1</mn><mn>2</mn></msubsup><mo>&#160;</mo><mo>+</mo><msubsup><mi>F</mi><mn>2</mn><mn>2</mn></msubsup><mo>&#160;</mo></msqrt><mspace linebreak="newline"></mspace></mrow><annotation encoding="application/vnd.wiris.mtweb-params+json">{&#34;fontSize&#34;:&#34;13px&#34;,&#34;fontStyle&#34;:&#34;normal&#34;}</annotation></semantics></math>`;
    var svg  = MathJax.mathml2svg(mml);
    var div = document.createElement('div');
    div.innerHTML = svg.innerHTML.trim();

    return div.firstChild;
}

When I try to run it: convertMMlToSvg(), I get following error:

TypeError: Cannot read property 'getElementsByTagName' of null
    at e.tags (mml-svg.js:1)
    at e.transform (mml3.js:1)
    at e.mmlFilter (mml3.js:1)
    at e.execute (mml-svg.js:1)
    at e.t.executeFilters (mml-svg.js:1)
    at e.compile (mml-svg.js:1)
    at e.t.compile (mml-svg.js:1)
    at Object.renderMath (mml-svg.js:1)
    at e.renderConvert (mml-svg.js:1)
    at e.t.convert (mml-svg.js:1)

I am using this lib to render this

<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/mml-svg.js"></script>

Does anyone know what could be the cause of it?

To reproduce, here you have jsbin As you can there is confing for MathML in order to order avoid error: Unknown node type "mstack".

dpvc commented 1 year ago

It looks like this is an issue in WebKit (and Blink), so affects Chrome, Safari, and Edge, but not Firefox. The mml3 extension uses an XSLT transform to convert the elementary math tags to other presentation MathML tags, and it appears that the WebKit XSLT transformer fails on HTML that contains the entity &#xA0; (but not other numeric entities) and that is causing the error message you are getting. (The transfer returns a null document, and when MathJax tried to locate the <math> element in that, it fails.)

The expression you list above includes <mo>&#xA0;</mo>, apparently to adjust the spacing, which is a bad idea, or perhaps due to how your math editor (Wiris?) handles spaces within your input (which really should be ignored). In any case, it is those elements that are causing the problem. They really shouldn't be there, as they will cause the expression to be badly spaced.

This is a configuration that would remove the <mo>&#xA0;</mo> elements, allowing the output to be processed:

    MathJax = {
      loader: {load: ['[mml]/mml3']},
      startup: {
        ready() {
          MathJax.startup.defaultReady();
          MathJax.startup.document.inputJax[0].preFilters.add((arg) => {
            arg.data = arg.data.replace(/<mo>\&#160;<\/mo>/g, '');
          });
        }
      }
    };

See if that doesn't resolve the issue for you.

dpvc commented 1 year ago

I've made a pull request to resolve this in the next release.

chrisooo3 commented 1 year ago

@dpvc thanks for reply, it helped with one type of formulas, but when try to render this formula:

<math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>&#8712;</mo><mfenced open="&#60;" close="&#62;"><mrow><mn>1</mn><mo>;</mo><mn>2</mn></mrow></mfenced></mrow><annotation encoding="application/vnd.wiris.mtweb-params+json">{"fontSize":"13px","fontStyle":"normal"}</annotation></semantics></math>

I also get the same error :(

dpvc commented 1 year ago

OK, this seems to be due to an HTML serialization being done internally that causes the mfenced to have an open="<" attribute, which is not valid for XML parsing. That it a little harder to patch, but if you use

    MathJax = {
      loader: {load: ['[mml]/mml3']},
      startup: {
        ready() {
          const {Mml3} = MathJax._.input.mathml.mml3.mml3;
          MathJax.startup.defaultReady();
          const mml3 = new Mml3(MathJax.startup.document);
          const adaptor = MathJax.startup.document.adaptor;
          const processor = new XSLTProcessor();
          const parsed = adaptor.parse(Mml3.XSLT, 'text/xml');
          processor.importStylesheet(parsed);
          mml3.transform = (node) => {
            const div = adaptor.node('div', {}, [adaptor.clone(node)]);
            const dom = adaptor.parse(adaptor.serializeXML(div), 'text/xml');
            const mml = processor.transformToDocument(dom);
            return (mml ? adaptor.tags(mml, 'math')[0] : node);
          };
          const MML = MathJax.startup.document.inputJax[0];
          MML.mmlFilters.items.pop();  // remove old filter
          MML.mmlFilters.add(mml3.mmlFilter.bind(mml3));
        }
      }
    };

in place of the configuration I gave above, I think that will work for you.