tags:

views:

5161

answers:

3

I have the following XML document:

<projects>
  <project>
   <name>Shockwave</name> 
   <language>Ruby</language> 
   <owner>Brian May</owner> 
   <state>New</state> 
   <startDate>31/10/2008 0:00:00</startDate> 
  </project>
  <project>
   <name>Other</name> 
   <language>Erlang</language> 
   <owner>Takashi Miike</owner> 
   <state> Canceled </state> 
   <startDate>07/11/2008 0:00:00</startDate> 
  </project>
...

And I'd like to get this from the transformation (XSLT) result:

Shockwave,Ruby,Brian May,New,31/10/2008 0:00:00
Other,Erlang,Takashi Miike,Cancelled,07/11/2008 0:00:00

Does anyone know the XSLT to achieve this? I'm using .net in case that matters.

Thanks!

A: 

Consider ignoring the additional layer (XSLT) and using your .NET programming language directly.

XSLT's strength is more in converting one XML into another XML format.

stesch
Why the downvotes?
stesch
@stesch: I would be tempted myself to downvote, but someone already did it. :) My reasons are that for a question like "How can I fly from A to B"? your answer is: "Do not fly, drive!". Also, how do you know .NET is used and XSLT processing is an "additional layer"?
Dimitre Novatchev
@Dimitre Novatchev: I read the question.
stesch
OK, I drop the last part of my comment (for .NET being used), but not for the "additional layer". This is essentially an XSLT question, the .NET part is just something, in the author's own words, "in case that matters". Note also, that .NET must be spelled capitalized to distinguish from other uses.
Dimitre Novatchev
@Dimitre Novatchev: I don't expect the XSLT to execute itself on its own. There's some kind of program behind it that uses it. And most of the time XSLT just adds complexity that isn't needed. CVS is best handled by CVS aware libraries. Like you don't parse XML with regexps.
stesch
"XSLT's strength is more in converting one XML into another XML format." - This is the flaw. XSL isn't just for converting into XML. The output data can be anything. Doesn't have to be XML at all, just that xml is the most frequently used method. The real strength of XSL is to use alternate stylesheets to convert the same XML dataset into various formats, eg. XML, HTML, text, csv, anything-you-like. The other problem with coding direct in .NET is it's not flexible. You want to change the output format, you have to rebuild the code.
tjmoore
the reason why using .net matters is that its implementation of xslt and xpath is incomplete - i believe it is 1.0 only. As for his question he does clearly ask for the solution in xslt not in the technology of your choice.
John Nicholas
@MrTortoise: It's the technology of his choice. I don't recommend .NET. All given solutions work with the example XML, not with every kind of data. CSV is more complex than just putting commas between values.
stesch
+4  A: 

Found a XML transform stylesheet here (site itself is in german)

The stylesheet there could be helpful:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
<xsl:output method="text" encoding="iso-8859-1"/>

<xsl:strip-space elements="*" />

<xsl:template match="/*/child::*">
<xsl:for-each select="child::*">
<xsl:if test="position() != last()">"<xsl:value-of select="normalize-space(.)"/>",    </xsl:if>
<xsl:if test="position()  = last()">"<xsl:value-of select="normalize-space(.)"/>"<xsl:text>&#xD;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Perhaps you want to remove the quotes inside the xsl:if tags so it doesn't put your values into quotes, depending on where you want to use the CSV file.

schnaader
You're the man!
Pablo Fernandez
Be careful, if there is a comma in the original data, it is not escaped. You may want to add a test with contains() and an escape with translate().
bortzmeyer
+7  A: 

Here is a version with configurable parameters that you can set programmatically:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output method="text" encoding="iso-8859-1"/>

  <xsl:param name="delim" select="string(',')" />
  <xsl:param name="quote" select="string('&quot;')" />
  <xsl:param name="break" select="string('&#xD;')" />

  <xsl:template match="/">
    <xsl:apply-templates select="projects/project" />
  </xsl:template>

  <xsl:template match="project">
    <xsl:apply-templates />
    <xsl:if test="following-sibling::*">
      <xsl:value-of select="$break" />
    </xsl:if>
  </xsl:template>

  <xsl:template match="*">
    <!-- remove normalize-space() if you want keep white-space at it is --> 
    <xsl:value-of select="concat($quote, normalize-space(.), $quote)" />
    <xsl:if test="following-sibling::*">
      <xsl:value-of select="$delim" />
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()" />
</xsl:stylesheet>
Tomalak
I like the mandatory quoting. At least when importing into, Excel, it takes care of the case where there is a $delim in the original data.
bortzmeyer