-->

Parsing MathML to plain math expression

2019-01-26 02:45发布

问题:

I am using MathDox formula editor to produce MathML. Now I want to convert the MathML produced by MathDox to expression which I can later use to evaluate to find the answer.

For eg:

MathML:
<math xmlns='http://www.w3.org/1998/Math/MathML'>
 <mrow>
  <mn>3</mn>
  <mo>+</mo>
  <mn>5</mn>
 </mrow>
</math>

Want to convert to expression as:
3+5

Now I can use 3+5 to get answer 8.

I am in a search of javascript or c# solution for this conversion. Tried to google it, but didn't get much help. Somewhat closer solution I found here, but it is a desktop application and commercial too. However, I want open source web app solution for my problem. Any help will be appreciated.

Note: For simplicity I've mentioned only simple addition in example above but the mathml can also contain complex epression like derivations and log.

回答1:

This can be achieved using the following steps in JavaScript:

  1. Convert from MathML to XML DOM
  2. Convert from XML DOM to plain text
  3. Use the "eval" function to get the decimal value of the expression

The following code does precisely that:

function getDOM(xmlstring) {
    parser=new DOMParser();
    return parser.parseFromString(xmlstring, "text/xml");
}

function remove_tags(node) {
    var result = "";
    var nodes = node.childNodes;
    var tagName = node.tagName;
    if (!nodes.length) {
        if (node.nodeValue == "π") result = "pi";
        else if (node.nodeValue == " ") result = "";
        else result = node.nodeValue;
    } else if (tagName == "mfrac") {
        result = "("+remove_tags(nodes[0])+")/("+remove_tags(nodes[1])+")";
    } else if (tagName == "msup") {
        result = "Math.pow(("+remove_tags(nodes[0])+"),("+remove_tags(nodes[1])+"))";
    } else for (var i = 0; i < nodes.length; ++i) {
        result += remove_tags(nodes[i]);
    }

    if (tagName == "mfenced") result = "("+result+")";
    if (tagName == "msqrt") result = "Math.sqrt("+result+")";

    return result;
}

function stringifyMathML(mml) {
   xmlDoc = getDOM(mml);
   return remove_tags(xmlDoc.documentElement);
}

// Some testing

s = stringifyMathML("<math><mn>3</mn><mo>+</mo><mn>5</mn></math>");
alert(s);
alert(eval(s));

s = stringifyMathML("<math><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>+</mo><mn>1</mn></math>");
alert(s);
alert(eval(s));

s = stringifyMathML("<math><msup><mn>2</mn><mn>4</mn></msup></math>");
alert(s);
alert(eval(s));

s = stringifyMathML("<math><msqrt><mn>4</mn></msqrt></math>");
alert(s);
alert(eval(s));

Following the previous code, it is possible to extend the accepted MathML. For example, it would be easy to add trigonometry or any other custom function.

For the purpose of this post, I used the tool from mathml editor to build the MathML (used in the test part of the code).