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

Schematron自定义命名空间localFunctions引发SXST0001验证错误

解决Schematron自定义函数调用触发SXST0001错误

使用schxslt 10.1.0编译包含自定义命名空间函数的Schematron文件后,通过SaxonCS 12.5.0验证XML时触发SXST0001错误,注释函数调用行则验证正常,更换命名空间URI也无法解决问题。


命名空间定义

<schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fct="localFunctions" queryBinding="xslt2">
    <ns prefix="gl-plt" uri="http://www.xbrl.org/int/gl/plt/2010-04-16"/>
    <ns prefix="gl-cor" uri="http://www.xbrl.org/int/gl/cor/2006-10-25"/>
    <ns prefix="gl-bus" uri="http://www.xbrl.org/int/gl/bus/2006-10-25"/>
    <ns prefix="gl-muc" uri="http://www.xbrl.org/int/gl/muc/2006-10-25"/>
    <ns prefix="xbrli" uri="http://www.xbrl.org/2003/instance"/>
    <ns prefix="ds" uri="http://www.w3.org/2000/09/xmldsig#"/>
    <ns prefix="xades" uri="http://uri.etsi.org/01903/v1.3.2#"/>
    <ns prefix="edefter" uri="http://www.edefter.gov.tr"/>
    <ns prefix="fct" uri="localFunctions"/>
    <ns prefix="defterek" uri="http://www.edefter.gov.tr/ek"/>
    <title>Büyük defter dokümanlarını kontrol etmek için gerekli olan schematron kuralları</title>
    <let name="periodCoveredStart" value="/edefter:defter/xbrli:xbrl/gl-cor:accountingEntries/gl-cor:documentInfo/gl-cor:periodCoveredStart"/>
    <let name="periodCoveredEnd" value="/edefter:defter/xbrli:xbrl/gl-cor:accountingEntries/gl-cor:documentInfo/gl-cor:periodCoveredEnd"/>
    <let name="vknTckn" value="/edefter:defter/xbrli:xbrl/xbrli:context/xbrli:entity/xbrli:identifier"/>
    <let name="donemYil" value="substring($periodCoveredStart,1,4)"/>
    <let name="donemAy" value="substring($periodCoveredStart,6,2)"/>
    <let name="donem" value="number(concat($donemYil,$donemAy))"/>
    <let name="dosyaAdi" value="base-uri()"/>
</schema>

引发问题的规则

<pattern id="accountingentries">
    <rule context="/edefter:defter/xbrli:xbrl/gl-cor:accountingEntries">
        <assert test="gl-cor:documentInfo">gl-cor:documentInfo zorunlu bir elemandır.</assert>
        <assert test="gl-cor:entityInformation">gl-cor:entityInformation zorunlu bir elemandır.</assert>
        <let name="accoundMainIdList" value="gl-cor:entryHeader/gl-cor:entryDetail[1]/gl-cor:account/normalize-space(gl-cor:accountMainID)"/>
        <!-- 注释此行可解决问题,但该函数是验证必需部分 -->
        <assert test="fct:isSorted($accoundMainIdList)">Büyük defterde hesaplar, ana hesap numarası bazında sıralı olmalıdır.</assert>
        <let name="altHesabiOlmayanAnaHesapListesi" value="gl-cor:entryHeader/gl-cor:entryDetail[1]/gl-cor:account[count(gl-cor:accountSub)=0]/normalize-space(gl-cor:accountMainID)"/>
        <let name="altHesabiOlmayanAnaHesapSayisi" value="count($altHesabiOlmayanAnaHesapListesi)"/>
        <let name="farkliAltHesabiOlmayanAnaHesapSayisi" value="count(distinct-values($altHesabiOlmayanAnaHesapListesi))"/>
        <assert test="$altHesabiOlmayanAnaHesapSayisi = $farkliAltHesabiOlmayanAnaHesapSayisi">Alt hesabı olmayan aynı hesaplar aynı gl-cor:entryHeader elemanı içerisinde bulunmalıdır.</assert>
        <let name="altHesapListesi" value="gl-cor:entryHeader/gl-cor:entryDetail[1]/gl-cor:account/gl-cor:accountSub/normalize-space(gl-cor:accountSubID)"/>
        <let name="altHesapSayisi" value="count($altHesapListesi)"/>
        <let name="farkliAltHesapSayisi" value="count(distinct-values($altHesapListesi))"/>
        <assert test="$altHesapSayisi = $farkliAltHesapSayisi">Aynı alt hesaplar aynı gl-cor:entryHeader elemanı içerisinde bulunmalıdır.</assert>
    </rule>
</pattern>

原始函数定义

<xsl:function name="fct:isSorted" as="xs:boolean">
    <xsl:param name="accoundMainIdList" as="xs:string*"/>
    <xsl:variable name="sortedAccountMainIdList" as="xs:string*">
        <xsl:for-each select="$accoundMainIdList">
            <xsl:sort/>
            <xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="s1">
        <xsl:value-of select="string-join($accoundMainIdList,'|')"/>
    </xsl:variable>
    <xsl:variable name="s2">
        <xsl:value-of select="string-join($sortedAccountMainIdList,'|')"/>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="$s1 = $s2">
            <xsl:value-of select="true()"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="false()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:function>

问题原因及解决步骤

SXST0001错误源于XSLT样式表编译失败,核心原因是schxslt默认不会识别直接放在<schema>中的XSLT函数,同时原函数的序列处理逻辑存在类型不匹配问题。

1. 用<sch:xslt>包裹自定义函数

schxslt要求自定义XSLT代码必须放在<sch:xslt>元素内,才能在编译时将其合并到生成的验证样式表中。修改后的函数定义如下:

<sch:xslt>
    <xsl:function name="fct:isSorted" as="xs:boolean">
        <xsl:param name="accoundMainIdList" as="xs:string*"/>
        <!-- 改用perform-sort直接返回排序后的字符串序列,避免节点类型转换错误 -->
        <xsl:variable name="sortedAccountMainIdList" as="xs:string*">
            <xsl:perform-sort select="$accoundMainIdList">
                <xsl:sort/>
            </xsl:perform-sort>
        </xsl:variable>
        <!-- 简化变量定义与返回逻辑 -->
        <xsl:variable name="s1" select="string-join($accoundMainIdList,'|')"/>
        <xsl:variable name="s2" select="string-join($sortedAccountMainIdList,'|')"/>
        <xsl:sequence select="$s1 = $s2"/>
    </xsl:function>
</sch:xslt>

2. 优化序列处理逻辑

原函数使用<xsl:for-each>生成排序结果时,实际会创建节点序列而非字符串序列,容易引发类型不匹配。改用<xsl:perform-sort>可直接返回排序后的字符串序列,同时简化变量定义和返回逻辑,减少潜在错误。

3. 确认命名空间一致性

确保<schema>元素的xmlns:fct属性与<ns prefix="fct" uri="localFunctions"/>的URI完全一致,避免命名空间绑定冲突。

完成以上修改后,重新用schxslt编译Schematron文件,再通过SaxonCS验证即可解决SXST0001错误。


内容的提问来源于stack exchange,提问作者Cemal Çelik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 19:55:54