假设我有此MathML文档
<?xml version="1.0" encoding="UTF-8”?>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mi> f </mi>
<mo> ⁡ </mo>
<mrow>
<mo> ( </mo>
<mi> x </mi>
<mo> ) </mo>
</mrow>
</math>
假设我想“举起” mi
和mrow
的孩子,我应该得到(让我们忽略此处的空白更改)
<?xml version="1.0" encoding="UTF-8"?>
<math xmlns="http://www.w3.org/1998/Math/MathML">
f
<mo> ⁡ </mo>
<mo> ( </mo>
x
<mo> ) </mo>
</math>
我应该如何用HXT编写它?
我是Haskell新手...所以我现在所拥有的只是
-- Dealing with command line arguments and stuff…
processRootElement :: IOSArrow XmlTree XmlTree
processRootElement
= processTopDown -- What goes here?
答案 0 :(得分:3)
XmlTree = NTree XNode
表示每个XmlTree
都有构造
NTree XNode [XMLTree]
第一个参数是当前节点,第二个参数是子节点列表。
processTopDown
将接受您提供的树形转换,并生成一个递归应用的树形转换。
首先,让我们在单个节点上定义所需的树转换:
该转换不会“提升”当前节点的子节点,因为这在根节点上是不可能的。
执行此操作的一个好方法是使用processChildren
,这是一个箭头,可让我们基于旧子节点为当前节点指定新子节点。为此,我们需要使用conditional arrows
然后我们可以将设计分为两部分,一个用于匹配我们想要的标签的谓词,另一个是我们要执行的转换
提醒自己what forms和XNode
可以采取的行动,我们感兴趣的是
XTag QName XmlTrees
对于给定的标签名称,我们希望在这种形式的节点上进行匹配。为此,我们编写了一个辅助函数
filterOnQName :: QName -> XNode -> Bool
filterOnQName qname (XTag xqname _)
| qname == xqname = True
| otherwise = False
filterOnQName _ _ = False
为了易于使用,我们希望将标签写为字符串,因此我们将使用mkName
将它们转换为QName
。那么我们更有用的过滤器功能是
filterTags :: [String] -> XmlTree -> Bool
filterTags tagNames (NTree xnode _) = any (\qname -> filterOnQName qname xnode) (map mkName tagNames)
但这不是箭头,出于以后我们将要看到的原因,我们需要它。我们可以简单地使用isA
childFilter tags = isA (filterTags tags)
我们要使用两个箭头来表示变换主体-一个用于过滤器匹配时,另一个用于当过滤器不匹配时。
对于不这样的情况,转换很容易-我们想保留当前节点。
filterFailed = this
在这里,this
是身份箭头-它什么也不做。
当过滤器匹配时,我们想得到孩子-首先,让我们编写一个帮助程序
getChildren :: XmlTree -> [XmlTree]
getChildren (NTree _ children) = children
由于我们正在使用列表箭头,因此可以方便地使用arrL
将其直接变成箭头liftChildren = arrL getChildren
我们现在可以使用ifA
的箭头版本if
将其变成单个箭头
liftMatchedChildren tags = ifA (childFilter tags) liftChildren filterFailed
最后,我们可以描述所需的转换
processRootElement
= processTopDown (processChildren (liftMatchedChildren ["mi", "mrow"]))