我有这个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>
您发布的样式表会抛出错误,因为指定的模板丢失。
不过,我认为实际问题已经足够清楚了,所以这里有一个简化的示例,您可以将其用作起点:
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,"",""
或者,您可以分两遍进行转换:首先,通过使每个警告成为一个完整步骤(包含父步骤中的所有数据)来“展平”输入;然后统一处理结果,为每个步骤创建一行。