如何使用lxml进行Python XPath不区分大小写搜索?

7
我正在尝试使用XPath中的lower-case函数匹配国家或地区名。由于translate功能有点混乱,因此我使用lower-case。我相信我的Python版本2.6.6支持XPath 2.0,因为lower-case仅适用于XPath 2.0。
我需要知道如何在我的情况下使用lower-case。希望这个示例可以自说明。我希望输出['USA', 'US'](如果lower-case将Country和country视为相同,则可以同时输出这两个国家)。 HTML: doc.htm
<html>
    <table>
        <tr>
            <td>
                Name of the Country : <span> USA </span>
            </td>
        </tr>
        <tr>
            <td>
                Name of the country : <span> UK </span>
            </td>
        </tr>
</table>

Python :

import lxml.html as lh

doc = open('doc.htm', 'r')
out = lh.parse(doc)
doc.close()

print out.xpath('//table/tr/td[text()[contains(. , "Country")]]/span/text()')
# Prints : [' USA ']
print out.xpath('//table/tr/td[text()[contains(. , "country")]]/span/text()')
# Prints : [' UK ']

print out.xpath('//table/tr/td[lower-case(text())[contains(. , "country")]]/span/text()')
# Prints : [<Element td at 0x15db2710>]

更新:

out.xpath('//table/tr/td[text()[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") , "country")]]/span/text()')

现在问题是,我能否将翻译部分存储为全局变量“handlecase”,并在执行XPath时打印该全局变量?
类似这样的代码可以实现:
handlecase = """translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")"""

out.xpath('//table/tr/td[text()[contains(%s , "country")]]/span/text()' % (handlecase))

但为了简单明了起见,我想这样运行它:

out.xpath('//table/tr/td[text()[contains(handlecase , "country")]]/span/text()')

3
根据lxml XPath文档lxml支持XPath 1.0,因此使用lxml时只能使用translate函数。 - Martijn Pieters
在这种情况下,我不确定为什么在我使用小写字母时它没有抱怨。在这个例子场景中,我也没有太多运气使用“translate”。谢谢! - ThinkCode
可能是重复问题 - JWiley
谢谢提供链接。这更像是一个小写字母的讨论,而不是翻译。我实际上通过执行以下操作使翻译工作正常:out.xpath('//table/tr/td[lower-case(text())[contains( translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") , "country")]]/span/text()')。如果在此情况下无法应用小写字母,则管理员可以关闭此帖子。谢谢! - ThinkCode
但是如果您使用lower-case(),lxml确实会抱怨:“lxml.etree.XPathEvalError:Unregistered function”。在“*我实际上通过做...”之后的代码肯定不正确。 - mzjn
它运行正常!handlecase = 'translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")' out.xpath('//table/tr/td[text()[contains(%s , "country")]]/span/text()' % (handlecase)) - ThinkCode
2个回答

5
我认为最简单的方法是编写一个XPath扩展函数来实现您想要的功能。
通过这样做,您可以编写一个 lower-case() 函数或者一个不区分大小写的搜索功能。
您可以在这里找到详细信息: http://lxml.de/extensions.html

3
非常好的回答,但没有示例你是无法获胜的。 - mykhal
我并不是在试图获胜,只是想要帮助。我曾考虑给出一个例子,但我觉得链接中已经有足够的例子了。 - stranac

3

用途:

   //td[translate(substring(text()[1], string-length(text()[1]) - 9),
                  'COUNTRY :',
                  'country'
                  )
        =
         'country'
       ]
        /span/text()

XSLT基于验证:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "//td[translate(substring(text()[1], string-length(text()[1]) - 9),
                  'COUNTRY :',
                  'country'
                  )
        =
         'country'
       ]
        /span/text()
       "/>
 </xsl:template>
</xsl:stylesheet>

当在提供的XML文档上应用此转换时:
<html>
        <table>
            <tr>
                <td>
                    Name of the Country : <span> USA </span>
                </td>
            </tr>
            <tr>
                <td>
                    Name of the country : <span> UK </span>
                </td>
            </tr>
        </table>
</html>

XPath表达式将被评估,并选择两个文本节点被复制到输出中:
 USA  UK 

说明:

  1. 我们使用XPath 1.0表达式的特定变体实现XPath 2.0标准函数ends-with($text, $s):即:

.....

$s = substring($text, string-length($text) - string-length($s) +1)

.2. 接下来,使用translate()函数将长度为10的字符串转换为小写,消除任何空格或":"字符。

.3. 如果结果是字符串(全部小写)“country”,则选择此的s=span子节点的子文本节点(在此情况下仅有一个)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接