Suppose I have this MathML document
<?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>
Suppose I want to “lift” the children of mi and mrow, I should get (let’s ignore the whitespace change here)
<?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>
How should I write that with HXT?
I’m a Haskell newbie... so all I have right now is
-- Dealing with command line arguments and stuff…
processRootElement :: IOSArrow XmlTree XmlTree
processRootElement
= processTopDown -- What goes here?
Quick type rundown
meaning that every
XmlTreehas the constructionWhere the first argument is the current node, and the second argument is the list of children.
The creative process
processTopDownwill take the tree transformation you provide and produce a tree transformation which applies it recursively.First, let's define the tree transformation you want on a single node:
The transformation doesn't "lift" the children of current node, because that wouldn't be possible on the root.
A good way to do this would be to use
processChildren, which is an arrow which lets us specify new children for the current node based on the old children. To do this, we'll need to use conditional arrowsWe can then split the design into two parts, a predicate for matching the tags we want, and the transformation we want to perform
The predicate
Reminding ourselves of what forms an
XNodecan take, the one we're interested in isWe want to match on nodes of this form, for our given tag names. For this, we write a helper function
For ease of use, we want to write the tags as strings, so we'll use
mkNameto convert them intoQNames. Then our more useful filter function isBut this isn't an arrow, which we need it to be for reasons we'll see later. We can simply turn it into one with
isAThe transformation
We're going two need two arrows for the transformation body - one for when the filter matches, and one for when it doesn't.
For when it doesn't, the transformation is easy - we want to keep the current node.
Here,
thisis the identity arrow - it does nothing.When the filter matches, we want to get the children - first, let's write a helper
Handily, because we're working with list arrows, we can turn this straight into an arrow using arrL
Combining them
We can now turn this into a single arrow, using
ifA, the arrow version ofifAnd finally, we can describe the transformation we wanted