为什么runConduit不发送所有数据? 为什么行为不如预期为什么它表现得如此如何实现预期的行为

如何解决为什么runConduit不发送所有数据? 为什么行为不如预期为什么它表现得如此如何实现预期的行为

这是我正在解析的xml:

<?xml version="1.0" encoding="utf-8"?>
<data>
<row ows_Document='Weekly Report 10.21.2020'
     ows_Category='Weekly Report'/>
<row ows_Document='Daily Update 10.20.2020'
     ows_Category='Daily Update'/>
<row ows_Document='Weekly Report 10.14.2020'
     ows_Category='Weekly Report'/>
<row ows_Document='Weekly Report 10.07.2020'
     ows_Category='Weekly Report'/>
<row ows_Document='Spanish: Reporte Semanal 07.10.2020' 
     ows_Category='Weekly Report'/>
</data>

我一直在尝试找出如何使管道解析器拒绝记录的方法,除非ows_CategoryWeekly Report并且ows_Document不包含Spanish。首先,我在解析后使用了一个虚拟值(在下面的parseDoc'中)将它们过滤掉,但是后来我意识到我应该能够使用Maybe(在下面的其他相同的parseDoc中) ),以及joinMaybe事件解析器根据名称或属性匹配而失败的tag'层折叠起来。它可以编译,但是行为异常,显然甚至没有尝试将某些元素发送到解析器!怎么可能呢?

{-# LANGUAGE OverloadedStrings #-}

import           Conduit
import           Control.Monad
import qualified Data.ByteString.Lazy.Char8 as L8
import           Data.Foldable
import           Data.String
import qualified Data.Text                  as T
import           Data.XML.Types
import           Text.XML.Stream.Parse

newtype Doc = Doc
  { name :: String
  } deriving (Show)

main :: IO ()
main = do
  r <- L8.readFile "oha.xml"

  let doc = Doc . T.unpack
      check (x,y) a b = if y == "Weekly Report" && not (T.isInfixOf "Spanish" x) then a else b

      t :: (MonadThrow m,MonadIO m) => ((T.Text,T.Text) -> ConduitT Event o m c)
                                     -> ConduitT Event o m (Maybe c)
      t f = tag' "row" ((,) <$> requireAttr "ows_Document" <*> requireAttr "ows_Category") $ \x -> do
        liftIO $ print x
        f x

      parseDoc,parseDoc' :: (MonadThrow m,MonadIO m) => ConduitT Event o m (Maybe Doc)
      parseDoc  = (join <$>) . t $ \z@(x,_) -> return $       check z (Just $ doc x)  Nothing -- this version doesn't get sent all of the data! why!?!?
      parseDoc' =              t $ \z@(x,_) -> return $ doc $ check z             x $ T.pack bad -- dummy value

      parseDocs :: (MonadThrow m,MonadIO m) => ConduitT Event o m (Maybe Doc)
                                             -> ConduitT Event o m [Doc]
      parseDocs = f tagNoAttr "data" . many'
      f g n = force (n <> " required") . g (fromString n)

      go p = runConduit $ parseLBS def r .| parseDocs p
      bad = "no good"

  traverse_ print =<<                              go parseDoc
  putStrLn ""
  traverse_ print =<< filter ((/= bad) . name) <$> go parseDoc'

输出-请注意,parseDoc甚至没有发送任何一条记录(应该成功的记录,从10.14开始),而parseDoc'的行为却是预期的:

("Weekly Report 10.21.2020","Weekly Report")
("Daily Update 10.20.2020","Daily Update")
("Weekly Report 10.07.2020","Weekly Report")
("Spanish: Reporte Semanal 07.10.2020","Weekly Report")
Doc {name = "Weekly Report 10.21.2020"}
Doc {name = "Weekly Report 10.07.2020"}

("Weekly Report 10.21.2020","Daily Update")
("Weekly Report 10.14.2020","Weekly Report")
("Weekly Report 10.07.2020","Weekly Report")
Doc {name = "Weekly Report 10.21.2020"}
Doc {name = "Weekly Report 10.14.2020"}
Doc {name = "Weekly Report 10.07.2020"}

当我尝试通过删除与ows_Category有关的所有内容来进一步简化时,突然parseDoc可以正常工作,确立了这个想法的合理性吗?当我改为删除与ows_Document有关的所有内容时,问题仍然存在。

我怀疑我应该使用requireAttrRaw来执行此操作,但我无法理解它并且找不到文档/示例。

这和Applicative有关系吗?-现在,我考虑了一下,它应该不会因为检查值而失败,对吧?

更新

我从作者那里找到了该库的先前版本的answer,其中包括在类似情况下令人着迷的force "fail msg" $ return Nothing,但它放弃了所有解析,而不仅仅是使当前解析失败。 / p>

comment建议我需要引发异常,并且在source中,他们使用类似lift $ throwM $ XmlException "failed check" $ Just event的东西,但是像force ... return Nothing那样,这会杀死所有解析,只是当前的解析器。我也不知道该如何使用event

这里有一个合并的pull request,声称已解决了此问题,但并未讨论如何使用它,只是说它“微不足道”:)

答案

要明确答案:

  parseAttributes :: AttrParser (T.Text,T.Text)
  parseAttributes = do
    d <- requireAttr "ows_Document"
    c <- requireAttr "ows_Category"
    ignoreAttrs
    guard $ not (T.isInfixOf "Spanish" d) && c == "Weekly Report"
    return d

  parseDoc :: (MonadThrow m,MonadIO m) => ConduitT Event o m (Maybe Doc)
  parseDoc = tag' "row" parseAttributes $ return . doc

或者,因为在这种情况下,可以独立检查属性值:

  parseAttributes = requireAttrRaw' "ows_Document" (not . T.isInfixOf "Spanish")
                 <* requireAttrRaw' "ows_Category" ("Weekly Report" ==)
                 <* ignoreAttrs
    where requireAttrRaw' n f = requireAttrRaw ("required attr value failed condition: " <> n) $ \(n',as) ->
            asum $ (\(ContentText a) -> guard (n' == fromString n && f a) *> pure a) <$> as

但后者留下了有关requireAttrRaw的这些问题:

  • 如果我们负责验证Name,我们是否不需要知道名称空间?
  • 为什么requireAttrRaw向我们发送[Content]而不是两个Maybe Content,而每个给ContentTextContentEntity发送给我们?
  • 我们应该如何处理ContentEntity“用于传递解析”?

解决方法

tl; dr tag' "row" parseAttributes parseContent中,check函数属于parseAttributes,而不属于parseContent


为什么行为不如预期

xml-conduit(尤其是围绕以下不变量设计的):

  1. 当解析器的类型为ConduitT Event o m (Maybe a)时,Maybe层将编码Event是否已使用
  2. tag' parseName parseAttributes parseContent仅在EventparseName都成功的情况下消耗parseAttributes s
  3. tag' parseName parseAttributes parseContent仅在parseContentparseName都成功的情况下运行parseAttributes

parseDoc中:

  • check部分中调用parseContent函数;在这个阶段,tag'已经承诺要消耗Event,按照不变式2
  • 将两叠Maybe层堆叠在一起join
    • check函数的输出,该函数编码当前<row/>元素是否相关
    • 来自Maybe签名的“标准” tag'层,它根据不变式1编码Event是否已被消耗

这实质上打破了不变式1:当check返回Nothing时,parseDoc返回Nothing,尽管消耗了整个Event元素中的<row/> 。 这会导致xml-conduit的所有组合器(尤其是many')的不确定行为(在下面进行分析。)


为什么它表现得如此

many'组合器依靠不变量1来完成其工作。 它定义为many' consumer = manyIgnore consumer ignoreAnyTreeContent,即:

  1. 尝试consumer
  2. 如果consumer返回Nothing,然后使用ignoreAnyTreeContent跳过元素或内容,假设consumer尚未使用元素或内容,然后递归回到步骤(1)

在您的情况下,consumer会为Nothing项目返回Daily Update 10.20.2020,即使完整的<row/>元素已被消耗。因此,运行ignoreAnyTreeContent是跳过特定<row/>的一种方法,但实际上最终却跳过了下一个(Weekly Report 10.14.2020)。


如何实现预期的行为

check逻辑移至parseAttributes部分,以使Event的消耗与check是否通过有关。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res