XML-XSLT-CSV转换

XML-XSLT-CSV转换,xml,csv,xslt,export-to-csv,Xml,Csv,Xslt,Export To Csv,我正在尝试通过XSLT将XML文档转换为CSV。目前还不能达到预期的效果 XML如下所示: <projects> <project> <name>Shockwave</name> <language>Ruby</language> <owner>Brian May</owner> <state>New</state> <star

我正在尝试通过XSLT将XML文档转换为CSV。目前还不能达到预期的效果

XML如下所示:

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

冲击波
红宝石
布赖恩·梅
新的
31/10/2008 0:00:00
其他
二郎
三池隆志
取消
07/11/2008 0:00:00
XSLT如下所示:

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

,

;
并输出如下:

而要求转换为CSV,如下所示: 标题是第一行。然后在开始日期后换行

名称、语言、所有者、州、起始日期

Shockwave,Ruby,Brian May,纽约,31/10/2008 0:00:00

其他,二郎,三池隆志,取消,07/11/2008 0:00:00


问题在于这句话

  <xsl:if test="position() != last()">
    <xsl:value-of select="normalize-space(.)"/>,
  </xsl:if>

,
您正在输出逗号,但逗号后的换行符也将被输出。如果整个文本节点都是空白,XSLT将只忽略空白。一旦包含非空白字符,它也会输出缩进

所以,你需要把它改成这个

  <xsl:if test="position() != last()">
    <xsl:value-of select="normalize-space(.)"/><xsl:text>,</xsl:text>
  </xsl:if>

,
话虽如此,您可以进一步简化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="/*/child::*">
    <xsl:for-each select="child::*">
      <xsl:if test="position() > 1">
        <xsl:text>,</xsl:text>
      </xsl:if>
      <xsl:value-of select="normalize-space(.)"/>
    </xsl:for-each>
    <xsl:text>&#xD;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

,

;
编辑:如果要输出标题行,请将此模板添加到XSLT

<xsl:template match="/*">
   <xsl:for-each select="*[1]/*">
      <xsl:if test="position() > 1">
        <xsl:text>,</xsl:text>
      </xsl:if>
      <xsl:value-of select="local-name()"/>
   </xsl:for-each>
   <xsl:text>&#xD;</xsl:text>
   <xsl:apply-templates />
</xsl:template>

,

;

问题在于这句话

  <xsl:if test="position() != last()">
    <xsl:value-of select="normalize-space(.)"/>,
  </xsl:if>

,
您正在输出逗号,但逗号后的换行符也将被输出。如果整个文本节点都是空白,XSLT将只忽略空白。一旦包含非空白字符,它也会输出缩进

所以,你需要把它改成这个

  <xsl:if test="position() != last()">
    <xsl:value-of select="normalize-space(.)"/><xsl:text>,</xsl:text>
  </xsl:if>

,
话虽如此,您可以进一步简化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="/*/child::*">
    <xsl:for-each select="child::*">
      <xsl:if test="position() > 1">
        <xsl:text>,</xsl:text>
      </xsl:if>
      <xsl:value-of select="normalize-space(.)"/>
    </xsl:for-each>
    <xsl:text>&#xD;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

,

;
编辑:如果要输出标题行,请将此模板添加到XSLT

<xsl:template match="/*">
   <xsl:for-each select="*[1]/*">
      <xsl:if test="position() > 1">
        <xsl:text>,</xsl:text>
      </xsl:if>
      <xsl:value-of select="local-name()"/>
   </xsl:for-each>
   <xsl:text>&#xD;</xsl:text>
   <xsl:apply-templates />
</xsl:template>

,

;

很酷。成功了。有没有办法在不进行硬编码的情况下添加标题?我在回答中添加了一个例子。顺便说一句,在除第一行之外的每行之前输出逗号(取决于处理器)可能比在除最后一行之外的每行之后输出逗号更有效。测试你是否在最后一行可能会涉及很多昂贵的前瞻。酷。成功了。有没有办法在不进行硬编码的情况下添加标题?我在回答中添加了一个例子。顺便说一句,在除第一行之外的每行之前输出逗号(取决于处理器)可能比在除最后一行之外的每行之后输出逗号更有效。测试你是否在最后一行可能涉及很多昂贵的前瞻。