HXT:输入可以用箭头语法改变吗?

问题描述 投票:0回答:2

使用以下代码

{-# 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
不应该保持相同吗?

xml haskell xml-parsing hxt arrow-abstraction
2个回答
2
投票

不,输入不能更改,而且也不会更改。

您在行中编程的内容

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

1
投票

编辑:好的,现在你已经完全改变了你的问题!

工作示例应解释如下:

对于顶级标签

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
[]
© www.soinside.com 2019 - 2024. All rights reserved.