提问人:Ana Filipa Ferreira 提问时间:10/11/2023 最后编辑:Charudatta ManwatkarAna Filipa Ferreira 更新时间:10/13/2023 访问量:50
使用 xslt 将 XML 转 CSV,创建一个额外的行
XML to CSV using xslt create an extra line
问:
我有这个 XML,我想要一个 csv 格式: 我正在将python与lxml.etree库一起使用
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RsuProtocol schemaVersion="1.11" RefSchemaFile="xxxx.xsd">
<UpdateStep>
<Phase>x1Activation</Phase>
<TimestampStart>1687771672000</TimestampStart>
<TimestampEnd>1687771828000</TimestampEnd>
</UpdateStep>
<UpdateStep>
<Phase>x2Execution</Phase>
<TimestampStart>1687771828000</TimestampStart>
<TimestampEnd>1687771907000</TimestampEnd>
<Warning>
<WarnCode>0x00000000</WarnCode>
<Count>2</Count>
<FirstOccurrence>1687771907</FirstOccurrence>
<SpecificWarnCode>blablabla</SpecificWarnCode>
<WarnMessage>Hello</WarnMessage>
</Warning>
<Warning>
<WarnCode>0x11111111</WarnCode>
<Count>1</Count>
<FirstOccurrence>1687771907</FirstOccurrence>
<SpecificWarnCode>helo</SpecificWarnCode>
<WarnMessage>Hello</WarnMessage>
</Warning>
</UpdateStep>
<UpdateStep>
<Phase>x3MguCompletion</Phase>
<TimestampStart>1687771907000</TimestampStart>
<TimestampEnd>1687771965000</TimestampEnd>
</UpdateStep>
</RsuProtocol>
我想要这个输出:
"1","x1Activation","","2023-06-26 09:27:52.000000000","2023-06-26 09:30:28.000000000","","","","",""
"2","x2Execution","","2023-06-26 09:30:28.000000000","2023-06-26 09:31:47.000000000","0x00000000","2","2023-06-26 09:31:47.000000000","blablabla","Hello"
"3","x2Execution","","2023-06-26 09:30:28.000000000","2023-06-26 09:31:47.000000000","0x11111111","1","2023-06-26 09:31:47.000000000","helo","Hello"
"4","x3Completion","","2023-06-26 09:31:47.000000000","2023-06-26 09:32:45.000000000","","","","",""
我有这个输出:
"1","x1Activation","","2023-06-26 09:27:52.000000000","2023-06-26 09:30:28.000000000","","","","",""
"2","x2Execution","","2023-06-26 09:30:28.000000000","2023-06-26 09:31:47.000000000","0x00000000","2","2023-06-26 09:31:47.000000000","blablabla","Hello"
"3","x3Completion","","2023-06-26 09:31:47.000000000","2023-06-26 09:32:45.000000000","","","","",""
使用我正在使用的 xslt,我只获取 Phase= 'x2Execution' 的一行,我想获取两个“警告”信息,阶段的每一行一个。
这是我正在使用的 xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/RsuProtocol" name="FBM_UPDATE">
<xsl:for-each select="UpdateStep">
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="position()"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="Phase"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="DiagnosisAddress"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data">
<xsl:call-template name="get-datetime-from-timestamp">
<xsl:with-param name="timestamp">
<xsl:call-template name="convert-to-null">
<xsl:with-param name="input" select="TimestampStart"/>
<xsl:with-param name="value" select="'-1'"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data">
<xsl:call-template name="get-datetime-from-timestamp">
<xsl:with-param name="timestamp">
<xsl:call-template name="convert-to-null">
<xsl:with-param name="input" select="TimestampEnd"/>
<xsl:with-param name="value" select="'-1'"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="Warning/WarnCode"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="Warning/Count"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data">
<xsl:call-template name="get-datetime-from-timestamp">
<xsl:with-param name="timestamp">
<xsl:call-template name="convert-to-null">
<xsl:with-param name="input" select="Warning/FirstOccurrence"/>
<xsl:with-param name="value" select="'-1'"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="Warning/SpecificWarnCode"/>
</xsl:call-template>
<xsl:call-template name="format-csv-field">
<xsl:with-param name="data" select="Warning/WarnMessage"/>
<xsl:with-param name="no-delim" select="'true'"/>
</xsl:call-template>
<xsl:value-of select="$new-line"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答:
0赞
michael.hor257k
10/11/2023
#1
您发布的样式表会引发错误,因为缺少命名模板。
不过,我认为实际问题已经足够清楚了,所以这里有一个简化的例子,你可以用它作为你的起点:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/RsuProtocol">
<xsl:apply-templates select="UpdateStep"/>
</xsl:template>
<xsl:template match="UpdateStep">
<xsl:variable name="common">
<xsl:text>,</xsl:text>
<xsl:value-of select="Phase"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="TimestampStart"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="TimestampEnd"/>
<xsl:text>,</xsl:text>
</xsl:variable>
<xsl:choose>
<xsl:when test="Warning">
<xsl:apply-templates select="Warning">
<xsl:with-param name="common" select="$common"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:number count="UpdateStep[not(Warning)] | Warning" level="any"/>
<xsl:value-of select="$common"/>
<xsl:text>"","" </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Warning">
<xsl:param name="common"/>
<xsl:number count="UpdateStep[not(Warning)] | Warning" level="any"/>
<xsl:value-of select="$common"/>
<xsl:value-of select="WarnCode"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="Count"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
应用于输入 XML 示例,这将产生:
结果
1,x1Activation,1687771672000,1687771828000,"",""
2,x2Execution,1687771828000,1687771907000,0x00000000,2
3,x2Execution,1687771828000,1687771907000,0x11111111,1
4,x3MguCompletion,1687771907000,1687771965000,"",""
或者,您可以分 2 次进行转换:首先,通过使每个警告成为完整步骤来“展平”输入,其中包含父步骤中的所有数据;然后统一处理结果,为每个步骤创建一行。
评论
0赞
Ana Filipa Ferreira
10/11/2023
谢谢,每行的第一个值 position() 呢?Souldn 我们不是为每个 UpdateStep 都有一个 for-each 吗?
0赞
Ana Filipa Ferreira
10/11/2023
这是我使用的 python 脚本 ''' file_xslt = “main.xslt” 解析器 = ET。XMLParser(recover=True) xslt = ET.parse(file_xslt, parser=parser) transform = ET.XSLT(xslt) dom = ET.parse('code/src2.xml') newdom = transform(dom) result = str(newdom, 'UTF-8') print(result) ''' 我根据您的建议获得了一个空结果,您知道可能出了什么问题吗?谢谢
0赞
michael.hor257k
10/11/2023
1. 除非您选择我回答中提到的替代方法,否则您不能使用该功能。我正在使用该指令按顺序对每一行进行编号,无论它是由(空)还是由 .2. 我已经使用您的输入测试了我的答案,结果就是我发布的。恐怕我不知道你这边会有什么问题。--- 附言请不要在评论中发布代码。position()
xsl:number
UpdateStep
Warning
评论