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
相关产品推荐
相关产品推荐

