XML to CSV Using XSLT

2018-12-31 12:35发布

问题:

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.

回答1:

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

The stylesheet added here could be helpful:

<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=\"/*/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.



回答2:

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\">
  <xsl:output method=\"text\" encoding=\"utf-8\" />

  <xsl:param name=\"delim\" select=\"\',\'\" />
  <xsl:param name=\"quote\" select=\"\'&quot;\'\" />
  <xsl:param name=\"break\" select=\"\'&#xA;\'\" />

  <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>


回答3:

This xsl:stylesheet can use a specified list of column headers and will ensure that the rows will be ordered correctly.

<?xml version=\"1.0\"?>
<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:csv=\"csv:csv\">
    <xsl:output method=\"text\" encoding=\"utf-8\" />
    <xsl:strip-space elements=\"*\" />

    <xsl:variable name=\"delimiter\" select=\"\',\'\" />

    <csv:columns>
        <column>name</column>
        <column>sublease</column>
        <column>addressBookID</column>
        <column>boundAmount</column>
        <column>rentalAmount</column>
        <column>rentalPeriod</column>
        <column>rentalBillingCycle</column>
        <column>tenureIncome</column>
        <column>tenureBalance</column>
        <column>totalIncome</column>
        <column>balance</column>
        <column>available</column>
    </csv:columns>

    <xsl:template match=\"/property-manager/properties\">
        <!-- Output the CSV header -->
        <xsl:for-each select=\"document(\'\')/*/csv:columns/*\">
                <xsl:value-of select=\".\"/>
                <xsl:if test=\"position() != last()\">
                    <xsl:value-of select=\"$delimiter\"/>
                </xsl:if>
        </xsl:for-each>
        <xsl:text>&#xa;</xsl:text>

        <!-- Output rows for each matched property -->
        <xsl:apply-templates select=\"property\" />
    </xsl:template>

    <xsl:template match=\"property\">
        <xsl:variable name=\"property\" select=\".\" />

        <!-- Loop through the columns in order -->
        <xsl:for-each select=\"document(\'\')/*/csv:columns/*\">
            <!-- Extract the column name and value -->
            <xsl:variable name=\"column\" select=\".\" />
            <xsl:variable name=\"value\" select=\"$property/*[name() = $column]\" />

            <!-- Quote the value if required -->
            <xsl:choose>
                <xsl:when test=\"contains($value, \'&quot;\')\">
                    <xsl:variable name=\"x\" select=\"replace($value, \'&quot;\',  \'&quot;&quot;\')\"/>
                    <xsl:value-of select=\"concat(\'&quot;\', $x, \'&quot;\')\"/>
                </xsl:when>
                <xsl:when test=\"contains($value, $delimiter)\">
                    <xsl:value-of select=\"concat(\'&quot;\', $value, \'&quot;\')\"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select=\"$value\"/>
                </xsl:otherwise>
            </xsl:choose>

            <!-- Add the delimiter unless we are the last expression -->
            <xsl:if test=\"position() != last()\">
                <xsl:value-of select=\"$delimiter\"/>
            </xsl:if>
        </xsl:for-each>

        <!-- Add a newline at the end of the record -->
        <xsl:text>&#xa;</xsl:text>
    </xsl:template>

</xsl:stylesheet>


标签: xml xslt csv