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

如何用XSLT 1.0追踪XML继承树并生成有序Python类?

XSLT 1.0 处理XML Schema继承树生成Python类的解决方案

1. 递归模板追踪继承树

完全可以用递归<call-template name="supertype"/>实现继承树的追踪,核心逻辑是先处理父类,再处理子类,确保父类定义出现在子类之前。

实现思路

  1. 先定义一个key快速通过类名查找对应的Schema类型节点:
<xsl:key name="type-by-name" match="xs:complexType" use="@name"/>
  1. 编写递归模板,先递归处理当前类的父类,再输出当前类的代码:
<xsl:template name="process-type">
  <xsl:param name="type-name"/>
  <xsl:param name="processed-types"/> <!-- 记录已处理的类,用于去重 -->

  <xsl:variable name="current-type" select="key('type-by-name', $type-name)"/>
  <xsl:if test="$current-type">
    <!-- 获取父类名称(适配extension/restriction两种继承方式) -->
    <xsl:variable name="supertype-name">
      <xsl:choose>
        <xsl:when test="$current-type/xs:extension">
          <xsl:value-of select="$current-type/xs:extension/@base"/>
        </xsl:when>
        <xsl:when test="$current-type/xs:restriction">
          <xsl:value-of select="$current-type/xs:restriction/@base"/>
        </xsl:when>
        <xsl:otherwise/>
      </xsl:choose>
    </xsl:variable>

    <!-- 递归处理父类:如果父类存在且未处理,先调用模板处理父类 -->
    <xsl:if test="$supertype-name != '' and not(contains($processed-types, concat('|', $supertype-name, '|')))">
      <xsl:call-template name="process-type">
        <xsl:with-param name="type-name" select="$supertype-name"/>
        <xsl:with-param name="processed-types" select="$processed-types"/>
      </xsl:call-template>
    </xsl:if>

    <!-- 输出当前类的Python代码(仅当未处理过时) -->
    <xsl:if test="not(contains($processed-types, concat('|', $type-name, '|')))">
      <xsl:text>class </xsl:text>
      <xsl:value-of select="$type-name"/>
      <xsl:if test="$supertype-name != ''">
        <xsl:text>(</xsl:text>
        <xsl:value-of select="$supertype-name"/>
        <xsl:text>):</xsl:text>
      </xsl:if>
      <xsl:text>&#10;    # 生成类属性/方法的逻辑&#10;</xsl:text>
      <!-- 更新已处理类的标记 -->
      <xsl:variable name="new-processed" select="concat($processed-types, '|', $type-name, '|')"/>
      <!-- 后续模板调用时传递new-processed作为更新后的状态 -->
    </xsl:if>
  </xsl:if>
</xsl:template>

这个递归会从目标子类向上遍历到顶层父类,再从顶层开始依次输出,保证父类定义先于子类。

2. 检查类是否已生成(避免重复输出)

XSLT 1.0没有可变变量,需通过状态传递或节点集实现已处理类的追踪:

方法1:字符串标记传递

初始化一个带分隔符的字符串(比如用|包裹类名),在递归调用中传递更新后的字符串:

<!-- 初始状态:空标记,用|作为首尾分隔符避免匹配子串 -->
<xsl:variable name="initial-processed" select="'|'"/>

调用模板时传入该变量,每次处理完类后拼接新的类名到标记中,用contains($processed-types, concat('|', $type-name, '|'))判断是否已处理。

方法2:节点集记录(更可靠,需处理器支持EXSLT)

如果你的XSLT处理器支持EXSLT的exsl:node-set,可以维护一个节点列表记录已处理类:

<!-- 初始化空节点集 -->
<xsl:variable name="processed-nodes">
  <processed-types/>
</xsl:variable>

<!-- 标记类为已处理的辅助模板 -->
<xsl:template name="mark-processed">
  <xsl:param name="type-name"/>
  <xsl:variable name="current-set" select="exsl:node-set($processed-nodes)"/>
  <xsl:copy-of select="$current-set"/>
  <type><xsl:value-of select="$type-name"/></type>
</xsl:template>

检查时判断exsl:node-set($processed-nodes)/type[text()=$type-name]是否存在,存在则跳过输出。

注意事项

  • 加入循环检测:如果Schema中存在循环继承(虽然XML Schema规范不允许,但需防异常),可在递归中加入路径追踪,避免无限递归。
  • 遍历所有类:最终调用时,遍历所有xs:complexType[@name]节点,逐个调用process-type模板,确保所有类都被处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:31:28