Haskell: how to write a XSLT transform function without returning IO or arrows

671 Views Asked by At

I want to use hxt-xslt to transform a string containing a source xml based on a second string containing the xslt to a result xml string. So basically, I want a function of the type:

transf :: String -> String -> String
transf    xmlStr  xsltStr = ...

I searched around, there isn't an example for xslt in hxt documentation, and the closest thing I can find is the code from this SO answer.

My problem is that the example and library uses IO and arrows heavily. I want to adapt the code and "strip" the IO and arrow to obtain a plain transform function that returns a String or Maybe String, but I don't know much about arrows.

I ask this because I need to parse HTMLs embedded in a CSV file. Having results in IO and Arrows makes it really difficult for the XSLT code to work with the rest of my code.

Based on @chi's comment on the origin version of the question, I looked into the documentation, and the closest thing I can get is the following code (by guessing and brute-forcing 3 out of the 4 functions in Text.XML.HXT.XSLT.{Compilation,Application}):

{-# LANGUAGE Arrows, PackageImports #-} 

import "hxt" Text.XML.HXT.Core 
import "hxt-xslt" Text.XML.HXT.XSLT.Application
import "hxt-xslt" Text.XML.HXT.XSLT.Compilation
import "hxt-xslt" Text.XML.HXT.XSLT.Common

--strXml = "<?xml version='1.0' encoding='UTF-8'?>\n"
strXml = "<catalog>\n  <cd>\n    <title>Empire Burlesque</title>\n    <artist>Bob Dylan</artist>\n    <country>USA</country>\n    <company>Columbia</company>\n    <price>10.90</price>\n    <year>1985</year>\n  </cd>\n</catalog> "

--strXslt = "<?xml version='1.0'?>\n\n"
strXslt = "<xsl:stylesheet version='1.0'\nxmlns:xsl='http://www.w3.org/1999/XSL/Transform'>\n\n<xsl:template  match='/'>\n  <html>\n  <body>\n    <h2>My CD Collection</h2>\n    <table border='1'>\n      <tr bgcolor='#9acd32'>\n        <th>Title</th>\n        <th>Artist</th>\n      </tr>\n      <xsl:for-each select='catalog/cd'>\n        <tr>\n          <td><xsl:value-of select='title'/></td>\n          <td><xsl:value-of select='artist'/></td>\n        </tr>\n      </xsl:for-each>\n    </table>\n  </body>\n  </html>\n</xsl:template>\n\n</xsl:stylesheet> "

applyStylesheetStr strXslt strXml  = 
    let
        xml = head $ runLA xread strXml
        xslt = assembleStylesheet (prepareXSLTDocument $head $ runLA xread strXslt) []
    in
      showTrees $ applyStylesheet xslt xml

The example XML and XSLT string came from a w3schools tutorial.

So far, the code is without IO, and arrows. And it outputs:

*Main> applyStylesheetStr strXslt strXml
"\n  \n    Empire Burlesque\n    Bob Dylan\n    USA\n    Columbia\n    10.90\n    1985\n  \n"

I have a few questions here:

  1. I noticed that xread as used above cannot take standard XML headers like <?xml version='1.0' encoding='UTF-8'?>. If included in the XML or XSLT, it returns an error. Is this expected or I am using it wrong?

  2. The correct output should be an HTML table as follows, when using IO/Arrows code from the SO answer:

    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <tr>
        <td>Empire Burlesque</td>
        <td>Bob Dylan</td>
      </tr>
    </table>

How should I fix my code to get the pure XSLT transform?

Thanks.

0

There are 0 best solutions below