<?xml version="1.0" encoding="UTF-8"?>
<code>
  <code>module Main where

import Text.XML.HaXml
import Text.XML.HaXml.Parse
import Text.XML.HaXml.Posn
import Text.XML.HaXml.Util
import System.Environment (getArgs)
import System.IO (IOMode(..), hClose, hGetContents, hPutStr, openFile)
import Data.List

main = do 
  args &lt;- getArgs
  case args of
    [collada, ma] -&gt; process collada ma
    _ -&gt; argError
    
process :: String -&gt; String -&gt; IO ()  
process collada ma = do
  colladah &lt;- openFile collada  ReadMode
  mah &lt;- openFile ma ReadMode
  colladaStr &lt;- hGetContents colladah
  maStr &lt;- hGetContents mah
  
  -- Parse the COLLADA file and get the FOV animation data.
  let (Document _ _ root _) = xmlParse collada colladaStr
  let rootElem = CElem root noPos
  let animations = tag "COLLADA" /&gt; tag "library_animations" /&gt; tag "animation" $ rootElem
  let fovAnimation = (filter isFovAnimation animations) !! 0
  let sources = keep /&gt; tag "source" /&gt; tag "float_array" $ fovAnimation
  let times = map ((*24.0) . (read :: String -&gt; Float)) $ words $ tagTextContent (sources !! 0)
  let values = map (yfovToFocalLength . (read :: String -&gt; Float)) $ words $ tagTextContent (sources !! 1)
  let (CElem (Elem _ attributes _) _) = sources !! 0
  let (_, AttValue (Left countVal:_)) = attributes !! 0
  let count = read countVal :: Int
--putStrLn $ show count
--putStrLn $ show values
  
  -- Parse the ma file and get the name of the camera node.
  let createLine = (filter isCustomCameraCreate $ lines maStr) !! 0
  let !cameraName = takeWhile isNotQuote $ drop 1 $ dropWhile isNotQuote createLine
--putStrLn cameraName
  hClose mah
  
  -- Append the ma file with the FOV animation.
  mah2 &lt;- openFile ma AppendMode
  let createNode = "createNode animCurveTU -n \"" ++ cameraName ++ "_focalLength\";\n\tsetAttr \".tan\" 10;\n\tsetAttr \".wgt\" no;\n\tsetAttr -s " ++ (show count) ++ " \".ktv[0:" ++ (show (count - 1)) ++ "]\" "
  hPutStr mah2 createNode
  hPutStr mah2 (concat $ map pairToString $ zip times values) 
  hPutStr mah2 ";\n"
  let connectAttr = "connectAttr \"" ++ cameraName ++ "_focalLength.o\" \"" ++ cameraName ++ ".fl\";"
  hPutStr mah2 connectAttr
  
  hClose colladah
  hClose mah2

isFovAnimation animation = 
  let (CElem (Elem _ attributes _) _) = animation
  in let (_, AttValue (Left idStr:_)) = attributes !! 0
     in isSuffixOf "FOV" idStr

yfovToFocalLength yfov = yAperture / (tan (yfov * 0.5 * pi / 180.0) * 2.0)
                            where yAperture = 25.4 * 0.581
     
isCustomCameraCreate line = "createNode camera -n" `isPrefixOf` line

isNotQuote char = char /= '"'

pairToString pair = " " ++ (show . fst $ pair) ++ " " ++ (show . snd $ pair)

argError = putStrLn
  "Usage: add_fov_to_ma.exe COLLADA_filename ma_filename\n"</code>
  <comment>It's a simple command-line tool to read an XML file, get some data from it, convert them and append the converted data to a ma (Maya ascii) file.
This is the second program I've ever written in Haskell, so I think it would be far from good or ideal Haskell code. So I want some teachings from you about what can be improved &amp; how things should be done in Haskell.</comment>
  <created-at type="datetime">2010-02-03T10:21:29+00:00</created-at>
  <id type="integer">1167</id>
  <language>Haskell</language>
  <permalink>code-from-a-novice-haskell-user</permalink>
  <refactors-count type="integer">0</refactors-count>
  <title>Code from a novice Haskell user</title>
  <trackback-url></trackback-url>
  <updated-at type="datetime">2010-02-03T10:21:29+00:00</updated-at>
  <user-id type="integer">1912</user-id>
  <refactors type="array"/>
</code>
