2013-12-15 141 views
1

获取光标的内容假设有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&amp;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  "]] 
  1. 为什么有3个答案是什么?查询将定义里面<span class="user-hover">标签内容更准确?
  2. 如何删除空间缩进和换行符自动符号

UPD:?换言之,问题是如何删除所有嵌套的标签(它不不管有多少),并获得第一级内容只有,这是"This Value!"(和空格和换行符)。

回答

2

问题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最终的结果....

+0

我已经更新了这个问题,看看:) –

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!"] 
+0

我已经更新了这个问题('last'似乎是一个坏主意) –