Haskell:树上的箭头,XML,Hxt:将文本叶子转换为子树
Haskell: arrows on trees, XML, and Hxt: Transform text leaves into subtrees
背景
Freeplane 应用程序似乎已经结束了长达数十年的死亡。我正在从中提取数据。 Freeplane 将数据存储为 XML。我采取的首要步骤之一是使该格式均质化。
问题,以及我想做什么
我的目标是将 .xml
格式文件中的每个 XText
项目转换为名为 "node" 的 XTag
并具有名为 "TEXT" 的属性。我已经完成了,但是以一种看起来不雅的方式。
我想这样做:
do
t <- getText
eelem "node" >>> addAttr "TEXT" t
但是当我尝试时,我被告知 IOSLA arrow 没有 monad 实例,因此 do
-notation 不可用。
这样的事情可能吗?
我做了什么
我深入研究了原始的、深度递归的 XmlTree 数据类型,结果是:
module Ask where
import Control.Category hiding ((.), id)
import Control.Arrow
import Text.XML.HXT.Core
import Data.Tree.NTree.TypeDefs
textToNode :: IOSArrow XmlTree XmlTree
textToNode = arr f where
f :: XmlTree -> XmlTree
f (NTree (XText s) children) =
-- `children` is always an empty subtree for Text items
let attrs = [ NTree
(XAttr $ mkName "TEXT")
[NTree (XText s) []] ]
in NTree (XTag (mkName "node") attrs) children
f x = x
go :: IO [XmlTree]
go =
runX $
readDocument [withValidate no] "flat.xml"
>>> deepest (ifA isText textToNode none)
>>> putXmlTree "-"
要查看实际效果,请创建一个名为 "flat.xml" 的文件,其中包含:
<doc>
<a>1</a>
<b>2</b>
</doc>
当您 运行 go
时,您会取回“1”和“2”,但会像这样插入 XTag
s:
---XTag "node"
| "TEXT"="1"
(您还会得到一些空格;这并不重要。)
Arrow
没有 do
表示法,但它确实有类似的东西,称为 proc
表示法或箭头语法。请特别参阅 this question 这两个符号之间的关系。有了这个,你可以写出你想要做的类似风格:
textToNode :: IOSArrow XmlTree XmlTree
textToNode = proc x -> do
text <- getText -< x
node <- eelem "node" -<< text
tree <- addAttr "TEXT" text -<< node
returnA -< tree
在这里,<-
类似于它的 monadic 对应物,-<< val
的作用类似于 -< returnA val
并允许您链接箭头。请注意,您必须启用 GHC 语言扩展:
{-# LANGUAGE Arrows #-}
背景
Freeplane 应用程序似乎已经结束了长达数十年的死亡。我正在从中提取数据。 Freeplane 将数据存储为 XML。我采取的首要步骤之一是使该格式均质化。
问题,以及我想做什么
我的目标是将 .xml
格式文件中的每个 XText
项目转换为名为 "node" 的 XTag
并具有名为 "TEXT" 的属性。我已经完成了,但是以一种看起来不雅的方式。
我想这样做:
do
t <- getText
eelem "node" >>> addAttr "TEXT" t
但是当我尝试时,我被告知 IOSLA arrow 没有 monad 实例,因此 do
-notation 不可用。
这样的事情可能吗?
我做了什么
我深入研究了原始的、深度递归的 XmlTree 数据类型,结果是:
module Ask where
import Control.Category hiding ((.), id)
import Control.Arrow
import Text.XML.HXT.Core
import Data.Tree.NTree.TypeDefs
textToNode :: IOSArrow XmlTree XmlTree
textToNode = arr f where
f :: XmlTree -> XmlTree
f (NTree (XText s) children) =
-- `children` is always an empty subtree for Text items
let attrs = [ NTree
(XAttr $ mkName "TEXT")
[NTree (XText s) []] ]
in NTree (XTag (mkName "node") attrs) children
f x = x
go :: IO [XmlTree]
go =
runX $
readDocument [withValidate no] "flat.xml"
>>> deepest (ifA isText textToNode none)
>>> putXmlTree "-"
要查看实际效果,请创建一个名为 "flat.xml" 的文件,其中包含:
<doc>
<a>1</a>
<b>2</b>
</doc>
当您 运行 go
时,您会取回“1”和“2”,但会像这样插入 XTag
s:
---XTag "node"
| "TEXT"="1"
(您还会得到一些空格;这并不重要。)
Arrow
没有 do
表示法,但它确实有类似的东西,称为 proc
表示法或箭头语法。请特别参阅 this question 这两个符号之间的关系。有了这个,你可以写出你想要做的类似风格:
textToNode :: IOSArrow XmlTree XmlTree
textToNode = proc x -> do
text <- getText -< x
node <- eelem "node" -<< text
tree <- addAttr "TEXT" text -<< node
returnA -< tree
在这里,<-
类似于它的 monadic 对应物,-<< val
的作用类似于 -< returnA val
并允许您链接箭头。请注意,您必须启用 GHC 语言扩展:
{-# LANGUAGE Arrows #-}