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

如何使用name()动态应用模板?XSLT转JSON数组元素处理问询

解决XSLT转JSON时动态处理数组元素的问题

我之前也遇到过类似的需求,给你两种实用的解决方案,分场景选择就行:

方案1:预先指定需要转为数组的元素(推荐,可控性强)

如果你明确知道哪些节点是数组容器(比如你的示例里的<tax-lines>),可以先定义一个变量存储这些节点名称,然后针对性处理:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8"/>

  <!-- 定义需要转为数组的容器节点名称 -->
  <xsl:variable name="array-containers" select="('tax-lines', 'items')"/>

  <!-- 根节点处理,输出JSON外层结构 -->
  <xsl:template match="/order">
    {
      <xsl:apply-templates select="*"/>
    }
  </xsl:template>

  <!-- 处理普通节点(非数组容器) -->
  <xsl:template match="*[not(local-name() = $array-containers)]">
    "<xsl:value-of select="local-name()"/>" : "<xsl:value-of select="."/>"<xsl:if test="following-sibling::*">,</xsl:if>
  </xsl:template>

  <!-- 处理数组容器节点 -->
  <xsl:template match="*[local-name() = $array-containers]">
    "<xsl:value-of select="local-name()"/>" : [
      <xsl:apply-templates select="*"/>
    ]<xsl:if test="following-sibling::*">,</xsl:if>
  </xsl:template>

  <!-- 处理数组内的元素节点 -->
  <xsl:template match="*[parent::*[local-name() = $array-containers]]">
    {
      <xsl:apply-templates select="*"/>
    }<xsl:if test="position() != last()">,</xsl:if>
  </xsl:template>
</xsl:stylesheet>

这个方案的好处是你完全可控,想把哪个节点转成数组就加进array-containers变量就行,适合你已经明确数组结构的场景。

方案2:动态判断数组(自动识别多子节点的容器)

如果你的XML结构不固定,需要自动识别“包含多个同名子节点”的容器为数组,可以通过判断子节点数量来实现:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8"/>

  <xsl:template match="/order">
    {
      <xsl:apply-templates select="*"/>
    }
  </xsl:template>

  <!-- 处理普通节点 -->
  <xsl:template match="*[not(count(*[local-name() = local-name(*[1])]) = count(*))]">
    "<xsl:value-of select="local-name()"/>" : "<xsl:value-of select="."/>"<xsl:if test="following-sibling::*">,</xsl:if>
  </xsl:template>

  <!-- 处理自动识别的数组容器 -->
  <xsl:template match="*[count(*[local-name() = local-name(*[1])]) = count(*)]">
    "<xsl:value-of select="local-name()"/>" : [
      <xsl:apply-templates select="*"/>
    ]<xsl:if test="following-sibling::*">,</xsl:if>
  </xsl:template>

  <!-- 处理数组内的元素 -->
  <xsl:template match="*[parent::*[count(*[local-name() = local-name(current())]) = count(parent::*)]]">
    {
      <xsl:apply-templates select="*"/>
    }<xsl:if test="position() != last()">,</xsl:if>
  </xsl:template>
</xsl:stylesheet>

这个方案会自动把所有“子节点名称完全一致”的容器转成数组,适合XML结构灵活多变的场景。

进阶:用XSLT 3.0简化开发

如果你的环境支持XSLT 3.0,直接用内置的JSON序列化功能会更省心,不用手动拼接字符串:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="json" indent="yes"/>

  <!-- 自定义数组节点列表 -->
  <xsl:param name="array-nodes" select="'tax-lines'"/>

  <xsl:template match="/order">
    <xsl:map>
      <xsl:apply-templates select="*"/>
    </xsl:map>
  </xsl:template>

  <xsl:template match="*">
    <xsl:choose>
      <xsl:when test="local-name() = $array-nodes">
        <!-- 转为JSON数组 -->
        <xsl:map-entry key="concat('''', local-name(), '''')" 
                       select="array{*!map{
                         for $child in * return
                           concat('''', local-name($child), ''': ', 
                             if ($child castable as xs:number) then number($child) else concat('''', string($child), '''')
                           )
                       }}"/>
      </xsl:when>
      <xsl:otherwise>
        <!-- 转为普通键值对 -->
        <xsl:map-entry key="concat('''', local-name(), '''')" 
                       select="if (castable as xs:number) then number(.) else string(.)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

你可以根据自己的XSLT版本和业务场景选择对应的方案,测试的时候记得用你提供的<order> XML示例验证一下,调整细节即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:43:36