如何从 xml 中删除空行到 XSLT3.0 中的 CSV 输出
How to remove empty lines from xml to CSV output in XSLT3.0
我有 XML 数据,我使用 XSLT 从 XML 转换为输出 csv 格式的文本。它在满足过滤条件时生成输出。我现在需要代码在不满足过滤条件时停止生成任何输出。目前不满足过滤条件时生成header
我尝试设置全局变量,但 none 似乎可以使用 2 个正在使用的模板。
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="delimiter" select="','"/>
<xsl:param name="xslt.transform.params"></xsl:param>
<xsl:variable name="countryCode">
<xsl:value-of select="$xslt.transform.params"/>
</xsl:variable>
<csv:columns>
<column>ORIG</column>
<column>CUST</column>
<column>PARTY</column>
<column>ACCOUNT1</column>
<column>ACCOUNT2</column>
<column>CURRENCY</column>
<column>SUM1</column>
<column>SUM2</column>
<column>SUM3</column>
<column>SUM4</column>
<column>SUM5</column>
<column>SUM6</column>
<column>SUM7</column>
<column>SUM8</column>
<column>SUM9</column>
<column>SUM10</column>
<column>SUM11</column>
<column>SUM12</column>
</csv:columns>
<xsl:template match="/">
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="/DATA/G">
<xsl:variable name="result" select="."/>
<xsl:variable name="orgsysref" select="ORIG"/>
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:variable name="vCountry" select="fn:substring($orgsysref,1,2)"/>
<xsl:if test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode">
<xsl:variable name="column" select="."/>
<xsl:variable name="value" select="$result/*[name() = $column]"/>
<xsl:value-of select="$value"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
输入信息:
<DATA>
<G>
<ORIG>test107015196</ORIG>
<CUST>30AB00000197776</CUST>
<PARTY>customer</PARTY>
<ACCOUNT1>0432007015196</ACCOUNT1>
<ACCOUNT2>Customer</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>440.26</SUM1>
<SUM2>3</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>16.66</SUM5>
<SUM6>1</SUM6>
<SUM7>423.6</SUM7>
<SUM8>2</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
<G>
<ORIG>test106438731</ORIG>
<CUST>3000KJ3324638</CUST>
<PARTY>Distrißüter</PARTY>
<ACCOUNT1>04910438731</ACCOUNT1>
<ACCOUNT2>Distrißüter</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>312.18</SUM1>
<SUM2>1</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>312.18</SUM5>
<SUM6>1</SUM6>
<SUM7>0</SUM7>
<SUM8>0</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
<G>
<ORIG>test203084024</ORIG>
<CUST>30XY0013478518</CUST>
<PARTY>Test UAT DE</PARTY>
<ACCOUNT1>0492003f084024</ACCOUNT1>
<ACCOUNT2>Testing UAT DE</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>2745.79</SUM1>
<SUM2>12</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>2751.68</SUM5>
<SUM6>11</SUM6>
<SUM7>-5.89</SUM7>
<SUM8>1</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
</DATA>
实际结果:
ORIG,CUST,PARTY,ACCOUNT1,ACCOUNT2,CURRENCY,SUM1,SUM2,SUM3,SUM4,SUM5,SUM6,SUM7,SUM8,SUM9,SUM10,SUM11,SUM12
预期结果:没有任何 headers 的输出。
谢谢!
将<xsl:text>
</xsl:text>
移动到xsl:if
中并改变嵌套,将<xsl:for-each select="document('')/*/csv:columns/*">
包裹到xsl:if
中,在我看来好像是test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode"
不以任何方式取决于 for-each
.
的值
最后,整个代码看起来像 XSLT 1,而不是使用 XSLT 2 或 3 功能(如 [=16= 类型的变量],仅在模式或应用模板中与 =
进行比较, xsl:value-of separator
输出逗号分隔值)。
您在每列循环内执行的工作可以在其外部完成,解决此问题即可解决问题:
<xsl:template match="/DATA/G">
<xsl:variable name="result" select="."/>
<xsl:variable name="orgsysref" select="ORIG"/>
<xsl:variable name="vCountry" select="fn:substring($orgsysref,1,2)"/>
<xsl:if test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode">
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:variable name="column" select="."/>
<xsl:variable name="value" select="$result/*[name() = $column]"/>
<xsl:value-of select="$value"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
注意换行符现在是如何在条件语句中输出的。
作为奖励,请对您的代码发表一些评论:
(a) 在除第一个以外的每个项目之前输出分隔符比在除最后一个以外的每个项目之后输出分隔符效率更高。那是因为它不涉及前瞻(last()
的评估),所以它不会干扰流水线评估。一些处理器当然会为你优化这个。
(b) 在 运行 时使用 document('') 访问样式表是 XSLT 1.0 的一个非常糟糕的后遗症。将数据放在全局变量中要好得多。对于 document(''),(i) 源样式表必须在执行时可用,而不仅仅是在编译时,并且 (ii) 您必须阅读它两次,因为源文档中的空白剥离规则与样式表中的那些。
我有 XML 数据,我使用 XSLT 从 XML 转换为输出 csv 格式的文本。它在满足过滤条件时生成输出。我现在需要代码在不满足过滤条件时停止生成任何输出。目前不满足过滤条件时生成header
我尝试设置全局变量,但 none 似乎可以使用 2 个正在使用的模板。
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="delimiter" select="','"/>
<xsl:param name="xslt.transform.params"></xsl:param>
<xsl:variable name="countryCode">
<xsl:value-of select="$xslt.transform.params"/>
</xsl:variable>
<csv:columns>
<column>ORIG</column>
<column>CUST</column>
<column>PARTY</column>
<column>ACCOUNT1</column>
<column>ACCOUNT2</column>
<column>CURRENCY</column>
<column>SUM1</column>
<column>SUM2</column>
<column>SUM3</column>
<column>SUM4</column>
<column>SUM5</column>
<column>SUM6</column>
<column>SUM7</column>
<column>SUM8</column>
<column>SUM9</column>
<column>SUM10</column>
<column>SUM11</column>
<column>SUM12</column>
</csv:columns>
<xsl:template match="/">
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="/DATA/G">
<xsl:variable name="result" select="."/>
<xsl:variable name="orgsysref" select="ORIG"/>
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:variable name="vCountry" select="fn:substring($orgsysref,1,2)"/>
<xsl:if test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode">
<xsl:variable name="column" select="."/>
<xsl:variable name="value" select="$result/*[name() = $column]"/>
<xsl:value-of select="$value"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
输入信息:
<DATA>
<G>
<ORIG>test107015196</ORIG>
<CUST>30AB00000197776</CUST>
<PARTY>customer</PARTY>
<ACCOUNT1>0432007015196</ACCOUNT1>
<ACCOUNT2>Customer</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>440.26</SUM1>
<SUM2>3</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>16.66</SUM5>
<SUM6>1</SUM6>
<SUM7>423.6</SUM7>
<SUM8>2</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
<G>
<ORIG>test106438731</ORIG>
<CUST>3000KJ3324638</CUST>
<PARTY>Distrißüter</PARTY>
<ACCOUNT1>04910438731</ACCOUNT1>
<ACCOUNT2>Distrißüter</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>312.18</SUM1>
<SUM2>1</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>312.18</SUM5>
<SUM6>1</SUM6>
<SUM7>0</SUM7>
<SUM8>0</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
<G>
<ORIG>test203084024</ORIG>
<CUST>30XY0013478518</CUST>
<PARTY>Test UAT DE</PARTY>
<ACCOUNT1>0492003f084024</ACCOUNT1>
<ACCOUNT2>Testing UAT DE</ACCOUNT2>
<CURRENCY>EUR</CURRENCY>
<SUM1>2745.79</SUM1>
<SUM2>12</SUM2>
<SUM3>0</SUM3>
<SUM4>0</SUM4>
<SUM5>2751.68</SUM5>
<SUM6>11</SUM6>
<SUM7>-5.89</SUM7>
<SUM8>1</SUM8>
<SUM9>0</SUM9>
<SUM10>0</SUM10>
<SUM11>0</SUM11>
<SUM12>0</SUM12>
</G>
</DATA>
实际结果:
ORIG,CUST,PARTY,ACCOUNT1,ACCOUNT2,CURRENCY,SUM1,SUM2,SUM3,SUM4,SUM5,SUM6,SUM7,SUM8,SUM9,SUM10,SUM11,SUM12
预期结果:没有任何 headers 的输出。
谢谢!
将<xsl:text>
</xsl:text>
移动到xsl:if
中并改变嵌套,将<xsl:for-each select="document('')/*/csv:columns/*">
包裹到xsl:if
中,在我看来好像是test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode"
不以任何方式取决于 for-each
.
最后,整个代码看起来像 XSLT 1,而不是使用 XSLT 2 或 3 功能(如 [=16= 类型的变量],仅在模式或应用模板中与 =
进行比较, xsl:value-of separator
输出逗号分隔值)。
您在每列循环内执行的工作可以在其外部完成,解决此问题即可解决问题:
<xsl:template match="/DATA/G">
<xsl:variable name="result" select="."/>
<xsl:variable name="orgsysref" select="ORIG"/>
<xsl:variable name="vCountry" select="fn:substring($orgsysref,1,2)"/>
<xsl:if test="$vCountry = fn:substring-before($countryCode,'|') or $vCountry = fn:substring-after($countryCode, '|') or $vCountry = $countryCode">
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:variable name="column" select="."/>
<xsl:variable name="value" select="$result/*[name() = $column]"/>
<xsl:value-of select="$value"/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
注意换行符现在是如何在条件语句中输出的。
作为奖励,请对您的代码发表一些评论:
(a) 在除第一个以外的每个项目之前输出分隔符比在除最后一个以外的每个项目之后输出分隔符效率更高。那是因为它不涉及前瞻(last()
的评估),所以它不会干扰流水线评估。一些处理器当然会为你优化这个。
(b) 在 运行 时使用 document('') 访问样式表是 XSLT 1.0 的一个非常糟糕的后遗症。将数据放在全局变量中要好得多。对于 document(''),(i) 源样式表必须在执行时可用,而不仅仅是在编译时,并且 (ii) 您必须阅读它两次,因为源文档中的空白剥离规则与样式表中的那些。