使用以下代码
{-# LANGUAGE Arrows #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
import Text.XML.HXT.Core
parseXml :: IOSArrow XmlTree XmlTree
parseXml = getChildren >>> getChildren >>>
proc x -> do
y <- x >- hasName "item"
returnA -< x
main :: IO ()
main = do
person <- runX (readString [withValidate no]
"<xml><item>John</item><item2>Smith</item2></xml>"
>>> parseXml)
putStrLn $ show person
return ()
我得到了输出
[NTree (XTag "item" []) [NTree (XText "John") []]]
所以看来
hasName "item"
被应用到了x
,这是我没想到的。使用 arrowp 我得到 parseXml
:
parseXml
= getChildren >>> getChildren >>>
(arr (\ x -> (x, x)) >>>
(first (hasName "item") >>> arr (\ (y, x) -> x)))
所以我有箭头图
y
/-- hasName "item" ---
x /
-- getChildren -- getChildren ---\x->(x,x) \(y,x)->x --- final result
\ /
\---------------------/
为什么
hasName "item"
也应用于元组的第二位?我认为 haskell 中没有状态,并且 hasName "item" x
返回一个新对象,而不是更改 x
的内部状态。
相关问题:分解箭头外的箭头 do 表示法是否有效?
我有以下代码:
{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Core
data Person = Person { forname :: String, surname :: String } deriving (Show)
parseXml :: IOSArrow XmlTree Person
parseXml = proc x -> do
forname <- x >- this /> this /> hasName "fn" /> getText
surname <- x >- this /> this /> hasName "sn" /> getText
returnA -< Person forname surname
main :: IO ()
main = do
person <- runX (readString [withValidate no]
"<p><fn>John</fn><sn>Smith</sn></p>"
>>> parseXml)
putStrLn $ show person
return ()
如果我运行它,一切正常并且我得到输出
[Person {forname = "John", surname = "Smith"}]
但是如果我更改
parseXml
以避免 this
语句
parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>> proc x -> do
forname <- x >- hasName "fn" /> getText
surname <- x >- hasName "sn" /> getText
returnA -< Person forname surname
无法再解析任何人(输出为
[]
)。调查问题
parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>>
proc x -> do
forname <- x >- withTraceLevel 5 traceTree >>> hasName "fn" /> getText
surname <- x >- hasName "sn" /> getText
returnA -< Person forname surname
我得到了输出
content of:
============
---XTag "fn"
|
+---XText "John"
content of:
============
---XTag "sn"
|
+---XText "Smith"
[]
所以一切看起来都很好,但是有了代码
parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>>
proc x -> do
forname <- x >- hasName "fn" /> getText
surname <- x >- withTraceLevel 5 traceTree >>> hasName "sn" /> getText
returnA -< Person forname surname
我得到了
content of:
============
---XTag "fn"
|
+---XText "John"
[]
所以在我看来,输入
x
的值在两个语句之间发生变化。看起来 hasName "fn"
在附加到 x
箭头之前已应用于 surname
。但是两条线之间的 x
不应该保持相同吗?
不,输入不能更改,而且也不会更改。
您在行中编程的内容
proc x -> do
y <- x >- hasName "item"
returnA -< x
只是一个过滤器,删除所有未命名为
item
的节点。
他的相当于箭头
hasName "item" `guards` this
您可以使用
进行测试{-# LANGUAGE Arrows #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module Main where
import Text.XML.HXT.Core
parseXml0 :: IOSArrow XmlTree XmlTree
parseXml0 = getChildren >>> getChildren >>>
proc x -> do
_ <- hasName "item" -< x
returnA -< x
parseXml1 :: IOSArrow XmlTree XmlTree
parseXml1 = getChildren >>> getChildren >>>
(hasName "item" `guards` this)
main1 :: Show c => IOSArrow XmlTree c -> IO ()
main1 parseXml = do
person <- runX (readString [withValidate no]
"<xml><item>John</item><item2>Smith</item2></xml>"
>>> parseXml)
putStrLn $ show person
return ()
main :: IO ()
main = main1 parseXml0 >> main1 parseXml1
编辑:好的,现在你已经完全改变了你的问题!
工作示例应解释如下:
对于顶级标签
x
getText
) 的所有文本 (this /> this
),其中名称为 "fn"
(hasName "fn"
),使用 forname
来保存这些值getText
) 的所有文本 (this /> this
),其中名称为 "sn"
(hasName "sn"
),使用 surname
来保存这些值Person forname surname
这看起来可行,但可能并没有达到您认为的效果。 例如,尝试在输入
"<p><fn>John</fn><sn>Smith</sn><fn>Anne</fn><sn>Jones</sn></p>"
上运行代码。 打印了四个名字。
损坏的示例应解释如下:
为了每一个孙子
x
x
具有名称 "fn"
,则将文本存储在 forname
中(否则跳到下一个 x
)x
具有名称 "sn"
,则将文本存储在 surname
中(否则跳到下一个 x
)标签不能有名称
"fn"
和 名称 "sn"
! 因此,每个标签都会被跳过。
您的调查只是显示了跳过标签的计算点。 在第一种情况下,两个标签都存在,因为尚未过滤任何内容。 在第二种情况下,仅存在
"fn"
标签,因为第一个命令已过滤掉其他所有内容。
编辑:您可能会发现这个示例(根据列表单子完成)很有启发性。
import Control.Monad ((>=>))
data XML = Text String | Tag String [XML] deriving Show
this :: a -> [a]
this = return
(/>) :: (a -> [XML]) -> (XML -> [c]) -> a -> [c]
f /> g = f >=> getChildren >=> g
(>--) :: a -> (a -> b) -> b
x >-- f = f x
getChildren :: XML -> [XML]
getChildren (Text _) = []
getChildren (Tag _ c) = c
hasName :: String -> XML -> [XML]
hasName _ (Text _) = []
hasName n i@(Tag n' _) = if n == n' then [i] else []
getText :: XML -> [String]
getText (Text t) = [t]
getText (Tag _ _) = []
parseXML :: XML -> [(String, String)]
parseXML = \x -> do
forname <- x >-- (this /> this /> hasName "fn" /> getText)
surname <- x >-- (this /> this /> hasName "sn" /> getText)
return (forname, surname)
parseXMLBroken :: XML -> [(String, String)]
parseXMLBroken = getChildren >=> getChildren >=> \x -> do
forname <- x >-- (hasName "fn" /> getText)
surname <- x >-- (hasName "sn" /> getText)
return (forname, surname)
runX :: (XML -> a) -> XML -> a
runX f xml = f (Tag "/" [xml])
xml :: XML
xml = (Tag "p" [ Tag "fn" [Text "John"]
, Tag "sn" [Text "Smith"] ])
example1 = runX parseXML xml
example2 = runX parseXMLBroken xml
*Main> example1
[("John","Smith")]
*Main> example2
[]