我有一些XML输出,我想将其转换为CSV,但是对于包含键/值对的数据,它已被证明是最困难的。我已经尝试了很多次迭代,我终于需要一些帮助了。这是需要使用XSLT 1.0转换的XML。
<?xml version="1.0" encoding="UTF-8"?>
<status>
<snapshot>
<metrics>
<entry>
<key>time</key>
<value>1001</value>
</entry>
<entry>
<key>bytes</key>
<value>104</value>
</entry>
<entry>
<key>input</key>
<value>13321</value>
</entry>
<entry>
<key>output</key>
<value>11002</value>
</entry>
</metrics>
<timestamp>2016-01-12T01:00</timestamp>
<metrics>
<entry>
<key>time</key>
<value>1002</value>
</entry>
<entry>
<key>bytes</key>
<value>105</value>
</entry>
<entry>
<key>input</key>
<value>13322</value>
</entry>
<entry>
<key>output</key>
<value>11003</value>
</entry>
</metrics>
<timestamp>2016-01-12T02:00</timestamp>
</snapshot>
</status>
我希望输出看起来像这样:
time,bytes,input,output,timestamp
1001,104,13321,11002,2016-01-12T01:00
1002,105,13322,11003,2016-01-12T02:00
===添加我正在使用的XSLT ===
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="delimiter" select="','"/>
<xsl:key name="field" match="entry/*" use="name()"/>
<xsl:template match="/">
<xsl:for-each select="/*/*/*/*/*[generate-id()=generate-id(key('field', name())[1])]">
<xsl:value-of select="name()"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:for-each select="/*/sObject">
<xsl:variable name="property" select="." />
<xsl:for-each select="$property/*">
<xsl:variable name="value" select="." />
<xsl:value-of select="$value"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:if test="position() = last()">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
根据您给出的示例xml和信息,请尝试以下 XSLT 1.0 这是一个带有动态方法的改进的简化版本。如果您的XML略有变化,您不必更改样式表(例如,添加entries
):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xsl:output method="text"/>
<xsl:strip-space elements="status snapshot"/>
<xsl:template match="snapshot">
<!-- generate the headline -->
<xsl:apply-templates select="metrics[1]/entry/key | timestamp[1]" mode="heading"/>
<xsl:text> </xsl:text>
<!-- generate the content -->
<xsl:for-each select="metrics">
<xsl:for-each select="entry/value">
<xsl:value-of select="concat(., ',')"/>
</xsl:for-each>
<xsl:value-of select="following-sibling::*[name() = 'timestamp'][1]"/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="metrics/entry/key" mode="heading">
<xsl:value-of select="concat(., ',')"/>
</xsl:template>
<xsl:template match="timestamp" mode="heading">
<xsl:value-of select="name()"/>
</xsl:template>
</xsl:stylesheet>
<强>结果:强>
time,bytes,input,output,timestamp
1001,104,13321,11002,2016-01-12T01:00
1002,105,13322,11003,2016-01-12T02:00
<强>要求:强>
所有entry
及其子项始终存在且相同。
答案 1 :(得分:0)
这也适用于XSLT 1.0
定义四个必需列。然后只选择匹配的键/值对。这样,输出中将考虑缺少键/值对,并忽略任何其他对。分隔符和列名称可以作为参数传递。
缺点:更改密钥名称时没有灵活性。
delims=