XSLT 2.0 按另一个样式表中的变量排序

Posted

技术标签:

【中文标题】XSLT 2.0 按另一个样式表中的变量排序【英文标题】:XSLT 2.0 Sort by variable from another style sheet 【发布时间】:2020-01-16 19:46:16 【问题描述】:

我需要创建按从另一个 XSLT 中提取的数值排序的 XML,我将其用作交叉引用。 以下源 XML (source.xml) 在 Partner/Header/@whse 处有四个字母字符。

<?xml version="1.0" encoding="UTF-8"?>
<Partner partnerId="TradingPartner1">
    <Header whse="NCCH" >
        <Contract claimNumber="00000000" />
    </Header>
    <Header whse="TXAU" >
        <Contract claimNumber="00000000" />
    </Header>
    <Header whse="LANO" >
        <Contract claimNumber="00000000" />
    </Header>
    <Header whse="MIGR">
        <Contract claimNumber="00000000" />
    </Header>
    <Header whse="TXHO">
        <Contract claimNumber="00000000" />
    </Header>
</Partner>

我需要交叉引用字母字符以获取 DUNS+4。 我使用这个 XSLT (Duns_config.xslt) 来获取 DUNS。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template name="SHIPTODUNS">
    <xsl:param name="Whse" />
    <xsl:choose>
        <xsl:when test="$Whse = 'LANO'"><xsl:value-of select="'0044893600101'" /></xsl:when>
        <xsl:when test="$Whse = 'TXHO'"><xsl:value-of select="'0044893600103'" /></xsl:when>
        <xsl:when test="$Whse = 'TXAU'"><xsl:value-of select="'0044893600105'" /></xsl:when>
        <xsl:when test="$Whse = 'NCCH'"><xsl:value-of select="'0044893600214'" /></xsl:when>
        <xsl:when test="$Whse = 'MIGR'"><xsl:value-of select="'8949713340601'" /></xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

在主 XSLT (Transaction.xslt) 中,我包含了 Duns_config.xslt 并调用 SHIPTODUNS 将数据放入变量 $headerDuns。 然后我得到 DUNS+4 的最后三位,并将它们放入变量 $varWhse 并尝试按此变量排序:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:include href="Duns_config.xslt"/> 
    <xsl:template match="Partner">
        <Partner partnerId="./@partnerId">
            <xsl:apply-templates select="./Header" />
        </Partner>
    </xsl:template>

    <xsl:template match="Header">
        <xsl:variable name="headerDuns">
            <xsl:call-template name = "SHIPTODUNS">
                <xsl:with-param name="Whse" select="./@whse" />
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="varWhse">           
            <xsl:value-of select="substring($headerDuns, 11, 3)" />
        </xsl:variable>
        <xsl:for-each select="current()">
        <xsl:sort select="$varWhse" />
        <transaction varwhse="$varWhse">
            <duns number="$headerDuns" />
        </transaction>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出未按 $varWhse 排序:

<?xml version="1.0" encoding="UTF-8"?>
<Partner partnerId="TradingPartner1">
   <transaction varwhse="214">
      <duns number="0044893600214"/>
   </transaction>
   <transaction varwhse="105">
      <duns number="0044893600105"/>
   </transaction>
   <transaction varwhse="101">
      <duns number="0044893600101"/>
   </transaction>
   <transaction varwhse="601">
      <duns number="8949713340601"/>
   </transaction>
   <transaction varwhse="103">
      <duns number="0044893600103"/>
   </transaction>
</Partner>

我希望数据像这样出来:

<?xml version="1.0" encoding="UTF-8"?>
<Partner partnerId="TradingPartner1">
   <transaction varwhse="101">
      <duns number="0044893600101"/>
   </transaction>
   <transaction varwhse="103">
      <duns number="0044893600103"/>
   </transaction>
   <transaction varwhse="105">
      <duns number="0044893600105"/>
   </transaction>
   <transaction varwhse="214">
      <duns number="0044893600214"/>
   </transaction>
   <transaction varwhse="601">
      <duns number="8949713340601"/>
   </transaction>
</Partner>

有人看到我做错了什么或有其他方法吗? 这是我在这个网站上的第一篇文章。这是很多信息,我希望它是有道理的。

【问题讨论】:

这是未来的有用参考 【参考方案1】:

您的代码的一个问题是您的Header 模板中的xsl:sort 不是第一条指令; xsl:sort 必须是第一条指令。另一个问题是排序出现在Header 模板中,但它必须应用于更高级别。要纠正这些错误,必须对模板进行一些重组。

对于以下解决方案,我选择将所有逻辑放入一个模板中 - 分两步:

    用包含item 元素的子数据结构填充名为mapping 的变量。 使用排序 xsl:for-each 遍历该变量并输出transaction 元素。

结果如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:include href="Duns_config.xslt"/> 

    <xsl:template match="Partner">
        <Partner partnerId="./@partnerId">
            <xsl:variable name="mapping">
                <xsl:for-each select="Header">
                    <xsl:variable name="headerDuns">
                        <xsl:call-template name = "SHIPTODUNS">
                            <xsl:with-param name="Whse" select="@whse" />
                        </xsl:call-template>
                    </xsl:variable>
                    <xsl:variable name="varWhse">           
                        <xsl:value-of select="substring($headerDuns, 11, 3)" />
                    </xsl:variable>
                    <item>
                        <whse><xsl:value-of select="$varWhse" /></whse>
                        <duns><xsl:value-of select="$headerDuns" /></duns>
                    </item>
                </xsl:for-each>
            </xsl:variable>
            <xsl:for-each select="$mapping/item">
                <xsl:sort select="whse" />        <!-- See how xsl:sort is the first instruction -->
                <transaction varwhse="whse">
                    <duns number="duns"/>
                </transaction>
            </xsl:for-each>
        </Partner>
    </xsl:template>

</xsl:stylesheet>

它的输出是:

<?xml version="1.0" encoding="UTF-8"?>
<Partner partnerId="TradingPartner1">
   <transaction varwhse="101">
      <duns number="0044893600101"/>
   </transaction>
   <transaction varwhse="103">
      <duns number="0044893600103"/>
   </transaction>
   <transaction varwhse="105">
      <duns number="0044893600105"/>
   </transaction>
   <transaction varwhse="214">
      <duns number="0044893600214"/>
   </transaction>
   <transaction varwhse="601">
      <duns number="8949713340601"/>
   </transaction>
</Partner>

如你所愿。

【讨论】:

感谢您的帮助。我能够将它应用到我的 XSLT 并获得所需的结果!!我从来没有想过一个变量里面有一个变量......更不用说一个里面的两个了:)。这实际上开辟了一种完全不同的思维方式来解决我将来遇到的问题!!!!【参考方案2】:

得到choose的结果后应用排序。发生的情况是您仍在生成 xml 输出,但您在 Header 项目级别对其进行排序。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:include href="Duns_config.xslt"/> 
    <xsl:template match="Partner">
        <xsl:variable name="partial">
            <PartnerTemp partnerId="./@partnerId">
                <xsl:apply-templates select="./Header" />
            </PartnerTemp>
        </xsl:variable>
        <xsl:apply-templates select="$partial"></xsl:apply-templates>
    </xsl:template>
    <xsl:template match="PartnerTemp">
        <Partner partnerId="./@partnerId">
            <xsl:perform-sort select="transaction">
                <xsl:sort select="@varwhse"/>
            </xsl:perform-sort>
        </Partner>
    </xsl:template>
    <xsl:template match="Header">
        <xsl:variable name="headerDuns">
            <xsl:call-template name = "SHIPTODUNS">
                <xsl:with-param name="Whse" select="./@whse" />
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="varWhse">           
            <xsl:value-of select="substring($headerDuns, 11, 3)" />
        </xsl:variable>

        <xsl:for-each select="current()">               
            <transaction varwhse="$varWhse">              
                <duns number="$headerDuns" />
            </transaction>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

【讨论】:

这个解决方案也有效!感谢您提供另一种获得相同结果的方法。

以上是关于XSLT 2.0 按另一个样式表中的变量排序的主要内容,如果未能解决你的问题,请参考以下文章

为啥 XSLT 文档被认为是“样式表”?

当我将 XSLT 样式表应用到 XML 文件时,啥也没有出现

对同一个 XSL 样式表使用不同的 HTML 模板

可以使用 XSLT 样式表填充现有 Excel 工作表吗?

SQL选择表中具有最大值的行,按另一列排序

xslt - 检查文档是不是存在