【问题标题】:Get following node in different ancestor using lxml and xpath使用 lxml 和 xpath 在不同的祖先中获取以下节点
【发布时间】:2014-01-17 22:37:16
【问题描述】:

我正在编写一个可以读取数学方程式的文本转语音程序。我有一个线程需要提取数学方程(如 MathJax SVG)并将它们解析为散文。

由于内容的布局方式,数学方程式可以任意嵌套在其他元素中,如段落、粗体、表格等。

使用对当前元素的引用,我如何获得下一个<span class="MathJax_SVG">,它可能嵌入在其他父/祖先中?

我尝试使用以下方法解决它:

nextMath = currentElement.xpath('following::.//span[@class=\'MathJax_SVG\']')

什么也不返回,尽管我可以从视觉上确认它后面有东西。我尝试删除句点,但 lxml 抱怨我的 XPath 格式不正确。

你们以前遇到过这种情况吗?

附:这是一个测试文档来说明我的观点:

<html>
   <head>
      <title>Test Document</title>
   </head>
   <body>
      <h1 id="mainHeading">The Quadratic Formula</h1>
      <p>The quadratic formula is used to solve quadratic equations. Here is the formula:</p>
      <p><span class="MathJax_SVG" id="MathJax_Element_Frame_1">removed the SVG</span></p>
      <p>Here are some possible values when you use the formula:</p>
      <p>
      <table>
         <tr>
            <td><span class="MathJax_SVG" id="MathJax_Element_Frame_2">removed the SVG</span></td>
            <td><span class="MathJax_SVG" id="MathJax_Element_Frame_3">removed the SVG</span></td>
         </tr>
         <tr>
            <td><span class="MathJax_SVG" id="MathJax_Element_Frame_4">removed the SVG</span></td>
            <td><span class="MathJax_SVG" id="MathJax_Element_Frame_5">removed the SVG</span></td>
         </tr>
      </table>
      </p>
   </body>
</html>

更新

了解到lxml 不支持绝对位置。这可能是相关的。

一些测试代码(假设您将 HTML 保存为 test.html)

from lxml import html

# Get my html element
with open('test.html', 'r') as f:
    myHtml = html.fromstring(f.read())

# Get the first MathJax element
start = myHtml.find('.//h1[@id=\'mainHeading\']')

print 'My start:', html.tostring(start)

# Get next math equation
nextXPath = 'following::.//span[@class=\'MathJax_SVG\']'
nextElem = start.xpath(nextXPath)

if len(nextElem) > 0:
    print 'Next equation:', html.tostring(nextElem[0])
else:
    print 'No next equation...'

【问题讨论】:

  • 似乎following 在使用子元素时的行为与following-siblings 完全相同。这应该是一个错误,因为子元素引用了它们的父元素。

标签: python xpath lxml


【解决方案1】:

您需要遍历文档吗?您也可以直接搜索 MathJax_SVG 类的 span 元素:

from lxml import etree
doc = etree.parse(open("test-document.html")).getroot()
maths = doc.xpath("//span[@class='MathJax_SVG']")

【讨论】:

  • 是的,我必须反复执行此操作。实际上可能有数以万计的方程,并且由于此代码旨在实时运行,因此它必须非常快速。我将发布我正在使用的测试代码。
  • 嗯,生成器意义上的迭代器。
【解决方案2】:

我最终创建了自己的函数来获得我想要的东西。我称它为getNext(elem, xpathString)。如果有更有效的方法来做到这一点,我会全力以赴。我对它的性能没有信心。

from lxml import html

def getNext(elem, xpathString):
    '''
    Gets the next element defined by XPath. The element returned
    may be itself.
    '''
    myElem = elem
    nextElem = elem.find(xpathString)

    while nextElem is None:

        if myElem.getnext() is not None:
            myElem = myElem.getnext()
            nextElem = myElem.find(xpathString)

        else:
            if myElem.getparent() is not None:
                myElem = myElem.getparent()
            else:
                break

    return nextElem


# Get my html element
with open('test.html', 'r') as f:
    myHtml = html.fromstring(f.read())

# Get the first MathJax element
start = myHtml.find('.//span[@id=\'MathJax_Element_Frame_1\']')

print 'My start:', html.tostring(start)

# Get next math equation
nextXPath = './/span[@class=\'MathJax_SVG\']'
nextElem = getNext(start, nextXPath)

if nextElem is not None:
    print 'Next equation:', html.tostring(nextElem)
else:
    print 'No next equation...'

【讨论】:

  • 以上代码错误。它不考虑元素的子元素,因为它们会被跳过。
  • 另外,有数以万计的方程,我可以看到这个函数很快就会溢出堆栈。
猜你喜欢
  • 2011-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 2020-01-09
  • 2011-08-26
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多