HXT を使用して、非常に適切に形成された HTMl テーブルのテーブルからレコードを抽出しようとしています。SO と HXT のドキュメントに関するいくつかの例を確認しました。たとえば、次のとおりです。
- サブツリーからの値の抽出
- http://adit.io/posts/2012-04-14-working_with_HTML_in_haskell.html
- https://www.schoolofhaskell.com/school/advanced-haskell/xml-parsing-with-validation
- Haskell HXT を IO の外で実行していますか?
- hxtで倍数のhtmlテーブルを抽出する
- Haskellでhtmlを解析する
- http://neilbartlett.name/blog/2007/08/01/haskell-explaining-arrows-through-xml-transformationa/
- https://wiki.haskell.org/HXT/Practical/Simple2
- https://wiki.haskell.org/HXT/Practical/Simple1
- HaskellでHXTを使用してhtmlテーブルの行をグループ化する
- Haskell で HXT を使用して複数の子ノードを解析する
私の問題は次のとおりです。
既知の ID でテーブルを一意に識別し、そのテーブル内の各 tr に対してレコード オブジェクトを作成し、これをレコードのリストとして返します。
ここに私のHTMLがあります
<!DOCTYPE html>
<head>
<title>FakeHTML</title>
</head>
<body>
<table id="fakeout-dont-get-me">
<thead><tr><td>Null</td></tr></thead>
<tbody><tr><td>Junk!</td></tr></tbody>
</table>
<table id="Greatest-Table">
<thead>
<tr><td>Name</td><td>Favorite Rock</td></tr>
</thead>
<tbody>
<tr id="rock1">
<td>Fred</td>
<td>Igneous</td>
</tr>
<tr id="rock2">
<td>Bill</td>
<td>Sedimentary</td>
</tr>
</tbody>
</table>
</body>
</html>
これは、これを解析するための2つの異なるアプローチとともに、私が試しているコードです。まず、インポート...
{-# LANGUAGE Arrows, OverloadedStrings, DeriveDataTypeable, FlexibleContexts #-}
import Text.XML.HXT.Core
import Text.HandsomeSoup
import Text.XML.HXT.XPath.XPathEval
import Data.Tree.NTree.TypeDefs
import Text.XML.HXT.XPath.Arrows
私が欲しいのは、たとえばからのRockrecsのリストです...
recs = [("rock1", "Name", "Fred", "Favorite Rock", "Igneous"),
("rock2", "Name", "Bill", "Favorite Rock", "Sedimentary")]
data Rockrec = Rockrec { rockID:: String,
rockName :: String,
rockFav :: String} deriving Show
rocks = [(\(a,_,b,_,c) -> Rockrec a b c ) r | r <- recs]
-- [Rockrec {rockID = "rock1", rockName = "Fred", rockFav = "Igneous"},
-- Rockrec {rockID = "rock2", rockName = "Bill", rockFav = "Sedimentary"}]
[XMLTree] の束を返した後、runLA でバインドを使用する最初の方法を次に示します。つまり、適切なテーブルを取得するためだけに最初の解析を行い、その最初のグラブの後でツリー行を処理します。
試行 1
getTab = do
dt <- Prelude.readFile "fake.html"
let html = parseHtml dt
tab <- runX $ html //> hasAttrValue "id" (== "Greatest-Table")
return tab
-- hmm, now this gets tricky...
-- table <- getTab
node tag = multi (hasName tag)
-- a la https://stackoverflow.com/questions/3901492/running-haskell-hxt-outside-of-io?rq=1
getIt :: ArrowXml cat => cat (Data.Tree.NTree.TypeDefs.NTree XNode) (String, String)
getIt = (node "tr" >>>
(getAttrValue "id" &&& (node "td" //> getText)))
これはちょっとうまくいきます。少しマッサージする必要がありますが、実行できます...
-- table >>= runLA getIt
-- [("","Name"),("","Favorite Rock"),("rock1","Fred"),("rock1","Igneous"),("rock2","Bill"),("rock2","Sedimentary")]
これは、 https://wiki.haskell.org/HXT/Practical/Simple1に触発された 2 番目のアプローチ です。ここで、{-# LANGUAGE Arrows -} の何かに依存していると思います (偶然にも上記の rec のリスト内包表記が壊れています)、より読みやすい do ブロックでこれを行うために proc 関数を使用します。とはいえ、これの最小バージョンをコンパイルすることさえできません。
試行 2
getR :: ArrowXml cat => cat XmlTree Rockrec
getR = (hasAttrValue "id" (== "Greatest-Table")) >>>
proc x -> do
rockId <- getText -< x
rockName <- getText -< x
rockFav <- getText -< x
returnA -< Rockrec rockId rockName rockFav
編集
アレックからの以下のコメントに応じて、タイプの問題
λ> getR [table]
<interactive>:56:1-12: error:
• Couldn't match type ‘NTree XNode’ with ‘[[XmlTree]]’
Expected type: [[XmlTree]] -> Rockrec
Actual type: XmlTree -> Rockrec
• The function ‘getR’ is applied to one argument,
its type is ‘cat0 XmlTree Rockrec’,
it is specialized to ‘XmlTree -> Rockrec’
In the expression: getR [table]
In an equation for ‘it’: it = getR [table]
λ> getR table
<interactive>:57:1-10: error:
• Couldn't match type ‘NTree XNode’ with ‘[XmlTree]’
Expected type: [XmlTree] -> Rockrec
Actual type: XmlTree -> Rockrec
• The function ‘getR’ is applied to one argument,
its type is ‘cat0 XmlTree Rockrec’,
it is specialized to ‘XmlTree -> Rockrec’
In the expression: getR table
In an equation for ‘it’: it = getR table
編集終了
要素を選択していなくても、上記を実行できません。また、最初の td を rockName に、2 番目の td を rockFav に配置する方法、これらにイテレータを含める方法についても少し困惑しています (2 つだけではなく、多くの td フィールドがあると仮定します)。
これを行う方法に関するその他の一般的なヒントは、より簡単に高く評価されます。