1

假设有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!"(以及空格和换行符)。

4

2 回答 2

2

问题1-为什么有3个答案?

您导航到的数据包含“user-hover”跨度标签的子项......拉出不重要的东西,您的节点看起来像这样

<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功能为您进行空白剥离。


要获得您想要的值,您需要在查询中提供更多信息......数据是否始终位于“用户悬停”跨度元素的第三位?它总是在一个<span class="aui-avatar aui-avatar-small" />元素之后吗?是否将用户悬停元素中的所有内容与剥离的空格连接起来?一旦你回答了这个问题,解决方案应该是显而易见的。


更新答案-

使用您提供的额外信息,我可以在答案中添加更多信息。

简短的回答是 - 删除“Prelude.map 内容”,并在管道中添加“>=> 内容”,然后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 剥离最终结果......

于 2013-12-15T21:16:47.993 回答
1

有多个答案的原因是user-hoverspan 有多个子代:aui-avatarspan 之前的子代(仅包含空格)、aui-avatarspan 和包含"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!"]
于 2013-12-15T21:04:47.727 回答