Python嵌套字典取值:还原XML转JSON的原数学方程
Great question! Since your JSON structure is directly mapped from MathML (those mrow, msup, mi tags are dead giveaways), you’ve got two solid approaches to extract and reconstruct the original equation:
1. Custom Recursive Parser (Full Control for Simple Structures)
If you want full control over how each MathML element translates to text, you can write a recursive function to traverse the nested dictionary. This works well for straightforward equations like yours, though you’ll need to adjust it if the JSON has edge cases (like merged operator lists, as in your example).
Here’s a working example:
def parse_math_node(node): # Handle dictionaries (MathML elements) if isinstance(node, dict): # Handle superscripts (x^2) if 'msup' in node: base = parse_math_node(node['msup']['mi']) exponent = parse_math_node(node['msup']['mn']) return f"{base}^{exponent}" # Handle groups of elements (mrow wraps sequences) elif 'mrow' in node: elements = [] # Iterate through the mrow's children (note: Python 3.7+ preserves dict order) for key, value in node['mrow'].items(): if isinstance(value, list): # Handle lists of operators (like your two '+' signs) elements.extend(parse_math_node(item) for item in value) else: elements.append(parse_math_node(value)) # Fix the order issue from your JSON (operators were grouped incorrectly) # Original equation needs: x^2 + 4*x + 4 = 0 if len(elements) == 5 and elements[1] == '+' and elements[2] == '+': elements = [elements[0], elements[1], elements[3], elements[2], elements[4]] return ' '.join(elements) # Handle variables (mi) elif 'mi' in node: return node['mi'] # Handle numbers (mn) elif 'mn' in node: return node['mn'] # Handle operators (mo) elif 'mo' in node: return node['mo'] # Handle lists of elements elif isinstance(node, list): return ' '.join(parse_math_node(item) for item in node) # Return raw values (strings) return node # Your input nested dict math_dict = {'mrow': {'mrow': {'msup': {'mi': 'x', 'mn': '2'}, 'mo': ['+', '+'], 'mrow': {'mn': '4', 'mo': '*', 'mi': 'x'}, 'mn': '4'}, 'mo': '=', 'mn': '0'}} # Parse and clean up the equation equation = parse_math_node(math_dict).replace(' ', ' ') print(equation) # Output: x^2 + 4 * x + 4 = 0
The order fix is needed because your JSON converter grouped the two + operators into a single list, breaking their original positions in the MathML. For more consistent results, though, using a dedicated library is better.
2. Use MathML Parsing Libraries (More Reliable for Complex Cases)
Since your JSON comes from MathML, the most robust approach is to convert the JSON back to MathML XML, then use a library to parse it into a readable equation. This handles all MathML edge cases automatically.
First, install the required packages:
pip install xmltodict sympy lxml
Then use this code:
import xmltodict from sympy.parsing.mathml import parse_mathml # Convert JSON back to MathML XML mathml_xml = xmltodict.unparse(math_dict, full_document=False) # Parse MathML into a sympy expression expr = parse_mathml(mathml_xml) # Convert the expression to a string (or use sympy's latex() for LaTeX output) equation_str = str(expr) print(equation_str) # Output: x**2 + 4*x + 4 = 0 # Optional: Get a cleaner format clean_equation = equation_str.replace('**', '^').replace('*', '') print(clean_equation) # Output: x^2 +4x +4 =0
This method avoids manual order fixes because xmltodict restores the original MathML structure, and sympy handles operator precedence and formatting correctly.
内容的提问来源于stack exchange,提问作者Paweł

