[Haskell-cafe] How do I insert an element in HaXml?
Jeremy Shaw
jeremy.shaw at linspireinc.com
Mon May 21 14:31:56 EDT 2007
At Sun, 20 May 2007 10:55:26 +0100,
Malcolm Wallace wrote:
>
> "Jeremy Shaw" <jeremy.shaw at linspireinc.com> writes:
>
> > How do I create a HaXml filter that adds a new element as a child of
> > an existing element. For example, let's say I have the XML document:
> > <a> <b/> <c/> </a>
> > How do I add a new element under <a /> so that I have the document:
> > <a> <newElement/> <b/> <c/> </a>
>
> Using the combinators, it goes something like this:
>
> mkElem "a" [ mkElem "newElement" []
> , children ] `o` tag "a"
>
> Having matched the outer tag, you then rebuild it with some extra stuff
> added. Obviously you would abstract the common pattern if you do this
> frequently:
>
> insertAtStart :: String -> String -> CFilter
> insertAtStart outer newelem =
> mkElem outer [ mkElem newElem []
> , children ] `o` tag outer
Thanks! I should probably mention that I don't actually have a
specific problem I am trying to solve here. I am trying to write a
tutorial on how to use the combinators, and there is a certain class
of problems I can't seem to handle. I am not sure if it is because
there is a hole in my understanding, or if there is an hole in what
the combinators can express. The hole is related to operations that
want to edit the children of a element in some sort of aggregate
manner. The current example is inserting a new element. Another
example is sorting the children.
Going back to the example at hand, what if I don't know the name and
attributes of the parent? For example, if I have the document:
<top>
<section attr="value1">
<b />
<b />
</section>
<section2 attr="value3">
<b />
</section2>
<othersection attr=\"value2\"/>
</top>
And a I want to add single <newElement /> to any child of <top> that
already has one or more <b /> element, so I get this output:
<top>
<section attr="value1">
<newElement />
<b />
<b />
</section>
<section2 attr="value3">
<newElement />
<b />
</section2>
<othersection attr="value2"/>
</top>
A solution that comes close is this filter:
> chip ((chip (mkElem "newElement" [] `union` keep)) `when` (elm /> tag "b"))
Except that it will produce a <newElement /> for *every* <b />,
whereas I only want a single <newElement /> per parent.
If I introduce a new (poorly named) primitive:
> editElem :: CFilter -> CFilter
> editElem f c@(CElem (Elem name as _)) = [ CElem (Elem name as (f c)) ]
Then I can express the filter like this:
> chip (editElem (mkElem "newElement" [] `union` children) `when` (keep /> tag "b"))
But, I don't see an obvious way to implement 'editElem' using the
existing combinators.
On the other hand, 'chip' can be implemented in terms of 'editElem':
> chip' = editElem children
but, I am not sure what implications that has, if any.
thanks!
j.
More information about the Haskell-Cafe
mailing list