views:

2773

answers:

3

I'm trying to write an XSLT that will transform an XML document that I have to a CSV file. Here's a sample of the XML:

<?xml version="1.0" encoding="utf-8"?>
  <Import>
     <Users>
        <User ID="user_1" EmailAddress="[email protected]">
            <Contact FirstName="John" LastName="Doe" />
            <Address Street1="808 Elm St" City="Anywhere" State="NY" />
        </User>

        <User ID="user_2" EmailAddress="[email protected]">
            <Contact FirstName="Jane" LastName="Noone" />
             <Address Street1="123 Some Rd" City="Anywhere" State="NY" />
        </User>     
     </Users>
   </Import>

What I want is an XSLT that will output like so:

John,Doe,808 Elm St,Anywhere,NY
Jane,Noone,123 Some Rd,Anywhere,NY

I think I have the C# code correct to initiate the transform, but just in case I don't, here's that code as well:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Configuration;

namespace UserTransform
{
    class Program
    {
        static void Main(string[] args)
        {
            string oldXML = ConfigurationSettings.AppSettings["XMLToBeTransformed"];
            string xsltLocation = ConfigurationSettings.AppSettings["XSLTfile"];
            string newCSV = ConfigurationSettings.AppSettings["NewCSVLocation"];

            XslCompiledTransform transform = new XslCompiledTransform();
            transform.Load(xsltLocation);
            transform.Transform(oldXML, newCSV);
        }
    }
}
+5  A: 

Create a template that matches all users, then pull out the information you need in the order you want:

<xsl:template match="//User">
  <xsl:value-of select="Contact/@FirstName"/>,
  <xsl:value-of select="Contact/@LastName"/>,
  <!--etc-->
</xsl:template>

Obviously you'll need to make sure whitespace is handled the way you want it to be, with newlines in the right places. I'll leave this as an exercise to the reader.

Welbog
Thanks. It's at least finally retrieving the values I want from my sample XML file (though the formatting is all crazy still). For some reason I'm getting line breaks and weird extra spaces in there using the following XSLT:<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="iso-8859-1"/> <xsl:strip-space elements="*" /> <xsl:template match="//User"> <xsl:value-of select="Contact/@FirstName"/>, <xsl:value-of select="Contact/@LastName"/>, </xsl:template></xsl:stylesheet>
mad_typist
A: 

In my experience I've always used XSLT on the client side of things not server side which is what you seem to be attempting with C#

Andrew G. Johnson
Well, that xslt is used from an exe... but in general it is *safer* to use xslt at the server... it is very painful to try to write xslt to deal with every browser variant's xslt processor.
Marc Gravell
Maybe not a very helpful answer... I have certainly used XSLT server side in Java to transform XML data. Fast, efficient, standard. What if your clients can't use javascript?
Brabster
Maybe I'm confused on the meaning of XSLT, is it an umbrella for any and all XML transformations? For example if I use PHP's SimpleXML library to parse through through some XML and spit it out as HTML, CSV or whatever is that considered XSLT? I thought XSLT was it's own markup/language
Andrew G. Johnson
XSLT is a strictly defined language with dozens of compatible implementations.
alamar
+2  A: 

I always prefer to let the browser process the XML relieving the server to carry on with more demanding job. That said, here's a sample XSLT that should translate your XML and present it in a CSV format as shown above.

Hope this sample code helps, if not, let me know.

<xsl:stylesheet version="1.0">
    <xsl:template match="/">
        <table>
            <xsl:for-each select="//User">
                <tr>
                    <td>
                        <xsl:value-of select="conat('[', @ID, ']')"/>
                        <xsl:value-of select="','"/>
                        <xsl:value-of select="Contact/@FirstName"/>
                        <xsl:value-of select="','"/>
                        <xsl:value-of select="Contact/@LastName"/>
                        <xsl:value-of select="','"/>
                        <xsl:value-of select="Address/@Street1"/>
                        <xsl:value-of select="','"/>
                        <xsl:value-of select="Address/@City"/>
                        <xsl:value-of select="','"/>
                        <xsl:value-of select="Address/@State"/>
                    </td>
                </tr>
             </xsl:for-each>
        </table>
     </xsl:template>
</xsl:stylesheet>
I'm sorry but that's not going to work, because your code would make three extra line breaks. Consider using <xsl:text> for commas.
alamar
Thanks for your comment, alamar. I have posted the whole solution on my blog, please have a look and let me know if you are still experiencing any line breaks. I have also explained a few things you may want to know about the output. Here's the post: http://www.jroller.com/evans/entry/using_xslt_to_transform_xml
It would have been better to just put the ',' and '[' in their own xsl:value-of elements. That would let you format it as you want, and not introduce extra line breaks. Actually... I'll edit it to that format.
jsight