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

问题描述 投票:0回答:1

我有这个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>

python csv xml-parsing xslt-1.0
1个回答
0
投票

您发布的样式表会抛出错误,因为指定的模板丢失。

不过,我认为实际问题已经足够清楚了,所以这里有一个简化的示例,您可以将其用作起点:

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,"",""

或者,您可以分两遍进行转换:首先,通过使每个警告成为一个完整步骤(包含父步骤中的所有数据)来“展平”输入;然后统一处理结果,为每个步骤创建一行。

© www.soinside.com 2019 - 2024. All rights reserved.