2013-04-20 135 views
1

从Fedora 17切换到18后,对于相同的lxml代码,我得到了不同的解析行为,这显然是由于底层库的不同版本(libxml2和libxslt版本已更改)。如何控制lxml xpath text()函数中的换行处理?

这里是有两个版本不同的结果lxml的代码示例:

from io import BytesIO 
from lxml import etree 

myHtmlString = \ 
    '<!doctype html public "-//w3c//dtd html 4.0 transitional//en">\r\n'+\ 
    '<html>\r\n'+\ 
    '<head>\r\n'+\ 
    ' <title>Title</title>\r\n'+\ 
    '</head>\r\n'+\ 
    '<body/>\r\n'+\ 
    '</html>\r\n' 
myFile = BytesIO(myHtmlString) 
myTree = etree.parse(myFile, etree.HTMLParser()) 
myTextElements = myTree.xpath("//text()") 
myFullText = ''.join([myEl for myEl in myTextElements]) 

assert myFullText == 'Title', repr(myFullText) 

的F17版本经过断言,即xpath("//text()")只返回文本'Title',而F18版本失败输出

Traceback (most recent call last): 
    File "TestLxml.py", line 17, in <module> 
    assert myFullText == 'Title', repr(myFullText) 
AssertionError: '\r\n\r\n Title\r\n\r\n\r\n' 

显然,f18版本处理换行符和空格与f17版本不同。

有没有办法控制这种行为? (可选参数在某处?) 甚至更​​好,是否有方法可以使用新库恢复旧行为?

回答

1

在XML中,text()按原样返回文本内的文本(未划掉),所以如果您有任何空格字符,制表符,它们将包含新行。

这可能是你用+和\ n \ r意外测试两个不同的字符串来构造多行字符串的方式。

如果您将字符串更改为三重报价字符串,如下面的示例并测试它。

from io import BytesIO 
from lxml import etree 


html = ''' 
    <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> 
    <html> 
    <head> 
     <title>Title</title> 
    </head> 
    <body/> 
    </html> 
''' 
tree = etree.parse(BytesIO(html), etree.HTMLParser()) 
text_elements = tree.xpath("//text()") 
full_text = ''.join(text_elements) 
assert full_text == 'Title', repr(full_text) 

你也可以看到,周围有空格或新行文本使他们的文本()函数返回的一部分。见下面的title

html = ''' 
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> 
<html> 
<head> 
    <title> Title </title> 
</head> 
<body/> 
</html> 
''' 
tree = etree.parse(BytesIO(html), etree.HTMLParser()) 
text_elements = tree.xpath("//text()") 
full_text = ''.join(text_elements) 
assert full_text == ' Title ', repr(full_text) 

如果你不需要空格,你总是可以自己调用字符串strip()。如果您确定即使您的代码中未包含空格,您也会获得空格,那么您应该将其报告为lxml mailing list上的一个错误。