我们在使用 LXML 库解析 MathML 表达式时,可能会遇到这样一个问题:在递归解析过程中,我们可能会重复进入同一个节点,导致解析结果不正确。例如,我们希望将以下 MathML 表达式解析为 Python 表达式:
<?xml version="1.0"?>
<math xmlns="http://www.w3.org/1998/Math/MathML" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/1998/Math/MathML http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd">
<mrow>
<mfrac>
<mn>3</mn>
</mn>
<mn>5</mn>
</mn>
</mfrac>
</mrow>
</math>
如果我们使用以下代码来解析该表达式:
def parseMML(mmlinput):
from lxml import etree
from StringIO import *
from lxml import objectify
exppy=[]
events = ("start", "end")
context = etree.iterparse(StringIO(mmlinput),events=events)
for action, elem in context:
if (action=='start') and (elem.tag=='mrow'):
exppy+='('
if (action=='end') and (elem.tag=='mrow'):
exppy+=')'
if (action=='start') and (elem.tag=='mfrac'):
mmlaux=etree.tostring(elem[0])
exppy+=parseMML(mmlaux)
exppy+='/'
mmlaux=etree.tostring(elem[1])
exppy+=parseMML(mmlaux)
if action=='start' and elem.tag=='mn': #this is a number
exppy+=elem.text
return (exppy)
那么我们得到的解析结果将是:
['(', '(', '3', ')', '/', '(', '5', ')', '(', '3', ')', '(', '5', ')', ')']
而不是我们期望的:
['(', '(', '3', ')', '/', '(', '5', ')', ')']
这是因为在解析 mfrac
节点时,我们递归调用了 parseMML
函数两次,分别解析了分子和分母。而在解析分子时,我们又递归调用了 parseMML
函数,导致重复进入了 mrow
节点。
为了解决这个问题,我们可以使用一个栈来保存已经解析过的节点。当我们开始解析一个新的节点时,我们可以将该节点压入栈中。当我们完成解析该节点时,我们可以将该节点从栈中弹出。这样,我们就能够避免重复进入同一个节点。
以下代码演示了如何使用栈来避免重复进入同一个节点:
def parseMML(mmlinput):
from lxml import etree
from StringIO import *
from lxml import objectify
exppy=[]
events = ("start", "end")
context = etree.iterparse(StringIO(mmlinput),events=events)
nodestack=[]
for action, elem in context:
if action=='start' and elem.tag in nodestack:
continue
if (action=='start') and (elem.tag=='mrow'):
nodestack.append(elem.tag)
exppy+='('
if (action=='end') and (elem.tag=='mrow'):
nodestack.pop()
exppy+=')'
if (action=='start') and (elem.tag=='mfrac'):
nodestack.append(elem.tag)
mmlaux=etree.tostring(elem[0])
exppy+=parseMML(mmlaux)
exppy+='/'
mmlaux=etree.tostring(elem[1])
exppy+=parseMML(mmlaux)
if action=='start' and elem.tag=='mn': #this is a number
exppy+=elem.text
return (exppy)
使用该代码,我们可以得到正确的解析结果:
['(', '(', '3', ')', '/', '(', '5', ')', ')']
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。