我有一个XML文件,我试图将其转换为csv。 我已经在过去做过类似的事情,但这次的问题是我的CSV列包含XML中的父项。这导致了问题。
给出以下示例XML结构:
<...>
<thing name="Type1">
<...>
<category name="cat1">
<value>12.65456</value>
</category>
<category name="cat2">
<value>4.56785</value>
</category>
<category name="cat3">
<value>1.3658</value>
</category>
</...>
</thing>
<thing name="Type2">
<...>
<category name="cat1">
<value>xx.xxxxx</value>
</category>
<category name="cat2">
<value>xx.xxxxx</value>
</category>
<category name="cat3">
<value>xx.xxxxx</value>
</category>
<category name="cat4">
<value>xx.xxxx</value>
</category>
</...>
</thing>
<thing name="Type3">
<...>
<category name="cat1">
<value>xx.xxxxx</value>
</category>
<category name="cat2">
<value>xx.xxxxx</value>
</category>
<category name="cat4">
<value>xx.xxxx</value>
</category>
</...>
</thing>
</...>
请注意在XML文档中:
我想获得以下输出csv文件
Type1 Type2 Type3 ....
cat1 12.65456 xx.xxxx xx.xxxx
cat2 4.56785 xx.xxxx xx.xxxx
cat3 1.3658 xx.xxxx
cat4 xx.xxxx xx.xxxx
.... ..... ....... .......
(请注意,为了便于阅读,我添加了标签,但我在转换中使用了逗号。这不重要。)
起初,我试图仔细检查每件事情:
<xsl:template match=".../thing">
<xsl:for-each select="category">
<xsl:choose>
<xsl:when test="@name='cat1'">
...
</xsl:when>
<xsl:when test="@name='cat2'">
...
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
但这里的问题是输出的行会被扰乱:
12.65456 xx.xxxx xx.xxxx 4.56785 xx.xxxx xx.xxxx ....
我也尝试直接点击类别
<xsl:template match=".../thing/category[cat1]">
....
</xsl:template>
<xsl:template match=".../thing/category[cat2]">
....
</xsl:template>
....
但由于XSLT通过树的方式,我也无法确保输出的顺序是正确的。
最后,我一直在研究如何拯救&#34;成长&#34;结果变成了变量,但事实证明在XSLT中不能覆盖变量。
所以我的问题是:有没有办法在树中运行以便获得所需的输出?
任何领导都会非常感激:)。
谢谢, 于连
答案 0 :(得分:2)
首先,让我们有一个可行的输入示例:
<强> XML 强>
<root>
<thing name="Type1">
<wrapper>
<category name="cat1">
<value>1.10</value>
</category>
<category name="cat2">
<value>1.20</value>
</category>
<category name="cat3">
<value>1.30</value>
</category>
</wrapper>
</thing>
<thing name="Type2">
<wrapper>
<category name="cat1">
<value>2.10</value>
</category>
<category name="cat2">
<value>2.20</value>
</category>
<category name="cat3">
<value>2.30</value>
</category>
<category name="cat4">
<value>2.40</value>
</category>
</wrapper>
</thing>
<thing name="Type3">
<wrapper>
<category name="cat1">
<value>3.10</value>
</category>
<category name="cat2">
<value>3.20</value>
</category>
<category name="cat4">
<value>3.40</value>
</category>
</wrapper>
</thing>
</root>
现在,简而言之,您希望为category/@name
的每个不同值和每个thing
的数据单元创建一行。
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/root">
<xsl:variable name="columns" select="thing"/>
<!-- header -->
<xsl:text>Category	</xsl:text>
<xsl:value-of select="$columns/@name" separator="	"/>
<xsl:text> </xsl:text>
<!-- data -->
<xsl:for-each select="distinct-values(thing/wrapper/category/@name)">
<xsl:variable name="cat" select="."/>
<xsl:value-of select="$cat"/>
<xsl:text>	</xsl:text>
<xsl:for-each select="$columns">
<xsl:value-of select="wrapper/category[@name=$cat]/value" />
<xsl:if test="position()!=last()">
<xsl:text>	</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<强>结果强>
Category Type1 Type2 Type3
cat1 1.10 2.10 3.10
cat2 1.20 2.20 3.20
cat3 1.30 2.30
cat4 2.40 3.40
使用键获取每个数据单元格的值可以提高效率。
答案 1 :(得分:1)
您可以通过以下方式执行此操作:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="root">
<xsl:variable name="thisRoot" select="."/>
<!-- Title line -->
<!-- Empty title for categories -->
<xsl:text>	</xsl:text>
<!-- Type names -->
<xsl:variable name="types" select="thing/@name"/>
<xsl:value-of select="string-join($types, '	')"/>
<xsl:text>
</xsl:text>
<!-- A line for each category -->
<xsl:variable name="categories" select="distinct-values(//category/@name)"/>
<xsl:for-each select="$categories">
<!-- The current category -->
<xsl:variable name="thisCateg" select="."/>
<xsl:value-of select="."/>
<xsl:text>	</xsl:text>
<!-- Loop for each type in this row -->
<xsl:for-each select="$types">
<xsl:variable name="thisType" select="."/>
<xsl:value-of select=
"$thisRoot/thing[@name = $thisType]//category[@name = $thisCateg]/value"/>
<xsl:if test="position() < last()">
<xsl:text>	</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:transform>
请注意,需要将当前对象(.
)存储在变量中
供将来参考,因为当前对象的当前分配
不同地方的变化。
从输入文件中读取类型和类别,无需硬编码 它们在XSLT脚本中。
对于您的数据(略有变化),我得到以下结果:
Type1 Type2 Type3
cat1 12.65456 xx.xxxx1 yy.xxxx1
cat2 4.56785 xx.xxxx2 yy.xxxx2
cat3 1.3658 xx.xxxx3 yy.xxxx3
cat4 xx.xxx4 xx.xxx4