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()

有没有办法在 XSLT 转换中用应用模板替换 for-each?

xslt for-each 和排序问题

从多个for-each XSLT段输出HTML