使用 XSLT 将 XML 转换为 CSV,用于在单个标记中以空格分隔的多个记录
Posted
技术标签:
【中文标题】使用 XSLT 将 XML 转换为 CSV,用于在单个标记中以空格分隔的多个记录【英文标题】:XML to CSV using XSLT for multiple records separated by space in single tag 【发布时间】:2021-05-12 17:46:20 【问题描述】:我们正在尝试使用 XSLT 将 XML 转换为 CSV。我试过这个链接XML to CSV Using XSLT和Converting XML to CSV (using XSLT)。
它将普通 xml 转换为 csv,但在我的情况下,我无法获取 所需的输出。 在我的例子中,我有多个记录,这些记录在单个标记中用空格分隔,如下面的 xml 输入中所述。例如:- 项目和评级标签包含由空格分隔的多条记录。
输入 XML:
<?xml version = "1.0"?>
<?xml-stylesheet type = "text/xsl" version="2.0" href = "csvconverted.xsl"?>
<TestData>
<project>Project-1 Project-2 Project-3</project>
<rating>2 3 5</rating>
<date>21-12-2018 21-06-2020 21-12-20</date>
</TestData>
XSL:-
<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="'"'" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="TestData" />
</xsl:template>
<xsl:template match="TestData">
<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>
预期输出:
project,rating,date
Project-1,2,21-12-2018
Project-2,3,21-06-2020
Project-3,5,21-12-20
使用上述代码的实际输出:-
"Project-1 Project-2 Project-3","2 3 5","21-12-2018 21-06-2020 21-12-20"
如果您能进一步指导我,将不胜感激。
【问题讨论】:
您是否仅限于 XSLT 1.0?如果是这样,您将使用哪个处理器?您需要一种完全不同的方法,将空格分隔的字符串标记为单独的值。 感谢您的回复和关注。由于我是这项新技术的新手,所以我不限于版本。我的要求是,当我们在浏览器中打开它时,它应该返回预期的输出,如我的示例所示。我看过你的个人资料,看起来你是这项技术的专家 :),我希望你能在这方面指导我。谢谢 恐怕我被你的回复弄糊涂了。您想要一个 CSV 结果。浏览器与它有什么关系?浏览器显示 html,而不是 CSV。浏览器仅限于 XSLT 1.0,没有扩展。请说明您的确切处理链。 @michael.hor257k ,我有需要使用 xslt 将其转换为 csv 的示例 xml。当我们打开这个转换后的 xml(例如在浏览器或记事本++中)时,它应该以 csv 格式显示转换后的值。 【参考方案1】:我假设您使用的是不支持扩展的 XSLT 1.0 处理器。
我还将假设输入 XML 的结构是预先知道的,唯一不同的是 3 个以空格分隔的字符串中的值的数量。
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/TestData">
<!-- header -->
<xsl:text>project,rating,date </xsl:text>
<xsl:call-template name="generate-rows">
<xsl:with-param name="project" select="project"/>
<xsl:with-param name="rating" select="rating"/>
<xsl:with-param name="date" select="date"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="generate-rows">
<xsl:param name="project"/>
<xsl:param name="rating"/>
<xsl:param name="date"/>
<xsl:param name="delimiter" select="' '"/>
<!-- generate row -->
<xsl:value-of select="substring-before(concat($project, $delimiter), $delimiter)" />
<xsl:text>,</xsl:text>
<xsl:value-of select="substring-before(concat($rating, $delimiter), $delimiter)" />
<xsl:text>,</xsl:text>
<xsl:value-of select="substring-before(concat($date, $delimiter), $delimiter)" />
<xsl:text> </xsl:text>
<xsl:if test="contains($project, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="generate-rows">
<xsl:with-param name="project" select="substring-after($project, $delimiter)"/>
<xsl:with-param name="rating" select="substring-after($rating, $delimiter)"/>
<xsl:with-param name="date" select="substring-after($date, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
演示:https://xsltfiddle.liberty-development.net/3MEdvhL
【讨论】:
感谢您的回答。上述解决方案对我有用。因为我是新手,所以如果你能解释一下它的工作原理,我将不胜感激。:) 它的工作原理是调用一个递归模板,该模板通过从 3 个以空格分隔的字符串中的每个字符串中提取第一个标记来创建一行,然后使用字符串的其余部分调用自身。 --附言如果您的数据提供者充分利用 XML 格式,那么这些都不是必需的,在这种格式中,数据应该被结构化为元素和属性,而不是分隔字符串。 --- P.P.S.如果您可以使用标记化函数(作为扩展函数或作为 XSLT 2.0 的一部分),这可能会简单得多。以上是关于使用 XSLT 将 XML 转换为 CSV,用于在单个标记中以空格分隔的多个记录的主要内容,如果未能解决你的问题,请参考以下文章