假设有xml文件:
<span id="assignee-val">
<span class="user-hover" id="issue_summary_assignee_m" rel="m">
<span class="aui-avatar aui-avatar-small"><div class="aui-avatar-inner"><img src="/secure/useravatar?size=small&avatarId=10222" /></div></span>
This Value!
</span>
</span>
问题是如何从这个xml中获取"This Value!"
。
这就是我所拥有的:(
> :m + Control.Applicative Data.ByteString.Lazy Text.HTML.DOM Text.XML.Cursor
> Prelude.map content . (element "span" >=> "id" `attributeIs` "assignee-val" >=> child >=> element "span" >=> "class" `attributeIs` "user-hover" >=> child) . fromDocument . parseLBS <$> Data.ByteString.Lazy.readFile "xmlfile"
[["\n "],[],["\n This Value!\n "]]
<span class="user-hover">
标记内的内容? UPD :换句话说,问题是如何删除所有嵌套代码(无论有多少内容)并获得第一级内容 ,"This Value!"
(以及空格和换行符)。
答案 0 :(得分:2)
问题1-为什么有3个答案?
您导航到的数据包含“user-hover”span标记的子项....拉出不重要的东西,您的节点看起来像这样
<span class="user-hover">
<span />
This Value!
</span>
XML解析器将其视为
<span class="user-hover">[TextNode "\n "]<span />[TextNode "\n This Value!\n"]</span>
因此,“user-hover”元素确实有3个孩子。
[TextNode "\n ", <span />, TextNode "\n This Value!\n"]
然后将“内容”应用于这些值中的每一个。由于span元素中没有任何内部内容,因此返回“”,然后得到:
[["\n "], [], ["\n This Value!\n"]]
问题2-如何自动删除空格缩进和换行符号?
根据xml规范,xml解析器必须保留空间。 XML游标库中可能有工具为您剥离此空间(某些xml处理库为您提供了打开自动后处理空白剥离的选项),但我不知道它。只需在查询后删除另一个调用中的空格。
您可以使用Data.Text.strip
函数为您执行空格剥离。
要获得所需的值,您需要在查询中获得更多信息....数据是否始终位于“user-hover”span元素的第三个位置?它总是在<span class="aui-avatar aui-avatar-small" />
元素之后吗?是否将用户悬停元素中的所有内容与空格剥离连接起来?一旦你回答这个问题,解决方案应该是显而易见的。
更新回答 -
根据您提供的额外信息,我可以在答案中添加更多信息。
简短的回答是 - 删除“Prelude.map内容”,并在管道中添加“&gt; =&gt;内容”,然后再添加一个Data.Text.concat
到最终输出。
以下是详细信息......
Text.XML.Cursor中的几乎所有函数都是a->[a]
形式,其中的想法是将每个过滤器应用于节点列表,然后连接结果。这非常类似于XPath中发生的事情,并且明显地模仿了它。
好消息是,我刚才描述的模式正是数组monad的工作原理....如果你使用bind a->[a]
将一堆(>>=)
函数链接在一起,那么管道基本上就会做管道中每个阶段的concat . map f
。当您将map content
添加到前面时,它可以正常工作,但只能完成图书馆打算在完整的XPath工具中执行的预期作业的一半。它删除了文本内容,但从未连接结果。以这种方式使用时,content
仅返回元素内文本节点中文本的列表。您仍然需要最后一个concat将这些文本项连接在一起。
当我使用管道时:
Data.Text.concat . (child >=> element "span" >=> "id" `attributeIs` "assignee-val" >=> child >=> element "span" >=> "class" `attributeIs` "user-hover" >=> child >=> content) . fromDocument . parseLBS <$> Data.ByteString.Lazy.readFile "file.xml"
我得到了结果
"\n \n This Value!\n "
如果你想......你仍然可以用Data.Text.strip剥离最终结果。
答案 1 :(得分:1)
有多个答案的原因是user-hover
范围有多个孩子:aui-avatar
范围之前的孩子(只包含空格),aui-avatar
范围和一个包含"This Value!"
。要获得最后一个值,您应该只查看结果集的最后一个元素,而不是重写查询:
λ> import Control.Applicative
λ> import qualified Data.ByteString.Lazy as L
λ> import qualified Data.Text as T
λ> import Text.HTML.DOM
λ> import Text.XML.Cursor
λ> :set -XOverloadedStrings
λ> let assignee = element "span" >=> "id" `attributeIs` "assignee-val"
λ> let hover = element "span" >=> "class" `attributeIs` "user-hover"
λ> map T.strip . content . last . (assignee >=> child >=> hover >=> child) . fromDocument . parseLBS <$> L.readFile "xmlfile"
["This Value!"]