You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BizTalk:XSLT1.0中如何将多节点值传入C#函数获取目标用户?

问题描述

需要用XSLT 1.0处理指定XML数据,筛选出CookTime时间戳最新的Burger节点,并将对应的User值写入<LatestBurgerCook>节点。

原始XML数据

<xml>
<Burger>
  <CookTime>"2023-04-03T15:13:33.8100000"</CookTime>
  <User>Billy</User>
</Burger>
<Burger>
  <CookTime>"2023-04-01T15:13:33.8100000"</CookTime>
  <User>Bob</User>
</Burger>
<Burger>
  <CookTime>"2023-04-03T17:13:33.8100000"</CookTime>
  <User>Jill</User>
</Burger>
</xml>

预期输出

<LatestBurgerCook>
   Jill
</LatestBurgerCook>

尝试的实现方式

尝试通过调用C#函数传递多个CookTime节点实现逻辑,编写的XSLT片段如下:

<xsl:variable name="maxCookedTime">
   <xsl:value-of select="userCSharp:LoadLatestCookTime(xml/Burger/CookTime)"/>
</xsl:variable name="maxCookedTime">

对应的C#函数(无法正常工作):

public static string LoadLatestCookTime(XPathNodeIterator nodes)
{
    List<DateTime> dateTimes = new List<DateTime>();
        
    foreach(var node in nodes)
        dateTimes.Add(Convert.ToDateTime(s));
            
    DateTime maximumDateTime = dateTimes.Max();
            
    return maximumDateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffffff");
}

咨询问题

  1. 上述方式是否可行?若方法有误,问题出在哪里?
  2. 在仅支持XSLT 1.0 + MSXSL C#函数的限制下,还有哪些可行方案?

解决方案

一、原方法的问题与修正

原思路可行,但C#函数存在两处关键错误:

  • 遍历XPathNodeIterator时未正确迭代:需调用MoveNext()才能遍历节点,直接foreach无法正常获取内容。
  • 未正确处理节点值:代码中使用了未定义的变量s,且未去除CookTime值前后的双引号,导致时间转换失败。

修正后的C#函数

public static string LoadLatestCookTime(XPathNodeIterator nodes)
{
    List<DateTime> dateTimes = new List<DateTime>();
    while (nodes.MoveNext())
    {
        // 去除时间字符串前后的双引号后转换为DateTime
        string timeStr = nodes.Current.Value.Trim('"');
        if (DateTime.TryParse(timeStr, out DateTime dt))
        {
            dateTimes.Add(dt);
        }
    }
    if (dateTimes.Count == 0)
        return string.Empty;
    DateTime maximumDateTime = dateTimes.Max();
    // 返回带双引号的格式,与原CookTime格式匹配
    return $"\"{maximumDateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffffff")}\"";
}

配套完整XSLT代码

需先声明C#扩展函数的命名空间,再通过获取到的最大时间戳匹配对应Burger节点:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:userCSharp="urn:cs-functions"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                exclude-result-prefixes="userCSharp msxsl">

  <msxsl:script language="C#" implements-prefix="userCSharp">
    <![CDATA[
    public static string LoadLatestCookTime(XPathNodeIterator nodes)
    {
        List<DateTime> dateTimes = new List<DateTime>();
        while (nodes.MoveNext())
        {
            string timeStr = nodes.Current.Value.Trim('"');
            if (DateTime.TryParse(timeStr, out DateTime dt))
            {
                dateTimes.Add(dt);
            }
        }
        if (dateTimes.Count == 0)
            return string.Empty;
        DateTime maximumDateTime = dateTimes.Max();
        return $"\"{maximumDateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffffff")}\"";
    }
    ]]>
  </msxsl:script>

  <xsl:template match="/">
    <LatestBurgerCook>
      <xsl:variable name="maxTime" select="userCSharp:LoadLatestCookTime(xml/Burger/CookTime)"/>
      <xsl:value-of select="xml/Burger[CookTime = $maxTime]/User"/>
    </LatestBurgerCook>
  </xsl:template>

</xsl:stylesheet>

二、纯XSLT 1.0方案(无需C#函数)

利用ISO8601时间戳的字符串排序特性,直接对Burger节点按CookTime降序排序,取第一个节点的User值:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <LatestBurgerCook>
      <xsl:for-each select="xml/Burger">
        <!-- 去掉引号后按文本降序排序,ISO8601格式字符串大的时间更晚 -->
        <xsl:sort select="translate(CookTime, '&quot;', '')" data-type="text" order="descending"/>
        <xsl:if test="position() = 1">
          <xsl:value-of select="User"/>
        </xsl:if>
      </xsl:for-each>
    </LatestBurgerCook>
  </xsl:template>

</xsl:stylesheet>

内容的提问来源于stack exchange,提问作者Kieran Ojakangas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:02:47