我正在尝试使用XSLT将XML文件转换为CSV。我有以下要转换的XML文件(手动简化版)。每个XML文件可以包含N条记录,其中N条可以变化。
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<reportheader>
<name>REPORT 1</name>
<version>v1</version>
</reportheader>
<recordtype>
<account>
<accountname>B</accountname>
</account>
<record>
<time>12:00:00</time>
<qty>10</qty>
<price>20</price>
</record>
<record>
<time>16:00:00</time>
<qty>20</qty>
<price>10</price>
</record>
</recordtype>
<recordtype>
<account>
<accountname>A</accountname>
</account>
<record>
<time>16:00:00</time>
<qty>5</qty>
<price>10</price>
</record>
</recordtype>
</report>
所需的输出如下:
name|version|accountname|time|qty|price
REPORT 1|v1|B|12:00:00|10|20
REPORT 1|v1|B|16:00:00|20|10
REPORT 1|v1|A|16:00:00|5|10
我当前的方法是拥有两个脚本。一个XSLT,输出所有根节点和直接父节点。然后,在第二个XSLT中,我计算记录节点的数量,并循环N次遍历csv列名称。然后,我寻找匹配/ record / time [N]的例子。当前方法大量借鉴了https://pragmaticintegrator.wordpress.com/2012/10/28/transforming-xml-to-csv-via-xslt/。
我目前的方法有两个问题。在图1中,假设每个记录始终具有每个可用字段。 2.我无法为记录分配正确的帐户,因为100条记录可能只有6个帐户。它们在xml文件中“松散耦合”的方式使我的方法无效。
有人可以帮助我找到一种更强大有效的方法吗?预先感谢。
答案 0 :(得分:1)
通过使用ancestor
轴查找表亲值,您可以一次性完成操作
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<xsl:text>name|version|accountname|time|qty|price
</xsl:text>
<xsl:apply-templates select="//record"/>
</xsl:template>
<xsl:template match="record">
<xsl:value-of select="ancestor::report/reportheader/name"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="ancestor::report/reportheader/version"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="ancestor::recordtype/account/accountname"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="time"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="qty"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="price"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
<xsl:output method="text"/>
<xsl:template match="report">
<xsl:for-each select="reportheader">
<xsl:value-of select="name/local-name(),version/local-name(), following-sibling::recordtype[1]/account/accountname/local-name(),following-sibling::recordtype[1]/record[1]/time/local-name(),following-sibling::recordtype[1]/record[1]/qty/local-name(),following-sibling::recordtype[1]/record[1]/price/local-name()" separator="|"/>
</xsl:for-each>
<xsl:for-each select="recordtype/record">
<xsl:text>
</xsl:text>
<xsl:value-of select=" ancestor::report/reportheader/name,ancestor::report/reportheader/version, preceding-sibling::account/accountname,time,qty,price" separator="|"/>
</xsl:for-each>
</xsl:template>
You may also try it.