使用Text.XML.Cursor来获取特定的HTML表列

问题描述:

我想解析一个HTML页面使用Haskell和Text.XML.Cursor包。我的目标是返回列表中的第三列值。我花了最后4个小时试图让它工作。但是,似乎我无法理解XPath和Text.XML.Cursor在概念上的工作原理。使用Text.XML.Cursor来获取特定的HTML表列

所以任务是:

  1. 在某个地方找到<table class="forumTable">标签文档
  2. 在每<tr>标签在它采取第三<td>标签
  3. 在细胞内有一个单一的<a>标签, content其中我想添加到列表中。不是href属性,但值<a></a>

    之间

具体而言,我解析 this link,我试图获得与论坛名称列的值(话题之后下一个)。

这是尽我所能。好像是回到表

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并与他们一起玩,事情变得更好。另外,我建议仔细阅读解释什么是CursorAxis的部分。

上面的代码工作如下(教学)。首先,我们使用提供的库函数获取main a cursor到文档的根目录。然后我们一起组成cursor,findNodescontent。运算符$.//表示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前更改&/>=>,你可以保持该呼叫(均实现是等价的)。

+0

谢谢!没想到你可以像列表一样使用轴! – tna0y