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

SAXON-HE 10.6下用XSLT将同名元素追加序号转为属性的方法

问题描述
  • 待转换的源XML文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<toplevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <address>
        <line>address line a</line>
        <line>address line b</line>
        <line>address line c</line>
        <line>address line d</line>
    </address>
</toplevel>
  • 源XML结构遵循的XSD Schema定义:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="toplevel">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="address"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="address">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="4" ref="line"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="line" type="xs:string"/>
</xs:schema>
  • 目标转换结果格式(使用SAXON-HE 10.6执行XSLT转换实现):
<?xml version="1.0" encoding="UTF-8"?>
<toplevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <address line1="address line a" line2="address line b" line3="address line c" line4="address line d"/>
</toplevel>
  • 现有XSLT存在的问题:仅当源XML中line元素自带编号属性时可正常运行,实际源数据的line元素无内置编号;尝试添加xsl:for-each逻辑、定义变量均无法实现为生成的line属性追加连续序号的效果。已知line元素最大数量固定为4,支持硬编码实现,但不清楚对应语法,需要可在SAXON-HE 10.6中直接运行的可行方案。
  • 现有存在问题的XSLT代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/">
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates mode="copy" select="."/>
        
    </xsl:template>
    
    <xsl:template match="* | text() | @*" mode="copy">
        <xsl:copy>
            
            <xsl:apply-templates mode="copy" select="@*"/>
            <xsl:apply-templates mode="copy"/>
        </xsl:copy>
        
    </xsl:template>
    
    <xsl:template match="*"/>
    
    <xsl:template match="toplevel" mode="copy">  
        <xsl:copy>            
            <xsl:apply-templates mode="copy" select="address"/> 
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="address" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="convert-to-attr" select="*"/>            
        </xsl:copy> 
    </xsl:template>
    
    <xsl:template match="*" mode="convert-to-attr">
        <xsl:attribute name="{name()}" select="text()"/>
    </xsl:template>
</xsl:stylesheet>
实现方案

问题核心是属性生成逻辑直接使用了line元素本身的名称,没有追加遍历序号。XSLT内置的position()函数可以直接获取当前处理节点在选中节点集合中的顺序位置,不需要额外定义变量,也不需要复杂循环,修改convert-to-attr模式的模板即可实现需求,完全兼容SAXON-HE 10.6的XSLT 2.0支持规范。

修正后的完整XSLT代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/">
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates mode="copy" select="."/>
    </xsl:template>
    
    <xsl:template match="* | text() | @*" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="copy" select="@*"/>
            <xsl:apply-templates mode="copy"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*"/>
    
    <xsl:template match="toplevel" mode="copy">  
        <xsl:copy>            
            <xsl:apply-templates mode="copy" select="address"/> 
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="address" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="convert-to-attr" select="line"/>            
        </xsl:copy> 
    </xsl:template>
    
    <!-- 核心修改:用position()获取序号拼接属性名 -->
    <xsl:template match="line" mode="convert-to-attr">
        <xsl:attribute name="line{position()}" select="."/>
    </xsl:template>
</xsl:stylesheet>

硬编码实现版本(可选)

如果需要严格固定生成4个line属性,哪怕源文件中line数量不足4也生成对应空值属性,可以直接硬编码选取对应位置的line节点,替换上述代码中address匹配的模板即可:

<xsl:template match="address" mode="copy">
    <xsl:copy>
        <xsl:attribute name="line1" select="line[1]"/>
        <xsl:attribute name="line2" select="line[2]"/>
        <xsl:attribute name="line3" select="line[3]"/>
        <xsl:attribute name="line4" select="line[4]"/>
    </xsl:copy> 
</xsl:template>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:12:32