【问题标题】:Convert complicated yet simple XML to CSV using XSLT使用 XSLT 将复杂而简单的 XML 转换为 CSV
【发布时间】:2013-11-14 10:34:16
【问题描述】:

我正在尝试使用 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

基于 cmets 添加更多信息:我需要进入元素文本并对其进行操作(添加/编辑/删除文本)。如果 XSLT 2.0 能够轻松地操作文本,我愿意使用它。每行文本之间有一个 LF 和 CR。请让我知道最好的方法。谢谢!

问候, 阿米特

【问题讨论】:

  • 嗯,基本上Details 元素已经是 CSV 文件,所以您的XSLT 需要做的就是输出标题,然后是那个元素的内容,对吗?
  • 是的,就目前而言,一个空的转换会得到除标题之外的所有内容(因为默认模板将选择元素文本)。
  • 或者您是否试图让 XSLT 检查 CSV 中的数据,以便您可以操纵日期列以在输出中获取比输入更多的列,如示例中所示?如果是这样,我不确定 XSLT 是否适合这项工作,因为那不是 XML 结构。为什么不使用更通用的脚本语言,例如 Perl、Awk、PHP 等?
  • 如果您确实需要查看数据内部,而不仅仅是将其复制到输出中,那么执行此操作的方式将取决于您使用的是 XSLT 1.0 还是 2.0。 XSLT 2.0 具有更强大的文本操作功能。询问 XSLT 问题时,请务必说明您使用的是哪个版本。
  • Details 标签中的每一行文本之间是否已经有换行符?

标签: xml xslt csv export-to-csv


【解决方案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 分钟)做出了一些假设。这可能需要改变。

【讨论】:

    猜你喜欢
    • 2020-06-10
    • 2015-02-07
    • 1970-01-01
    • 2019-02-02
    • 2017-05-23
    • 2011-10-28
    相关资源
    最近更新 更多