[Haskell-cafe] A long day with HXT

nadine.and.henry at pobox.com nadine.and.henry at pobox.com
Sat May 7 00:26:31 CEST 2011

Dear Group,

I have just spent many hours staring at code and losing some hair.  My
hope is to save you the same experience someday.  Here was my goal:

Take some XML, like <photo url="somewhere" align="left" alt=""/> and
replace the align attribute with a class attribute, but only if the
value of the align attribute was not null.  This led to to followed
(hugely condensed) attempts:


> {-# LANGUAGE Arrows #-}
> import Text.XML.HXT.Core
> -- <photo  url="somewhere" align="left" alt=""/>
> testString = "<photo  url=\"somewhere\" align=\"left\" alt=\"\"/>"
> toClass :: b -> QName
> toClass = const (mkName "class")
> try f = runLA (xread >>> processTopDown f) testString
> test1 = try $  
>   hasAttrValue "align" (not.null) >>> 
>   processAttrl (changeAttrName toClass `when` hasName "align" )
> test2 = try $ processAttrl 
>   (changeAttrName toClass `when` hasAttrValue "align" (not.null))
> test3 = try $ processAttrl 
>   (changeAttrName toClass `when` hasName "align")
>   `when`  hasAttrValue "align" (not.null)
> run = do
>   print test1
>   print test2
>   print test3

result of run:

[NTree (XTag "photo" [NTree (XAttr "url") [NTree (XText "somewhere") []],NTree (XAttr "class") [NTree (XText "left") []],NTree (XAttr "alt") []]) []]
[NTree (XTag "photo" [NTree (XAttr "url") [NTree (XText "somewhere") []],NTree (XAttr "align") [NTree (XText "left") []],NTree (XAttr "alt") []]) []]
[NTree (XTag "photo" [NTree (XAttr "url") [NTree (XText "somewhere") []],NTree (XAttr "class") [NTree (XText "left") []],NTree (XAttr "alt") []]) []]

test1 and test3 performed as desired, needless to say I started out
with something similar to test2 and was almost crying because the
align attribute didn't change.  Why?

In test1, I run through the tree and select the elements which have a
non-null align attribute.  (hasAttrValue "align" (not.null)) Then for
each of these elements I process their attributes.  (processAttrl)
where I change the attribute name to "class" (changeAttrName toClass)
WHEN the attribute name is "align" (`when` hasName "align")  Result: Joy

In test2, I run through the tree and process every attribute list
(processAttrl) I change the name of the attribute to "class"
(changeAttrName toClass) WHEN the align attribute is not null (`when`
hasAttrValue "align" (not.null))) Result: Nothing changes, - No Joy

In test3, I run through the tree process every attribute list
(processAttrl) WHEN the align attribute is not null (`when` hasAttrValue
"align" (not.null)) and in that case I change the attribute name to
"class" (changeAttrName toClass) WHEN the attribute is named "align"
(`when` hasName "align")  Result: Joy

After staring at test2 for more time that I would like to acknowledge,
I (think) I realized the following.  In test2 I thought the
(hasAttrValue "align" (not.null)) was referring to the tree that was
coming into the test, but actually it is referring to the list of
attributes that is generated by processAttrl.  This list of attributes
does not itself have any attributes, thus the (hasAttrValue "align"
(not.null)) code never succeeds, and thus the (changeAttrName toClass)
is never executed.

Lessons learned: I'm not really sure, but it is these kind of subtleties
that make me sometimes long for my old friend Perl.

Best wishes,
Henry Laxen

Nadine & Henry Laxen    Belle, Venus, Aphrodite
10580 N. McCarran Blvd. Adonis, Miss Parker & Jarod
Suite 115-396           Via Alta # 6
Reno, Nevada            Chapala, Jalisco, Mexico 
89503-1896              CP 45900
         The rest is silence.  (Hamlet)

More information about the Haskell-Cafe mailing list