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”,但会像这样插入 XTags:

---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 #-}