Prior to v12.1 Row was not handled well by MathML export:

Now it is ok:

ExportString[Row[{1}], "MathML"]

 <math xmlns='http://www.w3.org/1998/Math/MathML'>
<semantics>
<mrow>
<mn>1</mn>
</mrow>
<annotation encoding='Mathematica'>TemplateBox[List[&quot;1&quot;], &quot;RowDefault&quot;]</annotation>
</semantics>
[/itex]


But I need to fix that issue for projects where earlier versions are used.

Is there a general way to add conversion rules or at least a fix for Row?

• Looks like the relevant function is SystemConvertMathMLDumpBoxesToSMML- if you want to look at it with GeneralUtiitiesPrintDefinitions, you'll probably need to remove the limit on the number of definitions with DownValues@GeneralUtilitiesPrintDefinitions = DownValues@GeneralUtilitiesPrintDefinitions /. 256 -> \[Infinity]; or similar – Lukas Lang Jul 31 at 15:42

Expanding my comment into a concrete answer: Using GeneralUtilitiesPrintDefinitions to look at the functions responsible for the "MathML" export1, it looks like the core function is SystemConvertMathMLDumpBoxesToSMML:

(* remove limit on number of definitions *)
DownValues@GeneralUtilitiesPrintDefinitions =
DownValues@GeneralUtilitiesPrintDefinitions /. 256 -> Infinity;
(* print definitions of the function *)
GeneralUtilitiesPrintDefinitions@SystemConvertMathMLDumpBoxesToSMML;


The following sections outline how to fix the following three issues:

1. ExportString[Row[{1}], "MathML"] doesn't work before version 12.1 due to missing transformation rules for TemplateBox
2. ExportString[ToBoxes[a==b],"MathML"] exports the == as &#10869;, since the character mappings are not set properly
3. ExportString[a==b,"MathML"] exports the == as &#63449; (even with the fix for 2.), since there is no mapping for \[LongEqual] (the TraditionalForm version of ==) in the default mappings

# Adding rules for box structures

In version 12.1, there are two definitions that seem to be responsible for the conversion of TemplateBox expressions (which is what Row is converted to by ToBoxes) - extracting them and adding them in e.g. 11.3 yields the following result:

Begin["SystemConvertMathMLDump"];

BoxesToSMML[whole : TemplateBox[{__}, _, ___]] /; ! alreadyWrapped := Block[
XMLElement[
"semantics",
{},
{
BoxesToSMML@BoxFormTemplateBoxToDisplayBoxes@whole,
BoxesToSMML@annotationWrapper@TagBox[whole, "MathMLMathematicaTag"]
}
]
];

BoxesToSMML[whole : TemplateBox[{___}, _, ___]] :=
BoxesToSMML@BoxFormTemplateBoxToDisplayBoxes@whole;

End[];

ExportString[Row[{1}], "MathML"]

<math xmlns='http://www.w3.org/1998/Math/MathML'>
<semantics>
<mrow>
<mn>1</mn>
</mrow>
<annotation encoding='Mathematica'>TemplateBox[List[&quot;1&quot;], &quot;RowDefault&quot;]</annotation>
</semantics>
[/itex]


The definitions effectively use BoxFormTemplateBoxToDisplayBoxes to convert arbitrary TemplateBox expressions to their resulting boxes, so this should work for (almost) all TemplateBox expressions, not just Row.

# Specifying the mappings for special characters

It looks like special characters are not exported properly, even though there is a list for special character mappings for MathML2:

ExportString[ToBoxes[a == b], "MathML"]

<math xmlns='http://www.w3.org/1998/Math/MathML'>
<mrow>
<mi>a</mi>
<mo>&#10869;</mo>
<mi>b</mi>
</mrow>
[/itex]


The list of mappings (which is not used by default for some reason) does include a case for \[Equal]:

SystemConvertMLStringDataDump$UnicodeToMathML2Entities (* {..., "\[Equal]" -> "&Equal;" ,...} *)  Luckily, the necessary option for SystemConvertXMLDumpWriteSymbolicXML is passed through from the top-level, so we can just add it: ExportString[ToBoxes[a == b], "MathML", "Entities" -> "MathML"]  <math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mi>a</mi> <mo>&Equal;</mo> <mi>b</mi> </mrow> [/itex]  Possible values for "Entities" can be found in the definition of SystemConvertXMLDumpaddEntitiesToExportFunction: "HTML" "MathML" "MathML1" "MathML2" _String->_String _String:>_String (* equivalent to the previous, the delayed evaluation doesn't work *) {...} (* list of allowed values *)  # Adding custom rules to the character mappings Unfortunately, the above fix is not enough for a==b: ExportString[a == b, "MathML", "Entities" -> "MathML"] <math xmlns='http://www.w3.org/1998/Math/MathML'> <mrow> <mi>a</mi> <mo>&#63449;</mo> <mi>b</mi> </mrow> [/itex]  The issue is that by default, the boxes are created using MakeBoxes[expr,TraditionalForm], which formats == as \[LongEqual], which is not in the list of mappings. Since SystemConvertXMLDumpdetermineEntityExportFunction memoizes the conversion functions and since the first call to the MathML exporter resets the list of mappings, we have to be a bit creative to get the mapping in there: (* needs fresh kernel session *) (* load the MathML exporter, but without setting "Entities" to avoid memoization *) ExportString[a == b, "MathML", "Entities" -> {"x" -> "x"}]; (* add custom character mappings *) SystemConvertMLStringDataDump$UnicodeToMathML2Entities =
SystemConvertMLStringDataDump\$UnicodeToMathML2Entities~Union~{
"\[LongEqual]" -> "&Equal;"
};

(* now it works *)
ExportString[a == b, "MathML", "Entities" -> "MathML"]

<math xmlns='http://www.w3.org/1998/Math/MathML'>
<mrow>
<mi>a</mi>
<mo>&Equal;</mo>
<mi>b</mi>
</mrow>
[/itex]


1For the curious: The call tree essentially looks like this:

• ExportString to Export (which is used to export to a temporary file):
• ExportString
• SystemConvertersDumpExportStringTest
• Export
• Export to SystemConvertersDumpexport (this is the function which calls the correct function for a given format)
• Export
• SystemConvertersDumpExportTest
• SystemConvertersDumpExportInternal
• SystemConvertersDumpexport
• SystemConvertersDumpexport to SystemConvertMathMLDumpBoxesToSMML (which is the function we're interested in)
• SystemConvertersDumpexport
• SystemConvertMathMLDumpmathMLExport
• SystemConvertMathMLDumpexportMathMLAux
• SystemConvertMathMLDumpexportFunction
• XMLMathMLBoxesToSymbolicMathML
• SystemConvertMathMLDumpincludeFormat
• SystemConvertMathMLDumpBoxesToSMML

2The relevant part of the call tree here is (starting from above):

• see above until SystemConvertMathMLDumpexportMathMLAux
• SystemConvertXMLDumpWriteSymbolicXML
• SystemConvertXMLDumpdetermineEntityExportFunction
• SystemConvertXMLDumpaddEntitiesToExportFunction
• Thanks for your time! Can you add a piece for the part where XMLElements are converted to the final string? I think I need to adjust that part to solve and issue I have with == being exported as a non standard unicode character: ExportString[a == b, "MathML"] – Kuba Aug 4 at 10:53
• @Kuba It took some trying, but I found an ok-ish workaround (added to the post). Instead of modifying the "MathML"mappings as in the third part, you could probably also specify them manually as "Entities"->{"MathML", "\[LongEqual]"->...} (not tested though), but I felt it's cleaner to modify the mappings themselves instead to include the missing rules – Lukas Lang Aug 4 at 17:55