从非标准化的XML
获取光标的内容假设有xml文件:从非标准化的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>
的问题是如何让"This Value!"
出这个XML的。
这是我有:(
> :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 "]]
- 为什么有3个答案是什么?查询将定义里面
<span class="user-hover">
标签内容更准确? - 如何删除空间缩进和换行符自动符号
UPD:?换言之,问题是如何删除所有嵌套的标签(它不不管有多少),并获得第一级内容只有,这是"This Value!"
(和空格和换行符)。
问题1为什么有3个答案?
你导航到数据秉着“用户悬停” span标签的孩子....拉出不重要的东西,你的节点看起来像这样
<span class="user-hover">
<span />
This Value!
</span>
的XML解析器看到这作为
<span class="user-hover">[TextNode "\n "]<span />[TextNode "\n This Value!\n"]</span>
因此,“用户悬停”元素确实有3个孩子。
[TextNode "\n ", <span />, TextNode "\n This Value!\n"]
然后,将“内容”应用于这些值中的每一个。由于跨度元素没有任何内部的内容在里面,它返回“”,你会得到:
[["\n "], [], ["\n This Value!\n"]]
问题2 - 您如何自动删除空间缩进和换行的符号?
根据xml规范,xml解析器必须保留空间。可能有XML游标库中的工具为你分配这个空间(一些xml处理库给你选项来打开自动后处理空白剥离),但我并不知道它。查询后,在另一个调用中删除空白。您可以使用Data.Text.strip
函数为您执行空白删除。
为了得到你想要的值,你需要在查询更多信息....将把数据始终处于“用户悬停” span元素的第三位?它会始终在<span class="aui-avatar aui-avatar-small" />
元素之后吗?是否将user-hover元素中的所有内容与空白字符串连接起来?一旦你回答了这个问题,解决方案应该很明显。
更新答案 -
您所提供的额外的信息,我可以添加更多的信息到答案。
简短的回答是,删除“Prelude.map内容”,并在管道中添加“> =>内容”,然后在最终输出中再添加一个Data.Text.concat
。
这里是为什么....
几乎所有Text.XML.Cursor函数的形式为a->[a]
,这里的想法是每个过滤器应用于节点列表,然后CONCAT的细节结果。这非常类似于XPath中发生的情况,并且在此之后进行了明确的建模。
的好处是,我刚才描述的模式正是数组单子是如何工作....如果要链接的一堆使用绑定(>>=)
a->[a]
功能,该管道将基本上做一个concat . map f
每个阶段的管道。当您将map content
添加到前面时,它可以工作,但只完成了图书馆希望在完整的XPath工具中执行的一半预期工作。它提取了文本内容,但没有连接结果。以这种方式使用时,content
仅返回元素内文本节点中文本的列表。您仍然需要最后一个连字符将这些文本项目连接在一起。
当我用管道:
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最终的结果....
的原因有多种答案是,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!"]
我已经更新了这个问题('last'似乎是一个坏主意) –
我已经更新了这个问题,看看:) –