xml - XSLT - Nested XML to CSV output
问题描述
I am trying to convert a XML file to CSV using XSLT. I have the following (manually simplified version) of the XML file that I would like to convert. Each XML file can contain N number of records where N may vary.
<?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>
The desired output would be the following:
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
My current approach is to have two scripts. One XSLT that outputs all root nodes and the direct parent. In the second XSLT I then count the number of record nodes and loop through the csv column names N times. I then look for example to match /record/time[N]. The current approach borrows heavily from: https://pragmaticintegrator.wordpress.com/2012/10/28/transforming-xml-to-csv-via-xslt/ .
There are two problems with my current approach. 1, it assumes that every record always has every field available. 2. I cannot assign the right account to the records, because there might be only 6 accounts for 100 records. The way they are "loosely coupled" in the xml files makes my approach invalid.
Can someone help me find a more robust and efficient approach? Thanks in advance.
解决方案
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>
推荐阅读
- shell - 合并终端中的文件夹和文件覆盖重复项
- aws-lambda - 具有 2 层的 aws lambda 函数 - 无服务器框架 yaml 文件
- python - pypdf - 在 pdf 文件中写入时,孟加拉语单词被破坏
- react-native - 如何在 React Native(Android)中正确地将元素聚焦在“位置:”绝对“”视图中
- c - 为什么我的从数组计算平均值的代码不起作用?
- flutter - 从 sql 检索的布尔值作为字符串
- pandas - 创建具有不等长度列表的熊猫数据框
- sql - 如何从通过“路径”列存储的树层次结构中过滤出具有某些继承标志的子树?
- python - 如何修复 TypeError:“NoneType”对象不可迭代
- database-design - 用于在通知源上存储通用过滤器的数据库设计