使用xslt将XML转换为CSV创建额外的行

l3zydbqr  于 2023-10-13  发布在  其他
关注(0)|答案(1)|浏览(101)

我有这个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'的一行,我想获得两个“warning”信息,每个“warning”信息用于阶段的每一行。

这是我使用的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>
sh7euo9m

sh7euo9m1#

您发布的样式表抛出错误,因为命名模板丢失。
尽管如此,我认为实际问题已经足够清楚了,所以这里有一个简化的例子,你可以用它作为你的起点:

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>"",""&#10;</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>&#10;</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个过程中进行转换:首先,通过使每个警告成为一个完整的步骤,包含来自父步骤的所有数据,来“扁平化”输入;然后统一处理结果,为每一步创建一行。

相关问题