我在这个结构中有一个xml文件(见下文),我需要从中生成csv输出。
<Root>
<Metadata>
<id>A001</id>
<name>Test</name>
</Metadata>
<Employers>
<Employer id="111">
<Employee id="aaa"><Name>Rick</Name></Employee>
<Employee id="bbb"><Name>Ram</Name></Employee>
</Employer>
<Employer id="222">
<Employee id="ddd"><Name>Bob</Name></Employee>
<Employee id="dcc"><Name>Tan</Name></Employee>
</Employer>
</Employers>
</Root>
使用xsl我需要生成如下所示的csv输出:
A001, Test, 111, aaa, Rick
A001, Test, 111, bbb, Ram
A001, Test, 222, ddd, Bob
A001, Test, 222, dcc, Tan
任何人都可以告诉我如何生成这个? 仅供参考,我能够生成雇主数据元素,但无法生成元数据 每个元素和每个雇主排。
答案 0 :(得分:2)
以下是遵循RFC4180的解决方案的成绩单。逗号后的额外空间不应该在那里。
数据:
T:\ftemp>type emp2csv.xml
<Root>
<Metadata>
<id>A001</id>
<name>Test</name>
</Metadata>
<Employers>
<Employer id="111">
<Employee id="aaa"><Name>Rick</Name></Employee>
<Employee id="bbb"><Name>Ram</Name></Employee>
</Employer>
<Employer id="222">
<Employee id="ddd"><Name>Bob</Name></Employee>
<Employee id="dcc"><Name>Tan</Name></Employee>
</Employer>
</Employers>
</Root>
执行:
T:\ftemp>call xslt emp2csv.xml emp2csv.xsl
A001,Test,111,aaa,Rick
A001,Test,111,bbb,Ram
A001,Test,222,ddd,Bob
A001,Test,222,dcc,Tan
样式表:
T:\ftemp>type emp2csv.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text"/>
<xsl:variable name="commonFields"
select="/*/Metadata/id | /*/Metadata/name"/>
<xsl:template match="/">
<xsl:apply-templates select="Root/Employers/Employer/Employee"/>
</xsl:template>
<!--these elements are CSV fields-->
<xsl:template match="Employee">
<xsl:for-each select="$commonFields | ../@id | @id | Name">
<xsl:call-template name="doThisField"/>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<!--put out a field escaping content-->
<xsl:template name="doThisField">
<!--field value escaped per RFC4180-->
<xsl:choose>
<xsl:when test="contains(.,'"') or
contains(.,',') or
contains(.,'
')">
<xsl:text>"</xsl:text>
<xsl:call-template name="escapeQuote"/>
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--escape a double quote in the current node value with two double quotes-->
<xsl:template name="escapeQuote">
<xsl:param name="rest" select="."/>
<xsl:choose>
<xsl:when test="contains($rest,'"')">
<xsl:value-of select="substring-before($rest,'"')"/>
<xsl:text>""</xsl:text>
<xsl:call-template name="escapeQuote">
<xsl:with-param name="rest" select="substring-after($rest,'"')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$rest"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
编辑删除多余的模板规则。
答案 1 :(得分:1)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/Root">
<xsl:apply-templates select="Employers/Employer/Employee" />
</xsl:template>
<xsl:template match="/Root/Employers/Employer/Employee">
<xsl:value-of select="../../../Metadata/id"/>
<xsl:call-template name="delim" />
<xsl:value-of select="../../../Metadata/name"/>
<xsl:call-template name="delim" />
<xsl:value-of select="../@id"/>
<xsl:call-template name="delim" />
<xsl:value-of select="@id"/>
<xsl:call-template name="delim" />
<xsl:value-of select="./Name"/>
<xsl:call-template name="linebreak" />
</xsl:template>
<xsl:template name="delim">
<xsl:text>, </xsl:text>
</xsl:template>
<xsl:template name="linebreak">
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
如果您需要Windows样式行结尾(例如,相当于<xsl:text>
</xsl:text>
vs <xsl:text>
</xsl:text>
,请使用\n
(回车符+换行符)代替\r\n
(换行符)在大多数语言中)。
注意:分隔符和换行符在他们自己的模板中,使您可以轻松修改字符而无需在多个位置更新/必须深入了解用于将数据拉到一起的模板。