XSLT for-each 无法提取值
Posted
技术标签:
【中文标题】XSLT for-each 无法提取值【英文标题】:XSLT for-each not able to extract values 【发布时间】:2020-05-16 18:18:57 【问题描述】:我正在尝试使用 xslt 将 xml 转换为所需的 xml。但我无法正确使用 for - each 并且值返回 null。任何人都可以帮助进行 xslt 转换。
这里是 我正在使用的 XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<INB>
<SEG>
<TRN>RAN</TRN>
<VER>8.3</VER>
<WHS>699</WHS>
<xsl:for-each select="message/Lines">
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<xsl:if test="not(normalize-space(message/Lines/Nbr)) = ''">
<NUM>
<xsl:value-of select="normalize-space(message/Lines/Nbr)"/>
</NUM>
</xsl:if>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
</xsl:for-each>
</SEG>
</INB>
</xsl:template>
</xsl:stylesheet>
这是输入 XML:
<message>
<PoNbr>451617926</PoNbr>
<whCode/>
<unitCode/>
<dnrbTime/>
<Lines>
<Nbr>451617926</Nbr>
</Lines>
<Lines>
<Nbr>2</Nbr>
</Lines>
</message>
下面是它返回的输出
在下面它返回的输出中没有使用 for each 语句映射的 Nbr。
输出:
<INB>
<SEG>
<TRN>RAN</TRN>
<VER>8.3</VER>
<WHS>699</WHS>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM/>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM/>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
</SEG>
</INB>
预期输出:
<INB>
<SEG>
<TRN>RAN</TRN>
<VER>8.3</VER>
<WHS>699</WHS>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM>451617926</NUM>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM>2</NUM>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
</SEG>
</INB>
【问题讨论】:
【参考方案1】:仅更改以下代码
<xsl:if test="not(normalize-space(message/Lines/Nbr)) = ''">
改成
<xsl:if test="not(normalize-space(message/Lines/Nbr)='')">
【讨论】:
还需要修复主要的bug;主要错误是未能理解xsl:for-each
更改上下文的常见错误。【参考方案2】:
我调整了所有的 XPath 表达式。看看吧。
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/message">
<INB>
<SEG>
<TRN>RAN</TRN>
<VER>8.3</VER>
<WHS>699</WHS>
<xsl:for-each select="Lines">
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<xsl:if test="not(normalize-space(Nbr)) = ''">
<NUM>
<xsl:value-of select="normalize-space(Nbr)"/>
</NUM>
</xsl:if>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
</xsl:for-each>
</SEG>
</INB>
</xsl:template>
</xsl:stylesheet>
输出 XML
<?xml version='1.0' encoding='UTF-8' ?>
<INB>
<SEG>
<TRN>RAN</TRN>
<VER>8.3</VER>
<WHS>699</WHS>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM>451617926</NUM>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
<LINE>
<SENAM>LINE_SEG</SENAM>
<INVSLN>0</INVSLN>
<EXPQTY>0</EXPQTY>
<NUM>2</NUM>
<STS>A</STS>
<PRT>----</PRT>
</LINE>
</SEG>
</INB>
【讨论】:
此解决方案无法修复@AjeetSingh 在test
表达式中指出的错误。表达式 not(normalize-space(Nbr))
在此数据集上返回 false。比较 false 和 "" 在 XPath 2.0 下是错误的,但在 XPath 1.0 下返回 true。所以它是偶然(在这个数据上)起作用的——一个典型的例子说明为什么需要在 XPath 2.0 中进行更强大的类型检查。
顺便说一句,成语test="normalize-space(Nbr)"
在 1.0 和 2.0 上都有效。有些人不喜欢隐式的 string->boolean 转换,我确实不喜欢,但是这个习惯用法很常见也很方便,我用起来很舒服。并且 Saxon 对其进行了优化——它实际上并不构造规范化的字符串,只是测试是否有任何非空格字符。以上是关于XSLT for-each 无法提取值的主要内容,如果未能解决你的问题,请参考以下文章
XSLT 2.0:根据 for-each -group 的当前索引评估和修改元素值
如何在 XSLT 中打破 for-each 以及如何更新 XSLT 中的现有变量
XSLT - 在嵌套的 for-each 中查找 position()