使用 XSLT 将 XML 转换为 CSV(节点路径为 header)
Convert XML to CSV (with node path as header) using XSLT
如何使用 XSLT 将以下 XML 转换为 CSV?
<tXML>
<Header>
<Source>XPTO</Source>
<User_ID>127</User_ID>
<Message_Type>Ship</Message_Type>
<Company_ID>105</Company_ID>
<Msg_Locale>English (United States)</Msg_Locale>
<Version>2017</Version>
</Header>
<Message>
<Ship>
<ShipSummary>
<ComName>XPTO 123</ComName>
<FacName>6</FacName>
</ShipSummary>
</Ship>
</Message>
</tXML>
tXML/Header/Source
tXML/Header/User_ID
tXML/Header/Message_Type
tXML/Header/Company_ID
tXML/Header/Msg_Locale
tXML/Header/Version
tXML/Message/Ship/ShipSummary/ComName
tXML/Message/Ship/ShipSummary/FacName
XPTO
127
Ship
105
English (United States)
2017
XPTO 123
6
如何获取每个值的“节点路径”,并将其用作 header?
当我 运行 使用 xsltproc 的以下 XSLT 时,我得到了您想要的输出(除了一个例外,末尾有一个额外的空白列)。
非常感谢@Daniel_Haley their solution 打印节点路径的一般问题(如果你喜欢这个,请投票回答)。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:strip-space elements="*" />
<xsl:variable name="delim">;</xsl:variable>
<xsl:template match="/">
<!-- Recurse document for header -->
<xsl:copy>
<xsl:apply-templates select="node()" mode="header"/>
</xsl:copy>
<!-- Linebreak after last column in header -->
<xsl:text>
</xsl:text>
<!-- Recurse document for values -->
<xsl:copy>
<xsl:apply-templates select="node()" />
</xsl:copy>
<!-- Linebreak after last column in row -->
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()">
<xsl:copy-of select="." />
<xsl:value-of select="$delim"/>
</xsl:template>
<!-- -->
<xsl:template match="text()" mode="header">
<xsl:for-each select="ancestor::*">
<xsl:choose>
<!-- avoid beginning slash (at root) -->
<xsl:when test="position() = 1">
<xsl:value-of select="local-name()" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('/',local-name())" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" />
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$delim"/>
<!-- <xsl:apply-templates select="node()" /> -->
</xsl:template>
</xsl:stylesheet>
tXML/Header/Source
tXML/Header/User_ID
tXML/Header/Message_Type
tXML/Header/Company_ID
tXML/Header/Msg_Locale
tXML/Header/Version
tXML/Message/Ship/ShipSummary/ComName
tXML/Message/Ship/ShipSummary/FacName
XPTO
127
Ship
105
English (United States)
2017
XPTO 123
6
如何使用 XSLT 将以下 XML 转换为 CSV?
<tXML>
<Header>
<Source>XPTO</Source>
<User_ID>127</User_ID>
<Message_Type>Ship</Message_Type>
<Company_ID>105</Company_ID>
<Msg_Locale>English (United States)</Msg_Locale>
<Version>2017</Version>
</Header>
<Message>
<Ship>
<ShipSummary>
<ComName>XPTO 123</ComName>
<FacName>6</FacName>
</ShipSummary>
</Ship>
</Message>
</tXML>
tXML/Header/Source | tXML/Header/User_ID | tXML/Header/Message_Type | tXML/Header/Company_ID | tXML/Header/Msg_Locale | tXML/Header/Version | tXML/Message/Ship/ShipSummary/ComName | tXML/Message/Ship/ShipSummary/FacName |
---|---|---|---|---|---|---|---|
XPTO | 127 | Ship | 105 | English (United States) | 2017 | XPTO 123 | 6 |
如何获取每个值的“节点路径”,并将其用作 header?
当我 运行 使用 xsltproc 的以下 XSLT 时,我得到了您想要的输出(除了一个例外,末尾有一个额外的空白列)。
非常感谢@Daniel_Haley their solution 打印节点路径的一般问题(如果你喜欢这个,请投票回答)。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:strip-space elements="*" />
<xsl:variable name="delim">;</xsl:variable>
<xsl:template match="/">
<!-- Recurse document for header -->
<xsl:copy>
<xsl:apply-templates select="node()" mode="header"/>
</xsl:copy>
<!-- Linebreak after last column in header -->
<xsl:text>
</xsl:text>
<!-- Recurse document for values -->
<xsl:copy>
<xsl:apply-templates select="node()" />
</xsl:copy>
<!-- Linebreak after last column in row -->
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()">
<xsl:copy-of select="." />
<xsl:value-of select="$delim"/>
</xsl:template>
<!-- -->
<xsl:template match="text()" mode="header">
<xsl:for-each select="ancestor::*">
<xsl:choose>
<!-- avoid beginning slash (at root) -->
<xsl:when test="position() = 1">
<xsl:value-of select="local-name()" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('/',local-name())" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" />
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$delim"/>
<!-- <xsl:apply-templates select="node()" /> -->
</xsl:template>
</xsl:stylesheet>
tXML/Header/Source | tXML/Header/User_ID | tXML/Header/Message_Type | tXML/Header/Company_ID | tXML/Header/Msg_Locale | tXML/Header/Version | tXML/Message/Ship/ShipSummary/ComName | tXML/Message/Ship/ShipSummary/FacName | |
---|---|---|---|---|---|---|---|---|
XPTO | 127 | Ship | 105 | English (United States) | 2017 | XPTO 123 | 6 |