使用Text.XML.Cursor来获取特定的HTML表列
我想解析一个HTML页面使用Haskell和Text.XML.Cursor
包。我的目标是返回列表中的第三列值。我花了最后4个小时试图让它工作。但是,似乎我无法理解XPath和Text.XML.Cursor
在概念上的工作原理。使用Text.XML.Cursor来获取特定的HTML表列
所以任务是:
- 在某个地方找到
<table class="forumTable">
标签文档 - 在每
<tr>
标签在它采取第三<td>
标签 - 在细胞内有一个单一的
<a>
标签,content
其中我想添加到列表中。不是href
属性,但值<a>
和</a>
之间
这是尽我所能。好像是回到表
findNodes :: Cursor -> [Cursor]
findNodes = element "table" >=> attributeIs "class" "forumTable" &// element "tr" &/ element "td" &/ element "a" >=> child
extractData = T.concat . content
...
let cursor = fromDocument $ parseLBS $ simpleHTTP "http://www.sql.ru/forum/sqlru-3-days/2"
let lines = cursor $// findNodes &| extractData
我寻求一个解决我的问题,以及如何这一切工作的说明里面的<a>
标签的所有内容。谢谢。
我已经想通了!
考虑以下输入文件:
<html>
<head>
<title>Haskell XML Parsing Example</title>
</head>
<body>
<table class="forumTable">
<tbody>
<tr>
<td> <a href="#1">1</a> </td>
<td> <a href="#2">2</a> </td>
<td> <a href="#3">3</a> </td>
<td> <a href="#4">4</a> </td>
</tr>
<tr>
<td> <a href="#5">5</a> </td>
<td> <a href="#6">6</a> </td>
</tr>
<tr>
<td> <a href="#7">7</a> </td>
<td> <a href="#8">8</a> </td>
<td> <a href="#9">9</a> </td>
<td> <a href="#10">10</a> </td>
<td> <a href="#11">11</a> </td>
</tr>
</tbody>
</table>
</body>
</html>
而Haskell代码:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Text.IO as T
import Text.XML.Cursor
import Text.XML
select3rd :: Name -> Axis
select3rd name =
helper . (child >=> element name)
where
helper (_:_:x:_) = [x]
helper _ = []
findNodes :: Cursor -> [Cursor]
findNodes =
element "table" >=> attributeIs "class" "forumTable"
&// element "tr" >=> select3rd "td"
&/ element "a"
main :: IO()
main = do
doc <- Text.XML.readFile def "res/test.html"
let cursor = fromDocument doc
mapM_ T.putStrLn (cursor $.// findNodes &/ content)
这需要一些时间,直到你了解所有这些运营商($.//
,&/
等)工作,但几次阅读documentation并与他们一起玩,事情变得更好。另外,我建议仔细阅读解释什么是Cursor
和Axis
的部分。
上面的代码工作如下(教学)。首先,我们使用提供的库函数获取main
a cursor
到文档的根目录。然后我们一起组成cursor
,findNodes
和content
。运算符$.//
表示findNodes
必须在当前游标(cursor
)及其所有后代的上下文中运行。换句话说,它只是意味着findNodes
将访问整个HTML树。试试看,并使用$/
而不是$.//
。您会注意到findNodes
将不会使用element "table"
找到<table>
元素,因为<table>
并非直接位于<html>
(这是cursor
当前指向的位置)的下方。然后,在findNodes
中,我们使用>=>
运算符编写element "table"
和attributeIs "class" "forumTable"
,因为右侧的函数(rhs)必须在由左侧(lhs)返回的Axis
上执行。
之后,我们使用&//
算子来筛选<table>
内部的<tr>
。和以前一样,如果我们只&/
使用时,<tr>
s就不会被发现,因为有一个封闭<tbody>
标签和&/
只看眼前的后代(或子女)。请注意,当我们在一个LHS Cursor
,运营商与$
开始,而当我们有一个Axis
,他们与&
开始。最后,我们有select3rd
轴,它允许节点的第三个子节点存在时进行命名选择。我们用它来选择每个<tr>
中的第三个<td>
。希望到现在为止,应该很容易理解它是如何工作的。
您的问题中的代码在使用>=>
运算符的findNodes
末尾调用child
。只要你还content
前更改&/
到>=>
,你可以保持该呼叫(均实现是等价的)。
谢谢!没想到你可以像列表一样使用轴! – tna0y