2013-11-03 61 views
0

我试图使用XSLT将XML(由源生成)转换为CSV。使用XSLT将复杂而简单的XML转换为CSV

以下是由外部源生成的输入XML。我不确定这是否是一个有效的XML,因为Details标记的值是一个大列表。

<Data> 
<Details COLUMNS="Counterparty,Iteration,StartDateTime,Quantity"> 
ABC,1,23/10/2013 06:00,10 
ABC,1,23/10/2013 06:30,12 
ABC,1,23/10/2013 07:00,15 
ABC,1,23/10/2013 07:30,5 
ABC,1,23/10/2013 08:00,180 
ABC,1,23/10/2013 08:30,87 
ABC,1,23/10/2013 09:00,88 
ABC,1,23/10/2013 09:30,56 
ABC,1,23/10/2013 10:00,13 
ABC,1,24/10/2013 00:00,0 
ABC,1,24/10/2013 00:30,8.7 
ABC,1,24/10/2013 01:00,100.9 
ABC,1,24/10/2013 01:30,1.1 
ABC,1,24/10/2013 02:00,2.2 
ABC,1,24/10/2013 02:30,3.2 
ABC,1,24/10/2013 03:00,20 
ABC,1,24/10/2013 03:30,30 
</Details> 
</Data> 

我想创建一个XSLT,可以将此XML转换为CSV,如下所示。我在网上查看了许多链接,但无法创建这样的XSL转换。请帮忙!

Counterparty,StartDate,StartTime,EndTime,Volume 
ABC,23/10/2013,0600,0630,10 
ABC,23/10/2013,0630,0700,12 
ABC,23/10/2013,0700,0730,15 
ABC,23/10/2013,0730,0800,5 
ABC,23/10/2013,0800,0830,180 
. 
. 
. 
. 
ABC,24/10/2013,0300,0330,20 
ABC,24/10/2013,0330,0400,30 

添加基于注释的详细信息:我需要去的元素文本中,并对其进行操作(添加/修改/删除文本)。如果能够在没有太多麻烦的情况下操作文本,我愿意使用XSLT 2.0。每行文本之间有一个LF和CR。请让我知道最好的方法。谢谢!

问候, 阿米特

+1

好吧,基本上'Details'元素已经*是一个CSV文件,所以你所有的XSLT需要做的就是输出标题,然后输出这个元素的内容吧? – IMSoP

+0

是的,就像现在这样,一个空转换将会为你提供除标题外的所有内容(因为默认模板将选择元素文本)。 – harpo

+0

或者您是否试图让XSLT检查CSV中的数据,以便您可以操纵日期列以在输出中获取比输入更多的列,如示例中所示?如果是这样,我不确定XSLT是否是正确的工具,因为这不是一个XML结构。为什么不使用更通用的脚本语言,比如Perl,Awk,PHP等? – IMSoP

回答

1

下面的XSLT 2.0产生所需的输出

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet 
    version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes" /> 

    <xsl:template match="/Data"> 
    <xsl:text>Counterparty,StartDate,StartTime,EndTime,Volume&#10;</xsl:text> 

    <xsl:for-each select="tokenize(Details/text(), '[&#10;&#13;]')"> 

     <xsl:analyze-string select="." regex="\s*([^,]+,[^,]+,[^,]+) +([0-9]+):([0-9]+),([0-9\.]+)"> 

     <xsl:matching-substring> 
      <xsl:variable name="prefix" select="regex-group(1)"/> 
      <xsl:variable name="hours" select="regex-group(2)"/> 
      <xsl:variable name="minutes" select="regex-group(3)"/> 
      <xsl:variable name="suffix" select="regex-group(4)"/> 

      <xsl:variable name="startTime" select="number($hours) * 60 + number($minutes)"/> 
      <xsl:variable name="endTime" select="$startTime + 30"/> 
      <xsl:variable name="endHours" select="format-number($endTime div 60, '00')"/> 
      <xsl:variable name="endMinutes" select="format-number($endTime mod 60, '00')"/> 

      <xsl:value-of select="concat($prefix, ',', $hours, $minutes, ',', $endHours, $endMinutes, ',', $suffix)"/><xsl:text>&#10;</xsl:text>   
     </xsl:matching-substring> 

     </xsl:analyze-string> 
    </xsl:for-each> 

    </xsl:template> 

</xsl:stylesheet> 

注:

  • 的XSLT使有关输入文件的列的内容的一些假设和他们的分离器。如果问题中提供的示例不能很好地表示生产数据,则可能必须更改regex表达式。
  • 转换应该适用于所有具有行分隔符换行符和/或换行符或其任意组合的输入文件。虽然我没有尝试过。
  • XSLT对如何导出结束时间做了一些假设(+30分钟)。这可能不得不改变。